Browse Source

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 6 years ago
parent
commit
e8278d0d5b

+ 68 - 26
src/render/metal/SDL_render_metal.m

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

+ 18 - 10
src/render/metal/SDL_shaders_metal.metal

@@ -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
+ 851 - 609
src/render/metal/SDL_shaders_metal_ios.h


File diff suppressed because it is too large
+ 399 - 608
src/render/metal/SDL_shaders_metal_osx.h


File diff suppressed because it is too large
+ 851 - 609
src/render/metal/SDL_shaders_metal_tvos.h


Some files were not shown because too many files changed in this diff