Entra:     


Forum: VirtualDJ Plugins

Topic: Updates to the examples?
Would it possible to get the example code on wiki updated to show:

* current headers
* macOS Metal instead of OpenGL

? As someone who is struggling to get the Metal renderer to work, having a good example to work off of would be extremely helpful.

Thanks.

 

Inviato yesterday @ 9:49 pm
Here is the reference:

 VdjVideoEngineMetal = 5
 

Inside OnDraw, the device is a MTLRenderCommandEncoder:
    id<MTLRenderCommandEncoder> commandEncoder;
void *commandEncoderPtr = nullptr;
if (GetDevice(VdjVideoEngineMetal, (void**)&commandEncoderPtr)!=S_OK)
return S_FALSE;
commandEncoder = (__bridge id<MTLRenderCommandEncoder>)(commandEncoderPtr);


The texture you can get from vdj is a MTLTexture
id<MTLTexture> texture;
void *texturePtr = nullptr;
TVertex* vertices = nullptr;
if (GetTexture(VdjVideoEngineMetal, (void**)&texturePtr, &vertices)!=S_OK)
return S_FALSE;
texture = (__bridge id<MTLTexture>)(texturePtr);


To draw something, you'd also need some shaders. For just putting some texture on the screen, you could use vdj's however.
This is how the NDI plugin currently does it:
struct VIn_Texture
{
simd_float2 position;
simd_float2 texCoord;
simd_float4 color;
};

void CReceiveNDI::bitblt(void *texture)
{
float alpha = 1.f;
int srcX=0, srcY=0, srcWidth=curTextureW, srcHeight=curTextureH, dstX=0, dstY=0, dstWidth=width, dstHeight=height;
initImageSize(&srcX, &srcY, &srcWidth, &srcHeight, curTextureAR, 0, width, height, &dstX, &dstY, &dstWidth, &dstHeight);

if (!texture)
return;
if (width<=0 || height<=0 || srcWidth<=0 || srcHeight<=0)
return;

id<MTLTexture> localTexture = (__bridge id<MTLTexture>)texture;

VIn_Texture v[4];

v[0].color = {1.f, 1.f, 1.f, alpha};
v[0].texCoord = {srcX/(float)[localTexture width], srcY/(float)[localTexture height]};
v[0].position = {(float)dstX, (float)dstY};

v[1].color = v[0].color;
v[1].texCoord = {(srcX+srcWidth) / (float)[localTexture width], srcY / (float)[localTexture height]};
v[1].position = {(float)(dstX+dstWidth), (float)dstY};

v[3].color = v[0].color;
v[3].texCoord = {(srcX+srcWidth) / (float)[localTexture width], (srcY+srcHeight) / (float)[localTexture height]};
v[3].position = {(float)(dstX+dstWidth), (float)(dstY+dstHeight)};

v[2].color = v[0].color;
v[2].texCoord = {srcX / (float)[localTexture width], (srcY+srcHeight) / (float)[localTexture height]};
v[2].position = {(float)dstX, (float)(dstY+dstHeight)};

id<MTLRenderCommandEncoder> commandEncoder;
void *commandEncoderPtr = nullptr;
if (GetDevice(VdjVideoEngineMetal, (void**)&commandEncoderPtr)!=S_OK)
return;
commandEncoder = (__bridge id<MTLRenderCommandEncoder>)(commandEncoderPtr);

if (!pipelineTexture)
{
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
if (!shadersLib)
{
//Note: this currently uses the shaders from vdj
//it would be better to use your own shaders and include them in the plugin
id<MTLLibrary> newShadersLib = [[commandEncoder device] newDefaultLibrary];
if (!newShadersLib)
return;
shadersLib = (void*)CFBridgingRetain(newShadersLib);
}
pipelineDescriptor.label = @"Texture Pipeline";
pipelineDescriptor.vertexFunction = [(__bridge id<MTLLibrary>)shadersLib newFunctionWithName:@"renderVertexTexture"];
pipelineDescriptor.fragmentFunction = [(__bridge id<MTLLibrary>)shadersLib newFunctionWithName:@"renderFragmentTexture"];

pipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;

pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormatInvalid;

NSError *error = nil;
id<MTLRenderPipelineState> newPipelineTexture = [[commandEncoder device] newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
if (!newPipelineTexture)
return;
pipelineTexture = (void*)CFBridgingRetain(newPipelineTexture);
}
id<MTLRenderPipelineState> localPipelineTexture = (__bridge id<MTLRenderPipelineState>)pipelineTexture;

static constexpr int nbVertices = 4;
[commandEncoder setVertexBytes:v length:nbVertices*sizeof(VIn_Texture) atIndex:0];
[commandEncoder setFrontFacingWinding:MTLWindingClockwise];
[commandEncoder setCullMode:MTLCullModeNone];
[commandEncoder setRenderPipelineState:localPipelineTexture];
[commandEncoder setFragmentTexture:localTexture atIndex:0];

[commandEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:nbVertices];
}