From 633b9f6fb1efd1e582872f847865f9eb17d136cb Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 20 Jul 2024 09:34:34 -0700
Subject: [PATCH] Added SDL_SetRenderTextureAddressMode() and
SDL_GetRenderTextureAddressMode()
Fixes https://github.com/libsdl-org/SDL/issues/4820
Fixes https://github.com/libsdl-org/SDL/issues/12610
---
include/SDL3/SDL_render.h | 49 ++++++
src/dynapi/SDL_dynapi.sym | 2 +
src/dynapi/SDL_dynapi_overrides.h | 2 +
src/dynapi/SDL_dynapi_procs.h | 2 +
src/render/SDL_render.c | 94 +++++++++---
src/render/SDL_sysrender.h | 20 +--
src/render/direct3d/SDL_render_d3d.c | 52 ++++---
src/render/direct3d11/SDL_render_d3d11.c | 135 ++++++++---------
src/render/direct3d12/SDL_render_d3d12.c | 124 ++++++++-------
src/render/gpu/SDL_render_gpu.c | 141 ++++++++----------
src/render/metal/SDL_render_metal.m | 135 +++++++++--------
src/render/opengl/SDL_render_gl.c | 54 +++----
src/render/opengles2/SDL_render_gles2.c | 54 +++----
src/render/psp/SDL_render_psp.c | 55 ++++---
src/render/software/SDL_render_sw.c | 3 +-
src/render/software/SDL_triangle.c | 65 ++++----
src/render/software/SDL_triangle.h | 5 +-
src/render/vitagxm/SDL_render_vita_gxm.c | 35 +++--
.../vitagxm/SDL_render_vita_gxm_types.h | 3 +-
src/render/vulkan/SDL_render_vulkan.c | 124 +++++----------
20 files changed, 623 insertions(+), 531 deletions(-)
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index 33b6e1feb9c0e..63dbfa50be321 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 9f84fbbc91fdf..6ec8127dfa490 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 7ebb71721cae3..c00526490019d 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 fa12a5815aca5..31f56143e35c1 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 15949f75d6505..ca23ce5714ce8 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,18 +5137,38 @@ 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;
+ }
}
if (indices) {
@@ -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 2e6cc76cde051..5109b93451648 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 b816abfb1e0ae..5132a23226402 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 77d2faf828896..12fd5abc452c0 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 c7ba5e9fb007d..7b21e96354deb 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 coul
(Patch may be truncated, please check the link at the top of this post.)