Ver Fonte

metal: implement SDL_RenderCopyEx, and fix a memory leak in SDL_CreateTexture.

Alex Szpakowski há 7 anos atrás
pai
commit
85470a2f95

+ 92 - 5
src/render/metal/SDL_render_metal.m

@@ -116,6 +116,7 @@ SDL_RenderDriver METAL_RenderDriver = {
     @property (nonatomic, retain) NSMutableArray *mtlpipelinecopynearest;
     @property (nonatomic, retain) NSMutableArray *mtlpipelinecopylinear;
     @property (nonatomic, retain) id<MTLBuffer> mtlbufclearverts;
+    @property (nonatomic, retain) id<MTLBuffer> mtlbufidentitytransform;
     @property (nonatomic, retain) CAMetalLayer *mtllayer;
     @property (nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
 @end
@@ -322,6 +323,12 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
     data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined];
     data.mtlbufclearverts.label = @"SDL_RenderClear vertices";
 
+    float identitytx[16];
+    SDL_memset(identitytx, 0, sizeof(identitytx));
+    identitytx[0] = identitytx[5] = identitytx[10] = identitytx[15] = 1.0f;
+    data.mtlbufidentitytransform = [data.mtldevice newBufferWithBytes:identitytx length:sizeof(identitytx) options:0];
+    data.mtlbufidentitytransform.label = @"SDL_RenderCopy identity transform";
+
     // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
 
     renderer->WindowEvent = METAL_WindowEvent;
@@ -447,6 +454,10 @@ METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 
     texture->driverdata = (void*)CFBridgingRetain(texturedata);
 
+#if !__has_feature(objc_arc)
+    [mtltexture release];
+#endif
+
     return 0;
 }}
 
@@ -724,10 +735,11 @@ METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
     }
 
     [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(texturedata.mtlpipeline, texture->blendMode)];
-    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
-    [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
     [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
     [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
+    [data.mtlcmdencoder setVertexBuffer:data.mtlbufidentitytransform offset:0 atIndex:3];
+    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
+    [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
     [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
 
     return 0;
@@ -737,9 +749,83 @@ static int
 METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
-{
-    return SDL_Unsupported();  // !!! FIXME
-}
+{ @autoreleasepool {
+    METAL_ActivateRenderer(renderer);
+    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
+    METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
+    const float texw = (float) texturedata.mtltexture.width;
+    const float texh = (float) texturedata.mtltexture.height;
+    float transform[16];
+    float minu, maxu, minv, maxv;
+
+    minu = normtex(srcrect->x, texw);
+    maxu = normtex(srcrect->x + srcrect->w, texw);
+    minv = normtex(srcrect->y, texh);
+    maxv = normtex(srcrect->y + srcrect->h, texh);
+
+    if (flip & SDL_FLIP_HORIZONTAL) {
+        float tmp = maxu;
+        maxu = minu;
+        minu = tmp;
+    }
+    if (flip & SDL_FLIP_VERTICAL) {
+        float tmp = maxv;
+        maxv = minv;
+        minv = tmp;
+    }
+
+    const float uv[] = {
+        minu, maxv,
+        minu, minv,
+        maxu, maxv,
+        maxu, minv
+    };
+
+    const float xy[] = {
+        -center->x, dstrect->h - center->y,
+        -center->x, -center->y,
+        dstrect->w - center->x, dstrect->h - center->y,
+        dstrect->w - center->x, -center->y,
+    };
+
+    {
+        float rads = (float)(M_PI * (float) angle / 180.0f);
+        float c = cosf(rads), s = sinf(rads);
+        SDL_memset(transform, 0, sizeof(transform));
+
+        // matrix multiplication carried out on paper:
+        // |1     x+c| |c -s    |
+        // |  1   y+c| |s  c    |
+        // |    1    | |     1  |
+        // |        1| |       1|
+        //     move      rotate
+        transform[10] = transform[15] = 1.0f;
+        transform[0]  = c;
+        transform[1]  = s;
+        transform[4]  = -s;
+        transform[5]  = c;
+        transform[12] = dstrect->x + center->x;
+        transform[13] = dstrect->y + center->y;
+    }
+
+    float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+    if (texture->modMode) {
+        color[0] = ((float)texture->r) / 255.0f;
+        color[1] = ((float)texture->g) / 255.0f;
+        color[2] = ((float)texture->b) / 255.0f;
+        color[3] = ((float)texture->a) / 255.0f;
+    }
+
+    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(texturedata.mtlpipeline, texture->blendMode)];
+    [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
+    [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
+    [data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
+    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
+    [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
+    [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+
+    return 0;
+}}
 
 static int
 METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
@@ -826,6 +912,7 @@ METAL_DestroyRenderer(SDL_Renderer * renderer)
         [data.mtlpipelinecopynearest release];
         [data.mtlpipelinecopylinear release];
         [data.mtlbufclearverts release];
+        [data.mtlbufidentitytransform release];
         [data.mtllibrary release];
         [data.mtldevice release];
         [data.mtlpassdesc release];

+ 8 - 7
src/render/metal/SDL_shaders_metal.metal

@@ -5,8 +5,8 @@ using namespace metal;
 
 struct SolidVertexOutput
 {
-	float4 position [[position]];
-	float pointSize [[point_size]];
+    float4 position [[position]];
+    float pointSize [[point_size]];
 };
 
 vertex SolidVertexOutput SDL_Solid_vertex(const device float2 *position [[buffer(0)]],
@@ -14,11 +14,11 @@ vertex SolidVertexOutput SDL_Solid_vertex(const device float2 *position [[buffer
                                           uint vid [[vertex_id]])
 {
     SolidVertexOutput v;
-	v.position = projection * float4(position[vid].x, position[vid].y, 0.0f, 1.0f);
-	v.pointSize = 0.5f;
-	return v;
+    v.position = projection * float4(position[vid], 0.0f, 1.0f);
+    v.pointSize = 0.5f;
+    return v;
 }
- 
+
 fragment float4 SDL_Solid_fragment(constant float4 &col [[buffer(0)]])
 {
     return col;
@@ -33,10 +33,11 @@ struct CopyVertexOutput
 vertex CopyVertexOutput SDL_Copy_vertex(const device float2 *position [[buffer(0)]],
                                         const device float2 *texcoords [[buffer(1)]],
                                         constant float4x4 &projection [[buffer(2)]],
+                                        constant float4x4 &transform [[buffer(3)]],
                                         uint vid [[vertex_id]])
 {
     CopyVertexOutput v;
-    v.position = projection * float4(position[vid].x, position[vid].y, 0.0f, 1.0f);
+    v.position = (projection * transform) * float4(position[vid], 0.0f, 1.0f);
     v.texcoord = texcoords[vid];
     return v;
 }

Diff do ficheiro suprimidas por serem muito extensas
+ 775 - 315
src/render/metal/SDL_shaders_metal_ios.h


Diff do ficheiro suprimidas por serem muito extensas
+ 597 - 349
src/render/metal/SDL_shaders_metal_osx.h


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff