Skip to content

Commit

Permalink
metal: implement SDL_RenderCopyEx, and fix a memory leak in SDL_Creat…
Browse files Browse the repository at this point in the history
…eTexture.
  • Loading branch information
slime73 committed Jan 1, 2018
1 parent 047d387 commit 85470a2
Show file tree
Hide file tree
Showing 4 changed files with 1,493 additions and 1,353 deletions.
97 changes: 92 additions & 5 deletions src/render/metal/SDL_render_metal.m
Expand Up @@ -116,6 +116,7 @@ @interface METAL_RenderData : NSObject
@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
Expand Down Expand Up @@ -322,6 +323,12 @@ @implementation METAL_TextureData
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;
Expand Down Expand Up @@ -447,6 +454,10 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)

texture->driverdata = (void*)CFBridgingRetain(texturedata);

#if !__has_feature(objc_arc)
[mtltexture release];
#endif

return 0;
}}

Expand Down Expand Up @@ -724,10 +735,11 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
}

[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;
Expand All @@ -737,9 +749,83 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
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,
Expand Down Expand Up @@ -826,6 +912,7 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
[data.mtlpipelinecopynearest release];
[data.mtlpipelinecopylinear release];
[data.mtlbufclearverts release];
[data.mtlbufidentitytransform release];
[data.mtllibrary release];
[data.mtldevice release];
[data.mtlpassdesc release];
Expand Down
15 changes: 8 additions & 7 deletions src/render/metal/SDL_shaders_metal.metal
Expand Up @@ -5,20 +5,20 @@ 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)]],
constant float4x4 &projection [[buffer(2)]],
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;
Expand All @@ -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;
}
Expand Down

0 comments on commit 85470a2

Please sign in to comment.