1
$\begingroup$

I am trying to port my simple app from D3D12 to Metal and I am stuck at rendering a simple triangle.

The window does not show any primitives; only the clear color is visible.

Debugging my application, I noticed, that all primitives are clipped (Performance > Primitives > Primitives Clipped: 100%). I fail to understand why this happens, as these are my coordinates:

struct vertex { float x, y, z; };
static const struct vertex vertices[] =
{
    { 0.0f, 0.5f, 0.0f },
    { 0.5f, -0.5f, 0.0f },
    { -0.5f, -0.5f, 0.0f }
};

What I have tried so far:

  • Explicitly setting the viewport {0, 0, 800, 600, 0, 1}.
  • Explicitly setting scissors {0, 0, 800, 600}.
  • Setting the cull mode to MTLCullModeNone.
  • Setting the fill mode to MTLTriangleFillModeFill.
  • Changing the winding order.
  • Altering the vertex input layout; but I am confident, that mine matches the input.

Are there any pitfalls of Metal that I am missing? (i.e. setting the sample mask like in D3D12?)

My pipeline for reference:

    MTLRenderPipelineDescriptor* descriptor = [MTLRenderPipelineDescriptor new];
    descriptor.vertexFunction   = desc->vertex->handle;
    descriptor.fragmentFunction = desc->pixel->handle;
    descriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
    
    MTLVertexDescriptor* vs = descriptor.vertexDescriptor;
    vs.attributes[0].format = MTLVertexFormatFloat3;
    vs.attributes[0].offset = 0;
    vs.attributes[0].bufferIndex = 0;
    
    vs.layouts[0].stride        = sizeof(float) * 3;
    vs.layouts[0].stepFunction  = MTLVertexStepFunctionPerVertex;
    vs.layouts[0].stepRate      = 1;

Note, that I am NOT using MTKView.

The following is my shader used:

struct Out 
{
    float4 pos [[position]];
};

vertex Out vertexShader(
    const device float3* vertices [[buffer(0)]],
    unsigned int idx [[vertex_id]]
) {
    Out out;
    out.pos = float4(vertices[idx], 1.0);
    return out;
}


fragment float4 fragmentShader(Out in [[stage_in]])
{
    // TODO: Write fragment shader
    return float4(1, 0, 0, 1);
}

EDIT: I made following changes and my triangle is finally being rendered:

struct vertex { float x, y, z, w; };
static const struct vertex vertices[] =
{
    { 0.0f, 0.5f, 0.0f, 1.f },
    { 0.5f, -0.5f, 0.0f, 1.f},
    { -0.5f, -0.5f, 0.0f, 1.f }
};

// Vertex Descriptor
    MTLVertexDescriptor* vs = descriptor.vertexDescriptor;
    vs.attributes[0].format = MTLVertexFormatFloat4;
    vs.attributes[0].offset = 0;
    vs.attributes[0].bufferIndex = 0;
    
    vs.layouts[0].stride        = sizeof(float) * 4;
    vs.layouts[0].stepFunction  = MTLVertexStepFunctionPerVertex;
    vs.layouts[0].stepRate      = 1;

Shader:

struct Out 
{
    float4 pos [[position]];
};

vertex Out vertexShader(
    const device float4* vertices [[buffer(0)]],
    unsigned int idx [[vertex_id]]
) {
    Out out;
    out.pos = vertices[idx];
    return out;
}


fragment float4 fragmentShader(Out in [[stage_in]])
{
    // TODO: Write fragment shader
    return float4(1, 0, 0, 1);
}

I don't understand why my application fails, when using 3D vectors instead of 4D ones. Any ideas?

$\endgroup$
2
$\begingroup$

float3 in Metal Shading Language has the same size/alignment as float4, i.e. 16 bytes. I think your original code would have worked using packed_float3 (12 bytes) in the vertex shader.

$\endgroup$
1
  • $\begingroup$ Indeed, this was it! Thanks $\endgroup$ May 26 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.