Skip to content

Commit

Permalink
metal renderer: use vertex attributes instead of indexing into a buff…
Browse files Browse the repository at this point in the history
…er with the vertex id in the shader. Allows for more flexibility with vertex setup in the future.

Also optimize vertex buffer binding slightly.
  • Loading branch information
slime73 committed Aug 17, 2019
1 parent 55a46ab commit e8278d0
Show file tree
Hide file tree
Showing 5 changed files with 3,664 additions and 3,620 deletions.
94 changes: 68 additions & 26 deletions src/render/metal/SDL_render_metal.m
Expand Up @@ -265,8 +265,36 @@ - (void)dealloc
mtlpipedesc.vertexFunction = mtlvertfn;
mtlpipedesc.fragmentFunction = mtlfragfn;

MTLRenderPipelineColorAttachmentDescriptor *rtdesc = mtlpipedesc.colorAttachments[0];
MTLVertexDescriptor *vertdesc = [MTLVertexDescriptor vertexDescriptor];

switch (cache->vertexFunction) {
case SDL_METAL_VERTEX_SOLID:
/* position (float2) */
vertdesc.layouts[0].stride = sizeof(float) * 2;
vertdesc.layouts[0].stepFunction = MTLStepFunctionPerVertex;

vertdesc.attributes[0].format = MTLVertexFormatFloat2;
vertdesc.attributes[0].offset = 0;
vertdesc.attributes[0].bufferIndex = 0;
break;
case SDL_METAL_VERTEX_COPY:
/* position (float2), texcoord (float2) */
vertdesc.layouts[0].stride = sizeof(float) * 4;
vertdesc.layouts[0].stepFunction = MTLStepFunctionPerVertex;

vertdesc.attributes[0].format = MTLVertexFormatFloat2;
vertdesc.attributes[0].offset = 0;
vertdesc.attributes[0].bufferIndex = 0;

vertdesc.attributes[1].format = MTLVertexFormatFloat2;
vertdesc.attributes[1].offset = sizeof(float) * 2;
vertdesc.attributes[1].bufferIndex = 0;
break;
}

mtlpipedesc.vertexDescriptor = vertdesc;

MTLRenderPipelineColorAttachmentDescriptor *rtdesc = mtlpipedesc.colorAttachments[0];
rtdesc.pixelFormat = cache->renderTargetFormat;

if (blendmode != SDL_BLENDMODE_NONE) {
Expand Down Expand Up @@ -412,7 +440,7 @@ - (void)dealloc
}

static void
METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load, MTLClearColor *clear_color)
METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load, MTLClearColor *clear_color, id<MTLBuffer> vertex_buffer)
{
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;

Expand Down Expand Up @@ -455,6 +483,13 @@ - (void)dealloc
data.mtlcmdencoder.label = @"SDL metal renderer render target";
}

/* Set up buffer bindings for positions, texcoords, and color once here,
* the offsets are adjusted in the code that uses them. */
if (vertex_buffer != nil) {
[data.mtlcmdencoder setVertexBuffer:vertex_buffer offset:0 atIndex:0];
[data.mtlcmdencoder setFragmentBuffer:vertex_buffer offset:0 atIndex:0];
}

data.activepipelines = ChooseShaderPipelines(data, mtltexture.pixelFormat);

// make sure this has a definite place in the queue. This way it will
Expand Down Expand Up @@ -1042,21 +1077,24 @@ - (void)dealloc

cmd->data.draw.count = 1;

/* Interleaved positions and texture coordinates */
*(verts++) = dstrect->x;
*(verts++) = dstrect->y + dstrect->h;
*(verts++) = dstrect->x;
*(verts++) = dstrect->y;
*(verts++) = dstrect->x + dstrect->w;
*(verts++) = dstrect->y + dstrect->h;
*(verts++) = dstrect->x + dstrect->w;
*(verts++) = dstrect->y;

*(verts++) = normtex(srcrect->x, texw);
*(verts++) = normtex(srcrect->y + srcrect->h, texh);

*(verts++) = dstrect->x;
*(verts++) = dstrect->y;
*(verts++) = normtex(srcrect->x, texw);
*(verts++) = normtex(srcrect->y, texh);

*(verts++) = dstrect->x + dstrect->w;
*(verts++) = dstrect->y + dstrect->h;
*(verts++) = normtex(srcrect->x + srcrect->w, texw);
*(verts++) = normtex(srcrect->y + srcrect->h, texh);

*(verts++) = dstrect->x + dstrect->w;
*(verts++) = dstrect->y;
*(verts++) = normtex(srcrect->x + srcrect->w, texw);
*(verts++) = normtex(srcrect->y, texh);

Expand Down Expand Up @@ -1117,23 +1155,24 @@ - (void)dealloc
minv = tmp;
}

// vertices
/* Interleaved positions and texture coordinates */
*(verts++) = -center->x;
*(verts++) = dstrect->h - center->y;
*(verts++) = -center->x;
*(verts++) = -center->y;
*(verts++) = dstrect->w - center->x;
*(verts++) = dstrect->h - center->y;
*(verts++) = dstrect->w - center->x;
*(verts++) = -center->y;

// texcoords
*(verts++) = minu;
*(verts++) = maxv;

*(verts++) = -center->x;
*(verts++) = -center->y;
*(verts++) = minu;
*(verts++) = minv;

*(verts++) = dstrect->w - center->x;
*(verts++) = dstrect->h - center->y;
*(verts++) = maxu;
*(verts++) = maxv;

*(verts++) = dstrect->w - center->x;
*(verts++) = -center->y;
*(verts++) = maxu;
*(verts++) = minv;

Expand All @@ -1145,8 +1184,10 @@ - (void)dealloc
{
#if __has_feature(objc_arc)
__unsafe_unretained id<MTLRenderPipelineState> pipeline;
__unsafe_unretained id<MTLBuffer> vertex_buffer;
#else
id<MTLRenderPipelineState> pipeline;
id<MTLBuffer> vertex_buffer;
#endif
size_t constants_offset;
SDL_Texture *texture;
Expand All @@ -1169,7 +1210,7 @@ - (void)dealloc
size_t first = cmd->data.draw.first;
id<MTLRenderPipelineState> newpipeline;

METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, statecache->vertex_buffer);

if (statecache->viewport_dirty) {
MTLViewport viewport;
Expand Down Expand Up @@ -1205,7 +1246,7 @@ - (void)dealloc
}

if (statecache->color_dirty) {
[data.mtlcmdencoder setFragmentBuffer:mtlbufvertex offset:statecache->color_offset atIndex:0];
[data.mtlcmdencoder setFragmentBufferOffset:statecache->color_offset atIndex:0];
statecache->color_dirty = SDL_FALSE;
}

Expand All @@ -1222,7 +1263,7 @@ - (void)dealloc
statecache->constants_offset = constants_offset;
}

[data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:first atIndex:0]; // position
[data.mtlcmdencoder setVertexBufferOffset:first atIndex:0]; /* position/texcoords */
}

static void
Expand All @@ -1235,8 +1276,6 @@ - (void)dealloc

SetDrawState(renderer, cmd, texturedata.fragmentFunction, constants_offset, mtlbufvertex, statecache);

[data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.first+(8*sizeof (float)) atIndex:1]; // texcoords

if (texture != statecache->texture) {
METAL_TextureData *oldtexturedata = NULL;
if (statecache->texture) {
Expand All @@ -1263,6 +1302,7 @@ - (void)dealloc
id<MTLBuffer> mtlbufvertex = nil;

statecache.pipeline = nil;
statecache.vertex_buffer = nil;
statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
statecache.texture = NULL;
statecache.color_dirty = SDL_TRUE;
Expand All @@ -1286,6 +1326,8 @@ - (void)dealloc
#endif
mtlbufvertex.label = @"SDL vertex data";
SDL_memcpy([mtlbufvertex contents], vertices, vertsize);

statecache.vertex_buffer = mtlbufvertex;
}

// If there's a command buffer here unexpectedly (app requested one?). Commit it so we can start fresh.
Expand Down Expand Up @@ -1344,7 +1386,7 @@ - (void)dealloc
MTLClearColor color = MTLClearColorMake(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);

// get new command encoder, set up with an initial clear operation.
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color);
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color, mtlbufvertex);
break;
}

Expand Down Expand Up @@ -1403,7 +1445,7 @@ - (void)dealloc
Uint32 pixel_format, void * pixels, int pitch)
{ @autoreleasepool {
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);

[data.mtlcmdencoder endEncoding];
id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
Expand Down Expand Up @@ -1498,7 +1540,7 @@ - (void)dealloc
static void *
METAL_GetMetalCommandEncoder(SDL_Renderer * renderer)
{ @autoreleasepool {
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
return (__bridge void*)data.mtlcmdencoder;
}}
Expand Down
28 changes: 18 additions & 10 deletions src/render/metal/SDL_shaders_metal.metal
Expand Up @@ -3,19 +3,23 @@

using namespace metal;

struct SolidVertexInput
{
float2 position [[attribute(0)]];
};

struct SolidVertexOutput
{
float4 position [[position]];
float pointSize [[point_size]];
};

vertex SolidVertexOutput SDL_Solid_vertex(const device float2 *position [[buffer(0)]],
vertex SolidVertexOutput SDL_Solid_vertex(SolidVertexInput in [[stage_in]],
constant float4x4 &projection [[buffer(2)]],
constant float4x4 &transform [[buffer(3)]],
uint vid [[vertex_id]])
constant float4x4 &transform [[buffer(3)]])
{
SolidVertexOutput v;
v.position = (projection * transform) * float4(position[vid], 0.0f, 1.0f);
v.position = (projection * transform) * float4(in.position, 0.0f, 1.0f);
v.pointSize = 1.0f;
return v;
}
Expand All @@ -25,21 +29,25 @@ fragment float4 SDL_Solid_fragment(const device float4 &col [[buffer(0)]])
return col;
}

struct CopyVertexInput
{
float2 position [[attribute(0)]];
float2 texcoord [[attribute(1)]];
};

struct CopyVertexOutput
{
float4 position [[position]];
float2 texcoord;
};

vertex CopyVertexOutput SDL_Copy_vertex(const device float2 *position [[buffer(0)]],
const device float2 *texcoords [[buffer(1)]],
vertex CopyVertexOutput SDL_Copy_vertex(CopyVertexInput in [[stage_in]],
constant float4x4 &projection [[buffer(2)]],
constant float4x4 &transform [[buffer(3)]],
uint vid [[vertex_id]])
constant float4x4 &transform [[buffer(3)]])
{
CopyVertexOutput v;
v.position = (projection * transform) * float4(position[vid], 0.0f, 1.0f);
v.texcoord = texcoords[vid];
v.position = (projection * transform) * float4(in.position, 0.0f, 1.0f);
v.texcoord = in.texcoord;
return v;
}

Expand Down

0 comments on commit e8278d0

Please sign in to comment.