metal renderer: use vertex attributes instead of indexing into a buffer with the vertex id in the shader. Allows for more flexibility with vertex setup in the future.

Also optimize vertex buffer binding slightly.
This commit is contained in:
Alex Szpakowski 2019-08-17 16:53:08 -03:00
parent 55a46abf0a
commit e8278d0d5b
5 changed files with 3745 additions and 3701 deletions

View File

@ -265,8 +265,36 @@ MakePipelineState(METAL_RenderData *data, METAL_PipelineCache *cache,
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) {
@ -412,7 +440,7 @@ ChoosePipelineState(METAL_RenderData *data, METAL_ShaderPipelines *pipelines, SD
}
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;
@ -455,6 +483,13 @@ METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load,
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
@ -1042,21 +1077,24 @@ METAL_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * t
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);
@ -1117,23 +1155,24 @@ METAL_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture *
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;
@ -1145,8 +1184,10 @@ typedef struct
{
#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;
@ -1169,7 +1210,7 @@ SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Met
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;
@ -1205,7 +1246,7 @@ SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Met
}
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;
}
@ -1222,7 +1263,7 @@ SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Met
statecache->constants_offset = constants_offset;
}
[data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:first atIndex:0]; // position
[data.mtlcmdencoder setVertexBufferOffset:first atIndex:0]; /* position/texcoords */
}
static void
@ -1235,8 +1276,6 @@ SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t
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) {
@ -1263,6 +1302,7 @@ METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
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;
@ -1286,6 +1326,8 @@ METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
#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.
@ -1344,7 +1386,7 @@ METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
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;
}
@ -1403,7 +1445,7 @@ METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
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;
@ -1498,7 +1540,7 @@ METAL_GetMetalLayer(SDL_Renderer * renderer)
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;
}}

View File

@ -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;
}
@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff