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.
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.vertexFunction = mtlvertfn;
mtlpipedesc.fragmentFunction = mtlfragfn; 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; rtdesc.pixelFormat = cache->renderTargetFormat;
if (blendmode != SDL_BLENDMODE_NONE) { if (blendmode != SDL_BLENDMODE_NONE) {
@ -412,7 +440,7 @@ ChoosePipelineState(METAL_RenderData *data, METAL_ShaderPipelines *pipelines, SD
} }
static void 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; 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"; 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); data.activepipelines = ChooseShaderPipelines(data, mtltexture.pixelFormat);
// make sure this has a definite place in the queue. This way it will // 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; cmd->data.draw.count = 1;
/* Interleaved positions and texture coordinates */
*(verts++) = dstrect->x; *(verts++) = dstrect->x;
*(verts++) = dstrect->y + dstrect->h; *(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->x, texw);
*(verts++) = normtex(srcrect->y + srcrect->h, texh); *(verts++) = normtex(srcrect->y + srcrect->h, texh);
*(verts++) = dstrect->x;
*(verts++) = dstrect->y;
*(verts++) = normtex(srcrect->x, texw); *(verts++) = normtex(srcrect->x, texw);
*(verts++) = normtex(srcrect->y, texh); *(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->x + srcrect->w, texw);
*(verts++) = normtex(srcrect->y + srcrect->h, texh); *(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->x + srcrect->w, texw);
*(verts++) = normtex(srcrect->y, texh); *(verts++) = normtex(srcrect->y, texh);
@ -1117,23 +1155,24 @@ METAL_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture *
minv = tmp; minv = tmp;
} }
// vertices /* Interleaved positions and texture coordinates */
*(verts++) = -center->x; *(verts++) = -center->x;
*(verts++) = dstrect->h - center->y; *(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++) = minu;
*(verts++) = maxv; *(verts++) = maxv;
*(verts++) = -center->x;
*(verts++) = -center->y;
*(verts++) = minu; *(verts++) = minu;
*(verts++) = minv; *(verts++) = minv;
*(verts++) = dstrect->w - center->x;
*(verts++) = dstrect->h - center->y;
*(verts++) = maxu; *(verts++) = maxu;
*(verts++) = maxv; *(verts++) = maxv;
*(verts++) = dstrect->w - center->x;
*(verts++) = -center->y;
*(verts++) = maxu; *(verts++) = maxu;
*(verts++) = minv; *(verts++) = minv;
@ -1145,8 +1184,10 @@ typedef struct
{ {
#if __has_feature(objc_arc) #if __has_feature(objc_arc)
__unsafe_unretained id<MTLRenderPipelineState> pipeline; __unsafe_unretained id<MTLRenderPipelineState> pipeline;
__unsafe_unretained id<MTLBuffer> vertex_buffer;
#else #else
id<MTLRenderPipelineState> pipeline; id<MTLRenderPipelineState> pipeline;
id<MTLBuffer> vertex_buffer;
#endif #endif
size_t constants_offset; size_t constants_offset;
SDL_Texture *texture; 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; size_t first = cmd->data.draw.first;
id<MTLRenderPipelineState> newpipeline; id<MTLRenderPipelineState> newpipeline;
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL); METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, statecache->vertex_buffer);
if (statecache->viewport_dirty) { if (statecache->viewport_dirty) {
MTLViewport viewport; MTLViewport viewport;
@ -1205,7 +1246,7 @@ SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Met
} }
if (statecache->color_dirty) { 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; 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; statecache->constants_offset = constants_offset;
} }
[data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:first atIndex:0]; // position [data.mtlcmdencoder setVertexBufferOffset:first atIndex:0]; /* position/texcoords */
} }
static void 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); 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) { if (texture != statecache->texture) {
METAL_TextureData *oldtexturedata = NULL; METAL_TextureData *oldtexturedata = NULL;
if (statecache->texture) { if (statecache->texture) {
@ -1263,6 +1302,7 @@ METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
id<MTLBuffer> mtlbufvertex = nil; id<MTLBuffer> mtlbufvertex = nil;
statecache.pipeline = nil; statecache.pipeline = nil;
statecache.vertex_buffer = nil;
statecache.constants_offset = CONSTANTS_OFFSET_INVALID; statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
statecache.texture = NULL; statecache.texture = NULL;
statecache.color_dirty = SDL_TRUE; statecache.color_dirty = SDL_TRUE;
@ -1286,6 +1326,8 @@ METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
#endif #endif
mtlbufvertex.label = @"SDL vertex data"; mtlbufvertex.label = @"SDL vertex data";
SDL_memcpy([mtlbufvertex contents], vertices, vertsize); 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. // 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); 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. // get new command encoder, set up with an initial clear operation.
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color); METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color, mtlbufvertex);
break; break;
} }
@ -1403,7 +1445,7 @@ METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 pixel_format, void * pixels, int pitch) Uint32 pixel_format, void * pixels, int pitch)
{ @autoreleasepool { { @autoreleasepool {
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL); METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);
[data.mtlcmdencoder endEncoding]; [data.mtlcmdencoder endEncoding];
id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture; id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
@ -1498,7 +1540,7 @@ METAL_GetMetalLayer(SDL_Renderer * renderer)
static void * static void *
METAL_GetMetalCommandEncoder(SDL_Renderer * renderer) METAL_GetMetalCommandEncoder(SDL_Renderer * renderer)
{ @autoreleasepool { { @autoreleasepool {
METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL); METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
return (__bridge void*)data.mtlcmdencoder; return (__bridge void*)data.mtlcmdencoder;
}} }}

View File

@ -3,19 +3,23 @@
using namespace metal; using namespace metal;
struct SolidVertexInput
{
float2 position [[attribute(0)]];
};
struct SolidVertexOutput struct SolidVertexOutput
{ {
float4 position [[position]]; float4 position [[position]];
float pointSize [[point_size]]; 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 &projection [[buffer(2)]],
constant float4x4 &transform [[buffer(3)]], constant float4x4 &transform [[buffer(3)]])
uint vid [[vertex_id]])
{ {
SolidVertexOutput v; 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; v.pointSize = 1.0f;
return v; return v;
} }
@ -25,21 +29,25 @@ fragment float4 SDL_Solid_fragment(const device float4 &col [[buffer(0)]])
return col; return col;
} }
struct CopyVertexInput
{
float2 position [[attribute(0)]];
float2 texcoord [[attribute(1)]];
};
struct CopyVertexOutput struct CopyVertexOutput
{ {
float4 position [[position]]; float4 position [[position]];
float2 texcoord; float2 texcoord;
}; };
vertex CopyVertexOutput SDL_Copy_vertex(const device float2 *position [[buffer(0)]], vertex CopyVertexOutput SDL_Copy_vertex(CopyVertexInput in [[stage_in]],
const device float2 *texcoords [[buffer(1)]],
constant float4x4 &projection [[buffer(2)]], constant float4x4 &projection [[buffer(2)]],
constant float4x4 &transform [[buffer(3)]], constant float4x4 &transform [[buffer(3)]])
uint vid [[vertex_id]])
{ {
CopyVertexOutput v; CopyVertexOutput v;
v.position = (projection * transform) * float4(position[vid], 0.0f, 1.0f); v.position = (projection * transform) * float4(in.position, 0.0f, 1.0f);
v.texcoord = texcoords[vid]; v.texcoord = in.texcoord;
return v; 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