mirror of https://github.com/libsdl-org/SDL.git
Backported Metal sampler improvements from main
Fixes https://github.com/libsdl-org/SDL/issues/12988
This commit is contained in:
parent
5aec645191
commit
0897f4a7d1
|
|
@ -79,15 +79,10 @@ static const size_t CONSTANTS_OFFSET_DECODE_BT2020_LIMITED = ALIGN_CONSTANTS(16,
|
|||
static const size_t CONSTANTS_OFFSET_DECODE_BT2020_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT2020_LIMITED + sizeof(float) * 4 * 4);
|
||||
static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT2020_FULL + sizeof(float) * 4 * 4;
|
||||
|
||||
// Sampler types
|
||||
typedef enum
|
||||
{
|
||||
SDL_METAL_SAMPLER_NEAREST_CLAMP,
|
||||
SDL_METAL_SAMPLER_NEAREST_WRAP,
|
||||
SDL_METAL_SAMPLER_LINEAR_CLAMP,
|
||||
SDL_METAL_SAMPLER_LINEAR_WRAP,
|
||||
SDL_NUM_METAL_SAMPLERS
|
||||
} SDL_METAL_sampler_type;
|
||||
#define RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v) \
|
||||
(((scale_mode == SDL_SCALEMODE_NEAREST) << 0) | \
|
||||
((address_u == SDL_TEXTURE_ADDRESS_WRAP) << 1) | \
|
||||
((address_v == SDL_TEXTURE_ADDRESS_WRAP) << 2))
|
||||
|
||||
typedef enum SDL_MetalVertexFunction
|
||||
{
|
||||
|
|
@ -139,7 +134,7 @@ typedef struct METAL_ShaderPipelines
|
|||
@property(nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
|
||||
@property(nonatomic, retain) id<MTLLibrary> mtllibrary;
|
||||
@property(nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
|
||||
@property(nonatomic, retain) NSMutableArray<id<MTLSamplerState>> *mtlsamplers;
|
||||
@property(nonatomic, retain) NSMutableDictionary<NSNumber *, id<MTLSamplerState>> *mtlsamplers;
|
||||
@property(nonatomic, retain) id<MTLBuffer> mtlbufconstants;
|
||||
@property(nonatomic, retain) id<MTLBuffer> mtlbufquadindices;
|
||||
@property(nonatomic, assign) SDL_MetalView mtlview;
|
||||
|
|
@ -1295,6 +1290,9 @@ typedef struct
|
|||
__unsafe_unretained id<MTLBuffer> vertex_buffer;
|
||||
size_t constants_offset;
|
||||
SDL_Texture *texture;
|
||||
SDL_ScaleMode texture_scale_mode;
|
||||
SDL_TextureAddressMode texture_address_mode_u;
|
||||
SDL_TextureAddressMode texture_address_mode_v;
|
||||
bool cliprect_dirty;
|
||||
bool cliprect_enabled;
|
||||
SDL_Rect cliprect;
|
||||
|
|
@ -1452,6 +1450,58 @@ static bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|||
return true;
|
||||
}
|
||||
|
||||
static id<MTLSamplerState> GetSampler(SDL3METAL_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v)
|
||||
{
|
||||
NSNumber *key = [NSNumber numberWithInteger:RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v)];
|
||||
id<MTLSamplerState> mtlsampler = data.mtlsamplers[key];
|
||||
if (mtlsampler == nil) {
|
||||
MTLSamplerDescriptor *samplerdesc;
|
||||
samplerdesc = [[MTLSamplerDescriptor alloc] init];
|
||||
switch (scale_mode) {
|
||||
case SDL_SCALEMODE_NEAREST:
|
||||
samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
|
||||
samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
|
||||
break;
|
||||
case SDL_SCALEMODE_LINEAR:
|
||||
samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unknown scale mode: %d", scale_mode);
|
||||
return nil;
|
||||
}
|
||||
switch (address_u) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
samplerdesc.sAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
samplerdesc.sAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unknown texture address mode: %d", address_u);
|
||||
return nil;
|
||||
}
|
||||
switch (address_v) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
samplerdesc.tAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
samplerdesc.tAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
default:
|
||||
SDL_SetError("Unknown texture address mode: %d", address_v);
|
||||
return nil;
|
||||
}
|
||||
mtlsampler = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
|
||||
if (mtlsampler == nil) {
|
||||
SDL_SetError("Couldn't create sampler");
|
||||
return nil;
|
||||
}
|
||||
data.mtlsamplers[key] = mtlsampler;
|
||||
}
|
||||
return mtlsampler;
|
||||
}
|
||||
|
||||
static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
|
||||
id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
|
||||
{
|
||||
|
|
@ -1467,33 +1517,6 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|||
}
|
||||
|
||||
if (texture != statecache->texture) {
|
||||
id<MTLSamplerState> mtlsampler;
|
||||
|
||||
if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_NEAREST) {
|
||||
switch (cmd->data.draw.texture_address_mode) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_CLAMP];
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_WRAP];
|
||||
break;
|
||||
default:
|
||||
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
|
||||
}
|
||||
} else {
|
||||
switch (cmd->data.draw.texture_address_mode) {
|
||||
case SDL_TEXTURE_ADDRESS_CLAMP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_CLAMP];
|
||||
break;
|
||||
case SDL_TEXTURE_ADDRESS_WRAP:
|
||||
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_WRAP];
|
||||
break;
|
||||
default:
|
||||
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
|
||||
}
|
||||
}
|
||||
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
|
||||
|
||||
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
|
||||
#ifdef SDL_HAVE_YUV
|
||||
if (texturedata.yuv || texturedata.nv12) {
|
||||
|
|
@ -1503,6 +1526,20 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|||
#endif
|
||||
statecache->texture = texture;
|
||||
}
|
||||
|
||||
if (cmd->data.draw.texture_scale_mode != statecache->texture_scale_mode ||
|
||||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_u ||
|
||||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_v) {
|
||||
id<MTLSamplerState> mtlsampler = GetSampler(data, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_address_mode);
|
||||
if (mtlsampler == nil) {
|
||||
return false;
|
||||
}
|
||||
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
|
||||
|
||||
statecache->texture_scale_mode = cmd->data.draw.texture_scale_mode;
|
||||
statecache->texture_address_mode_u = cmd->data.draw.texture_address_mode;
|
||||
statecache->texture_address_mode_v = cmd->data.draw.texture_address_mode;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1523,6 +1560,9 @@ static bool METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
|
|||
statecache.vertex_buffer = nil;
|
||||
statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
|
||||
statecache.texture = NULL;
|
||||
statecache.texture_scale_mode = SDL_SCALEMODE_INVALID;
|
||||
statecache.texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID;
|
||||
statecache.texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID;
|
||||
statecache.shader_constants_dirty = true;
|
||||
statecache.cliprect_dirty = true;
|
||||
statecache.viewport_dirty = true;
|
||||
|
|
@ -1883,7 +1923,6 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
|
|||
int maxtexsize, quadcount = UINT16_MAX / 4;
|
||||
UInt16 *indexdata;
|
||||
size_t indicessize = sizeof(UInt16) * quadcount * 6;
|
||||
MTLSamplerDescriptor *samplerdesc;
|
||||
id<MTLCommandQueue> mtlcmdqueue;
|
||||
id<MTLLibrary> mtllibrary;
|
||||
id<MTLBuffer> mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices;
|
||||
|
|
@ -2043,27 +2082,7 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
|
|||
data.allpipelines = NULL;
|
||||
ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
|
||||
|
||||
static struct
|
||||
{
|
||||
MTLSamplerMinMagFilter filter;
|
||||
MTLSamplerAddressMode address;
|
||||
} samplerParams[] = {
|
||||
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeClampToEdge },
|
||||
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeRepeat },
|
||||
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeClampToEdge },
|
||||
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeRepeat },
|
||||
};
|
||||
SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_NUM_METAL_SAMPLERS);
|
||||
|
||||
data.mtlsamplers = [[NSMutableArray<id<MTLSamplerState>> alloc] init];
|
||||
samplerdesc = [[MTLSamplerDescriptor alloc] init];
|
||||
for (int i = 0; i < SDL_arraysize(samplerParams); ++i) {
|
||||
samplerdesc.minFilter = samplerParams[i].filter;
|
||||
samplerdesc.magFilter = samplerParams[i].filter;
|
||||
samplerdesc.sAddressMode = samplerParams[i].address;
|
||||
samplerdesc.tAddressMode = samplerParams[i].address;
|
||||
[data.mtlsamplers addObject:[data.mtldevice newSamplerStateWithDescriptor:samplerdesc]];
|
||||
}
|
||||
data.mtlsamplers = [[NSMutableDictionary<NSNumber *, id<MTLSamplerState>> alloc] init];
|
||||
|
||||
mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue