Parcourir la source

Make texture scale mode a part of the 2D renderer draw state

Also added texture addressing mode support to the PSP and Vita renderers (untested)

Fixes https://github.com/libsdl-org/SDL/issues/12461

(cherry picked from commit cb099ebd4f82bf85403fbc60713a6d463972a798)
Sam Lantinga il y a 1 mois
Parent
commit
b32cd4f84b

+ 1 - 0
include/SDL3/SDL_surface.h

@@ -82,6 +82,7 @@ typedef Uint32 SDL_SurfaceFlags;
  */
 typedef enum SDL_ScaleMode
 {
+    SDL_SCALEMODE_INVALID = -1,
     SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */
     SDL_SCALEMODE_LINEAR   /**< linear filtering */
 } SDL_ScaleMode;

+ 4 - 5
src/render/SDL_render.c

@@ -573,6 +573,9 @@ static SDL_RenderCommand *PrepQueueCmdDraw(SDL_Renderer *renderer, const SDL_Ren
             cmd->data.draw.color = *color;
             cmd->data.draw.blend = blendMode;
             cmd->data.draw.texture = texture;
+            if (texture) {
+                cmd->data.draw.texture_scale_mode = texture->scaleMode;
+            }
             cmd->data.draw.texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP;
         }
     }
@@ -1962,8 +1965,6 @@ bool SDL_GetTextureBlendMode(SDL_Texture *texture, SDL_BlendMode *blendMode)
 
 bool SDL_SetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode scaleMode)
 {
-    SDL_Renderer *renderer;
-
     CHECK_TEXTURE_MAGIC(texture, false);
 
     if (scaleMode != SDL_SCALEMODE_NEAREST &&
@@ -1971,12 +1972,10 @@ bool SDL_SetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode scaleMode)
         return SDL_InvalidParamError("scaleMode");
     }
 
-    renderer = texture->renderer;
     texture->scaleMode = scaleMode;
+
     if (texture->native) {
         return SDL_SetTextureScaleMode(texture->native, scaleMode);
-    } else {
-        renderer->SetTextureScaleMode(renderer, texture, scaleMode);
     }
     return true;
 }

+ 2 - 1
src/render/SDL_sysrender.h

@@ -34,6 +34,7 @@ extern "C" {
 
 typedef enum SDL_TextureAddressMode
 {
+    SDL_TEXTURE_ADDRESS_INVALID = -1,
     SDL_TEXTURE_ADDRESS_AUTO,
     SDL_TEXTURE_ADDRESS_CLAMP,
     SDL_TEXTURE_ADDRESS_WRAP,
@@ -155,6 +156,7 @@ typedef struct SDL_RenderCommand
             SDL_FColor color;
             SDL_BlendMode blend;
             SDL_Texture *texture;
+            SDL_ScaleMode texture_scale_mode;
             SDL_TextureAddressMode texture_address_mode;
         } draw;
         struct
@@ -224,7 +226,6 @@ struct SDL_Renderer
     bool (*LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture,
                        const SDL_Rect *rect, void **pixels, int *pitch);
     void (*UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture);
-    void (*SetTextureScaleMode)(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode);
     bool (*SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture);
     SDL_Surface *(*RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect);
     bool (*RenderPresent)(SDL_Renderer *renderer);

+ 38 - 32
src/render/direct3d/SDL_render_d3d.c

@@ -60,7 +60,7 @@ typedef struct
     bool updateSize;
     bool beginScene;
     bool enableSeparateAlphaBlend;
-    D3DTEXTUREFILTERTYPE scaleMode[3];
+    SDL_ScaleMode scaleMode[3];
     SDL_TextureAddressMode addressMode[3];
     IDirect3DSurface9 *defaultRenderTarget;
     IDirect3DSurface9 *currentRenderTarget;
@@ -89,7 +89,6 @@ typedef struct
 typedef struct
 {
     D3D_TextureRep texture;
-    D3DTEXTUREFILTERTYPE scaleMode;
     D3D9_Shader shader;
     const float *shader_params;
 
@@ -274,10 +273,14 @@ static void D3D_InitRenderState(D3D_RenderData *data)
     IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
 
     // Reset our current scale mode
-    SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
+    for (int i = 0; i < SDL_arraysize(data->scaleMode); ++i) {
+        data->scaleMode[i] = SDL_SCALEMODE_INVALID;
+    }
 
     // Reset our current address mode
-    SDL_zeroa(data->addressMode);
+    for (int i = 0; i < SDL_arraysize(data->addressMode); ++i) {
+        data->addressMode[i] = SDL_TEXTURE_ADDRESS_INVALID;
+    }
 
     // Start the render with beginScene
     data->beginScene = true;
@@ -533,7 +536,6 @@ static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
     if (!texturedata) {
         return false;
     }
-    texturedata->scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
 
     texture->internal = texturedata;
 
@@ -736,17 +738,6 @@ static void D3D_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     }
 }
 
-static void D3D_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
-
-    if (!texturedata) {
-        return;
-    }
-
-    texturedata->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
-}
-
 static bool D3D_SetRenderTargetInternal(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
@@ -926,12 +917,22 @@ static bool BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DW
     return true;
 }
 
-static void UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
+static void UpdateTextureScaleMode(D3D_RenderData *data, SDL_ScaleMode scaleMode, unsigned index)
 {
-    if (texturedata->scaleMode != data->scaleMode[index]) {
-        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, texturedata->scaleMode);
-        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, texturedata->scaleMode);
-        data->scaleMode[index] = texturedata->scaleMode;
+    if (scaleMode != data->scaleMode[index]) {
+        switch (scaleMode) {
+        case SDL_SCALEMODE_NEAREST:
+            IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, D3DTEXF_POINT);
+            IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
+            break;
+        case SDL_SCALEMODE_LINEAR:
+            IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+            IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+            break;
+        default:
+            break;
+        }
+        data->scaleMode[index] = scaleMode;
     }
 }
 
@@ -954,7 +955,7 @@ static void UpdateTextureAddressMode(D3D_RenderData *data, SDL_TextureAddressMod
     }
 }
 
-static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, SDL_TextureAddressMode addressMode, D3D9_Shader *shader, const float **shader_params)
+static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, D3D9_Shader *shader, const float **shader_params)
 {
     D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
 
@@ -962,9 +963,6 @@ static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, SDL_Te
         return SDL_SetError("Texture is not currently available");
     }
 
-    UpdateTextureScaleMode(data, texturedata, 0);
-    UpdateTextureAddressMode(data, addressMode, 0);
-
     *shader = texturedata->shader;
     *shader_params = texturedata->shader_params;
 
@@ -973,11 +971,6 @@ static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, SDL_Te
     }
 #ifdef SDL_HAVE_YUV
     if (texturedata->yuv) {
-        UpdateTextureScaleMode(data, texturedata, 1);
-        UpdateTextureScaleMode(data, texturedata, 2);
-        UpdateTextureAddressMode(data, addressMode, 1);
-        UpdateTextureAddressMode(data, addressMode, 2);
-
         if (!BindTextureRep(data->device, &texturedata->utexture, 1)) {
             return false;
         }
@@ -1012,7 +1005,7 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
             IDirect3DDevice9_SetTexture(data->device, 2, NULL);
         }
 #endif
-        if (texture && !SetupTextureState(data, texture, cmd->data.draw.texture_address_mode, &shader, &shader_params)) {
+        if (texture && !SetupTextureState(data, texture, &shader, &shader_params)) {
             return false;
         }
 
@@ -1049,6 +1042,20 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
 #endif
     }
 
+    if (texture) {
+        D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
+
+        UpdateTextureScaleMode(data, cmd->data.draw.texture_scale_mode, 0);
+        UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode, 0);
+
+        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);
+        }
+    }
+
     if (blend != data->drawstate.blend) {
         if (blend == SDL_BLENDMODE_NONE) {
             IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
@@ -1653,7 +1660,6 @@ static bool D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
 #endif
     renderer->LockTexture = D3D_LockTexture;
     renderer->UnlockTexture = D3D_UnlockTexture;
-    renderer->SetTextureScaleMode = D3D_SetTextureScaleMode;
     renderer->SetRenderTarget = D3D_SetRenderTarget;
     renderer->QueueSetViewport = D3D_QueueNoOp;
     renderer->QueueSetDrawColor = D3D_QueueNoOp;

+ 4 - 18
src/render/direct3d11/SDL_render_d3d11.c

@@ -122,7 +122,6 @@ typedef struct
     ID3D11Texture2D *stagingTexture;
     int lockedTexturePositionX;
     int lockedTexturePositionY;
-    D3D11_FILTER scaleMode;
     D3D11_Shader shader;
     const float *YCbCr_matrix;
 #ifdef SDL_HAVE_YUV
@@ -1172,7 +1171,6 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
     if (!textureData) {
         return false;
     }
-    textureData->scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
 
     texture->internal = textureData;
 
@@ -1796,17 +1794,6 @@ static void D3D11_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     SAFE_RELEASE(textureData->stagingTexture);
 }
 
-static void D3D11_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal;
-
-    if (!textureData) {
-        return;
-    }
-
-    textureData->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
-}
-
 static bool D3D11_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal;
@@ -2318,8 +2305,8 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
 
     D3D11_SetupShaderConstants(renderer, cmd, texture, &constants);
 
-    switch (textureData->scaleMode) {
-    case D3D11_FILTER_MIN_MAG_MIP_POINT:
+    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];
@@ -2331,7 +2318,7 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
             return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
         }
         break;
-    case D3D11_FILTER_MIN_MAG_MIP_LINEAR:
+    case SDL_SCALEMODE_LINEAR:
         switch (cmd->data.draw.texture_address_mode) {
         case SDL_TEXTURE_ADDRESS_CLAMP:
             textureSampler = rendererData->samplers[D3D11_SAMPLER_LINEAR_CLAMP];
@@ -2344,7 +2331,7 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
         }
         break;
     default:
-        return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode);
+        return SDL_SetError("Unknown scale mode: %d", cmd->data.draw.texture_scale_mode);
     }
 #ifdef SDL_HAVE_YUV
     if (textureData->yuv) {
@@ -2712,7 +2699,6 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
 #endif
     renderer->LockTexture = D3D11_LockTexture;
     renderer->UnlockTexture = D3D11_UnlockTexture;
-    renderer->SetTextureScaleMode = D3D11_SetTextureScaleMode;
     renderer->SetRenderTarget = D3D11_SetRenderTarget;
     renderer->QueueSetViewport = D3D11_QueueNoOp;
     renderer->QueueSetDrawColor = D3D11_QueueNoOp;

+ 4 - 18
src/render/direct3d12/SDL_render_d3d12.c

@@ -124,7 +124,6 @@ typedef struct
     DXGI_FORMAT mainTextureFormat;
     ID3D12Resource *stagingBuffer;
     D3D12_RESOURCE_STATES stagingResourceState;
-    D3D12_FILTER scaleMode;
     D3D12_Shader shader;
     const float *YCbCr_matrix;
 #ifdef SDL_HAVE_YUV
@@ -1574,7 +1573,6 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
     if (!textureData) {
         return false;
     }
-    textureData->scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? D3D12_FILTER_MIN_MAG_MIP_POINT : D3D12_FILTER_MIN_MAG_MIP_LINEAR;
 
     texture->internal = textureData;
     textureData->mainTextureFormat = textureFormat;
@@ -2244,17 +2242,6 @@ static void D3D12_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     D3D_SAFE_RELEASE(textureData->stagingBuffer);
 }
 
-static void D3D12_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    D3D12_TextureData *textureData = (D3D12_TextureData *)texture->internal;
-
-    if (!textureData) {
-        return;
-    }
-
-    textureData->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? D3D12_FILTER_MIN_MAG_MIP_POINT : D3D12_FILTER_MIN_MAG_MIP_LINEAR;
-}
-
 static bool D3D12_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     D3D12_RenderData *rendererData = (D3D12_RenderData *)renderer->internal;
@@ -2745,8 +2732,8 @@ static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
 
     D3D12_SetupShaderConstants(renderer, cmd, texture, &constants);
 
-    switch (textureData->scaleMode) {
-    case D3D12_FILTER_MIN_MAG_MIP_POINT:
+    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];
@@ -2758,7 +2745,7 @@ static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
             return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
         }
         break;
-    case D3D12_FILTER_MIN_MAG_MIP_LINEAR:
+    case SDL_SCALEMODE_LINEAR:
         switch (cmd->data.draw.texture_address_mode) {
         case SDL_TEXTURE_ADDRESS_CLAMP:
             textureSampler = &rendererData->samplers[D3D12_SAMPLER_LINEAR_CLAMP];
@@ -2771,7 +2758,7 @@ static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
         }
         break;
     default:
-        return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode);
+        return SDL_SetError("Unknown scale mode: %d", cmd->data.draw.texture_scale_mode);
     }
 #ifdef SDL_HAVE_YUV
     if (textureData->yuv) {
@@ -3248,7 +3235,6 @@ bool D3D12_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Proper
 #endif
     renderer->LockTexture = D3D12_LockTexture;
     renderer->UnlockTexture = D3D12_UnlockTexture;
-    renderer->SetTextureScaleMode = D3D12_SetTextureScaleMode;
     renderer->SetRenderTarget = D3D12_SetRenderTarget;
     renderer->QueueSetViewport = D3D12_QueueNoOp;
     renderer->QueueSetDrawColor = D3D12_QueueNoOp;

+ 8 - 10
src/render/gpu/SDL_render_gpu.c

@@ -335,11 +335,6 @@ static void GPU_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     GPU_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
 }
 
-static void GPU_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scale_mode)
-{
-    // nothing to do in this backend.
-}
-
 static bool GPU_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
@@ -494,8 +489,7 @@ static void PushUniforms(GPU_RenderData *data, SDL_RenderCommand *cmd)
     SDL_PushGPUVertexUniformData(data->state.command_buffer, 0, &uniforms, sizeof(uniforms));
 }
 
-static SDL_GPUSampler **SamplerPointer(
-    GPU_RenderData *data, SDL_TextureAddressMode address_mode, SDL_ScaleMode scale_mode)
+static SDL_GPUSampler **SamplerPointer(GPU_RenderData *data, SDL_TextureAddressMode address_mode, SDL_ScaleMode scale_mode)
 {
     return &data->samplers[scale_mode][address_mode - 1];
 }
@@ -575,7 +569,7 @@ static void Draw(
     if (tdata) {
         SDL_GPUTextureSamplerBinding sampler_bind;
         SDL_zero(sampler_bind);
-        sampler_bind.sampler = *SamplerPointer(data, cmd->data.draw.texture_address_mode, cmd->data.draw.texture->scaleMode);
+        sampler_bind.sampler = *SamplerPointer(data, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_scale_mode);
         sampler_bind.texture = tdata->texture;
         SDL_BindGPUFragmentSamplers(pass, 0, &sampler_bind, 1);
     }
@@ -785,6 +779,8 @@ static bool GPU_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
                same texture, we can combine them all into a single draw call. */
             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;
             const SDL_RenderCommandType thiscmdtype = cmd->command;
             SDL_RenderCommand *finalcmd = cmd;
             SDL_RenderCommand *nextcmd = cmd->next;
@@ -795,7 +791,10 @@ static bool GPU_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
                 const SDL_RenderCommandType nextcmdtype = nextcmd->command;
                 if (nextcmdtype != thiscmdtype) {
                     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.blend != thisblend) {
+                } else if (nextcmd->data.draw.texture != thistexture ||
+                           nextcmd->data.draw.texture_scale_mode != thisscalemode ||
+                           nextcmd->data.draw.texture_address_mode != thisaddressmode ||
+                           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.
                 } else {
@@ -1176,7 +1175,6 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
     renderer->UpdateTexture = GPU_UpdateTexture;
     renderer->LockTexture = GPU_LockTexture;
     renderer->UnlockTexture = GPU_UnlockTexture;
-    renderer->SetTextureScaleMode = GPU_SetTextureScaleMode;
     renderer->SetRenderTarget = GPU_SetRenderTarget;
     renderer->QueueSetViewport = GPU_QueueNoOp;
     renderer->QueueSetDrawColor = GPU_QueueNoOp;

+ 1 - 6
src/render/metal/SDL_render_metal.m

@@ -1070,10 +1070,6 @@ static void METAL_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     }
 }
 
-static void METAL_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-}
-
 static bool METAL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     @autoreleasepool {
@@ -1473,7 +1469,7 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
     if (texture != statecache->texture) {
         id<MTLSamplerState> mtlsampler;
 
-        if (texture->scaleMode == SDL_SCALEMODE_NEAREST) {
+        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];
@@ -2129,7 +2125,6 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
 #endif
         renderer->LockTexture = METAL_LockTexture;
         renderer->UnlockTexture = METAL_UnlockTexture;
-        renderer->SetTextureScaleMode = METAL_SetTextureScaleMode;
         renderer->SetRenderTarget = METAL_SetRenderTarget;
         renderer->QueueSetViewport = METAL_QueueSetViewport;
         renderer->QueueSetDrawColor = METAL_QueueNoOp;

+ 85 - 72
src/render/opengl/SDL_render_gl.c

@@ -137,7 +137,6 @@ typedef struct
     void *pixels;
     int pitch;
     SDL_Rect locked_rect;
-
 #ifdef SDL_HAVE_YUV
     // YUV texture support
     bool yuv;
@@ -147,7 +146,8 @@ typedef struct
     GLuint vtexture;
     bool vtexture_external;
 #endif
-
+    SDL_ScaleMode texture_scale_mode;
+    SDL_TextureAddressMode texture_address_mode;
     GL_FBOList *fbo;
 } GL_TextureData;
 
@@ -447,7 +447,6 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
     GLint internalFormat;
     GLenum format, type;
     int texture_w, texture_h;
-    GLenum scaleMode;
 
     GL_ActivateRenderer(renderer);
 
@@ -536,11 +535,10 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
 
     data->format = format;
     data->formattype = type;
-    scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? GL_NEAREST : GL_LINEAR;
+    data->texture_scale_mode = SDL_SCALEMODE_INVALID;
+    data->texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID;
     renderdata->glEnable(textype);
     renderdata->glBindTexture(textype, data->texture);
-    renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, scaleMode);
-    renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, scaleMode);
 #ifdef SDL_PLATFORM_MACOS
 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC
@@ -596,19 +594,11 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
         }
 
         renderdata->glBindTexture(textype, data->utexture);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
-                                    scaleMode);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
-                                    scaleMode);
         renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w + 1) / 2,
                                  (texture_h + 1) / 2, 0, format, type, NULL);
         SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_U_NUMBER, data->utexture);
 
         renderdata->glBindTexture(textype, data->vtexture);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
-                                    scaleMode);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
-                                    scaleMode);
         renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w + 1) / 2,
                                  (texture_h + 1) / 2, 0, format, type, NULL);
         SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_V_NUMBER, data->vtexture);
@@ -625,10 +615,6 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
             renderdata->glGenTextures(1, &data->utexture);
         }
         renderdata->glBindTexture(textype, data->utexture);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
-                                    scaleMode);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
-                                    scaleMode);
         renderdata->glTexImage2D(textype, 0, GL_LUMINANCE_ALPHA, (texture_w + 1) / 2,
                                  (texture_h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
         SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_UV_NUMBER, data->utexture);
@@ -822,38 +808,6 @@ static void GL_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
 }
 
-static void GL_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    GL_RenderData *renderdata = (GL_RenderData *)renderer->internal;
-    const GLenum textype = renderdata->textype;
-    GL_TextureData *data = (GL_TextureData *)texture->internal;
-    GLenum glScaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? GL_NEAREST : GL_LINEAR;
-
-    renderdata->glBindTexture(textype, data->texture);
-    renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
-    renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
-
-#ifdef SDL_HAVE_YUV
-    if (texture->format == SDL_PIXELFORMAT_YV12 ||
-        texture->format == SDL_PIXELFORMAT_IYUV) {
-        renderdata->glBindTexture(textype, data->utexture);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
-
-        renderdata->glBindTexture(textype, data->vtexture);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
-    }
-
-    if (texture->format == SDL_PIXELFORMAT_NV12 ||
-        texture->format == SDL_PIXELFORMAT_NV21) {
-        renderdata->glBindTexture(textype, data->utexture);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
-        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
-    }
-#endif
-}
-
 static bool GL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     GL_RenderData *data = (GL_RenderData *)renderer->internal;
@@ -1120,6 +1074,23 @@ static bool SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, cons
     return true;
 }
 
+static bool SetTextureScaleMode(GL_RenderData *data, GLenum textype, SDL_ScaleMode scaleMode)
+{
+    switch (scaleMode) {
+    case SDL_SCALEMODE_NEAREST:
+        data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        break;
+    case SDL_SCALEMODE_LINEAR:
+        data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        break;
+    default:
+        return SDL_SetError("Unknown texture scale mode: %d", scaleMode);
+    }
+    return true;
+}
+
 static bool SetTextureAddressMode(GL_RenderData *data, GLenum textype, SDL_TextureAddressMode addressMode)
 {
     switch (addressMode) {
@@ -1140,53 +1111,91 @@ static bool SetTextureAddressMode(GL_RenderData *data, GLenum textype, SDL_Textu
 static bool SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd)
 {
     SDL_Texture *texture = cmd->data.draw.texture;
-    const GL_TextureData *texturedata = (GL_TextureData *)texture->internal;
+    GL_TextureData *texturedata = (GL_TextureData *)texture->internal;
+    const GLenum textype = data->textype;
 
     SetDrawState(data, cmd, texturedata->shader, texturedata->shader_params);
 
     if (texture != data->drawstate.texture) {
-        const GLenum textype = data->textype;
 #ifdef SDL_HAVE_YUV
         if (texturedata->yuv) {
-            if (data->GL_ARB_multitexture_supported) {
-                data->glActiveTextureARB(GL_TEXTURE2_ARB);
-            }
+            data->glActiveTextureARB(GL_TEXTURE2_ARB);
             data->glBindTexture(textype, texturedata->vtexture);
 
-            if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) {
+            data->glActiveTextureARB(GL_TEXTURE1_ARB);
+            data->glBindTexture(textype, texturedata->utexture);
+        }
+        if (texturedata->nv12) {
+            data->glActiveTextureARB(GL_TEXTURE1_ARB);
+            data->glBindTexture(textype, texturedata->utexture);
+        }
+#endif
+        if (data->GL_ARB_multitexture_supported) {
+            data->glActiveTextureARB(GL_TEXTURE0_ARB);
+        }
+        data->glBindTexture(textype, texturedata->texture);
+
+        data->drawstate.texture = texture;
+    }
+
+    if (cmd->data.draw.texture_scale_mode != texturedata->texture_scale_mode) {
+#ifdef SDL_HAVE_YUV
+        if (texturedata->yuv) {
+            data->glActiveTextureARB(GL_TEXTURE2);
+            if (!SetTextureScaleMode(data, textype, cmd->data.draw.texture_scale_mode)) {
                 return false;
             }
 
-            if (data->GL_ARB_multitexture_supported) {
-                data->glActiveTextureARB(GL_TEXTURE1_ARB);
+            data->glActiveTextureARB(GL_TEXTURE1);
+            if (!SetTextureScaleMode(data, textype, cmd->data.draw.texture_scale_mode)) {
+                return false;
             }
-            data->glBindTexture(textype, texturedata->utexture);
 
-            if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) {
+            data->glActiveTextureARB(GL_TEXTURE0);
+        } else if (texturedata->nv12) {
+            data->glActiveTextureARB(GL_TEXTURE1);
+            if (!SetTextureScaleMode(data, textype, cmd->data.draw.texture_scale_mode)) {
                 return false;
             }
+
+            data->glActiveTextureARB(GL_TEXTURE0);
         }
-        if (texturedata->nv12) {
-            if (data->GL_ARB_multitexture_supported) {
-                data->glActiveTextureARB(GL_TEXTURE1_ARB);
+#endif
+        if (!SetTextureScaleMode(data, textype, cmd->data.draw.texture_scale_mode)) {
+            return false;
+        }
+
+        texturedata->texture_scale_mode = cmd->data.draw.texture_scale_mode;
+    }
+
+    if (cmd->data.draw.texture_address_mode != texturedata->texture_address_mode) {
+#ifdef SDL_HAVE_YUV
+        if (texturedata->yuv) {
+            data->glActiveTextureARB(GL_TEXTURE2);
+            if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) {
+                return false;
             }
-            data->glBindTexture(textype, texturedata->utexture);
 
+            data->glActiveTextureARB(GL_TEXTURE1);
             if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) {
                 return false;
             }
-        }
-#endif
-        if (data->GL_ARB_multitexture_supported) {
+
             data->glActiveTextureARB(GL_TEXTURE0_ARB);
-        }
-        data->glBindTexture(textype, texturedata->texture);
+        } else if (texturedata->nv12) {
+            data->glActiveTextureARB(GL_TEXTURE1);
+            if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) {
+                return false;
+            }
 
+            data->glActiveTextureARB(GL_TEXTURE0);
+        }
+#endif
         if (!SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode)) {
             return false;
         }
 
-        data->drawstate.texture = texture;
+        texturedata->texture_address_mode = cmd->data.draw.texture_address_mode;
     }
 
     return true;
@@ -1372,6 +1381,8 @@ static bool GL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
                same texture, we can combine them all into a single draw call. */
             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;
             const SDL_RenderCommandType thiscmdtype = cmd->command;
             SDL_RenderCommand *finalcmd = cmd;
             SDL_RenderCommand *nextcmd = cmd->next;
@@ -1381,7 +1392,10 @@ static bool GL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
                 const SDL_RenderCommandType nextcmdtype = nextcmd->command;
                 if (nextcmdtype != thiscmdtype) {
                     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.blend != thisblend) {
+                } else if (nextcmd->data.draw.texture != thistexture ||
+                           nextcmd->data.draw.texture_scale_mode != thisscalemode ||
+                           nextcmd->data.draw.texture_address_mode != thisaddressmode ||
+                           nextcmd->data.draw.blend != thisblend) {
                     break; // can't go any further on this draw call, different texture/blendmode copy up next.
                 } else {
                     finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
@@ -1656,7 +1670,6 @@ static bool GL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Pr
 #endif
     renderer->LockTexture = GL_LockTexture;
     renderer->UnlockTexture = GL_UnlockTexture;
-    renderer->SetTextureScaleMode = GL_SetTextureScaleMode;
     renderer->SetRenderTarget = GL_SetRenderTarget;
     renderer->QueueSetViewport = GL_QueueNoOp;
     renderer->QueueSetDrawColor = GL_QueueNoOp;

+ 79 - 51
src/render/opengles2/SDL_render_gles2.c

@@ -76,6 +76,8 @@ typedef struct GLES2_TextureData
     GLuint texture_u;
     GLuint texture_u_external;
 #endif
+    SDL_ScaleMode texture_scale_mode;
+    SDL_TextureAddressMode texture_address_mode;
     GLES2_FBOList *fbo;
 } GLES2_TextureData;
 
@@ -1029,6 +1031,23 @@ static bool SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, c
     return true;
 }
 
+static bool SetTextureScaleMode(GLES2_RenderData *data, GLenum textype, SDL_ScaleMode scaleMode)
+{
+    switch (scaleMode) {
+    case SDL_SCALEMODE_NEAREST:
+        data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        break;
+    case SDL_SCALEMODE_LINEAR:
+        data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        break;
+    default:
+        return SDL_SetError("Unknown texture scale mode: %d", scaleMode);
+    }
+    return true;
+}
+
 static bool SetTextureAddressMode(GLES2_RenderData *data, GLenum textype, SDL_TextureAddressMode addressMode)
 {
     switch (addressMode) {
@@ -1051,6 +1070,7 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, v
     GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
     GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
     SDL_Texture *texture = cmd->data.draw.texture;
+    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
     int ret;
 
     // Pick an appropriate shader
@@ -1172,19 +1192,66 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, v
     ret = SetDrawState(data, cmd, sourceType, vertices);
 
     if (texture != data->drawstate.texture) {
-        GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
 #ifdef SDL_HAVE_YUV
         if (tdata->yuv) {
             data->glActiveTexture(GL_TEXTURE2);
             data->glBindTexture(tdata->texture_type, tdata->texture_v);
 
-            if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
+            data->glActiveTexture(GL_TEXTURE1);
+            data->glBindTexture(tdata->texture_type, tdata->texture_u);
+
+            data->glActiveTexture(GL_TEXTURE0);
+        } else if (tdata->nv12) {
+            data->glActiveTexture(GL_TEXTURE1);
+            data->glBindTexture(tdata->texture_type, tdata->texture_u);
+
+            data->glActiveTexture(GL_TEXTURE0);
+        }
+#endif
+        data->glBindTexture(tdata->texture_type, tdata->texture);
+
+        data->drawstate.texture = texture;
+    }
+
+    if (cmd->data.draw.texture_scale_mode != tdata->texture_scale_mode) {
+#ifdef SDL_HAVE_YUV
+        if (tdata->yuv) {
+            data->glActiveTexture(GL_TEXTURE2);
+            if (!SetTextureScaleMode(data, tdata->texture_type, cmd->data.draw.texture_scale_mode)) {
                 return false;
             }
 
             data->glActiveTexture(GL_TEXTURE1);
-            data->glBindTexture(tdata->texture_type, tdata->texture_u);
+            if (!SetTextureScaleMode(data, tdata->texture_type, cmd->data.draw.texture_scale_mode)) {
+                return false;
+            }
+
+            data->glActiveTexture(GL_TEXTURE0);
+        } else if (tdata->nv12) {
+            data->glActiveTexture(GL_TEXTURE1);
+            if (!SetTextureScaleMode(data, tdata->texture_type, cmd->data.draw.texture_scale_mode)) {
+                return false;
+            }
 
+            data->glActiveTexture(GL_TEXTURE0);
+        }
+#endif
+        if (!SetTextureScaleMode(data, tdata->texture_type, cmd->data.draw.texture_scale_mode)) {
+            return false;
+        }
+
+        tdata->texture_scale_mode = cmd->data.draw.texture_scale_mode;
+    }
+
+    if (cmd->data.draw.texture_address_mode != tdata->texture_address_mode) {
+#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;
+            }
+
+            data->glActiveTexture(GL_TEXTURE1);
             if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
                 return false;
             }
@@ -1192,8 +1259,6 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, v
             data->glActiveTexture(GL_TEXTURE0);
         } else if (tdata->nv12) {
             data->glActiveTexture(GL_TEXTURE1);
-            data->glBindTexture(tdata->texture_type, tdata->texture_u);
-
             if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
                 return false;
             }
@@ -1201,13 +1266,11 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, v
             data->glActiveTexture(GL_TEXTURE0);
         }
 #endif
-        data->glBindTexture(tdata->texture_type, tdata->texture);
-
         if (!SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode)) {
             return false;
         }
 
-        data->drawstate.texture = texture;
+        tdata->texture_address_mode = cmd->data.draw.texture_address_mode;
     }
 
     return ret;
@@ -1384,6 +1447,8 @@ static bool GLES2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
                same texture, we can combine them all into a single draw call. */
             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;
             const SDL_RenderCommandType thiscmdtype = cmd->command;
             SDL_RenderCommand *finalcmd = cmd;
             SDL_RenderCommand *nextcmd = cmd->next;
@@ -1393,7 +1458,10 @@ static bool GLES2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
                 const SDL_RenderCommandType nextcmdtype = nextcmd->command;
                 if (nextcmdtype != thiscmdtype) {
                     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.blend != thisblend) {
+                } else if (nextcmd->data.draw.texture != thistexture ||
+                           nextcmd->data.draw.texture_scale_mode != thisscalemode ||
+                           nextcmd->data.draw.texture_address_mode != thisaddressmode ||
+                           nextcmd->data.draw.blend != thisblend) {
                     break; // can't go any further on this draw call, different texture/blendmode copy up next.
                 } else {
                     finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
@@ -1486,7 +1554,6 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
     GLES2_TextureData *data;
     GLenum format;
     GLenum type;
-    GLenum scaleMode;
 
     GLES2_ActivateRenderer(renderer);
 
@@ -1544,7 +1611,8 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
     data->texture_u = 0;
     data->texture_v = 0;
 #endif
-    scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? GL_NEAREST : GL_LINEAR;
+    data->texture_scale_mode = SDL_SCALEMODE_INVALID;
+    data->texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID;
 
     // Allocate a blob for image renderdata
     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
@@ -1583,8 +1651,6 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
         }
         renderdata->glActiveTexture(GL_TEXTURE2);
         renderdata->glBindTexture(data->texture_type, data->texture_v);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
         renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
         SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER, data->texture_v);
 
@@ -1599,8 +1665,6 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
         }
         renderdata->glActiveTexture(GL_TEXTURE1);
         renderdata->glBindTexture(data->texture_type, data->texture_u);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
         renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
         if (!GL_CheckError("glTexImage2D()", renderer)) {
             return false;
@@ -1622,8 +1686,6 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
         }
         renderdata->glActiveTexture(GL_TEXTURE1);
         renderdata->glBindTexture(data->texture_type, data->texture_u);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
         renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
         if (!GL_CheckError("glTexImage2D()", renderer)) {
             return false;
@@ -1648,8 +1710,6 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
     texture->internal = data;
     renderdata->glActiveTexture(GL_TEXTURE0);
     renderdata->glBindTexture(data->texture_type, data->texture);
-    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
-    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
     if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) {
         renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
         if (!GL_CheckError("glTexImage2D()", renderer)) {
@@ -1900,37 +1960,6 @@ static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
 }
 
-static void GLES2_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->internal;
-    GLES2_TextureData *data = (GLES2_TextureData *)texture->internal;
-    GLenum glScaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? GL_NEAREST : GL_LINEAR;
-
-#ifdef SDL_HAVE_YUV
-    if (data->yuv) {
-        renderdata->glActiveTexture(GL_TEXTURE2);
-        renderdata->glBindTexture(data->texture_type, data->texture_v);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
-
-        renderdata->glActiveTexture(GL_TEXTURE1);
-        renderdata->glBindTexture(data->texture_type, data->texture_u);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
-    } else if (data->nv12) {
-        renderdata->glActiveTexture(GL_TEXTURE1);
-        renderdata->glBindTexture(data->texture_type, data->texture_u);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
-        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
-    }
-#endif
-
-    renderdata->glActiveTexture(GL_TEXTURE0);
-    renderdata->glBindTexture(data->texture_type, data->texture);
-    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
-    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
-}
-
 static bool GLES2_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
@@ -2151,7 +2180,6 @@ static bool GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
 #endif
     renderer->LockTexture = GLES2_LockTexture;
     renderer->UnlockTexture = GLES2_UnlockTexture;
-    renderer->SetTextureScaleMode = GLES2_SetTextureScaleMode;
     renderer->SetRenderTarget = GLES2_SetRenderTarget;
     renderer->QueueSetViewport = GLES2_QueueNoOp;
     renderer->QueueSetDrawColor = GLES2_QueueNoOp;

+ 10 - 16
src/render/ps2/SDL_render_ps2.c

@@ -195,21 +195,6 @@ static bool PS2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
     return true;
 }
 
-static void PS2_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal;
-    /*
-     set texture filtering according to scaleMode
-     supported hint values are nearest (0, default) or linear (1)
-     gskit scale mode is either GS_FILTER_NEAREST (good for tile-map)
-     or GS_FILTER_LINEAR (good for scaling)
-     */
-    uint32_t gsKitScaleMode = (scaleMode == SDL_SCALEMODE_NEAREST
-                                   ? GS_FILTER_NEAREST
-                                   : GS_FILTER_LINEAR);
-    ps2_texture->Filter = gsKitScaleMode;
-}
-
 static bool PS2_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     return true;
@@ -458,6 +443,16 @@ static bool PS2_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_Rende
         const GSPRIMUVPOINT *verts = (GSPRIMUVPOINT *) (vertices + cmd->data.draw.first);
         GSTEXTURE *ps2_tex = (GSTEXTURE *)cmd->data.draw.texture->internal;
 
+        switch (cmd->data.draw.texture_scale_mode) {
+        case SDL_SCALEMODE_NEAREST:
+            ps2_tex->Filter = GS_FILTER_NEAREST;
+            break;
+        case SDL_SCALEMODE_LINEAR:
+            ps2_tex->Filter = GS_FILTER_LINEAR;
+            break;
+        default:
+            break;
+        }
         gsKit_TexManager_bind(data->gsGlobal, ps2_tex);
         gsKit_prim_list_triangle_goraud_texture_uv_3d(data->gsGlobal, ps2_tex, count, verts);
     } else {
@@ -695,7 +690,6 @@ static bool PS2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
     renderer->UpdateTexture = PS2_UpdateTexture;
     renderer->LockTexture = PS2_LockTexture;
     renderer->UnlockTexture = PS2_UnlockTexture;
-    renderer->SetTextureScaleMode = PS2_SetTextureScaleMode;
     renderer->SetRenderTarget = PS2_SetRenderTarget;
     renderer->QueueSetViewport = PS2_QueueSetViewport;
     renderer->QueueSetDrawColor = PS2_QueueNoOp;

+ 49 - 13
src/render/psp/SDL_render_psp.c

@@ -75,6 +75,8 @@ typedef struct
     unsigned int color;
     int shadeModel;
     SDL_Texture *texture;
+    SDL_ScaleMode texture_scale_mode;
+    SDL_TextureAddressMode texture_address_mode;
 } PSP_BlendState;
 
 typedef struct
@@ -538,20 +540,44 @@ 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) {
+    case SDL_SCALEMODE_NEAREST:
+        sceGuTexFilter(GU_NEAREST, GU_NEAREST);
+        break;
+    case SDL_SCALEMODE_LINEAR:
+        sceGuTexFilter(GU_LINEAR, GU_LINEAR);
+        break;
+    default:
+        break;
+    }
+}
+
 static void TextureActivate(SDL_Texture *texture)
 {
     PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal;
-    int scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? GU_NEAREST : GU_LINEAR;
 
     // Swizzling is useless with small textures.
     if (TextureShouldSwizzle(psp_texture, texture)) {
         TextureSwizzle(psp_texture, NULL);
     }
 
-    sceGuTexWrap(GU_REPEAT, GU_REPEAT);
     sceGuTexMode(psp_texture->format, 0, 0, psp_texture->swizzled);
-    sceGuTexFilter(scaleMode, scaleMode); // GU_NEAREST good for tile-map
-    // GU_LINEAR good for scaling
     sceGuTexImage(0, psp_texture->textureWidth, psp_texture->textureHeight, psp_texture->textureWidth, psp_texture->data);
 }
 
@@ -608,11 +634,6 @@ static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     PSP_UpdateTexture(renderer, texture, &rect, psp_texture->data, psp_texture->pitch);
 }
 
-static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    // Nothing to do because TextureActivate takes care of it
-}
-
 static bool PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     return true;
@@ -1034,6 +1055,11 @@ static void PSP_SetBlendState(PSP_RenderData *data, PSP_BlendState *state)
         }
     }
 
+    if (state->texture) {
+        SetTextureScaleMode(state->texture_scale_mode);
+        SetTextureAddressMode(state->texture_address_mode);
+    }
+
     *current = *state;
 }
 
@@ -1117,6 +1143,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
             PSP_BlendState state = {
                 .color = drawstate.color,
                 .texture = NULL,
+                .texture_scale_mode = SDL_SCALEMODE_INVALID,
+                .texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID,
                 .mode = cmd->data.draw.blend,
                 .shadeModel = GU_FLAT
             };
@@ -1132,6 +1160,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
             PSP_BlendState state = {
                 .color = drawstate.color,
                 .texture = NULL,
+                .texture_scale_mode = SDL_SCALEMODE_INVALID,
+                .texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID,
                 .mode = cmd->data.draw.blend,
                 .shadeModel = GU_FLAT
             };
@@ -1147,6 +1177,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
             PSP_BlendState state = {
                 .color = drawstate.color,
                 .texture = NULL,
+                .texture_scale_mode = SDL_SCALEMODE_INVALID,
+                .texture_address_mode = SDL_TEXTURE_ADDRESS_INVALID,
                 .mode = cmd->data.draw.blend,
                 .shadeModel = GU_FLAT
             };
@@ -1162,6 +1194,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
             PSP_BlendState state = {
                 .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,
                 .mode = cmd->data.draw.blend,
                 .shadeModel = GU_SMOOTH
             };
@@ -1176,6 +1210,8 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
             PSP_BlendState state = {
                 .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,
                 .mode = cmd->data.draw.blend,
                 .shadeModel = GU_SMOOTH
             };
@@ -1197,11 +1233,12 @@ static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
                 const VertTCV *verts = (VertTCV *)(gpumem + cmd->data.draw.first);
                 PSP_BlendState state = {
                     .color = drawstate.color,
-                    .texture = NULL,
+                    .texture = cmd->data.draw.texture,
+                    .texture_scale_mode = cmd->data.draw.texture_scale_mode,
+                    .texture_address_mode = cmd->data.draw.texture_address_mode,
                     .mode = cmd->data.draw.blend,
-                    .shadeModel = GU_FLAT
+                    .shadeModel = GU_SMOOTH
                 };
-                TextureActivate(cmd->data.draw.texture);
                 PSP_SetBlendState(data, &state);
                 sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
             }
@@ -1310,7 +1347,6 @@ static bool PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
     renderer->UpdateTexture = PSP_UpdateTexture;
     renderer->LockTexture = PSP_LockTexture;
     renderer->UnlockTexture = PSP_UnlockTexture;
-    renderer->SetTextureScaleMode = PSP_SetTextureScaleMode;
     renderer->SetRenderTarget = PSP_SetRenderTarget;
     renderer->QueueSetViewport = PSP_QueueNoOp;
     renderer->QueueSetDrawColor = PSP_QueueNoOp;

+ 10 - 15
src/render/software/SDL_render_sw.c

@@ -171,10 +171,6 @@ static void SW_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
 {
 }
 
-static void SW_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-}
-
 static bool SW_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     SW_RenderData *data = (SW_RenderData *)renderer->internal;
@@ -317,7 +313,7 @@ static bool Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *sur
 
 static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Texture *texture,
                             const SDL_Rect *srcrect, const SDL_Rect *final_rect,
-                            const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
+                            const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y, const SDL_ScaleMode scaleMode)
 {
     SDL_Surface *src = (SDL_Surface *)texture->internal;
     SDL_Rect tmp_rect;
@@ -412,7 +408,7 @@ static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Te
             result = false;
         } else {
             SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE);
-            result = SDL_BlitSurfaceScaled(src_clone, srcrect, src_scaled, &scale_rect, texture->scaleMode);
+            result = SDL_BlitSurfaceScaled(src_clone, srcrect, src_scaled, &scale_rect, scaleMode);
             SDL_DestroySurface(src_clone);
             src_clone = src_scaled;
             src_scaled = NULL;
@@ -429,7 +425,7 @@ static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Te
         SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, center,
                                        &rect_dest, &cangle, &sangle);
         src_rotated = SDLgfx_rotateSurface(src_clone, angle,
-                                           (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL,
+                                           (scaleMode == SDL_SCALEMODE_NEAREST) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL,
                                            &rect_dest, cangle, sangle, center);
         if (!src_rotated) {
             result = false;
@@ -460,7 +456,7 @@ static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Te
                     SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod);
                 }
                 // Renderer scaling, if needed
-                result = Blit_to_Screen(src_rotated, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode);
+                result = Blit_to_Screen(src_rotated, NULL, surface, &tmp_rect, scale_x, scale_y, scaleMode);
             } else {
                 /* The NONE blend mode requires three steps to get the pixels onto the destination surface.
                  * First, the area where the rotated pixels will be blitted to get set to zero.
@@ -470,7 +466,7 @@ static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Te
                 SDL_Rect mask_rect = tmp_rect;
                 SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE);
                 // Renderer scaling, if needed
-                result = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode);
+                result = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, scaleMode);
                 if (result) {
                     /* The next step copies the alpha value. This is done with the BLEND blend mode and
                      * by modulating the source colors with 0. Since the destination is all zeros, this
@@ -479,7 +475,7 @@ static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Te
                     SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0);
                     mask_rect = tmp_rect;
                     // Renderer scaling, if needed
-                    result = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode);
+                    result = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, scaleMode);
                     if (result) {
                         /* The last step gets the color values in place. The ADD blend mode simply adds them to
                          * the destination (where the color values are all zero). However, because the ADD blend
@@ -492,7 +488,7 @@ static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Te
                         } else {
                             SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD);
                             // Renderer scaling, if needed
-                            result = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode);
+                            result = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, scaleMode);
                             SDL_DestroySurface(src_rotated_rgb);
                         }
                     }
@@ -858,7 +854,7 @@ static bool SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
                         SDL_SetSurfaceColorMod(src, 255, 255, 255);
                         SDL_SetSurfaceAlphaMod(src, 255);
 
-                        SDL_BlitSurfaceScaled(src, srcrect, tmp, &r, texture->scaleMode);
+                        SDL_BlitSurfaceScaled(src, srcrect, tmp, &r, cmd->data.draw.texture_scale_mode);
 
                         SDL_SetSurfaceColorMod(tmp, rMod, gMod, bMod);
                         SDL_SetSurfaceAlphaMod(tmp, alphaMod);
@@ -869,7 +865,7 @@ static bool SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
                         // No need to set back r/g/b/a/blendmode to 'src' since it's done in PrepTextureForCopy()
                     }
                 } else {
-                    SDL_BlitSurfaceScaled(src, srcrect, surface, dstrect, texture->scaleMode);
+                    SDL_BlitSurfaceScaled(src, srcrect, surface, dstrect, cmd->data.draw.texture_scale_mode);
                 }
             }
             break;
@@ -889,7 +885,7 @@ static bool SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
 
             SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, &copydata->srcrect,
                             &copydata->dstrect, copydata->angle, &copydata->center, copydata->flip,
-                            copydata->scale_x, copydata->scale_y);
+                            copydata->scale_x, copydata->scale_y, cmd->data.draw.texture_scale_mode);
             break;
         }
 
@@ -1135,7 +1131,6 @@ bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, S
     renderer->UpdateTexture = SW_UpdateTexture;
     renderer->LockTexture = SW_LockTexture;
     renderer->UnlockTexture = SW_UnlockTexture;
-    renderer->SetTextureScaleMode = SW_SetTextureScaleMode;
     renderer->SetRenderTarget = SW_SetRenderTarget;
     renderer->QueueSetViewport = SW_QueueNoOp;
     renderer->QueueSetDrawColor = SW_QueueNoOp;

+ 36 - 25
src/render/vitagxm/SDL_render_vita_gxm.c

@@ -70,8 +70,6 @@ static bool VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
 static void VITA_GXM_UnlockTexture(SDL_Renderer *renderer,
                                    SDL_Texture *texture);
 
-static void VITA_GXM_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode);
-
 static bool VITA_GXM_SetRenderTarget(SDL_Renderer *renderer,
                                     SDL_Texture *texture);
 
@@ -216,7 +214,6 @@ static bool VITA_GXM_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window,
 #endif
     renderer->LockTexture = VITA_GXM_LockTexture;
     renderer->UnlockTexture = VITA_GXM_UnlockTexture;
-    renderer->SetTextureScaleMode = VITA_GXM_SetTextureScaleMode;
     renderer->SetRenderTarget = VITA_GXM_SetRenderTarget;
     renderer->QueueSetViewport = VITA_GXM_QueueNoOp;
     renderer->QueueSetDrawColor = VITA_GXM_QueueSetDrawColor;
@@ -295,9 +292,10 @@ static bool VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
         return SDL_OutOfMemory();
     }
 
-    texture->internal = vita_texture;
+    vita_texture->scale_mode = SDL_SCALEMODE_INVALID;
+    vita_texture->address_mode = SDL_TEXTURE_ADDRESS_INVALID;
 
-    VITA_GXM_SetTextureScaleMode(renderer, texture, texture->scaleMode);
+    texture->internal = vita_texture;
 
 #ifdef SDL_HAVE_YUV
     vita_texture->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
@@ -582,25 +580,6 @@ static void VITA_GXM_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     // This really improves framerate when using lock/unlock.
 }
 
-static void VITA_GXM_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *)texture->internal;
-
-    /*
-     set texture filtering according to scaleMode
-     supported hint values are nearest (0, default) or linear (1)
-     vitaScaleMode is either SCE_GXM_TEXTURE_FILTER_POINT (good for tile-map)
-     or SCE_GXM_TEXTURE_FILTER_LINEAR (good for scaling)
-     */
-
-    int vitaScaleMode = (scaleMode == SDL_SCALEMODE_NEAREST
-                             ? SCE_GXM_TEXTURE_FILTER_POINT
-                             : SCE_GXM_TEXTURE_FILTER_LINEAR);
-    gxm_texture_set_filters(vita_texture->tex, vitaScaleMode, vitaScaleMode);
-
-    return;
-}
-
 static bool VITA_GXM_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     return true;
@@ -909,9 +888,41 @@ static bool SetDrawState(VITA_GXM_RenderData *data, const SDL_RenderCommand *cmd
         }
     }
 
+    if (texture) {
+        VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *)texture->internal;
+
+        if (cmd->data.draw.texture_scale_mode != vita_texture->scale_mode) {
+            switch (cmd->data.draw.texture_scale_mode) {
+            case SDL_SCALEMODE_NEAREST:
+                gxm_texture_set_filters(vita_texture->tex, SCE_GXM_TEXTURE_FILTER_POINT, SCE_GXM_TEXTURE_FILTER_POINT);
+                break;
+            case SDL_SCALEMODE_LINEAR:
+                gxm_texture_set_filters(vita_texture->tex, SCE_GXM_TEXTURE_FILTER_LINEAR, SCE_GXM_TEXTURE_FILTER_LINEAR);
+                break;
+            default:
+                break;
+            }
+            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 (texture != data->drawstate.texture) {
         if (texture) {
-            VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *)cmd->data.draw.texture->internal;
+            VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *)texture->internal;
             sceGxmSetFragmentTexture(data->gxm_context, 0, &vita_texture->tex->gxm_tex);
         }
         data->drawstate.texture = texture;

+ 6 - 0
src/render/vitagxm/SDL_render_vita_gxm_tools.c

@@ -1122,6 +1122,12 @@ gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsig
     return texture;
 }
 
+void gxm_texture_set_address_mode(gxm_texture *texture, SceGxmTextureAddrMode u_mode, SceGxmTextureAddrMode v_mode)
+{
+    sceGxmTextureSetUAddrMode(&texture->gxm_tex, u_mode);
+    sceGxmTextureSetVAddrMode(&texture->gxm_tex, v_mode);
+}
+
 void gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter)
 {
     sceGxmTextureSetMinFilter(&texture->gxm_tex, min_filter);

+ 1 - 0
src/render/vitagxm/SDL_render_vita_gxm_tools.h

@@ -49,6 +49,7 @@ void gxm_finish(SDL_Renderer *renderer);
 gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale);
 void free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture);
 
+void gxm_texture_set_address_mode(gxm_texture *texture, SceGxmTextureAddrMode u_mode, SceGxmTextureAddrMode v_mode);
 void gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter);
 SceGxmTextureFormat gxm_texture_get_format(const gxm_texture *texture);
 

+ 2 - 0
src/render/vitagxm/SDL_render_vita_gxm_types.h

@@ -205,6 +205,8 @@ typedef struct
     float wscale;
     bool yuv;
     bool nv12;
+    SDL_ScaleMode scale_mode;
+    SDL_TextureAddressMode address_mode;
 } VITA_GXM_TextureData;
 
 #endif // SDL_RENDER_VITA_GXM_TYPES_H

+ 2 - 16
src/render/vulkan/SDL_render_vulkan.c

@@ -255,7 +255,6 @@ typedef struct
     VkRenderPass mainRenderpasses[VULKAN_RENDERPASS_COUNT];
     VkFramebuffer mainFramebuffer;
     VULKAN_Buffer stagingBuffer;
-    VkFilter scaleMode;
     SDL_Rect lockedRect;
     int width;
     int height;
@@ -2600,7 +2599,6 @@ static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, S
     } else {
         textureData->shader = SHADER_ADVANCED;
     }
-    textureData->scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
 
 #ifdef SDL_HAVE_YUV
     // YUV textures must have even width and height.  Also create Ycbcr conversion
@@ -3093,17 +3091,6 @@ static void VULKAN_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     VULKAN_DestroyBuffer(rendererData, &textureData->stagingBuffer);
 }
 
-static void VULKAN_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
-{
-    VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal;
-
-    if (!textureData) {
-        return;
-    }
-
-    textureData->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
-}
-
 static bool VULKAN_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
@@ -3775,7 +3762,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
 
     VULKAN_SetupShaderConstants(renderer, cmd, texture, &constants);
 
-    switch (textureData->scaleMode) {
+    switch (cmd->data.draw.texture_scale_mode) {
     case VK_FILTER_NEAREST:
         switch (cmd->data.draw.texture_address_mode) {
         case SDL_TEXTURE_ADDRESS_CLAMP:
@@ -3801,7 +3788,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
         }
         break;
     default:
-        return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode);
+        return SDL_SetError("Unknown scale mode: %d", cmd->data.draw.texture_scale_mode);
     }
 
     if (textureData->mainImage.imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
@@ -4290,7 +4277,6 @@ static bool VULKAN_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SD
 #endif
     renderer->LockTexture = VULKAN_LockTexture;
     renderer->UnlockTexture = VULKAN_UnlockTexture;
-    renderer->SetTextureScaleMode = VULKAN_SetTextureScaleMode;
     renderer->SetRenderTarget = VULKAN_SetRenderTarget;
     renderer->QueueSetViewport = VULKAN_QueueNoOp;
     renderer->QueueSetDrawColor = VULKAN_QueueNoOp;

+ 131 - 0
test/testautomation_render.c

@@ -1512,6 +1512,132 @@ static int SDLCALL render_testUVWrapping(void *arg)
     return TEST_COMPLETED;
 }
 
+/**
+ * Tests texture state changes
+ */
+static int SDLCALL render_testTextureState(void *arg)
+{
+    const Uint8 pixels[8] = {
+        0x00, 0x00, 0x00, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF
+    };
+    const SDL_Color expected[] = {
+        /* Step 0: plain copy */
+        { 0x00, 0x00, 0x00, 0xFF },
+        { 0xFF, 0xFF, 0xFF, 0xFF },
+        /* Step 1: color mod to red */
+        { 0x00, 0x00, 0x00, 0xFF },
+        { 0xFF, 0x00, 0x00, 0xFF },
+        /* Step 2: alpha mod to 128 (cleared to green) */
+        { 0x00, 0x7F, 0x00, 0xFF },
+        { 0x80, 0xFF, 0x80, 0xFF },
+        /* Step 3: nearest stretch */
+        { 0xFF, 0xFF, 0xFF, 0xFF },
+        { 0x00, 0xFF, 0x00, 0xFF },
+        /* Step 4: linear stretch */
+        { 0x80, 0x80, 0x80, 0xFF },
+        { 0x00, 0xFF, 0x00, 0xFF },
+    };
+    SDL_Texture *texture;
+    SDL_Rect rect;
+    SDL_FRect dst;
+    int i;
+
+    /* Clear surface to green */
+    SDL_SetRenderDrawColor(renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
+    SDL_RenderClear(renderer);
+
+    /* Create 2-pixel surface. */
+    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, 2, 1);
+    SDLTest_AssertCheck(texture != NULL, "Verify SDL_CreateTexture() result");
+    if (texture == NULL) {
+        return TEST_ABORTED;
+    }
+    SDL_UpdateTexture(texture, NULL, pixels, sizeof(pixels));
+
+    dst.x = 0.0f;
+    dst.y = 0.0f;
+    dst.w = 2.0f;
+    dst.h = 1.0f;
+
+    /* Step 0: plain copy */
+    SDL_RenderTexture(renderer, texture, NULL, &dst);
+    dst.y += 1;
+
+    /* Step 1: color mod to red */
+    SDL_SetTextureColorMod(texture, 0xFF, 0x00, 0x00);
+    SDL_RenderTexture(renderer, texture, NULL, &dst);
+    SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF);
+    dst.y += 1;
+
+    /* Step 2: alpha mod to 128 */
+    SDL_SetTextureAlphaMod(texture, 0x80);
+    SDL_RenderTexture(renderer, texture, NULL, &dst);
+    SDL_SetTextureAlphaMod(texture, 0xFF);
+    dst.y += 1;
+
+    /* Step 3: nearest stretch */
+    dst.w = 1;
+    SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
+    SDL_RenderTexture(renderer, texture, NULL, &dst);
+    dst.y += 1;
+
+    /* Step 4: linear stretch */
+    dst.w = 1;
+    SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_LINEAR);
+    SDL_RenderTexture(renderer, texture, NULL, &dst);
+    dst.y += 1;
+
+    /* Verify results */
+    rect.x = 0;
+    rect.y = 0;
+    rect.w = 2;
+    rect.h = 1;
+    for (i = 0; i < SDL_arraysize(expected); ) {
+        const int MAX_DELTA = 1;
+        SDL_Color actual;
+        int deltaR, deltaG, deltaB, deltaA;
+        SDL_Surface *surface = SDL_RenderReadPixels(renderer, &rect);
+
+        SDL_ReadSurfacePixel(surface, 0, 0, &actual.r, &actual.g, &actual.b, &actual.a);
+        deltaR = (actual.r - expected[i].r);
+        deltaG = (actual.g - expected[i].g);
+        deltaB = (actual.b - expected[i].b);
+        deltaA = (actual.a - expected[i].a);
+        SDLTest_AssertCheck(SDL_abs(deltaR) <= MAX_DELTA &&
+                            SDL_abs(deltaG) <= MAX_DELTA &&
+                            SDL_abs(deltaB) <= MAX_DELTA &&
+                            SDL_abs(deltaA) <= MAX_DELTA,
+                            "Validate left pixel at step %d, expected %d,%d,%d,%d, got %d,%d,%d,%d", i/2,
+                            expected[i].r, expected[i].g, expected[i].b, expected[i].a,
+                            actual.r, actual.g, actual.b, actual.a);
+        ++i;
+
+        SDL_ReadSurfacePixel(surface, 1, 0, &actual.r, &actual.g, &actual.b, &actual.a);
+        deltaR = (actual.r - expected[i].r);
+        deltaG = (actual.g - expected[i].g);
+        deltaB = (actual.b - expected[i].b);
+        deltaA = (actual.a - expected[i].a);
+        SDLTest_AssertCheck(SDL_abs(deltaR) <= MAX_DELTA &&
+                            SDL_abs(deltaG) <= MAX_DELTA &&
+                            SDL_abs(deltaB) <= MAX_DELTA &&
+                            SDL_abs(deltaA) <= MAX_DELTA,
+                            "Validate right pixel at step %d, expected %d,%d,%d,%d, got %d,%d,%d,%d", i/2,
+                            expected[i].r, expected[i].g, expected[i].b, expected[i].a,
+                            actual.r, actual.g, actual.b, actual.a);
+        ++i;
+
+        SDL_DestroySurface(surface);
+
+        rect.y += 1;
+    }
+
+    /* Clean up. */
+    SDL_DestroyTexture(texture);
+
+    return TEST_COMPLETED;
+}
+
 /* ================= Test References ================== */
 
 /* Render test cases */
@@ -1563,6 +1689,10 @@ static const SDLTest_TestCaseReference renderTestUVWrapping = {
     render_testUVWrapping, "render_testUVWrapping", "Tests geometry UV wrapping", TEST_ENABLED
 };
 
+static const SDLTest_TestCaseReference renderTestTextureState = {
+    render_testTextureState, "render_testTextureState", "Tests texture state changes", TEST_ENABLED
+};
+
 /* Sequence of Render test cases */
 static const SDLTest_TestCaseReference *renderTests[] = {
     &renderTestGetNumRenderDrivers,
@@ -1577,6 +1707,7 @@ static const SDLTest_TestCaseReference *renderTests[] = {
     &renderTestClipRect,
     &renderTestLogicalSize,
     &renderTestUVWrapping,
+    &renderTestTextureState,
     NULL
 };