diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index 33b6e1feb9..63dbfa50be 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -98,6 +98,21 @@ typedef enum SDL_TextureAccess SDL_TEXTUREACCESS_TARGET /**< Texture can be used as a render target */ } SDL_TextureAccess; +/** + * The addressing mode for a texture when used in SDL_RenderGeometry(). + * + * This affects how texture coordinates are interpreted outside of [0, 1] + * + * \since This enum is available since SDL 3.4.0. + */ +typedef enum SDL_TextureAddressMode +{ + SDL_TEXTURE_ADDRESS_INVALID = -1, + SDL_TEXTURE_ADDRESS_AUTO, /**< Wrapping is enabled if texture coordinates are outside [0, 1], this is the default */ + SDL_TEXTURE_ADDRESS_CLAMP, /**< Texture coordinates are clamped to the [0, 1] range */ + SDL_TEXTURE_ADDRESS_WRAP, /**< The texture is repeated (tiled) */ +} SDL_TextureAddressMode; + /** * How the logical size is mapped to the output. * @@ -2294,6 +2309,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9GridTiled(SDL_Renderer *rende * \since This function is available since SDL 3.2.0. * * \sa SDL_RenderGeometryRaw + * \sa SDL_SetRenderTextureAddressMode */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, SDL_Texture *texture, @@ -2326,6 +2342,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, * \since This function is available since SDL 3.2.0. * * \sa SDL_RenderGeometry + * \sa SDL_SetRenderTextureAddressMode */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, SDL_Texture *texture, @@ -2335,6 +2352,38 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, int num_vertices, const void *indices, int num_indices, int size_indices); +/** + * Set the texture addressing mode used in SDL_RenderGeometry(). + * + * \param renderer the rendering context. + * \param u_mode the SDL_TextureAddressMode to use for horizontal texture coordinates in SDL_RenderGeometry(). + * \param v_mode the SDL_TextureAddressMode to use for vertical texture coordinates in SDL_RenderGeometry(). + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_RenderGeometry + * \sa SDL_RenderGeometryRaw + * \sa SDL_GetRenderTextureAddressMode + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode u_mode, SDL_TextureAddressMode v_mode); + +/** + * Get the texture addressing mode used in SDL_RenderGeometry(). + * + * \param renderer the rendering context. + * \param u_mode a pointer filled in with the SDL_TextureAddressMode to use for horizontal texture coordinates in SDL_RenderGeometry(), may be NULL. + * \param v_mode a pointer filled in with the SDL_TextureAddressMode to use for vertical texture coordinates in SDL_RenderGeometry(), may be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_SetRenderTextureAddressMode + */ +extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode *u_mode, SDL_TextureAddressMode *v_mode); + /** * Read pixels from the current rendering target. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 9f84fbbc91..6ec8127dfa 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1246,6 +1246,8 @@ SDL3_0.0.0 { SDL_SetWindowProgressValue; SDL_GetWindowProgressState; SDL_GetWindowProgressValue; + SDL_SetRenderTextureAddressMode; + SDL_GetRenderTextureAddressMode; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 7ebb71721c..c005264900 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1271,3 +1271,5 @@ #define SDL_SetWindowProgressValue SDL_SetWindowProgressValue_REAL #define SDL_GetWindowProgressState SDL_GetWindowProgressState_REAL #define SDL_GetWindowProgressValue SDL_GetWindowProgressValue_REAL +#define SDL_SetRenderTextureAddressMode SDL_SetRenderTextureAddressMode_REAL +#define SDL_GetRenderTextureAddressMode SDL_GetRenderTextureAddressMode_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index fa12a5815a..31f56143e3 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1279,3 +1279,5 @@ SDL_DYNAPI_PROC(bool,SDL_SetWindowProgressState,(SDL_Window *a,SDL_ProgressState SDL_DYNAPI_PROC(bool,SDL_SetWindowProgressValue,(SDL_Window *a,float b),(a,b),return) SDL_DYNAPI_PROC(SDL_ProgressState,SDL_GetWindowProgressState,(SDL_Window *a),(a),return) SDL_DYNAPI_PROC(float,SDL_GetWindowProgressValue,(SDL_Window *a),(a),return) +SDL_DYNAPI_PROC(bool,SDL_SetRenderTextureAddressMode,(SDL_Renderer *a,SDL_TextureAddressMode b,SDL_TextureAddressMode c),(a,b,c),return) +SDL_DYNAPI_PROC(bool,SDL_GetRenderTextureAddressMode,(SDL_Renderer *a,SDL_TextureAddressMode *b,SDL_TextureAddressMode *c),(a,b,c),return) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 15949f75d6..ca23ce5714 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -584,7 +584,8 @@ static SDL_RenderCommand *PrepQueueCmdDraw(SDL_Renderer *renderer, const SDL_Ren if (texture) { cmd->data.draw.texture_scale_mode = texture->scaleMode; } - cmd->data.draw.texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP; + cmd->data.draw.texture_address_mode_u = SDL_TEXTURE_ADDRESS_CLAMP; + cmd->data.draw.texture_address_mode_v = SDL_TEXTURE_ADDRESS_CLAMP; cmd->data.draw.gpu_render_state = renderer->gpu_render_state; if (renderer->gpu_render_state) { renderer->gpu_render_state->last_command_generation = renderer->render_command_generation; @@ -727,13 +728,15 @@ static bool QueueCmdGeometry(SDL_Renderer *renderer, SDL_Texture *texture, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices, - float scale_x, float scale_y, SDL_TextureAddressMode texture_address_mode) + float scale_x, float scale_y, + SDL_TextureAddressMode texture_address_mode_u, SDL_TextureAddressMode texture_address_mode_v) { SDL_RenderCommand *cmd; bool result = false; cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_GEOMETRY, texture); if (cmd) { - cmd->data.draw.texture_address_mode = texture_address_mode; + cmd->data.draw.texture_address_mode_u = texture_address_mode_u; + cmd->data.draw.texture_address_mode_v = texture_address_mode_v; result = renderer->QueueGeometry(renderer, cmd, texture, xy, xy_stride, color, color_stride, uv, uv_stride, @@ -3739,7 +3742,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count result = QueueCmdGeometry(renderer, NULL, xy, xy_stride, &renderer->color, 0 /* color_stride */, NULL, 0, num_vertices, indices, num_indices, size_indices, - 1.0f, 1.0f, SDL_TEXTURE_ADDRESS_CLAMP); + 1.0f, 1.0f, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); } SDL_small_free(xy, isstack1); @@ -3920,7 +3923,7 @@ static bool SDL_RenderTextureInternal(SDL_Renderer *renderer, SDL_Texture *textu result = QueueCmdGeometry(renderer, texture, xy, xy_stride, &texture->color, 0 /* color_stride */, uv, uv_stride, num_vertices, indices, num_indices, size_indices, - scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); } else { const SDL_FRect rect = { dstrect->x * scale_x, dstrect->y * scale_y, dstrect->w * scale_x, dstrect->h * scale_y }; result = QueueCmdCopy(renderer, texture, srcrect, &rect); @@ -4083,7 +4086,7 @@ bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, &texture->color, 0 /* color_stride */, uv, uv_stride, num_vertices, indices, num_indices, size_indices, - scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP ); } return result; @@ -4233,7 +4236,7 @@ bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, result = QueueCmdGeometry(renderer, texture, xy, xy_stride, &texture->color, 0 /* color_stride */, uv, uv_stride, num_vertices, indices, num_indices, size_indices, - scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); } else { result = QueueCmdCopyEx(renderer, texture, &real_srcrect, dstrect, angle, &real_center, flip, scale_x, scale_y); } @@ -4285,7 +4288,8 @@ static bool SDL_RenderTextureTiled_Wrap(SDL_Renderer *renderer, SDL_Texture *tex return QueueCmdGeometry(renderer, texture, xy, xy_stride, &texture->color, 0 /* color_stride */, uv, uv_stride, num_vertices, indices, num_indices, size_indices, - view->current_scale.x, view->current_scale.y, SDL_TEXTURE_ADDRESS_WRAP); + view->current_scale.x, view->current_scale.y, + SDL_TEXTURE_ADDRESS_WRAP, SDL_TEXTURE_ADDRESS_WRAP); } static bool SDL_RenderTextureTiled_Iterate(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float scale, const SDL_FRect *dstrect) @@ -5032,7 +5036,7 @@ static bool SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, result = QueueCmdGeometry(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, prev, 3, 4, - scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); if (!result) { goto end; } @@ -5052,7 +5056,7 @@ static bool SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, result = QueueCmdGeometry(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, prev, 3, 4, - scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); if (!result) { goto end; } @@ -5077,7 +5081,8 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, { int i; int count = indices ? num_indices : num_vertices; - SDL_TextureAddressMode texture_address_mode; + SDL_TextureAddressMode texture_address_mode_u; + SDL_TextureAddressMode texture_address_mode_v; CHECK_RENDERER_MAGIC(renderer, false); @@ -5132,17 +5137,37 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, texture = texture->native; } - texture_address_mode = renderer->texture_address_mode; - if (texture_address_mode == SDL_TEXTURE_ADDRESS_AUTO && texture) { - texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP; + texture_address_mode_u = renderer->texture_address_mode_u; + texture_address_mode_v = renderer->texture_address_mode_v; + if (texture && + (texture_address_mode_u == SDL_TEXTURE_ADDRESS_AUTO || + texture_address_mode_u == SDL_TEXTURE_ADDRESS_AUTO)) { for (i = 0; i < num_vertices; ++i) { const float *uv_ = (const float *)((const char *)uv + i * uv_stride); float u = uv_[0]; float v = uv_[1]; - if (u < 0.0f || v < 0.0f || u > 1.0f || v > 1.0f) { - texture_address_mode = SDL_TEXTURE_ADDRESS_WRAP; - break; + if (u < 0.0f || u > 1.0f) { + if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_AUTO) { + texture_address_mode_u = SDL_TEXTURE_ADDRESS_WRAP; + if (texture_address_mode_v != SDL_TEXTURE_ADDRESS_AUTO) { + break; + } + } } + if (v < 0.0f || v > 1.0f) { + if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_AUTO) { + texture_address_mode_v = SDL_TEXTURE_ADDRESS_WRAP; + if (texture_address_mode_u != SDL_TEXTURE_ADDRESS_AUTO) { + break; + } + } + } + } + if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_AUTO) { + texture_address_mode_u = SDL_TEXTURE_ADDRESS_CLAMP; + } + if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_AUTO) { + texture_address_mode_v = SDL_TEXTURE_ADDRESS_CLAMP; } } @@ -5168,7 +5193,9 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, // For the software renderer, try to reinterpret triangles as SDL_Rect #ifdef SDL_VIDEO_RENDER_SW - if (renderer->software && texture_address_mode == SDL_TEXTURE_ADDRESS_CLAMP) { + if (renderer->software && + texture_address_mode_u == SDL_TEXTURE_ADDRESS_CLAMP && + texture_address_mode_v == SDL_TEXTURE_ADDRESS_CLAMP) { return SDL_SW_RenderGeometryRaw(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, indices, num_indices, size_indices); @@ -5180,7 +5207,36 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, indices, num_indices, size_indices, view->current_scale.x, view->current_scale.y, - texture_address_mode); + texture_address_mode_u, texture_address_mode_v); +} + +bool SDL_SetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode u_mode, SDL_TextureAddressMode v_mode) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + renderer->texture_address_mode_u = u_mode; + renderer->texture_address_mode_v = v_mode; + return true; +} + +bool SDL_GetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode *u_mode, SDL_TextureAddressMode *v_mode) +{ + if (u_mode) { + *u_mode = SDL_TEXTURE_ADDRESS_INVALID; + } + if (v_mode) { + *v_mode = SDL_TEXTURE_ADDRESS_INVALID; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (u_mode) { + *u_mode = renderer->texture_address_mode_u; + } + if (v_mode) { + *v_mode = renderer->texture_address_mode_v; + } + return true; } SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 2e6cc76cde..5109b93451 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -32,14 +32,6 @@ extern "C" { #endif -typedef enum SDL_TextureAddressMode -{ - SDL_TEXTURE_ADDRESS_INVALID = -1, - SDL_TEXTURE_ADDRESS_AUTO, - SDL_TEXTURE_ADDRESS_CLAMP, - SDL_TEXTURE_ADDRESS_WRAP, -} SDL_TextureAddressMode; - /** * A rectangle, with the origin at the upper left (double precision). */ @@ -187,7 +179,8 @@ typedef struct SDL_RenderCommand SDL_BlendMode blend; SDL_Texture *texture; SDL_ScaleMode texture_scale_mode; - SDL_TextureAddressMode texture_address_mode; + SDL_TextureAddressMode texture_address_mode_u; + SDL_TextureAddressMode texture_address_mode_v; SDL_GPURenderState *gpu_render_state; } draw; struct @@ -312,7 +305,8 @@ struct SDL_Renderer float color_scale; SDL_FColor color; /**< Color for drawing operations values */ SDL_BlendMode blendMode; /**< The drawing blend mode */ - SDL_TextureAddressMode texture_address_mode; + SDL_TextureAddressMode texture_address_mode_u; + SDL_TextureAddressMode texture_address_mode_v; SDL_GPURenderState *gpu_render_state; SDL_RenderCommand *render_commands; @@ -373,6 +367,12 @@ extern SDL_RenderDriver GPU_RenderDriver; // Clean up any renderers at shutdown extern void SDL_QuitRender(void); +#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)) +#define RENDER_SAMPLER_COUNT (((1 << 0) | (1 << 1) | (1 << 2)) + 1) + // Add a supported texture format to a renderer extern bool SDL_AddSupportedTextureFormat(SDL_Renderer *renderer, SDL_PixelFormat format); diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index b816abfb1e..5132a23226 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/src/render/direct3d/SDL_render_d3d.c @@ -61,7 +61,8 @@ typedef struct bool beginScene; bool enableSeparateAlphaBlend; SDL_ScaleMode scaleMode[3]; - SDL_TextureAddressMode addressMode[3]; + SDL_TextureAddressMode addressModeU[3]; + SDL_TextureAddressMode addressModeV[3]; IDirect3DSurface9 *defaultRenderTarget; IDirect3DSurface9 *currentRenderTarget; void *d3dxDLL; @@ -278,8 +279,11 @@ static void D3D_InitRenderState(D3D_RenderData *data) } // Reset our current address mode - for (int i = 0; i < SDL_arraysize(data->addressMode); ++i) { - data->addressMode[i] = SDL_TEXTURE_ADDRESS_INVALID; + for (int i = 0; i < SDL_arraysize(data->addressModeU); ++i) { + data->addressModeU[i] = SDL_TEXTURE_ADDRESS_INVALID; + } + for (int i = 0; i < SDL_arraysize(data->addressModeV); ++i) { + data->addressModeV[i] = SDL_TEXTURE_ADDRESS_INVALID; } // Start the render with beginScene @@ -937,22 +941,28 @@ static void UpdateTextureScaleMode(D3D_RenderData *data, SDL_ScaleMode scaleMode } } -static void UpdateTextureAddressMode(D3D_RenderData *data, SDL_TextureAddressMode addressMode, unsigned index) +static DWORD TranslateAddressMode(SDL_TextureAddressMode addressMode) { - if (addressMode != data->addressMode[index]) { - switch (addressMode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - break; - case SDL_TEXTURE_ADDRESS_WRAP: - IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - break; - default: - break; - } - data->addressMode[index] = addressMode; + switch (addressMode) { + case SDL_TEXTURE_ADDRESS_CLAMP: + return D3DTADDRESS_CLAMP; + case SDL_TEXTURE_ADDRESS_WRAP: + return D3DTADDRESS_WRAP; + default: + SDL_assert(!"Unknown texture address mode"); + return D3DTADDRESS_CLAMP; + } +} + +static void UpdateTextureAddressMode(D3D_RenderData *data, SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV, unsigned index) +{ + if (addressModeU != data->addressModeU[index]) { + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, TranslateAddressMode(addressModeU)); + data->addressModeU[index] = addressModeU; + } + if (addressModeV != data->addressModeV[index]) { + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, TranslateAddressMode(addressModeV)); + data->addressModeV[index] = addressModeV; } } @@ -1047,15 +1057,15 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) if (texture) { UpdateTextureScaleMode(data, cmd->data.draw.texture_scale_mode, 0); - UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode, 0); + UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v, 0); #ifdef SDL_HAVE_YUV D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; if (texturedata && texturedata->yuv) { UpdateTextureScaleMode(data, cmd->data.draw.texture_scale_mode, 1); UpdateTextureScaleMode(data, cmd->data.draw.texture_scale_mode, 2); - UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode, 1); - UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode, 2); + UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v, 1); + UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v, 2); } #endif // SDL_HAVE_YUV } diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 77d2faf828..12fd5abc45 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -50,16 +50,6 @@ /* !!! FIXME: vertex buffer bandwidth could be lower; only use UV coords when !!! FIXME: textures are needed. */ -// Sampler types -typedef enum -{ - D3D11_SAMPLER_NEAREST_CLAMP, - D3D11_SAMPLER_NEAREST_WRAP, - D3D11_SAMPLER_LINEAR_CLAMP, - D3D11_SAMPLER_LINEAR_WRAP, - D3D11_SAMPLER_COUNT -} D3D11_Sampler; - // Vertex shader, common values typedef struct { @@ -178,7 +168,7 @@ typedef struct ID3D11PixelShader *pixelShaders[NUM_SHADERS]; int blendModesCount; D3D11_BlendMode *blendModes; - ID3D11SamplerState *samplers[D3D11_SAMPLER_COUNT]; + ID3D11SamplerState *samplers[RENDER_SAMPLER_COUNT]; D3D_FEATURE_LEVEL featureLevel; bool pixelSizeChanged; @@ -538,7 +528,6 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) }; D3D11_BUFFER_DESC constantBufferDesc; - D3D11_SAMPLER_DESC samplerDesc; D3D11_RASTERIZER_DESC rasterDesc; // See if we need debug interfaces @@ -727,38 +716,6 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) goto done; } - // Create samplers to use when drawing textures: - static struct - { - D3D11_FILTER filter; - D3D11_TEXTURE_ADDRESS_MODE address; - } samplerParams[] = { - { D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_CLAMP }, - { D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_WRAP }, - { D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP }, - { D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_WRAP }, - }; - SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == D3D11_SAMPLER_COUNT); - SDL_zero(samplerDesc); - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.MipLODBias = 0.0f; - samplerDesc.MaxAnisotropy = 1; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - samplerDesc.MinLOD = 0.0f; - samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; - for (int i = 0; i < SDL_arraysize(samplerParams); ++i) { - samplerDesc.Filter = samplerParams[i].filter; - samplerDesc.AddressU = samplerParams[i].address; - samplerDesc.AddressV = samplerParams[i].address; - result = ID3D11Device_CreateSamplerState(data->d3dDevice, - &samplerDesc, - &data->samplers[i]); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [nearest-pixel filter]"), result); - goto done; - } - } - // Setup Direct3D rasterizer states SDL_zero(rasterDesc); rasterDesc.AntialiasedLineEnable = FALSE; @@ -2305,6 +2262,64 @@ static bool D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand * return true; } +static ID3D11SamplerState *D3D11_GetSamplerState(D3D11_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v) +{ + Uint32 key = RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v); + SDL_assert(key < SDL_arraysize(data->samplers)); + if (!data->samplers[key]) { + D3D11_SAMPLER_DESC samplerDesc; + SDL_zero(samplerDesc); + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 1; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + samplerDesc.MinLOD = 0.0f; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + switch (scale_mode) { + case SDL_SCALEMODE_NEAREST: + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + break; + case SDL_SCALEMODE_PIXELART: // Uses linear sampling + case SDL_SCALEMODE_LINEAR: + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + break; + default: + SDL_SetError("Unknown scale mode: %d", scale_mode); + return NULL; + } + switch (address_u) { + case SDL_TEXTURE_ADDRESS_CLAMP: + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + break; + default: + SDL_SetError("Unknown texture address mode: %d", address_u); + return NULL; + } + switch (address_v) { + case SDL_TEXTURE_ADDRESS_CLAMP: + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + break; + default: + SDL_SetError("Unknown texture address mode: %d", address_v); + return NULL; + } + HRESULT result = ID3D11Device_CreateSamplerState(data->d3dDevice, + &samplerDesc, + &data->samplers[key]); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT("ID3D11Device::CreateSamplerState", result); + return NULL; + } + } + return data->samplers[key]; +} + static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix) { SDL_Texture *texture = cmd->data.draw.texture; @@ -2319,35 +2334,11 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * D3D11_SetupShaderConstants(renderer, cmd, texture, &constants); - switch (cmd->data.draw.texture_scale_mode) { - case SDL_SCALEMODE_NEAREST: - switch (cmd->data.draw.texture_address_mode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - textureSampler = rendererData->samplers[D3D11_SAMPLER_NEAREST_CLAMP]; - break; - case SDL_TEXTURE_ADDRESS_WRAP: - textureSampler = rendererData->samplers[D3D11_SAMPLER_NEAREST_WRAP]; - break; - default: - return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); - } - break; - case SDL_SCALEMODE_PIXELART: // Uses linear sampling - case SDL_SCALEMODE_LINEAR: - switch (cmd->data.draw.texture_address_mode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - textureSampler = rendererData->samplers[D3D11_SAMPLER_LINEAR_CLAMP]; - break; - case SDL_TEXTURE_ADDRESS_WRAP: - textureSampler = rendererData->samplers[D3D11_SAMPLER_LINEAR_WRAP]; - break; - default: - return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); - } - break; - default: - return SDL_SetError("Unknown scale mode: %d", cmd->data.draw.texture_scale_mode); + textureSampler = D3D11_GetSamplerState(rendererData, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); + if (!textureSampler) { + return false; } + #ifdef SDL_HAVE_YUV if (textureData->yuv) { ID3D11ShaderResourceView *shaderResources[3]; diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c index c7ba5e9fb0..7b21e96354 100644 --- a/src/render/direct3d12/SDL_render_d3d12.c +++ b/src/render/direct3d12/SDL_render_d3d12.c @@ -56,16 +56,6 @@ extern "C" { /* !!! FIXME: vertex buffer bandwidth could be lower; only use UV coords when !!! FIXME: textures are needed. */ -// Sampler types -typedef enum -{ - D3D12_SAMPLER_NEAREST_CLAMP, - D3D12_SAMPLER_NEAREST_WRAP, - D3D12_SAMPLER_LINEAR_CLAMP, - D3D12_SAMPLER_LINEAR_WRAP, - D3D12_SAMPLER_COUNT -} D3D12_Sampler; - // Vertex shader, common values typedef struct { @@ -231,7 +221,8 @@ typedef struct D3D12_PipelineState *currentPipelineState; D3D12_VertexBuffer vertexBuffers[SDL_D3D12_NUM_VERTEX_BUFFERS]; - D3D12_CPU_DESCRIPTOR_HANDLE samplers[D3D12_SAMPLER_COUNT]; + D3D12_CPU_DESCRIPTOR_HANDLE samplers[RENDER_SAMPLER_COUNT]; + bool samplers_created[RENDER_SAMPLER_COUNT]; // Data for staging/allocating textures ID3D12Resource *uploadBuffers[SDL_D3D12_NUM_UPLOAD_BUFFERS]; @@ -419,6 +410,7 @@ static void D3D12_ReleaseAll(SDL_Renderer *renderer) D3D_SAFE_RELEASE(data->textureRTVDescriptorHeap); D3D_SAFE_RELEASE(data->srvDescriptorHeap); D3D_SAFE_RELEASE(data->samplerDescriptorHeap); + SDL_zeroa(data->samplers_created); D3D_SAFE_RELEASE(data->fence); for (i = 0; i < SDL_D3D12_NUM_BUFFERS; ++i) { @@ -796,7 +788,6 @@ static HRESULT D3D12_CreateDeviceResources(SDL_Renderer *renderer) D3D12_COMMAND_QUEUE_DESC queueDesc; D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc; - D3D12_SAMPLER_DESC samplerDesc; ID3D12DescriptorHeap *rootDescriptorHeaps[2]; // See if we need debug interfaces @@ -1114,31 +1105,9 @@ static HRESULT D3D12_CreateDeviceResources(SDL_Renderer *renderer) } // Create samplers to use when drawing textures: - static struct - { - D3D12_FILTER filter; - D3D12_TEXTURE_ADDRESS_MODE address; - } samplerParams[] = { - { D3D12_FILTER_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_CLAMP }, - { D3D12_FILTER_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_WRAP }, - { D3D12_FILTER_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_CLAMP }, - { D3D12_FILTER_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_WRAP }, - }; - SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == D3D12_SAMPLER_COUNT); - SDL_zero(samplerDesc); - samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - samplerDesc.MipLODBias = 0.0f; - samplerDesc.MaxAnisotropy = 1; - samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; - samplerDesc.MinLOD = 0.0f; - samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; D3D_CALL_RET(data->samplerDescriptorHeap, GetCPUDescriptorHandleForHeapStart, &data->samplers[0]); - for (i = 0; i < SDL_arraysize(samplerParams); ++i) { - samplerDesc.Filter = samplerParams[i].filter; - samplerDesc.AddressU = samplerParams[i].address; - samplerDesc.AddressV = samplerParams[i].address; + for (i = 0; i < SDL_arraysize(data->samplers); ++i) { data->samplers[i].ptr = data->samplers[0].ptr + i * data->samplerDescriptorSize; - ID3D12Device1_CreateSampler(data->d3dDevice, &samplerDesc, data->samplers[i]); } // Initialize the pool allocator for SRVs @@ -2743,6 +2712,59 @@ static bool D3D12_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand * return true; } +static D3D12_CPU_DESCRIPTOR_HANDLE *D3D12_GetSamplerState(D3D12_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v) +{ + Uint32 key = RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v); + SDL_assert(key < SDL_arraysize(data->samplers)); + if (!data->samplers_created[key]) { + D3D12_SAMPLER_DESC samplerDesc; + SDL_zero(samplerDesc); + samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 1; + samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; + samplerDesc.MinLOD = 0.0f; + samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; + switch (scale_mode) { + case SDL_SCALEMODE_NEAREST: + samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + break; + case SDL_SCALEMODE_PIXELART: // Uses linear sampling + case SDL_SCALEMODE_LINEAR: + samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; + break; + default: + SDL_SetError("Unknown scale mode: %d", scale_mode); + return NULL; + } + switch (address_u) { + case SDL_TEXTURE_ADDRESS_CLAMP: + samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + break; + default: + SDL_SetError("Unknown texture address mode: %d", address_u); + return NULL; + } + switch (address_v) { + case SDL_TEXTURE_ADDRESS_CLAMP: + samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + break; + default: + SDL_SetError("Unknown texture address mode: %d", address_v); + return NULL; + } + ID3D12Device1_CreateSampler(data->d3dDevice, &samplerDesc, data->samplers[key]); + data->samplers_created[key] = true; + } + return &data->samplers[key]; +} + static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix) { SDL_Texture *texture = cmd->data.draw.texture; @@ -2757,35 +2779,11 @@ static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand * D3D12_SetupShaderConstants(renderer, cmd, texture, &constants); - switch (cmd->data.draw.texture_scale_mode) { - case SDL_SCALEMODE_NEAREST: - switch (cmd->data.draw.texture_address_mode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - textureSampler = &rendererData->samplers[D3D12_SAMPLER_NEAREST_CLAMP]; - break; - case SDL_TEXTURE_ADDRESS_WRAP: - textureSampler = &rendererData->samplers[D3D12_SAMPLER_NEAREST_WRAP]; - break; - default: - return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); - } - break; - case SDL_SCALEMODE_PIXELART: // Uses linear sampling - case SDL_SCALEMODE_LINEAR: - switch (cmd->data.draw.texture_address_mode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - textureSampler = &rendererData->samplers[D3D12_SAMPLER_LINEAR_CLAMP]; - break; - case SDL_TEXTURE_ADDRESS_WRAP: - textureSampler = &rendererData->samplers[D3D12_SAMPLER_LINEAR_WRAP]; - break; - default: - return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); - } - break; - default: - return SDL_SetError("Unknown scale mode: %d", cmd->data.draw.texture_scale_mode); + textureSampler = D3D12_GetSamplerState(rendererData, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); + if (!textureSampler) { + return false; } + #ifdef SDL_HAVE_YUV if (textureData->yuv) { D3D12_CPU_DESCRIPTOR_HANDLE shaderResources[3]; diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index da28b7e55b..35a5e71398 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -83,7 +83,7 @@ typedef struct GPU_RenderData bool scissor_was_enabled; } state; - SDL_GPUSampler *samplers[3][2]; + SDL_GPUSampler *samplers[RENDER_SAMPLER_COUNT]; } GPU_RenderData; typedef struct GPU_TextureData @@ -505,13 +505,6 @@ static void PushFragmentUniforms(GPU_RenderData *data, SDL_RenderCommand *cmd) } } -static SDL_GPUSampler **SamplerPointer(GPU_RenderData *data, SDL_TextureAddressMode address_mode, SDL_ScaleMode scale_mode) -{ - SDL_assert(scale_mode < SDL_arraysize(data->samplers)); - SDL_assert((address_mode - 1) < SDL_arraysize(data->samplers[0])); - return &data->samplers[scale_mode][address_mode - 1]; -} - static void SetViewportAndScissor(GPU_RenderData *data) { SDL_SetGPUViewport(data->state.render_pass, &data->state.viewport); @@ -530,6 +523,58 @@ static void SetViewportAndScissor(GPU_RenderData *data) } } +static SDL_GPUSampler *GetSampler(GPU_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v) +{ + Uint32 key = RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v); + SDL_assert(key < SDL_arraysize(data->samplers)); + if (!data->samplers[key]) { + SDL_GPUSamplerCreateInfo sci; + SDL_zero(sci); + switch (scale_mode) { + case SDL_SCALEMODE_NEAREST: + sci.min_filter = SDL_GPU_FILTER_NEAREST; + sci.mag_filter = SDL_GPU_FILTER_NEAREST; + sci.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST; + break; + case SDL_SCALEMODE_PIXELART: // Uses linear sampling + case SDL_SCALEMODE_LINEAR: + sci.min_filter = SDL_GPU_FILTER_LINEAR; + sci.mag_filter = SDL_GPU_FILTER_LINEAR; + sci.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; + break; + default: + SDL_SetError("Unknown scale mode: %d", scale_mode); + return NULL; + } + switch (address_u) { + case SDL_TEXTURE_ADDRESS_CLAMP: + sci.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + sci.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + break; + default: + SDL_SetError("Unknown texture address mode: %d", address_u); + return NULL; + } + switch (address_v) { + case SDL_TEXTURE_ADDRESS_CLAMP: + sci.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + sci.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; + break; + default: + SDL_SetError("Unknown texture address mode: %d", address_v); + return NULL; + } + sci.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + + data->samplers[key] = SDL_CreateGPUSampler(data->device, &sci); + } + return data->samplers[key]; +} + static void Draw( GPU_RenderData *data, SDL_RenderCommand *cmd, Uint32 num_verts, @@ -603,7 +648,7 @@ static void Draw( GPU_TextureData *tdata = (GPU_TextureData *)cmd->data.draw.texture->internal; SDL_GPUTextureSamplerBinding sampler_bind; SDL_zero(sampler_bind); - sampler_bind.sampler = *SamplerPointer(data, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_scale_mode); + sampler_bind.sampler = GetSampler(data, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); sampler_bind.texture = tdata->texture; SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1); } @@ -835,7 +880,8 @@ static bool GPU_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *thistexture = cmd->data.draw.texture; SDL_BlendMode thisblend = cmd->data.draw.blend; SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode; - SDL_TextureAddressMode thisaddressmode = cmd->data.draw.texture_address_mode; + SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u; + SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v; const SDL_RenderCommandType thiscmdtype = cmd->command; SDL_RenderCommand *finalcmd = cmd; SDL_RenderCommand *nextcmd = cmd->next; @@ -848,7 +894,8 @@ static bool GPU_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, break; // can't go any further on this draw call, different render command up next. } else if (nextcmd->data.draw.texture != thistexture || nextcmd->data.draw.texture_scale_mode != thisscalemode || - nextcmd->data.draw.texture_address_mode != thisaddressmode || + nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u || + nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v || nextcmd->data.draw.blend != thisblend) { // FIXME should we check address mode too? break; // can't go any further on this draw call, different texture/blendmode copy up next. @@ -1080,8 +1127,8 @@ static void GPU_DestroyRenderer(SDL_Renderer *renderer) data->state.command_buffer = NULL; } - for (Uint32 i = 0; i < sizeof(data->samplers) / sizeof(SDL_GPUSampler *); ++i) { - SDL_ReleaseGPUSampler(data->device, ((SDL_GPUSampler **)data->samplers)[i]); + for (Uint32 i = 0; i < SDL_arraysize(data->samplers); ++i) { + SDL_ReleaseGPUSampler(data->device, data->samplers[i]); } if (data->backbuffer.texture) { @@ -1153,70 +1200,6 @@ static bool GPU_SetVSync(SDL_Renderer *renderer, const int vsync) return true; } -static bool InitSamplers(GPU_RenderData *data) -{ - struct - { - struct - { - SDL_TextureAddressMode address_mode; - SDL_ScaleMode scale_mode; - } sdl; - struct - { - SDL_GPUSamplerAddressMode address_mode; - SDL_GPUFilter filter; - SDL_GPUSamplerMipmapMode mipmap_mode; - Uint32 anisotropy; - } gpu; - } configs[] = { - { - { SDL_TEXTURE_ADDRESS_CLAMP, SDL_SCALEMODE_NEAREST }, - { SDL_GPU_SAMPLERADDRESSMODE_REPEAT, SDL_GPU_FILTER_NEAREST, SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, 0 }, - }, - { - { SDL_TEXTURE_ADDRESS_CLAMP, SDL_SCALEMODE_LINEAR }, - { SDL_GPU_SAMPLERADDRESSMODE_REPEAT, SDL_GPU_FILTER_LINEAR, SDL_GPU_SAMPLERMIPMAPMODE_LINEAR, 0 }, - }, - { - { SDL_TEXTURE_ADDRESS_CLAMP, SDL_SCALEMODE_PIXELART }, - { SDL_GPU_SAMPLERADDRESSMODE_REPEAT, SDL_GPU_FILTER_NEAREST, SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, 0 }, - }, - { - { SDL_TEXTURE_ADDRESS_WRAP, SDL_SCALEMODE_NEAREST }, - { SDL_GPU_SAMPLERADDRESSMODE_REPEAT, SDL_GPU_FILTER_NEAREST, SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, 0 }, - }, - { - { SDL_TEXTURE_ADDRESS_WRAP, SDL_SCALEMODE_LINEAR }, - { SDL_GPU_SAMPLERADDRESSMODE_REPEAT, SDL_GPU_FILTER_LINEAR, SDL_GPU_SAMPLERMIPMAPMODE_LINEAR, 0 }, - }, - { - { SDL_TEXTURE_ADDRESS_WRAP, SDL_SCALEMODE_PIXELART }, - { SDL_GPU_SAMPLERADDRESSMODE_REPEAT, SDL_GPU_FILTER_NEAREST, SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, 0 }, - }, - }; - - for (Uint32 i = 0; i < SDL_arraysize(configs); ++i) { - SDL_GPUSamplerCreateInfo sci; - SDL_zero(sci); - sci.max_anisotropy = configs[i].gpu.anisotropy; - sci.enable_anisotropy = configs[i].gpu.anisotropy > 0; - sci.address_mode_u = sci.address_mode_v = sci.address_mode_w = configs[i].gpu.address_mode; - sci.min_filter = sci.mag_filter = configs[i].gpu.filter; - sci.mipmap_mode = configs[i].gpu.mipmap_mode; - - SDL_GPUSampler *sampler = SDL_CreateGPUSampler(data->device, &sci); - - if (sampler == NULL) { - return false; - } - - *SamplerPointer(data, configs[i].sdl.address_mode, configs[i].sdl.scale_mode) = sampler; - } - - return true; -} - static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) { GPU_RenderData *data = NULL; @@ -1285,10 +1268,6 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P return false; } - if (!InitSamplers(data)) { - return false; - } - if (!SDL_ClaimWindowForGPUDevice(data->device, window)) { return false; } diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index 9649ff083f..58ca3857c8 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -79,16 +79,6 @@ 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; - typedef enum SDL_MetalVertexFunction { SDL_METAL_VERTEX_SOLID, @@ -139,7 +129,7 @@ typedef struct METAL_ShaderPipelines @property(nonatomic, retain) id mtlcmdencoder; @property(nonatomic, retain) id mtllibrary; @property(nonatomic, retain) id mtlbackbuffer; -@property(nonatomic, retain) NSMutableArray> *mtlsamplers; +@property(nonatomic, retain) NSMutableDictionary> *mtlsamplers; @property(nonatomic, retain) id mtlbufconstants; @property(nonatomic, retain) id mtlbufquadindices; @property(nonatomic, assign) SDL_MetalView mtlview; @@ -1301,6 +1291,9 @@ typedef struct __unsafe_unretained id 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; @@ -1466,6 +1459,59 @@ static bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c return true; } +static id 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 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_PIXELART: // Uses linear sampling + 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 mtlbufvertex, METAL_DrawStateCache *statecache) { @@ -1481,33 +1527,6 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c } if (texture != statecache->texture) { - id 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) { @@ -1517,6 +1536,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_u != statecache->texture_address_mode_u || + cmd->data.draw.texture_address_mode_v != statecache->texture_address_mode_v) { + id mtlsampler = GetSampler(data, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); + 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_u; + statecache->texture_address_mode_v = cmd->data.draw.texture_address_mode_v; + } return true; } @@ -1537,6 +1570,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; @@ -1897,7 +1933,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 mtlcmdqueue; id mtllibrary; id mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices; @@ -2057,27 +2092,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> 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> alloc] init]; mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared]; diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 093119b22e..81c930237c 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -149,7 +149,8 @@ typedef struct bool vtexture_external; #endif SDL_ScaleMode texture_scale_mode; - SDL_TextureAddressMode texture_address_mode; + SDL_TextureAddressMode texture_address_mode_u; + SDL_TextureAddressMode texture_address_mode_v; GL_FBOList *fbo; } GL_TextureData; @@ -538,7 +539,8 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P data->format = format; data->formattype = type; data->texture_scale_mode = SDL_SCALEMODE_INVALID; - data->texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID; + data->texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID; + data->texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID; renderdata->glEnable(textype); renderdata->glBindTexture(textype, data->texture); #ifdef SDL_PLATFORM_MACOS @@ -1099,21 +1101,23 @@ static bool SetTextureScaleMode(GL_RenderData *data, GLenum textype, SDL_ScaleMo return true; } -static bool SetTextureAddressMode(GL_RenderData *data, GLenum textype, SDL_TextureAddressMode addressMode) +static GLint TranslateAddressMode(SDL_TextureAddressMode addressMode) { switch (addressMode) { case SDL_TEXTURE_ADDRESS_CLAMP: - data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - break; + return GL_CLAMP_TO_EDGE; case SDL_TEXTURE_ADDRESS_WRAP: - data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_REPEAT); - data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_REPEAT); - break; + return GL_REPEAT; default: - return SDL_SetError("Unknown texture address mode: %d", addressMode); + SDL_assert(!"Unknown texture address mode"); + return GL_CLAMP_TO_EDGE; } - return true; +} + +static void SetTextureAddressMode(GL_RenderData *data, GLenum textype, SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV) +{ + data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, TranslateAddressMode(addressModeU)); + data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, TranslateAddressMode(addressModeV)); } static bool SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd) @@ -1192,34 +1196,28 @@ static bool SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd) texturedata->texture_scale_mode = cmd->data.draw.texture_scale_mode; } - if (cmd->data.draw.texture_address_mode != texturedata->texture_address_mode) { + if (cmd->data.draw.texture_address_mode_u != texturedata->texture_address_mode_u || + cmd->data.draw.texture_address_mode_v != texturedata->texture_address_mode_v) { #ifdef SDL_HAVE_YUV if (texturedata->yuv) { data->glActiveTextureARB(GL_TEXTURE2); - if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); data->glActiveTextureARB(GL_TEXTURE1); - if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); data->glActiveTextureARB(GL_TEXTURE0_ARB); } else if (texturedata->nv12) { data->glActiveTextureARB(GL_TEXTURE1); - if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); data->glActiveTextureARB(GL_TEXTURE0); } #endif - if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); - texturedata->texture_address_mode = cmd->data.draw.texture_address_mode; + texturedata->texture_address_mode_u = cmd->data.draw.texture_address_mode_u; + texturedata->texture_address_mode_v = cmd->data.draw.texture_address_mode_v; } return true; @@ -1406,7 +1404,8 @@ static bool GL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v SDL_Texture *thistexture = cmd->data.draw.texture; SDL_BlendMode thisblend = cmd->data.draw.blend; SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode; - SDL_TextureAddressMode thisaddressmode = cmd->data.draw.texture_address_mode; + SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u; + SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v; const SDL_RenderCommandType thiscmdtype = cmd->command; SDL_RenderCommand *finalcmd = cmd; SDL_RenderCommand *nextcmd = cmd->next; @@ -1418,7 +1417,8 @@ static bool GL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v break; // can't go any further on this draw call, different render command up next. } else if (nextcmd->data.draw.texture != thistexture || nextcmd->data.draw.texture_scale_mode != thisscalemode || - nextcmd->data.draw.texture_address_mode != thisaddressmode || + nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u || + nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v || nextcmd->data.draw.blend != thisblend) { break; // can't go any further on this draw call, different texture/blendmode copy up next. } else { diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index e415d2a4a9..aeecf31945 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -78,7 +78,8 @@ typedef struct GLES2_TextureData #endif GLfloat texel_size[4]; SDL_ScaleMode texture_scale_mode; - SDL_TextureAddressMode texture_address_mode; + SDL_TextureAddressMode texture_address_mode_u; + SDL_TextureAddressMode texture_address_mode_v; GLES2_FBOList *fbo; } GLES2_TextureData; @@ -1092,21 +1093,23 @@ static bool SetTextureScaleMode(GLES2_RenderData *data, GLenum textype, SDL_Scal return true; } -static bool SetTextureAddressMode(GLES2_RenderData *data, GLenum textype, SDL_TextureAddressMode addressMode) +static GLint TranslateAddressMode(SDL_TextureAddressMode addressMode) { switch (addressMode) { case SDL_TEXTURE_ADDRESS_CLAMP: - data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - break; + return GL_CLAMP_TO_EDGE; case SDL_TEXTURE_ADDRESS_WRAP: - data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_REPEAT); - data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_REPEAT); - break; + return GL_REPEAT; default: - return SDL_SetError("Unknown texture address mode: %d", addressMode); + SDL_assert(!"Unknown texture address mode"); + return GL_CLAMP_TO_EDGE; } - return true; +} + +static void SetTextureAddressMode(GLES2_RenderData *data, GLenum textype, SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV) +{ + data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, TranslateAddressMode(addressModeU)); + data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, TranslateAddressMode(addressModeV)); } static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, void *vertices) @@ -1287,34 +1290,28 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, v tdata->texture_scale_mode = cmd->data.draw.texture_scale_mode; } - if (cmd->data.draw.texture_address_mode != tdata->texture_address_mode) { + if (cmd->data.draw.texture_address_mode_u != tdata->texture_address_mode_u || + cmd->data.draw.texture_address_mode_v != tdata->texture_address_mode_v) { #ifdef SDL_HAVE_YUV if (tdata->yuv) { data->glActiveTexture(GL_TEXTURE2); - if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); data->glActiveTexture(GL_TEXTURE1); - if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); data->glActiveTexture(GL_TEXTURE0); } else if (tdata->nv12) { data->glActiveTexture(GL_TEXTURE1); - if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); data->glActiveTexture(GL_TEXTURE0); } #endif - if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) { - return false; - } + SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); - tdata->texture_address_mode = cmd->data.draw.texture_address_mode; + tdata->texture_address_mode_u = cmd->data.draw.texture_address_mode_u; + tdata->texture_address_mode_v = cmd->data.draw.texture_address_mode_v; } return ret; @@ -1493,7 +1490,8 @@ static bool GLES2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd SDL_Texture *thistexture = cmd->data.draw.texture; SDL_BlendMode thisblend = cmd->data.draw.blend; SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode; - SDL_TextureAddressMode thisaddressmode = cmd->data.draw.texture_address_mode; + SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u; + SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v; const SDL_RenderCommandType thiscmdtype = cmd->command; SDL_RenderCommand *finalcmd = cmd; SDL_RenderCommand *nextcmd = cmd->next; @@ -1505,7 +1503,8 @@ static bool GLES2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd break; // can't go any further on this draw call, different render command up next. } else if (nextcmd->data.draw.texture != thistexture || nextcmd->data.draw.texture_scale_mode != thisscalemode || - nextcmd->data.draw.texture_address_mode != thisaddressmode || + nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u || + nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v || nextcmd->data.draw.blend != thisblend) { break; // can't go any further on this draw call, different texture/blendmode copy up next. } else { @@ -1660,7 +1659,8 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD data->texture_v = 0; #endif data->texture_scale_mode = SDL_SCALEMODE_INVALID; - data->texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID; + data->texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID; + data->texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID; // Allocate a blob for image renderdata if (texture->access == SDL_TEXTUREACCESS_STREAMING) { diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 8dfbeb183b..a5ed438968 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -76,7 +76,8 @@ typedef struct int shadeModel; SDL_Texture *texture; SDL_ScaleMode texture_scale_mode; - SDL_TextureAddressMode texture_address_mode; + SDL_TextureAddressMode texture_address_mode_u; + SDL_TextureAddressMode texture_address_mode_v; } PSP_BlendState; typedef struct @@ -540,20 +541,6 @@ static bool TextureShouldSwizzle(PSP_TextureData *psp_texture, SDL_Texture *text return !((texture->access == SDL_TEXTUREACCESS_TARGET) && InVram(psp_texture->data)) && texture->access != SDL_TEXTUREACCESS_STREAMING && (texture->w >= 16 || texture->h >= 16); } -static void SetTextureAddressMode(SDL_TextureAddressMode addressMode) -{ - switch (addressMode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - sceGuTexWrap(GU_CLAMP, GU_CLAMP); - break; - case SDL_TEXTURE_ADDRESS_WRAP: - sceGuTexWrap(GU_REPEAT, GU_REPEAT); - break; - default: - break; - } -} - static void SetTextureScaleMode(SDL_ScaleMode scaleMode) { switch (scaleMode) { @@ -569,6 +556,24 @@ static void SetTextureScaleMode(SDL_ScaleMode scaleMode) } } +static int TranslateAddressMode(SDL_TextureAddressMode mode) +{ + switch (mode) { + case SDL_TEXTURE_ADDRESS_CLAMP: + return GU_CLAMP; + case SDL_TEXTURE_ADDRESS_WRAP: + return GU_REPEAT; + default: + SDL_assert(!"Unknown texture address mode"); + return GU_CLAMP; + } +} + +static void SetTextureAddressMode(SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV) +{ + sceGuTexWrap(TranslateAddressMode(addressModeU), TranslateAddressMode(addressModeV)); +} + static void TextureActivate(SDL_Texture *texture) { PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal; @@ -1058,7 +1063,7 @@ static void PSP_SetBlendState(PSP_RenderData *data, PSP_BlendState *state) if (state->texture) { SetTextureScaleMode(state->texture_scale_mode); - SetTextureAddressMode(state->texture_address_mode); + SetTextureAddressMode(state->texture_address_mode_u, state->texture_address_mode_v); } *current = *state; @@ -1145,7 +1150,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, .color = drawstate.color, .texture = NULL, .texture_scale_mode = SDL_SCALEMODE_INVALID, - .texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID, + .texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID, + .texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID, .mode = cmd->data.draw.blend, .shadeModel = GU_FLAT }; @@ -1162,7 +1168,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, .color = drawstate.color, .texture = NULL, .texture_scale_mode = SDL_SCALEMODE_INVALID, - .texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID, + .texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID, + .texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID, .mode = cmd->data.draw.blend, .shadeModel = GU_FLAT }; @@ -1179,7 +1186,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, .color = drawstate.color, .texture = NULL, .texture_scale_mode = SDL_SCALEMODE_INVALID, - .texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID, + .texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID, + .texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID, .mode = cmd->data.draw.blend, .shadeModel = GU_FLAT }; @@ -1196,7 +1204,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, .color = drawstate.color, .texture = cmd->data.draw.texture, .texture_scale_mode = cmd->data.draw.texture_scale_mode, - .texture_address_mode = cmd->data.draw.texture_address_mode, + .texture_address_mode_u = cmd->data.draw.texture_address_mode_u, + .texture_address_mode_v = cmd->data.draw.texture_address_mode_v, .mode = cmd->data.draw.blend, .shadeModel = GU_SMOOTH }; @@ -1212,7 +1221,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, .color = drawstate.color, .texture = cmd->data.draw.texture, .texture_scale_mode = cmd->data.draw.texture_scale_mode, - .texture_address_mode = cmd->data.draw.texture_address_mode, + .texture_address_mode_u = cmd->data.draw.texture_address_mode_u, + .texture_address_mode_v = cmd->data.draw.texture_address_mode_v, .mode = cmd->data.draw.blend, .shadeModel = GU_SMOOTH }; @@ -1236,7 +1246,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, .color = drawstate.color, .texture = cmd->data.draw.texture, .texture_scale_mode = cmd->data.draw.texture_scale_mode, - .texture_address_mode = cmd->data.draw.texture_address_mode, + .texture_address_mode_u = cmd->data.draw.texture_address_mode_u, + .texture_address_mode_v = cmd->data.draw.texture_address_mode_v, .mode = cmd->data.draw.blend, .shadeModel = GU_SMOOTH }; diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c index cde86b99a8..98e46e939c 100644 --- a/src/render/software/SDL_render_sw.c +++ b/src/render/software/SDL_render_sw.c @@ -925,7 +925,8 @@ static bool SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v surface, &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), ptr[0].color, ptr[1].color, ptr[2].color, - cmd->data.draw.texture_address_mode); + cmd->data.draw.texture_address_mode_u, + cmd->data.draw.texture_address_mode_v); } } else { GeometryFillData *ptr = (GeometryFillData *)verts; diff --git a/src/render/software/SDL_triangle.c b/src/render/software/SDL_triangle.c index c4e16d12cf..3023006eb6 100644 --- a/src/render/software/SDL_triangle.c +++ b/src/render/software/SDL_triangle.c @@ -42,7 +42,9 @@ static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, - SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, SDL_TextureAddressMode texture_address_mode); + SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, + SDL_TextureAddressMode texture_address_mode_u, + SDL_TextureAddressMode texture_address_mode_v); #if 0 bool SDL_BlitTriangle(SDL_Surface *src, const SDL_Point srcpoints[3], SDL_Surface *dst, const SDL_Point dstpoints[3]) @@ -184,11 +186,13 @@ static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Poin #define TRIANGLE_GET_TEXTCOORD \ int srcx = (int)(((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area); \ int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); \ - if (texture_address_mode == SDL_TEXTURE_ADDRESS_WRAP) { \ + if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_WRAP) { \ srcx %= src_surface->w; \ if (srcx < 0) { \ srcx += (src_surface->w - 1); \ } \ + } \ + if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_WRAP) { \ srcy %= src_surface->h; \ if (srcy < 0) { \ srcy += (src_surface->h - 1); \ @@ -465,7 +469,8 @@ bool SDL_SW_BlitTriangle( SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, SDL_Color c0, SDL_Color c1, SDL_Color c2, - SDL_TextureAddressMode texture_address_mode) + SDL_TextureAddressMode texture_address_mode_u, + SDL_TextureAddressMode texture_address_mode_v) { bool result = true; SDL_Surface *src_surface = src; @@ -539,32 +544,36 @@ bool SDL_SW_BlitTriangle( SDL_GetSurfaceBlendMode(src, &blend); // TRIANGLE_GET_TEXTCOORD interpolates up to the max values included, so reduce by 1 - if (texture_address_mode == SDL_TEXTURE_ADDRESS_CLAMP) { + if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_CLAMP || + texture_address_mode_v == SDL_TEXTURE_ADDRESS_CLAMP) { SDL_Rect srcrect; - int maxx, maxy; bounding_rect(s0, s1, s2, &srcrect); - maxx = srcrect.x + srcrect.w; - maxy = srcrect.y + srcrect.h; - if (srcrect.w > 0) { - if (s0->x == maxx) { - s0->x--; - } - if (s1->x == maxx) { - s1->x--; - } - if (s2->x == maxx) { - s2->x--; + if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_CLAMP) { + int maxx = srcrect.x + srcrect.w; + if (srcrect.w > 0) { + if (s0->x == maxx) { + s0->x--; + } + if (s1->x == maxx) { + s1->x--; + } + if (s2->x == maxx) { + s2->x--; + } } } - if (srcrect.h > 0) { - if (s0->y == maxy) { - s0->y--; - } - if (s1->y == maxy) { - s1->y--; - } - if (s2->y == maxy) { - s2->y--; + if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_CLAMP) { + int maxy = srcrect.y + srcrect.h; + if (srcrect.h > 0) { + if (s0->y == maxy) { + s0->y--; + } + if (s1->y == maxy) { + s1->y--; + } + if (s2->y == maxy) { + s2->y--; + } } } } @@ -716,7 +725,7 @@ bool SDL_SW_BlitTriangle( SDL_BlitTriangle_Slow(&tmp_info, s2_x_area, dstrect, (int)area, bias_w0, bias_w1, bias_w2, d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x, s2s0_x, s2s1_x, s2s0_y, s2s1_y, (int)w0_row, (int)w1_row, (int)w2_row, - c0, c1, c2, is_uniform, texture_address_mode); + c0, c1, c2, is_uniform, texture_address_mode_u, texture_address_mode_v); goto end; } @@ -788,7 +797,9 @@ static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, - SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, SDL_TextureAddressMode texture_address_mode) + SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, + SDL_TextureAddressMode texture_address_mode_u, + SDL_TextureAddressMode texture_address_mode_v) { SDL_Surface *src_surface = info->src_surface; const int flags = info->flags; diff --git a/src/render/software/SDL_triangle.h b/src/render/software/SDL_triangle.h index 1c5504cfd8..89f8abb8c8 100644 --- a/src/render/software/SDL_triangle.h +++ b/src/render/software/SDL_triangle.h @@ -24,8 +24,6 @@ #include "SDL_internal.h" -#include "../SDL_sysrender.h" // For SDL_TextureAddressMode - extern bool SDL_SW_FillTriangle(SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, SDL_BlendMode blend, SDL_Color c0, SDL_Color c1, SDL_Color c2); @@ -35,7 +33,8 @@ extern bool SDL_SW_BlitTriangle(SDL_Surface *src, SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, SDL_Color c0, SDL_Color c1, SDL_Color c2, - SDL_TextureAddressMode texture_address_mode); + SDL_TextureAddressMode texture_address_mode_u, + SDL_TextureAddressMode texture_address_mode_v); extern void trianglepoint_2_fixedpoint(SDL_Point *a); diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c index 9ad14c396a..79dd1163b5 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm.c +++ b/src/render/vitagxm/SDL_render_vita_gxm.c @@ -293,7 +293,8 @@ static bool VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, } vita_texture->scale_mode = SDL_SCALEMODE_INVALID; - vita_texture->address_mode = SDL_TEXTURE_ADDRESS_INVALID; + vita_texture->address_mode_u = SDL_TEXTURE_ADDRESS_INVALID; + vita_texture->address_mode_v = SDL_TEXTURE_ADDRESS_INVALID; texture->internal = vita_texture; @@ -806,6 +807,19 @@ static bool VITA_GXM_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) return true; } +static SceGxmTextureAddrMode TranslateAddressMode(SDL_TextureAddressMode mode) +{ + switch (mode) { + case SDL_TEXTURE_ADDRESS_CLAMP: + return SCE_GXM_TEXTURE_ADDR_CLAMP; + case SDL_TEXTURE_ADDRESS_WRAP: + return SCE_GXM_TEXTURE_ADDR_REPEAT; + default: + SDL_assert(!"Unknown texture address mode"); + return SCE_GXM_TEXTURE_ADDR_CLAMP; + } +} + static bool SetDrawState(VITA_GXM_RenderData *data, const SDL_RenderCommand *cmd) { SDL_Texture *texture = cmd->data.draw.texture; @@ -906,18 +920,13 @@ static bool SetDrawState(VITA_GXM_RenderData *data, const SDL_RenderCommand *cmd vita_texture->scale_mode = cmd->data.draw.texture_scale_mode; } - if (cmd->data.draw.texture_address_mode != vita_texture->address_mode) { - switch (cmd->data.draw.texture_address_mode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - gxm_texture_set_address_mode(vita_texture->tex, SCE_GXM_TEXTURE_ADDR_CLAMP, SCE_GXM_TEXTURE_ADDR_CLAMP); - break; - case SDL_TEXTURE_ADDRESS_WRAP: - gxm_texture_set_address_mode(vita_texture->tex, SCE_GXM_TEXTURE_ADDR_REPEAT, SCE_GXM_TEXTURE_ADDR_REPEAT); - break; - default: - break; - } - vita_texture->address_mode = cmd->data.draw.texture_address_mode; + if (cmd->data.draw.texture_address_mode_u != vita_texture->address_mode_u || + cmd->data.draw.texture_address_mode_v != vita_texture->address_mode_v) { + SceGxmTextureAddrMode mode_u = TranslateAddressMode(cmd->data.draw.texture_address_mode_u); + SceGxmTextureAddrMode mode_v = TranslateAddressMode(cmd->data.draw.texture_address_mode_v); + gxm_texture_set_address_mode(vita_texture->tex, mode_u, mode_v); + vita_texture->address_mode_u = cmd->data.draw.texture_address_mode_u; + vita_texture->address_mode_v = cmd->data.draw.texture_address_mode_v; } } diff --git a/src/render/vitagxm/SDL_render_vita_gxm_types.h b/src/render/vitagxm/SDL_render_vita_gxm_types.h index e23137f632..f56814be6e 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_types.h +++ b/src/render/vitagxm/SDL_render_vita_gxm_types.h @@ -206,7 +206,8 @@ typedef struct bool yuv; bool nv12; SDL_ScaleMode scale_mode; - SDL_TextureAddressMode address_mode; + SDL_TextureAddressMode address_mode_u; + SDL_TextureAddressMode address_mode_v; } VITA_GXM_TextureData; #endif // SDL_RENDER_VITA_GXM_TYPES_H diff --git a/src/render/vulkan/SDL_render_vulkan.c b/src/render/vulkan/SDL_render_vulkan.c index 1bda3715b5..82ee9f8a15 100644 --- a/src/render/vulkan/SDL_render_vulkan.c +++ b/src/render/vulkan/SDL_render_vulkan.c @@ -169,16 +169,6 @@ typedef enum { VULKAN_RENDERPASS_COUNT } VULKAN_RenderPass; -// Sampler types -typedef enum -{ - VULKAN_SAMPLER_NEAREST_CLAMP, - VULKAN_SAMPLER_NEAREST_WRAP, - VULKAN_SAMPLER_LINEAR_CLAMP, - VULKAN_SAMPLER_LINEAR_WRAP, - VULKAN_SAMPLER_COUNT -} VULKAN_Sampler; - // Vertex shader, common values typedef struct { @@ -196,15 +186,6 @@ static const float INPUTTYPE_SRGB = 1; static const float INPUTTYPE_SCRGB = 2; static const float INPUTTYPE_HDR10 = 3; -typedef enum -{ - SAMPLER_POINT_CLAMP, - SAMPLER_POINT_WRAP, - SAMPLER_LINEAR_CLAMP, - SAMPLER_LINEAR_WRAP, - NUM_SAMPLERS -} Sampler; - // Pixel shader constants, common values typedef struct { @@ -347,7 +328,7 @@ typedef struct uint32_t currentConstantBufferIndex; int32_t currentConstantBufferOffset; - VkSampler samplers[VULKAN_SAMPLER_COUNT]; + VkSampler samplers[RENDER_SAMPLER_COUNT]; VkDescriptorPool **descriptorPools; uint32_t *numDescriptorPools; uint32_t currentDescriptorPoolIndex; @@ -1950,42 +1931,6 @@ static VkResult VULKAN_CreateDeviceResources(SDL_Renderer *renderer, SDL_Propert VULKAN_CreateVertexBuffer(rendererData, i, SDL_VULKAN_VERTEX_BUFFER_DEFAULT_SIZE); } - // Create samplers - { - static struct - { - VkFilter filter; - VkSamplerAddressMode address; - } samplerParams[] = { - { VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, - { VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_REPEAT }, - { VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, - { VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT }, - }; - SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == VULKAN_SAMPLER_COUNT); - VkSamplerCreateInfo samplerCreateInfo = { 0 }; - samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCreateInfo.mipLodBias = 0.0f; - samplerCreateInfo.anisotropyEnable = VK_FALSE; - samplerCreateInfo.maxAnisotropy = 1.0f; - samplerCreateInfo.minLod = 0.0f; - samplerCreateInfo.maxLod = 1000.0f; - for (int i = 0; i < SDL_arraysize(samplerParams); ++i) { - samplerCreateInfo.magFilter = samplerParams[i].filter; - samplerCreateInfo.minFilter = samplerParams[i].filter; - samplerCreateInfo.addressModeU = samplerParams[i].address; - samplerCreateInfo.addressModeV = samplerParams[i].address; - result = vkCreateSampler(rendererData->device, &samplerCreateInfo, NULL, &rendererData->samplers[i]); - if (result != VK_SUCCESS) { - VULKAN_DestroyAll(renderer); - SET_ERROR_CODE("vkCreateSampler()", result); - return result; - } - } - } - SDL_PropertiesID props = SDL_GetRendererProperties(renderer); SDL_SetPointerProperty(props, SDL_PROP_RENDERER_VULKAN_INSTANCE_POINTER, rendererData->instance); SDL_SetNumberProperty(props, SDL_PROP_RENDERER_VULKAN_SURFACE_NUMBER, (Sint64)rendererData->surface); @@ -3762,6 +3707,42 @@ static bool VULKAN_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand return true; } +static VkSampler VULKAN_GetSampler(VULKAN_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v) +{ + Uint32 key = RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v); + SDL_assert(key < SDL_arraysize(data->samplers)); + if (!data->samplers[key]) { + VkSamplerCreateInfo samplerCreateInfo = { 0 }; + samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerCreateInfo.mipLodBias = 0.0f; + samplerCreateInfo.anisotropyEnable = VK_FALSE; + samplerCreateInfo.maxAnisotropy = 1.0f; + samplerCreateInfo.minLod = 0.0f; + samplerCreateInfo.maxLod = 1000.0f; + switch (scale_mode) { + case SDL_SCALEMODE_NEAREST: + samplerCreateInfo.magFilter = VK_FILTER_NEAREST; + samplerCreateInfo.minFilter = VK_FILTER_NEAREST; + break; + case SDL_SCALEMODE_PIXELART: // Uses linear sampling + case SDL_SCALEMODE_LINEAR: + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + break; + default: + SDL_SetError("Unknown scale mode: %d", scale_mode); + return VK_NULL_HANDLE; + } + VkResult result = vkCreateSampler(data->device, &samplerCreateInfo, NULL, &data->samplers[key]); + if (result != VK_SUCCESS) { + SET_ERROR_CODE("vkCreateSampler()", result); + return false; + } + } + return data->samplers[key]; +} static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix, VULKAN_DrawStateCache *stateCache) { @@ -3775,34 +3756,9 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand VULKAN_SetupShaderConstants(renderer, cmd, texture, &constants); - switch (cmd->data.draw.texture_scale_mode) { - case SDL_SCALEMODE_NEAREST: - switch (cmd->data.draw.texture_address_mode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - textureSampler = rendererData->samplers[VULKAN_SAMPLER_NEAREST_CLAMP]; - break; - case SDL_TEXTURE_ADDRESS_WRAP: - textureSampler = rendererData->samplers[VULKAN_SAMPLER_NEAREST_WRAP]; - break; - default: - return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); - } - break; - case SDL_SCALEMODE_PIXELART: // Uses linear sampling - case SDL_SCALEMODE_LINEAR: - switch (cmd->data.draw.texture_address_mode) { - case SDL_TEXTURE_ADDRESS_CLAMP: - textureSampler = rendererData->samplers[VULKAN_SAMPLER_LINEAR_CLAMP]; - break; - case SDL_TEXTURE_ADDRESS_WRAP: - textureSampler = rendererData->samplers[VULKAN_SAMPLER_LINEAR_WRAP]; - break; - default: - return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); - } - break; - default: - return SDL_SetError("Unknown scale mode: %d", cmd->data.draw.texture_scale_mode); + textureSampler = VULKAN_GetSampler(rendererData, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); + if (textureSampler == VK_NULL_HANDLE) { + return false; } if (textureData->mainImage.imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {