metal: Use sampler state objects instead of shader-declared samplers 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).
This commit is contained in:
Alex Szpakowski 2018-01-01 19:37:16 -04:00
parent cf45cf70e5
commit 639ea9fdbc
4 changed files with 1622 additions and 2080 deletions

View file

@ -114,8 +114,7 @@ typedef enum SDL_MetalVertexFunction
typedef enum SDL_MetalFragmentFunction typedef enum SDL_MetalFragmentFunction
{ {
SDL_METAL_FRAGMENT_SOLID, SDL_METAL_FRAGMENT_SOLID,
SDL_METAL_FRAGMENT_COPY_NEAREST, SDL_METAL_FRAGMENT_COPY,
SDL_METAL_FRAGMENT_COPY_LINEAR,
} SDL_MetalFragmentFunction; } SDL_MetalFragmentFunction;
typedef struct METAL_PipelineState typedef struct METAL_PipelineState
@ -142,8 +141,9 @@ typedef struct METAL_PipelineCache
@property (nonatomic, retain) id<MTLLibrary> mtllibrary; @property (nonatomic, retain) id<MTLLibrary> mtllibrary;
@property (nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer; @property (nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
@property (nonatomic) METAL_PipelineCache *mtlpipelineprims; @property (nonatomic) METAL_PipelineCache *mtlpipelineprims;
@property (nonatomic) METAL_PipelineCache *mtlpipelinecopynearest; @property (nonatomic) METAL_PipelineCache *mtlpipelinecopy;
@property (nonatomic) METAL_PipelineCache *mtlpipelinecopylinear; @property (nonatomic, retain) id<MTLSamplerState> mtlsamplernearest;
@property (nonatomic, retain) id<MTLSamplerState> mtlsamplerlinear;
@property (nonatomic, retain) id<MTLBuffer> mtlbufclearverts; @property (nonatomic, retain) id<MTLBuffer> mtlbufclearverts;
@property (nonatomic, retain) id<MTLBuffer> mtlbufidentitytransform; @property (nonatomic, retain) id<MTLBuffer> mtlbufidentitytransform;
@property (nonatomic, retain) CAMetalLayer *mtllayer; @property (nonatomic, retain) CAMetalLayer *mtllayer;
@ -155,7 +155,7 @@ typedef struct METAL_PipelineCache
@interface METAL_TextureData : NSObject @interface METAL_TextureData : NSObject
@property (nonatomic, retain) id<MTLTexture> mtltexture; @property (nonatomic, retain) id<MTLTexture> mtltexture;
@property (nonatomic) METAL_PipelineCache *mtlpipeline; @property (nonatomic, retain) id<MTLSamplerState> mtlsampler;
@end @end
@implementation METAL_TextureData @implementation METAL_TextureData
@ -227,8 +227,7 @@ GetFragmentFunctionName(SDL_MetalFragmentFunction function)
{ {
switch (function) { switch (function) {
case SDL_METAL_FRAGMENT_SOLID: return @"SDL_Solid_fragment"; 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: return @"SDL_Copy_fragment";
case SDL_METAL_FRAGMENT_COPY_LINEAR: return @"SDL_Copy_fragment_linear";
default: return nil; default: return nil;
} }
} }
@ -423,8 +422,17 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
data.mtllibrary.label = @"SDL Metal renderer shader library"; data.mtllibrary.label = @"SDL Metal renderer shader library";
data.mtlpipelineprims = MakePipelineCache(data, "SDL primitives pipeline ", SDL_METAL_VERTEX_SOLID, SDL_METAL_FRAGMENT_SOLID); 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.mtlpipelinecopy = MakePipelineCache(data, "SDL texture pipeline ", SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY);
data.mtlpipelinecopylinear = MakePipelineCache(data, "SDL texture pipeline (linear) ", SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY_LINEAR);
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 }; static const float clearverts[] = { 0, 0, 0, 3, 3, 0 };
data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined]; data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined];
@ -575,9 +583,9 @@ METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
METAL_TextureData *texturedata = [[METAL_TextureData alloc] init]; METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY); const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) { if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
texturedata.mtlpipeline = data.mtlpipelinecopynearest; texturedata.mtlsampler = data.mtlsamplernearest;
} else { } else {
texturedata.mtlpipeline = data.mtlpipelinecopylinear; texturedata.mtlsampler = data.mtlsamplerlinear;
} }
texturedata.mtltexture = mtltexture; texturedata.mtltexture = mtltexture;
@ -863,12 +871,13 @@ METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
color[3] = ((float)texture->a) / 255.0f; 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:xy length:sizeof(xy) atIndex:0];
[data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1]; [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
[data.mtlcmdencoder setVertexBuffer:data.mtlbufidentitytransform offset:0 atIndex:3]; [data.mtlcmdencoder setVertexBuffer:data.mtlbufidentitytransform offset:0 atIndex:3];
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0]; [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
[data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
return 0; return 0;
@ -945,12 +954,13 @@ METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
color[3] = ((float)texture->a) / 255.0f; 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:xy length:sizeof(xy) atIndex:0];
[data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1]; [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
[data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3]; [data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0]; [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
[data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
return 0; return 0;
@ -1025,6 +1035,8 @@ METAL_DestroyRenderer(SDL_Renderer * renderer)
[data.mtlcmdencoder release]; [data.mtlcmdencoder release];
[data.mtlcmdbuffer release]; [data.mtlcmdbuffer release];
[data.mtlcmdqueue release]; [data.mtlcmdqueue release];
[data.mtlsamplernearest release];
[data.mtlsamplerlinear release];
[data.mtlbufclearverts release]; [data.mtlbufclearverts release];
[data.mtlbufidentitytransform release]; [data.mtlbufidentitytransform release];
[data.mtllibrary release]; [data.mtllibrary release];
@ -1034,8 +1046,7 @@ METAL_DestroyRenderer(SDL_Renderer * renderer)
#endif #endif
DestroyPipelineCache(data.mtlpipelineprims); DestroyPipelineCache(data.mtlpipelineprims);
DestroyPipelineCache(data.mtlpipelinecopynearest); DestroyPipelineCache(data.mtlpipelinecopy);
DestroyPipelineCache(data.mtlpipelinecopylinear);
} }
SDL_free(renderer); SDL_free(renderer);

View file

@ -42,19 +42,10 @@ vertex CopyVertexOutput SDL_Copy_vertex(const device float2 *position [[buffer(0
return v; return v;
} }
fragment float4 SDL_Copy_fragment_nearest(CopyVertexOutput vert [[stage_in]], fragment float4 SDL_Copy_fragment(CopyVertexOutput vert [[stage_in]],
constant float4 &col [[buffer(0)]], constant float4 &col [[buffer(0)]],
texture2d<float> tex [[texture(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; 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;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff