Skip to content

Commit

Permalink
metal: Use sampler state objects instead of shader-declared samplers …
Browse files Browse the repository at this point in the history
…for linear vs nearest filtering.

This avoids a ton of shader duplication once multiple shaders that use samplers are added (e.g. the currently missing YUV shaders).
  • Loading branch information
slime73 committed Jan 1, 2018
1 parent cf45cf7 commit 639ea9f
Show file tree
Hide file tree
Showing 4 changed files with 1,478 additions and 1,936 deletions.
41 changes: 26 additions & 15 deletions src/render/metal/SDL_render_metal.m
Expand Up @@ -114,8 +114,7 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect
typedef enum SDL_MetalFragmentFunction
{
SDL_METAL_FRAGMENT_SOLID,
SDL_METAL_FRAGMENT_COPY_NEAREST,
SDL_METAL_FRAGMENT_COPY_LINEAR,
SDL_METAL_FRAGMENT_COPY,
} SDL_MetalFragmentFunction;

typedef struct METAL_PipelineState
Expand All @@ -142,8 +141,9 @@ @interface METAL_RenderData : NSObject
@property (nonatomic, retain) id<MTLLibrary> mtllibrary;
@property (nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
@property (nonatomic) METAL_PipelineCache *mtlpipelineprims;
@property (nonatomic) METAL_PipelineCache *mtlpipelinecopynearest;
@property (nonatomic) METAL_PipelineCache *mtlpipelinecopylinear;
@property (nonatomic) METAL_PipelineCache *mtlpipelinecopy;
@property (nonatomic, retain) id<MTLSamplerState> mtlsamplernearest;
@property (nonatomic, retain) id<MTLSamplerState> mtlsamplerlinear;
@property (nonatomic, retain) id<MTLBuffer> mtlbufclearverts;
@property (nonatomic, retain) id<MTLBuffer> mtlbufidentitytransform;
@property (nonatomic, retain) CAMetalLayer *mtllayer;
Expand All @@ -155,7 +155,7 @@ @implementation METAL_RenderData

@interface METAL_TextureData : NSObject
@property (nonatomic, retain) id<MTLTexture> mtltexture;
@property (nonatomic) METAL_PipelineCache *mtlpipeline;
@property (nonatomic, retain) id<MTLSamplerState> mtlsampler;
@end

@implementation METAL_TextureData
Expand Down Expand Up @@ -227,8 +227,7 @@ @implementation METAL_TextureData
{
switch (function) {
case SDL_METAL_FRAGMENT_SOLID: return @"SDL_Solid_fragment";
case SDL_METAL_FRAGMENT_COPY_NEAREST: return @"SDL_Copy_fragment_nearest";
case SDL_METAL_FRAGMENT_COPY_LINEAR: return @"SDL_Copy_fragment_linear";
case SDL_METAL_FRAGMENT_COPY: return @"SDL_Copy_fragment";
default: return nil;
}
}
Expand Down Expand Up @@ -423,8 +422,17 @@ @implementation METAL_TextureData
data.mtllibrary.label = @"SDL Metal renderer shader library";

data.mtlpipelineprims = MakePipelineCache(data, "SDL primitives pipeline ", SDL_METAL_VERTEX_SOLID, SDL_METAL_FRAGMENT_SOLID);
data.mtlpipelinecopynearest = MakePipelineCache(data, "SDL texture pipeline (nearest) ", SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY_NEAREST);
data.mtlpipelinecopylinear = MakePipelineCache(data, "SDL texture pipeline (linear) ", SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY_LINEAR);
data.mtlpipelinecopy = MakePipelineCache(data, "SDL texture pipeline ", SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY);

MTLSamplerDescriptor *samplerdesc = [[[MTLSamplerDescriptor alloc] init] autorelease];

samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
data.mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];

samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
data.mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];

static const float clearverts[] = { 0, 0, 0, 3, 3, 0 };
data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined];
Expand Down Expand Up @@ -575,9 +583,9 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
texturedata.mtlpipeline = data.mtlpipelinecopynearest;
texturedata.mtlsampler = data.mtlsamplernearest;
} else {
texturedata.mtlpipeline = data.mtlpipelinecopylinear;
texturedata.mtlsampler = data.mtlsamplerlinear;
}
texturedata.mtltexture = mtltexture;

Expand Down Expand Up @@ -863,12 +871,13 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
color[3] = ((float)texture->a) / 255.0f;
}

[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, texturedata.mtlpipeline, texture->blendMode)];
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.mtlpipelinecopy, texture->blendMode)];
[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 setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];

return 0;
Expand Down Expand Up @@ -945,12 +954,13 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
color[3] = ((float)texture->a) / 255.0f;
}

[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, texturedata.mtlpipeline, texture->blendMode)];
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.mtlpipelinecopy, 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 setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];

return 0;
Expand Down Expand Up @@ -1025,6 +1035,8 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
[data.mtlcmdencoder release];
[data.mtlcmdbuffer release];
[data.mtlcmdqueue release];
[data.mtlsamplernearest release];
[data.mtlsamplerlinear release];
[data.mtlbufclearverts release];
[data.mtlbufidentitytransform release];
[data.mtllibrary release];
Expand All @@ -1034,8 +1046,7 @@ static void METAL_ActivateRenderer(SDL_Renderer * renderer)
#endif

DestroyPipelineCache(data.mtlpipelineprims);
DestroyPipelineCache(data.mtlpipelinecopynearest);
DestroyPipelineCache(data.mtlpipelinecopylinear);
DestroyPipelineCache(data.mtlpipelinecopy);
}

SDL_free(renderer);
Expand Down
17 changes: 4 additions & 13 deletions src/render/metal/SDL_shaders_metal.metal
Expand Up @@ -42,19 +42,10 @@ vertex CopyVertexOutput SDL_Copy_vertex(const device float2 *position [[buffer(0
return v;
}

fragment float4 SDL_Copy_fragment_nearest(CopyVertexOutput vert [[stage_in]],
constant float4 &col [[buffer(0)]],
texture2d<float> tex [[texture(0)]])
fragment float4 SDL_Copy_fragment(CopyVertexOutput vert [[stage_in]],
constant float4 &col [[buffer(0)]],
texture2d<float> tex [[texture(0)]],
sampler s [[sampler(0)]])
{
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::nearest);
return tex.sample(s, vert.texcoord) * col;
}

fragment float4 SDL_Copy_fragment_linear(CopyVertexOutput vert [[stage_in]],
constant float4 &col [[buffer(0)]],
texture2d<float> tex [[texture(0)]])
{
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::linear);
return tex.sample(s, vert.texcoord) * col;
}

0 comments on commit 639ea9f

Please sign in to comment.