Bläddra i källkod

render: Remove the logical presentation render target.

Now we render directly to the window, scaling as appropriate. This fixes some
concerns the render target introduced, like the quality of the final scaled
output, how to step outside of the logical size temporarily to draw some
things sharply at the native resolution, and loss of sub-pixel precision.

Fixes #8736.
Ryan C. Gordon 7 månader sedan
förälder
incheckning
54459def69

+ 2 - 2
build-scripts/SDL_migration.cocci

@@ -1761,10 +1761,10 @@ expression e2;
 @@
 (
 - SDL_RenderSetLogicalSize(renderer, 0, 0)
-+ SDL_SetRenderLogicalPresentation(renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED, SDL_ScaleModeNearest)
++ SDL_SetRenderLogicalPresentation(renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED)
 |
 - SDL_RenderSetLogicalSize(renderer, e1, e2)
-+ SDL_SetRenderLogicalPresentation(renderer, e1, e2, SDL_LOGICAL_PRESENTATION_LETTERBOX, SDL_ScaleModeLinear)
++ SDL_SetRenderLogicalPresentation(renderer, e1, e2, SDL_LOGICAL_PRESENTATION_LETTERBOX)
 )
 @@
 @@

+ 1 - 1
examples/renderer/02-primitives/primitives.c

@@ -55,7 +55,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
     SDL_FRect rect;
 
     /* as you can see from this, rendering draws over whatever was drawn before it. */
-    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);  /* black, full alpha */
+    SDL_SetRenderDrawColor(renderer, 33, 33, 33, 255);  /* dark gray, full alpha */
     SDL_RenderClear(renderer);  /* start with a blank canvas. */
 
     /* draw a filled rectangle in the middle of the canvas. */

+ 26 - 12
examples/renderer/17-read-pixels/read-pixels.c

@@ -19,9 +19,11 @@
 static SDL_Window *window = NULL;
 static SDL_Renderer *renderer = NULL;
 static SDL_Texture *texture = NULL;
-static SDL_Texture *converted_texture = NULL;
 static int texture_width = 0;
 static int texture_height = 0;
+static SDL_Texture *converted_texture = NULL;
+static int converted_texture_width = 0;
+static int converted_texture_height = 0;
 
 #define WINDOW_WIDTH 640
 #define WINDOW_HEIGHT 480
@@ -68,12 +70,6 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 
     SDL_DestroySurface(surface);  /* done with this, the texture has a copy of the pixels now. */
 
-    converted_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, WINDOW_WIDTH, WINDOW_HEIGHT);
-    if (!texture) {
-        SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create conversion texture!", SDL_GetError(), NULL);
-        return SDL_APP_FAILURE;
-    }
-
     return SDL_APP_CONTINUE;  /* carry on with the program! */
 }
 
@@ -111,8 +107,13 @@ SDL_AppResult SDL_AppIterate(void *appstate)
     center.y = texture_height / 2.0f;
     SDL_RenderTextureRotated(renderer, texture, NULL, &dst_rect, rotation, &center, SDL_FLIP_NONE);
 
-    /* this whole thing is _super_ expensive. Seriously, don't do this in real life. */
+    /* this next whole thing is _super_ expensive. Seriously, don't do this in real life. */
+
+    /* Download the pixels of what has just been rendered. This has to wait for the GPU to finish rendering it and everything before it,
+       and then make an expensive copy from the GPU to system RAM! */
     surface = SDL_RenderReadPixels(renderer, NULL);
+
+    /* This is also expensive, but easier: convert the pixels to a format we want. */
     if (surface && (surface->format != SDL_PIXELFORMAT_RGBA8888) && (surface->format != SDL_PIXELFORMAT_BGRA8888)) {
         SDL_Surface *converted = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA8888);
         SDL_DestroySurface(surface);
@@ -120,6 +121,18 @@ SDL_AppResult SDL_AppIterate(void *appstate)
     }
 
     if (surface) {
+        /* Rebuild converted_texture if the dimensions have changed (window resized, etc). */
+        if ((surface->w != converted_texture_width) || (surface->h != converted_texture_height)) {
+            SDL_DestroyTexture(converted_texture);
+            converted_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, surface->w, surface->h);
+            if (!converted_texture) {
+                SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't (re)create conversion texture!", SDL_GetError(), NULL);
+                return SDL_APP_FAILURE;
+            }
+            converted_texture_width = surface->w;
+            converted_texture_height = surface->h;
+        }
+
         /* Turn each pixel into either black or white. This is a lousy technique but it works here.
            In real life, something like Floyd-Steinberg dithering might work
            better: https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering*/
@@ -130,9 +143,10 @@ SDL_AppResult SDL_AppIterate(void *appstate)
                 Uint8 *p = (Uint8 *) (&pixels[x]);
                 const Uint32 average = (((Uint32) p[1]) + ((Uint32) p[2]) + ((Uint32) p[3])) / 3;
                 if (average == 0) {
-                    p[0] = 0;  // turn off alpha for pure black pixels.
+                    p[0] = p[3] = 0xFF; p[1] = p[2] = 0;  /* make pure black pixels red. */
+                } else {
+                    p[1] = p[2] = p[3] = (average > 50) ? 0xFF : 0x00;  /* make everything else either black or white. */
                 }
-                p[1] = p[2] = p[3] = (average > 50) ? 0xFF : 0x00;
             }
         }
 
@@ -142,8 +156,8 @@ SDL_AppResult SDL_AppIterate(void *appstate)
 
         /* draw the texture to the top-left of the screen. */
         dst_rect.x = dst_rect.y = 0.0f;
-        dst_rect.w = ((float) WINDOW_WIDTH) / 2.0f;
-        dst_rect.h = ((float) WINDOW_WIDTH) / 2.0f;
+        dst_rect.w = ((float) WINDOW_WIDTH) / 4.0f;
+        dst_rect.h = ((float) WINDOW_HEIGHT) / 4.0f;
         SDL_RenderTexture(renderer, converted_texture, NULL, &dst_rect);
     }
 

+ 16 - 9
include/SDL3/SDL_render.h

@@ -1266,13 +1266,23 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *rend
 /**
  * Set a device independent resolution and presentation mode for rendering.
  *
- * This function sets the width and height of the logical rendering output. A
- * render target is created at the specified size and used for rendering and
- * then copied to the output during presentation.
+ * This function sets the width and height of the logical rendering output.
+ * The renderer will act as if the window is always the requested dimensions,
+ * scaling to the actual window resolution as necessary.
+ *
+ * This can be useful for games that expect a fixed size, but would like to
+ * scale the output to whatever is available, regardless of how a user resizes
+ * a window, or if the display is high DPI.
  *
  * You can disable logical coordinates by setting the mode to
  * SDL_LOGICAL_PRESENTATION_DISABLED, and in that case you get the full pixel
- * resolution of the output window.
+ * resolution of the output window; it is safe to toggle logical presentation
+ * during the rendering of a frame: perhaps most of the rendering is done to
+ * specific dimensions but to make fonts look sharp, the app turns off logical
+ * presentation while drawing text.
+ *
+ * Letterboxing will only happen if logical presentation is enabled during
+ * SDL_RenderPresent; be sure to reenable it first if you were using it.
  *
  * You can convert coordinates in an event into rendering coordinates using
  * SDL_ConvertEventToRenderCoordinates().
@@ -1281,7 +1291,6 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *rend
  * \param w the width of the logical resolution.
  * \param h the height of the logical resolution.
  * \param mode the presentation mode used.
- * \param scale_mode the scale mode used.
  * \returns true on success or false on failure; call SDL_GetError() for more
  *          information.
  *
@@ -1291,7 +1300,7 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *rend
  * \sa SDL_GetRenderLogicalPresentation
  * \sa SDL_GetRenderLogicalPresentationRect
  */
-extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode, SDL_ScaleMode scale_mode);
+extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode);
 
 /**
  * Get device independent resolution and presentation mode for rendering.
@@ -1302,8 +1311,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *
  * \param renderer the rendering context.
  * \param w an int to be filled with the width.
  * \param h an int to be filled with the height.
- * \param mode a pointer filled in with the presentation mode.
- * \param scale_mode a pointer filled in with the scale mode.
  * \returns true on success or false on failure; call SDL_GetError() for more
  *          information.
  *
@@ -1311,7 +1318,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer *
  *
  * \sa SDL_SetRenderLogicalPresentation
  */
-extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL_RendererLogicalPresentation *mode, SDL_ScaleMode *scale_mode);
+extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL_RendererLogicalPresentation *mode);
 
 /**
  * Get the final presentation rectangle for rendering.

+ 0 - 1
include/SDL3/SDL_test_common.h

@@ -103,7 +103,6 @@ typedef struct
     int logical_h;
     bool auto_scale_content;
     SDL_RendererLogicalPresentation logical_presentation;
-    SDL_ScaleMode logical_scale_mode;
     float scale;
     int depth;
     float refresh_rate;

+ 2 - 2
src/dynapi/SDL_dynapi_procs.h

@@ -499,7 +499,7 @@ SDL_DYNAPI_PROC(bool,SDL_GetRenderDrawBlendMode,(SDL_Renderer *a, SDL_BlendMode
 SDL_DYNAPI_PROC(bool,SDL_GetRenderDrawColor,(SDL_Renderer *a, Uint8 *b, Uint8 *c, Uint8 *d, Uint8 *e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(bool,SDL_GetRenderDrawColorFloat,(SDL_Renderer *a, float *b, float *c, float *d, float *e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetRenderDriver,(int a),(a),return)
-SDL_DYNAPI_PROC(bool,SDL_GetRenderLogicalPresentation,(SDL_Renderer *a, int *b, int *c, SDL_RendererLogicalPresentation *d, SDL_ScaleMode *e),(a,b,c,d,e),return)
+SDL_DYNAPI_PROC(bool,SDL_GetRenderLogicalPresentation,(SDL_Renderer *a, int *b, int *c, SDL_RendererLogicalPresentation *d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(bool,SDL_GetRenderLogicalPresentationRect,(SDL_Renderer *a, SDL_FRect *b),(a,b),return)
 SDL_DYNAPI_PROC(void*,SDL_GetRenderMetalCommandEncoder,(SDL_Renderer *a),(a),return)
 SDL_DYNAPI_PROC(void*,SDL_GetRenderMetalLayer,(SDL_Renderer *a),(a),return)
@@ -879,7 +879,7 @@ SDL_DYNAPI_PROC(bool,SDL_SetRenderColorScale,(SDL_Renderer *a, float b),(a,b),re
 SDL_DYNAPI_PROC(bool,SDL_SetRenderDrawBlendMode,(SDL_Renderer *a, SDL_BlendMode b),(a,b),return)
 SDL_DYNAPI_PROC(bool,SDL_SetRenderDrawColor,(SDL_Renderer *a, Uint8 b, Uint8 c, Uint8 d, Uint8 e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(bool,SDL_SetRenderDrawColorFloat,(SDL_Renderer *a, float b, float c, float d, float e),(a,b,c,d,e),return)
-SDL_DYNAPI_PROC(bool,SDL_SetRenderLogicalPresentation,(SDL_Renderer *a, int b, int c, SDL_RendererLogicalPresentation d, SDL_ScaleMode e),(a,b,c,d,e),return)
+SDL_DYNAPI_PROC(bool,SDL_SetRenderLogicalPresentation,(SDL_Renderer *a, int b, int c, SDL_RendererLogicalPresentation d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(bool,SDL_SetRenderScale,(SDL_Renderer *a, float b, float c),(a,b,c),return)
 SDL_DYNAPI_PROC(bool,SDL_SetRenderTarget,(SDL_Renderer *a, SDL_Texture *b),(a,b),return)
 SDL_DYNAPI_PROC(bool,SDL_SetRenderVSync,(SDL_Renderer *a, int b),(a,b),return)

+ 196 - 269
src/render/SDL_render.c

@@ -415,15 +415,15 @@ static SDL_RenderCommand *AllocateRenderCommand(SDL_Renderer *renderer)
 
 static void UpdatePixelViewport(SDL_Renderer *renderer, SDL_RenderViewState *view)
 {
-    view->pixel_viewport.x = (int)SDL_floorf(view->viewport.x * view->scale.x);
-    view->pixel_viewport.y = (int)SDL_floorf(view->viewport.y * view->scale.y);
+    view->pixel_viewport.x = (int)SDL_floorf((view->viewport.x * view->current_scale.x) + view->logical_offset.x);
+    view->pixel_viewport.y = (int)SDL_floorf((view->viewport.y * view->current_scale.y) + view->logical_offset.y);
     if (view->viewport.w >= 0) {
-        view->pixel_viewport.w = (int)SDL_ceilf(view->viewport.w * view->scale.x);
+        view->pixel_viewport.w = (int)SDL_ceilf(view->viewport.w * view->current_scale.x);
     } else {
         view->pixel_viewport.w = view->pixel_w;
     }
     if (view->viewport.h >= 0) {
-        view->pixel_viewport.h = (int)SDL_ceilf(view->viewport.h * view->scale.y);
+        view->pixel_viewport.h = (int)SDL_ceilf(view->viewport.h * view->current_scale.y);
     } else {
         view->pixel_viewport.h = view->pixel_h;
     }
@@ -431,10 +431,9 @@ static void UpdatePixelViewport(SDL_Renderer *renderer, SDL_RenderViewState *vie
 
 static bool QueueCmdSetViewport(SDL_Renderer *renderer)
 {
-    SDL_Rect viewport;
     bool result = true;
 
-    viewport = renderer->view->pixel_viewport;
+    SDL_Rect viewport = renderer->view->pixel_viewport;
 
     if (!renderer->viewport_queued ||
         SDL_memcmp(&viewport, &renderer->last_queued_viewport, sizeof(viewport)) != 0) {
@@ -459,19 +458,19 @@ static bool QueueCmdSetViewport(SDL_Renderer *renderer)
 
 static void UpdatePixelClipRect(SDL_Renderer *renderer, SDL_RenderViewState *view)
 {
-    view->pixel_clip_rect.x = (int)SDL_floorf(view->clip_rect.x * view->scale.x);
-    view->pixel_clip_rect.y = (int)SDL_floorf(view->clip_rect.y * view->scale.y);
-    view->pixel_clip_rect.w = (int)SDL_ceilf(view->clip_rect.w * view->scale.x);
-    view->pixel_clip_rect.h = (int)SDL_ceilf(view->clip_rect.h * view->scale.y);
+    const float scale_x = view->current_scale.x;
+    const float scale_y = view->current_scale.y;
+    view->pixel_clip_rect.x = (int)SDL_floorf((view->clip_rect.x * scale_x) + view->logical_offset.x);
+    view->pixel_clip_rect.y = (int)SDL_floorf((view->clip_rect.y * scale_y) + view->logical_offset.y);
+    view->pixel_clip_rect.w = (int)SDL_ceilf(view->clip_rect.w * scale_x);
+    view->pixel_clip_rect.h = (int)SDL_ceilf(view->clip_rect.h * scale_y);
 }
 
 static bool QueueCmdSetClipRect(SDL_Renderer *renderer)
 {
-    SDL_Rect clip_rect;
     bool result = true;
 
-    clip_rect = renderer->view->pixel_clip_rect;
-
+    SDL_Rect clip_rect = renderer->view->pixel_clip_rect;
     if (!renderer->cliprect_queued ||
         renderer->view->clipping_enabled != renderer->last_queued_cliprect_enabled ||
         SDL_memcmp(&clip_rect, &renderer->last_queued_cliprect, sizeof(clip_rect)) != 0) {
@@ -718,7 +717,6 @@ static bool QueueCmdGeometry(SDL_Renderer *renderer, SDL_Texture *texture,
     cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_GEOMETRY, texture);
     if (cmd) {
         cmd->data.draw.texture_address_mode = texture_address_mode;
-
         result = renderer->QueueGeometry(renderer, cmd, texture,
                                          xy, xy_stride,
                                          color, color_stride, uv, uv_stride,
@@ -794,7 +792,7 @@ static void UpdateHDRProperties(SDL_Renderer *renderer)
     UpdateColorScale(renderer);
 }
 
-static bool UpdateLogicalPresentation(SDL_Renderer *renderer);
+static void UpdateLogicalPresentation(SDL_Renderer *renderer);
 
 
 int SDL_GetNumRenderDrivers(void)
@@ -835,7 +833,6 @@ static bool SDLCALL SDL_RendererEventWatch(void *userdata, SDL_Event *event)
             if (event->type == SDL_EVENT_WINDOW_RESIZED ||
                 event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED ||
                 event->type == SDL_EVENT_WINDOW_METAL_VIEW_RESIZED) {
-                UpdateMainViewDimensions(renderer);
                 UpdateLogicalPresentation(renderer);
             } else if (event->type == SDL_EVENT_WINDOW_HIDDEN) {
                 renderer->hidden = true;
@@ -1057,6 +1054,10 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
     renderer->main_view.viewport.h = -1;
     renderer->main_view.scale.x = 1.0f;
     renderer->main_view.scale.y = 1.0f;
+    renderer->main_view.logical_scale.x = 1.0f;
+    renderer->main_view.logical_scale.y = 1.0f;
+    renderer->main_view.current_scale.x = 1.0f;
+    renderer->main_view.current_scale.y = 1.0f;
     renderer->view = &renderer->main_view;
     renderer->dpi_scale.x = 1.0f;
     renderer->dpi_scale.y = 1.0f;
@@ -1387,6 +1388,10 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert
     texture->view.viewport.h = -1;
     texture->view.scale.x = 1.0f;
     texture->view.scale.y = 1.0f;
+    texture->view.logical_scale.x = 1.0f;
+    texture->view.logical_scale.y = 1.0f;
+    texture->view.current_scale.x = 1.0f;
+    texture->view.current_scale.y = 1.0f;
     texture->renderer = renderer;
     texture->next = renderer->textures;
     if (renderer->textures) {
@@ -2485,7 +2490,7 @@ void SDL_UnlockTexture(SDL_Texture *texture)
     texture->locked_surface = NULL;
 }
 
-static bool SDL_SetRenderTargetInternal(SDL_Renderer *renderer, SDL_Texture *texture)
+bool SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
 {
     // texture == NULL is valid and means reset the target to the window
     if (texture) {
@@ -2537,46 +2542,35 @@ static bool SDL_SetRenderTargetInternal(SDL_Renderer *renderer, SDL_Texture *tex
     return true;
 }
 
-bool SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
-{
-    if (!texture && renderer->logical_target) {
-        return SDL_SetRenderTargetInternal(renderer, renderer->logical_target);
-    } else {
-        return SDL_SetRenderTargetInternal(renderer, texture);
-    }
-}
-
 SDL_Texture *SDL_GetRenderTarget(SDL_Renderer *renderer)
 {
     CHECK_RENDERER_MAGIC(renderer, NULL);
-
-    if (renderer->target == renderer->logical_target) {
+    if (!renderer->target) {
         return NULL;
-    } else {
-        return (SDL_Texture *)SDL_GetPointerProperty(SDL_GetTextureProperties(renderer->target), SDL_PROP_TEXTURE_PARENT_POINTER, renderer->target);
     }
+    return (SDL_Texture *) SDL_GetPointerProperty(SDL_GetTextureProperties(renderer->target), SDL_PROP_TEXTURE_PARENT_POINTER, renderer->target);
 }
 
-static bool UpdateLogicalPresentation(SDL_Renderer *renderer)
+static void UpdateLogicalPresentation(SDL_Renderer *renderer)
 {
-    float logical_w = 1.0f, logical_h = 1.0f;
-    float output_w = (float)renderer->main_view.pixel_w;
-    float output_h = (float)renderer->main_view.pixel_h;
-    float want_aspect = 1.0f;
-    float real_aspect = 1.0f;
-    float scale;
-
     if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED) {
-        // All done!
-        return true;
-    }
-
-    if (!SDL_GetTextureSize(renderer->logical_target, &logical_w, &logical_h)) {
-        goto error;
-    }
-
-    want_aspect = logical_w / logical_h;
-    real_aspect = output_w / output_h;
+        renderer->main_view.logical_offset.x = renderer->main_view.logical_offset.y = 0.0f;
+        renderer->main_view.logical_scale.x = renderer->main_view.logical_scale.y = 1.0f;
+        renderer->main_view.current_scale.x = renderer->main_view.scale.x;  // skip the multiplications against 1.0f.
+        renderer->main_view.current_scale.y = renderer->main_view.scale.y;
+        UpdateMainViewDimensions(renderer);
+        UpdatePixelClipRect(renderer, &renderer->main_view);
+        return;  // All done!
+    }
+
+    int iwidth, iheight;
+    SDL_GetRenderOutputSize(renderer, &iwidth, &iheight);
+    const float output_w = (float)iwidth;
+    const float output_h = (float)iheight;
+    const float logical_w = renderer->logical_w;
+    const float logical_h = renderer->logical_h;
+    const float want_aspect = logical_w / logical_h;
+    const float real_aspect = output_w / output_h;
 
     renderer->logical_src_rect.x = 0.0f;
     renderer->logical_src_rect.y = 0.0f;
@@ -2584,6 +2578,7 @@ static bool UpdateLogicalPresentation(SDL_Renderer *renderer)
     renderer->logical_src_rect.h = logical_h;
 
     if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE) {
+        float scale;
         if (want_aspect > real_aspect) {
             scale = (float)((int)output_w / (int)logical_w); // This an integer division!
         } else {
@@ -2609,7 +2604,7 @@ static bool UpdateLogicalPresentation(SDL_Renderer *renderer)
     } else if (want_aspect > real_aspect) {
         if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) {
             // We want a wider aspect ratio than is available - letterbox it
-            scale = output_w / logical_w;
+            const float scale = output_w / logical_w;
             renderer->logical_dst_rect.x = 0.0f;
             renderer->logical_dst_rect.w = output_w;
             renderer->logical_dst_rect.h = SDL_floorf(logical_h * scale);
@@ -2619,7 +2614,7 @@ static bool UpdateLogicalPresentation(SDL_Renderer *renderer)
                zoom so logical height matches the real height
                and the width will grow off the screen
              */
-            scale = output_h / logical_h;
+            const float scale = output_h / logical_h;
             renderer->logical_dst_rect.y = 0.0f;
             renderer->logical_dst_rect.h = output_h;
             renderer->logical_dst_rect.w = SDL_floorf(logical_w * scale);
@@ -2628,7 +2623,7 @@ static bool UpdateLogicalPresentation(SDL_Renderer *renderer)
     } else {
         if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) {
             // We want a narrower aspect ratio than is available - use side-bars
-            scale = output_h / logical_h;
+            const float scale = output_h / logical_h;
             renderer->logical_dst_rect.y = 0.0f;
             renderer->logical_dst_rect.h = output_h;
             renderer->logical_dst_rect.w = SDL_floorf(logical_w * scale);
@@ -2638,7 +2633,7 @@ static bool UpdateLogicalPresentation(SDL_Renderer *renderer)
                zoom so logical width matches the real width
                and the height will grow off the screen
              */
-            scale = output_w / logical_w;
+            const float scale = output_w / logical_w;
             renderer->logical_dst_rect.x = 0.0f;
             renderer->logical_dst_rect.w = output_w;
             renderer->logical_dst_rect.h = SDL_floorf(logical_h * scale);
@@ -2646,97 +2641,48 @@ static bool UpdateLogicalPresentation(SDL_Renderer *renderer)
         }
     }
 
-    SDL_SetTextureScaleMode(renderer->logical_target, renderer->logical_scale_mode);
+    renderer->main_view.logical_scale.x = (logical_w != 0.0f) ? renderer->logical_dst_rect.w / logical_w : 0.0f;
+    renderer->main_view.logical_scale.y = (logical_h != 0.0f) ? renderer->logical_dst_rect.h / logical_h : 0.0f;
+    renderer->main_view.current_scale.x = renderer->main_view.scale.x * renderer->main_view.logical_scale.x;
+    renderer->main_view.current_scale.y = renderer->main_view.scale.y * renderer->main_view.logical_scale.y;
+    renderer->main_view.logical_offset.x = renderer->logical_dst_rect.x;
+    renderer->main_view.logical_offset.y = renderer->logical_dst_rect.y;
 
-    if (!renderer->target) {
-        SDL_SetRenderTarget(renderer, renderer->logical_target);
-    }
-
-    return true;
-
-error:
-    SDL_SetRenderLogicalPresentation(renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED, SDL_SCALEMODE_NEAREST);
-    return false;
+    UpdateMainViewDimensions(renderer);  // this will replace pixel_w and pixel_h while making sure the dpi_scale is right.
+    renderer->main_view.pixel_w = (int) renderer->logical_dst_rect.w;
+    renderer->main_view.pixel_h = (int) renderer->logical_dst_rect.h;
+    UpdatePixelViewport(renderer, &renderer->main_view);
+    UpdatePixelClipRect(renderer, &renderer->main_view);
 }
 
-bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode, SDL_ScaleMode scale_mode)
+bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode)
 {
     CHECK_RENDERER_MAGIC(renderer, false);
 
-    if (mode == SDL_LOGICAL_PRESENTATION_DISABLED) {
-        if (renderer->logical_target) {
-            SDL_DestroyTexture(renderer->logical_target);
-        }
-    } else {
-        if (renderer->logical_target) {
-            SDL_PropertiesID props = SDL_GetTextureProperties(renderer->logical_target);
-            if (!props) {
-                goto error;
-            }
-
-            int existing_w = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_WIDTH_NUMBER, 0);
-            int existing_h = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0);
-
-            if (w != existing_w || h != existing_h) {
-                SDL_DestroyTexture(renderer->logical_target);
-            }
-        }
-        if (!renderer->logical_target) {
-            renderer->logical_target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_TARGET, w, h);
-            if (!renderer->logical_target) {
-                goto error;
-            }
-            SDL_SetTextureBlendMode(renderer->logical_target, SDL_BLENDMODE_NONE);
-        }
-    }
-
     renderer->logical_presentation_mode = mode;
-    renderer->logical_scale_mode = scale_mode;
+    renderer->logical_w = w;
+    renderer->logical_h = h;
 
-    return UpdateLogicalPresentation(renderer);
+    UpdateLogicalPresentation(renderer);
 
-error:
-    SDL_SetRenderLogicalPresentation(renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED, SDL_SCALEMODE_NEAREST);
-    return false;
+    return true;
 }
 
-bool SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL_RendererLogicalPresentation *mode, SDL_ScaleMode *scale_mode)
+bool SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL_RendererLogicalPresentation *mode)
 {
-    if (w) {
-        *w = 0;
-    }
-    if (h) {
-        *h = 0;
-    }
-    if (mode) {
-        *mode = SDL_LOGICAL_PRESENTATION_DISABLED;
-    }
-    if (scale_mode) {
-        *scale_mode = SDL_SCALEMODE_NEAREST;
-    }
+    #define SETVAL(ptr, val) if (ptr) { *ptr = val; }
 
-    CHECK_RENDERER_MAGIC(renderer, false);
+    SETVAL(w, 0);
+    SETVAL(h, 0);
+    SETVAL(mode, SDL_LOGICAL_PRESENTATION_DISABLED);
 
-    if (renderer->logical_target) {
-        SDL_PropertiesID props = SDL_GetTextureProperties(renderer->logical_target);
-        if (!props) {
-            return false;
-        }
+    CHECK_RENDERER_MAGIC(renderer, false);
 
-        if (w) {
-            *w = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_WIDTH_NUMBER, 0);
-        }
-        if (h) {
-            *h = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0);
-        }
-    }
+    SETVAL(w, renderer->logical_w);
+    SETVAL(h, renderer->logical_h);
+    SETVAL(mode, renderer->logical_presentation_mode);
 
-    if (mode) {
-        *mode = renderer->logical_presentation_mode;
-    }
-    if (scale_mode) {
-        *scale_mode = renderer->logical_scale_mode;
-    }
+    #undef SETVAL
 
     return true;
 }
@@ -2814,17 +2760,48 @@ static void SDL_RenderLogicalBorders(SDL_Renderer *renderer)
 
 static void SDL_RenderLogicalPresentation(SDL_Renderer *renderer)
 {
-    SDL_assert(renderer->target == NULL);
-    SDL_SetRenderViewport(renderer, NULL);
-    SDL_SetRenderClipRect(renderer, NULL);
-    SDL_SetRenderScale(renderer, 1.0f, 1.0f);
-    SDL_RenderLogicalBorders(renderer);
-    SDL_RenderTexture(renderer, renderer->logical_target, &renderer->logical_src_rect, &renderer->logical_dst_rect);
+    const SDL_RendererLogicalPresentation mode = renderer->logical_presentation_mode;
+    if (mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) {
+        // save off some state we're going to trample.
+        SDL_assert(renderer->view == &renderer->main_view);
+        SDL_RenderViewState *view = &renderer->main_view;
+        const int logical_w = renderer->logical_w;
+        const int logical_h = renderer->logical_h;
+        const float scale_x = view->scale.x;
+        const float scale_y = view->scale.y;
+        const bool clipping_enabled = view->clipping_enabled;
+        SDL_Rect orig_viewport, orig_cliprect;
+
+        SDL_copyp(&orig_viewport, &view->viewport);
+        if (clipping_enabled) {
+            SDL_copyp(&orig_cliprect, &view->clip_rect);
+        }
+
+        // trample some state.
+        SDL_SetRenderLogicalPresentation(renderer, logical_w, logical_h, SDL_LOGICAL_PRESENTATION_DISABLED);
+        SDL_SetRenderViewport(renderer, NULL);
+        if (clipping_enabled) {
+            SDL_SetRenderClipRect(renderer, NULL);
+        }
+        SDL_SetRenderScale(renderer, 1.0f, 1.0f);
+
+        // draw the borders.
+        SDL_RenderLogicalBorders(renderer);
+
+        // now set everything back.
+        renderer->logical_presentation_mode = mode;
+        SDL_SetRenderViewport(renderer, &orig_viewport);
+        if (clipping_enabled) {
+            SDL_SetRenderClipRect(renderer, &orig_cliprect);
+        }
+        SDL_SetRenderScale(renderer, scale_x, scale_y);
+
+        SDL_SetRenderLogicalPresentation(renderer, logical_w, logical_h, mode);
+    }
 }
 
 bool SDL_RenderCoordinatesFromWindow(SDL_Renderer *renderer, float window_x, float window_y, float *x, float *y)
 {
-    SDL_RenderViewState *view;
     float render_x, render_y;
 
     CHECK_RENDERER_MAGIC(renderer, false);
@@ -2834,22 +2811,13 @@ bool SDL_RenderCoordinatesFromWindow(SDL_Renderer *renderer, float window_x, flo
     render_y = window_y * renderer->dpi_scale.y;
 
     // Convert from pixels within the window to pixels within the view
-    if (renderer->logical_target) {
+    if (renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) {
         const SDL_FRect *src = &renderer->logical_src_rect;
         const SDL_FRect *dst = &renderer->logical_dst_rect;
         render_x = ((render_x - dst->x) * src->w) / dst->w;
         render_y = ((render_y - dst->y) * src->h) / dst->h;
     }
 
-    // Convert from pixels within the view to render coordinates
-    if (renderer->logical_target) {
-        view = &renderer->logical_target->view;
-    } else {
-        view = &renderer->main_view;
-    }
-    render_x = (render_x / view->scale.x) - view->viewport.x;
-    render_y = (render_y / view->scale.y) - view->viewport.y;
-
     if (x) {
         *x = render_x;
     }
@@ -2861,21 +2829,10 @@ bool SDL_RenderCoordinatesFromWindow(SDL_Renderer *renderer, float window_x, flo
 
 bool SDL_RenderCoordinatesToWindow(SDL_Renderer *renderer, float x, float y, float *window_x, float *window_y)
 {
-    SDL_RenderViewState *view;
-
     CHECK_RENDERER_MAGIC(renderer, false);
 
-    // Convert from render coordinates to pixels within the view
-    if (renderer->logical_target) {
-        view = &renderer->logical_target->view;
-    } else {
-        view = &renderer->main_view;
-    }
-    x = (view->viewport.x + x) * view->scale.x;
-    y = (view->viewport.y + y) * view->scale.y;
-
-    // Convert from pixels within the view to pixels within the window
-    if (renderer->logical_target) {
+    // Convert from render coordinates to pixels within the window
+    if (renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) {
         const SDL_FRect *src = &renderer->logical_src_rect;
         const SDL_FRect *dst = &renderer->logical_dst_rect;
         x = dst->x + ((x * dst->w) / src->w);
@@ -2905,49 +2862,31 @@ bool SDL_ConvertEventToRenderCoordinates(SDL_Renderer *renderer, SDL_Event *even
             SDL_RenderCoordinatesFromWindow(renderer, event->motion.x, event->motion.y, &event->motion.x, &event->motion.y);
 
             if (event->motion.xrel != 0.0f) {
-                SDL_RenderViewState *view;
-
                 // Convert from window coordinates to pixels within the window
                 float scale = renderer->dpi_scale.x;
 
                 // Convert from pixels within the window to pixels within the view
-                if (renderer->logical_target) {
+                if (renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) {
                     const SDL_FRect *src = &renderer->logical_src_rect;
                     const SDL_FRect *dst = &renderer->logical_dst_rect;
                     scale = (scale * src->w) / dst->w;
                 }
 
                 // Convert from pixels within the view to render coordinates
-                if (renderer->logical_target) {
-                    view = &renderer->logical_target->view;
-                } else {
-                    view = &renderer->main_view;
-                }
-                scale = (scale / view->scale.x);
-
                 event->motion.xrel *= scale;
             }
             if (event->motion.yrel != 0.0f) {
-                SDL_RenderViewState *view;
-
                 // Convert from window coordinates to pixels within the window
                 float scale = renderer->dpi_scale.y;
 
                 // Convert from pixels within the window to pixels within the view
-                if (renderer->logical_target) {
+                if (renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) {
                     const SDL_FRect *src = &renderer->logical_src_rect;
                     const SDL_FRect *dst = &renderer->logical_dst_rect;
                     scale = (scale * src->h) / dst->h;
                 }
 
                 // Convert from pixels within the view to render coordinates
-                if (renderer->logical_target) {
-                    view = &renderer->logical_target->view;
-                } else {
-                    view = &renderer->main_view;
-                }
-                scale = (scale / view->scale.y);
-
                 event->motion.yrel *= scale;
             }
         }
@@ -2993,6 +2932,7 @@ bool SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect)
     CHECK_RENDERER_MAGIC(renderer, false);
 
     if (rect) {
+        // !!! FIXME: fail if rect->w or rect->h are negative (we use this to mean "the whole viewport").
         SDL_copyp(&renderer->view->viewport, rect);
     } else {
         renderer->view->viewport.x = 0;
@@ -3014,17 +2954,18 @@ bool SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect)
     CHECK_RENDERER_MAGIC(renderer, false);
 
     if (rect) {
-        rect->x = renderer->view->viewport.x;
-        rect->y = renderer->view->viewport.y;
-        if (renderer->view->viewport.w >= 0) {
-            rect->w = renderer->view->viewport.w;
+        const SDL_RenderViewState *view = renderer->view;
+        rect->x = view->viewport.x;
+        rect->y = view->viewport.y;
+        if (view->viewport.w >= 0) {
+            rect->w = view->viewport.w;
         } else {
-            rect->w = (int)SDL_ceilf(renderer->view->pixel_w / renderer->view->scale.x);
+            rect->w = (int)SDL_ceilf(view->pixel_w / view->current_scale.x);
         }
         if (renderer->view->viewport.h >= 0) {
-            rect->h = renderer->view->viewport.h;
+            rect->h = view->viewport.h;
         } else {
-            rect->h = (int)SDL_ceilf(renderer->view->pixel_h / renderer->view->scale.y);
+            rect->h = (int)SDL_ceilf(view->pixel_h / view->current_scale.y);
         }
     }
     return true;
@@ -3043,17 +2984,23 @@ bool SDL_RenderViewportSet(SDL_Renderer *renderer)
 
 static void GetRenderViewportSize(SDL_Renderer *renderer, SDL_FRect *rect)
 {
+    const SDL_RenderViewState *view = renderer->view;
+    const float scale_x = view->current_scale.x;
+    const float scale_y = view->current_scale.y;
+
     rect->x = 0.0f;
     rect->y = 0.0f;
-    if (renderer->view->viewport.w >= 0) {
-        rect->w = (float)renderer->view->viewport.w;
+
+    if (view->viewport.w >= 0) {
+        rect->w = (float)view->viewport.w / scale_x;
     } else {
-        rect->w = renderer->view->pixel_w / renderer->view->scale.x;
+        rect->w = view->pixel_w / scale_x;
     }
-    if (renderer->view->viewport.h >= 0) {
-        rect->h = (float)renderer->view->viewport.h;
+
+    if (view->viewport.h >= 0) {
+        rect->h = (float)view->viewport.h / scale_y;
     } else {
-        rect->h = renderer->view->pixel_h / renderer->view->scale.y;
+        rect->h = view->pixel_h / scale_y;
     }
 }
 
@@ -3153,6 +3100,8 @@ bool SDL_SetRenderScale(SDL_Renderer *renderer, float scaleX, float scaleY)
 
     renderer->view->scale.x = scaleX;
     renderer->view->scale.y = scaleY;
+    renderer->view->current_scale.x = scaleX * renderer->view->logical_scale.x;
+    renderer->view->current_scale.y = scaleY * renderer->view->logical_scale.y;
     UpdatePixelViewport(renderer, renderer->view);
     UpdatePixelClipRect(renderer, renderer->view);
 
@@ -3362,11 +3311,13 @@ static bool RenderPointsWithRects(SDL_Renderer *renderer, const SDL_FPoint *fpoi
         return false;
     }
 
+    const float scale_x = renderer->view->current_scale.x;
+    const float scale_y = renderer->view->current_scale.y;
     for (i = 0; i < count; ++i) {
-        frects[i].x = fpoints[i].x * renderer->view->scale.x;
-        frects[i].y = fpoints[i].y * renderer->view->scale.y;
-        frects[i].w = renderer->view->scale.x;
-        frects[i].h = renderer->view->scale.y;
+        frects[i].x = fpoints[i].x * scale_x;
+        frects[i].y = fpoints[i].y * scale_y;
+        frects[i].w = scale_x;
+        frects[i].h = scale_y;
     }
 
     result = QueueCmdFillRects(renderer, frects, count);
@@ -3396,7 +3347,7 @@ bool SDL_RenderPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int coun
     }
 #endif
 
-    if (renderer->view->scale.x != 1.0f || renderer->view->scale.y != 1.0f) {
+    if ((renderer->view->current_scale.x != 1.0f) || (renderer->view->current_scale.y != 1.0f)) {
         result = RenderPointsWithRects(renderer, points, count);
     } else {
         result = QueueCmdDrawPoints(renderer, points, count);
@@ -3498,7 +3449,7 @@ static bool RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2,
         }
     }
 
-    if (renderer->view->scale.x != 1.0f || renderer->view->scale.y != 1.0f) {
+    if ((renderer->view->current_scale.x != 1.0f) || (renderer->view->current_scale.y != 1.0f)) {
         result = RenderPointsWithRects(renderer, points, numpixels);
     } else {
         result = QueueCmdDrawPoints(renderer, points, numpixels);
@@ -3509,11 +3460,10 @@ static bool RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2,
     return result;
 }
 
-static bool RenderLinesWithRectsF(SDL_Renderer *renderer,
-                                     const SDL_FPoint *points, const int count)
+static bool RenderLinesWithRectsF(SDL_Renderer *renderer, const SDL_FPoint *points, const int count)
 {
-    const float scale_x = renderer->view->scale.x;
-    const float scale_y = renderer->view->scale.y;
+    const float scale_x = renderer->view->current_scale.x;
+    const float scale_y = renderer->view->current_scale.y;
     SDL_FRect *frect;
     SDL_FRect *frects;
     int i, nrects = 0;
@@ -3600,13 +3550,13 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
     }
 #endif
 
-    if (renderer->line_method == SDL_RENDERLINEMETHOD_POINTS) {
-        result = RenderLinesWithRectsF(renderer, points, count);
-    } else if (renderer->line_method == SDL_RENDERLINEMETHOD_GEOMETRY) {
+    const bool islogical = ((renderer->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) && (renderer->view == &renderer->main_view));
+
+    if (islogical || (renderer->line_method == SDL_RENDERLINEMETHOD_GEOMETRY)) {
+        const float scale_x = renderer->view->current_scale.x;
+        const float scale_y = renderer->view->current_scale.y;
         bool isstack1;
         bool isstack2;
-        const float scale_x = renderer->view->scale.x;
-        const float scale_y = renderer->view->scale.y;
         float *xy = SDL_small_alloc(float, 4 * 2 * count, &isstack1);
         int *indices = SDL_small_alloc(int,
                                        (4) * 3 * (count - 1) + (2) * 3 * (count), &isstack2);
@@ -3722,7 +3672,9 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
         SDL_small_free(xy, isstack1);
         SDL_small_free(indices, isstack2);
 
-    } else if (renderer->view->scale.x != 1.0f || renderer->view->scale.y != 1.0f) {
+    } else if (renderer->line_method == SDL_RENDERLINEMETHOD_POINTS) {
+        result = RenderLinesWithRectsF(renderer, points, count);
+    } else if (renderer->view->scale.x != 1.0f || renderer->view->scale.y != 1.0f) {  /* we checked for logical scale elsewhere. */
         result = RenderLinesWithRectsF(renderer, points, count);
     } else {
         result = QueueCmdDrawLines(renderer, points, count);
@@ -3826,11 +3778,14 @@ bool SDL_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int cou
     if (!frects) {
         return false;
     }
+
+    const float scale_x = renderer->view->current_scale.x;
+    const float scale_y = renderer->view->current_scale.y;
     for (i = 0; i < count; ++i) {
-        frects[i].x = rects[i].x * renderer->view->scale.x;
-        frects[i].y = rects[i].y * renderer->view->scale.y;
-        frects[i].w = rects[i].w * renderer->view->scale.x;
-        frects[i].h = rects[i].h * renderer->view->scale.y;
+        frects[i].x = rects[i].x * scale_x;
+        frects[i].y = rects[i].y * scale_y;
+        frects[i].w = rects[i].w * scale_x;
+        frects[i].h = rects[i].h * scale_y;
     }
 
     result = QueueCmdFillRects(renderer, frects, count);
@@ -3842,8 +3797,10 @@ bool SDL_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int cou
 
 static bool SDL_RenderTextureInternal(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect)
 {
+    const float scale_x = renderer->view->current_scale.x;
+    const float scale_y = renderer->view->current_scale.y;
+    const bool use_rendergeometry = (!renderer->QueueCopy);
     bool result;
-    bool use_rendergeometry = (!renderer->QueueCopy);
 
     if (use_rendergeometry) {
         float xy[8];
@@ -3887,18 +3844,10 @@ 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,
-                                  renderer->view->scale.x,
-                                  renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP);
+                                  num_vertices, indices, num_indices, size_indices,
+                                  scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP);
     } else {
-        SDL_FRect rect;
-
-        rect.x = dstrect->x * renderer->view->scale.x;
-        rect.y = dstrect->y * renderer->view->scale.y;
-        rect.w = dstrect->w * renderer->view->scale.x;
-        rect.h = dstrect->h * renderer->view->scale.y;
-
+        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);
     }
     return result;
@@ -3958,7 +3907,6 @@ bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
     SDL_FRect real_dstrect;
     SDL_FPoint real_center;
     bool result;
-    int use_rendergeometry;
 
     if (flip == SDL_FLIP_NONE && (int)(angle / 360) == angle / 360) { // fast path when we don't need rotation or flipping
         return SDL_RenderTexture(renderer, texture, srcrect, dstrect);
@@ -3981,8 +3929,6 @@ bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
     }
 #endif
 
-    use_rendergeometry = (!renderer->QueueCopyEx);
-
     real_srcrect.x = 0.0f;
     real_srcrect.y = 0.0f;
     real_srcrect.w = (float)texture->w;
@@ -4013,6 +3959,10 @@ bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
 
     texture->last_command_generation = renderer->render_command_generation;
 
+    const float scale_x = renderer->view->current_scale.x;
+    const float scale_y = renderer->view->current_scale.y;
+
+    const bool use_rendergeometry = (!renderer->QueueCopyEx);
     if (use_rendergeometry) {
         float xy[8];
         const int xy_stride = 2 * sizeof(float);
@@ -4092,15 +4042,10 @@ 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,
-                                  renderer->view->scale.x,
-                                  renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP);
+                                  num_vertices, indices, num_indices, size_indices,
+                                  scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP);
     } else {
-
-        result = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip,
-                                renderer->view->scale.x,
-                                renderer->view->scale.y);
+        result = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip, scale_x, scale_y);
     }
     return result;
 }
@@ -4148,10 +4093,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,
-                            renderer->view->scale.x,
-                            renderer->view->scale.y, SDL_TEXTURE_ADDRESS_WRAP);
+                            num_vertices, indices, num_indices, size_indices,
+                            renderer->view->current_scale.x, renderer->view->current_scale.y, 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)
@@ -4503,6 +4446,8 @@ static bool SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer,
     float texw = 0.0f, texh = 0.0f;
     SDL_BlendMode blendMode = SDL_BLENDMODE_NONE;
     float r = 0, g = 0, b = 0, a = 0;
+    const float scale_x = renderer->view->current_scale.x;
+    const float scale_y = renderer->view->current_scale.y;
 
     // Save
     SDL_GetRenderDrawBlendMode(renderer, &blendMode);
@@ -4759,8 +4704,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,
-                                          renderer->view->scale.x,
-                                          renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP);
+                                          scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP);
                 if (!result) {
                     goto end;
                 }
@@ -4780,8 +4724,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,
-                                  renderer->view->scale.x,
-                                  renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP);
+                                  scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP);
         if (!result) {
             goto end;
         }
@@ -4905,18 +4848,14 @@ bool SDL_RenderGeometryRaw(SDL_Renderer *renderer,
 #endif
 
     return QueueCmdGeometry(renderer, texture,
-                              xy, xy_stride, color, color_stride, uv, uv_stride,
-                              num_vertices,
-                              indices, num_indices, size_indices,
-                              renderer->view->scale.x,
-                              renderer->view->scale.y, texture_address_mode);
+                            xy, xy_stride, color, color_stride, uv, uv_stride,
+                            num_vertices, indices, num_indices, size_indices,
+                            renderer->view->current_scale.x, renderer->view->current_scale.y,
+                            texture_address_mode);
 }
 
 SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
 {
-    SDL_Rect real_rect;
-    SDL_Surface *surface;
-
     CHECK_RENDERER_MAGIC(renderer, NULL);
 
     if (!renderer->RenderReadPixels) {
@@ -4926,7 +4865,7 @@ SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
 
     FlushRenderCommands(renderer); // we need to render before we read the results.
 
-    real_rect = renderer->view->pixel_viewport;
+    SDL_Rect real_rect = renderer->view->pixel_viewport;
 
     if (rect) {
         if (!SDL_GetRectIntersection(rect, &real_rect, &real_rect)) {
@@ -4934,7 +4873,7 @@ SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
         }
     }
 
-    surface = renderer->RenderReadPixels(renderer, &real_rect);
+    SDL_Surface *surface = renderer->RenderReadPixels(renderer, &real_rect);
     if (surface) {
         SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
 
@@ -5008,11 +4947,13 @@ bool SDL_RenderPresent(SDL_Renderer *renderer)
 
     CHECK_RENDERER_MAGIC(renderer, false);
 
-    if (renderer->logical_target) {
-        SDL_SetRenderTargetInternal(renderer, NULL);
-        SDL_RenderLogicalPresentation(renderer);
+    // !!! FIXME: fail if using a render target? Or just implicitly set the render target to NULL now?
+    if (renderer->view != &renderer->main_view) {
+        return SDL_SetError("Cannot present a render target");
     }
 
+    SDL_RenderLogicalPresentation(renderer);
+
     if (renderer->transparent_window) {
         SDL_RenderApplyWindowShape(renderer);
     }
@@ -5029,10 +4970,6 @@ bool SDL_RenderPresent(SDL_Renderer *renderer)
         presented = false;
     }
 
-    if (renderer->logical_target) {
-        SDL_SetRenderTargetInternal(renderer, renderer->logical_target);
-    }
-
     if (renderer->simulate_vsync ||
         (!presented && renderer->wanted_vsync)) {
         SDL_SimulateRenderVSync(renderer);
@@ -5053,22 +4990,12 @@ static bool SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying)
         // Renderer get destroyed, avoid to queue more commands
     } else {
         if (texture == renderer->target) {
-            SDL_SetRenderTargetInternal(renderer, NULL); // implies command queue flush
-
-            if (texture == renderer->logical_target) {
-                // Complete any logical presentation
-                SDL_RenderLogicalPresentation(renderer);
-                FlushRenderCommands(renderer);
-            }
+            SDL_SetRenderTarget(renderer, NULL); // implies command queue flush
         } else {
             FlushRenderCommandsIfTextureNeeded(texture);
         }
     }
 
-    if (texture == renderer->logical_target) {
-        renderer->logical_target = NULL;
-    }
-
     SDL_SetObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE, false);
 
     if (texture->next) {

+ 4 - 3
src/render/SDL_sysrender.h

@@ -63,7 +63,9 @@ typedef struct SDL_RenderViewState
     SDL_Rect pixel_clip_rect;
     bool clipping_enabled;
     SDL_FPoint scale;
-
+    SDL_FPoint logical_scale;
+    SDL_FPoint logical_offset;
+    SDL_FPoint current_scale;  // this is just `scale * logical_scale`, precalculated, since we use it a lot.
 } SDL_RenderViewState;
 
 // Define the SDL texture structure
@@ -240,9 +242,8 @@ struct SDL_Renderer
     Uint64 last_present;
 
     // Support for logical output coordinates
-    SDL_Texture *logical_target;
     SDL_RendererLogicalPresentation logical_presentation_mode;
-    SDL_ScaleMode logical_scale_mode;
+    int logical_w, logical_h;
     SDL_FRect logical_src_rect;
     SDL_FRect logical_dst_rect;
 

+ 7 - 5
src/render/opengl/SDL_render_gl.c

@@ -1465,7 +1465,6 @@ static SDL_Surface *GL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *
     SDL_PixelFormat format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ARGB8888;
     GLint internalFormat;
     GLenum targetFormat, type;
-    int w, h;
     SDL_Surface *surface;
 
     GL_ActivateRenderer(renderer);
@@ -1480,13 +1479,16 @@ static SDL_Surface *GL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *
         return NULL;
     }
 
-    SDL_GetCurrentRenderOutputSize(renderer, &w, &h);
+    int y = rect->y;
+    if (!renderer->target) {
+        int w, h;
+        SDL_GetRenderOutputSize(renderer, &w, &h);
+        y = (h - y) - rect->h;
+    }
 
     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
     data->glPixelStorei(GL_PACK_ROW_LENGTH, (surface->pitch / SDL_BYTESPERPIXEL(format)));
-
-    data->glReadPixels(rect->x, renderer->target ? rect->y : (h - rect->y) - rect->h,
-                       rect->w, rect->h, targetFormat, type, surface->pixels);
+    data->glReadPixels(rect->x, y, rect->w, rect->h, targetFormat, type, surface->pixels);
 
     if (!GL_CheckError("glReadPixels()", renderer)) {
         SDL_DestroySurface(surface);

+ 7 - 4
src/render/opengles2/SDL_render_gles2.c

@@ -1993,7 +1993,6 @@ static SDL_Surface *GLES2_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rec
 {
     GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
     SDL_PixelFormat format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_RGBA32;
-    int w, h;
     SDL_Surface *surface;
 
     surface = SDL_CreateSurface(rect->w, rect->h, format);
@@ -2001,10 +2000,14 @@ static SDL_Surface *GLES2_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rec
         return NULL;
     }
 
-    SDL_GetCurrentRenderOutputSize(renderer, &w, &h);
+    int y = rect->y;
+    if (!renderer->target) {
+        int w, h;
+        SDL_GetRenderOutputSize(renderer, &w, &h);
+        y = (h - y) - rect->h;
+    }
 
-    data->glReadPixels(rect->x, renderer->target ? rect->y : (h - rect->y) - rect->h,
-                       rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
+    data->glReadPixels(rect->x, y, rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
     if (!GL_CheckError("glReadPixels()", renderer)) {
         SDL_DestroySurface(surface);
         return NULL;

+ 7 - 4
src/render/vitagxm/SDL_render_vita_gxm.c

@@ -1080,7 +1080,6 @@ void read_pixels(int x, int y, size_t width, size_t height, void *data)
 static SDL_Surface *VITA_GXM_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
 {
     Uint32 format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
-    int w, h;
     SDL_Surface *surface;
 
     // TODO: read from texture rendertarget.
@@ -1094,10 +1093,14 @@ static SDL_Surface *VITA_GXM_RenderReadPixels(SDL_Renderer *renderer, const SDL_
         return NULL;
     }
 
-    SDL_GetCurrentRenderOutputSize(renderer, &w, &h);
+    int y = rect->y;
+    if (!renderer->target) {
+        int w, h;
+        SDL_GetRenderOutputSize(renderer, &w, &h);
+        y = (h - y) - rect->h;
+    }
 
-    read_pixels(rect->x, renderer->target ? rect->y : (h - rect->y) - rect->h,
-                rect->w, rect->h, surface->pixels);
+    read_pixels(rect->x, y, rect->w, rect->h, surface->pixels);
 
     // Flip the rows to be top-down if necessary
 

+ 2 - 37
src/test/SDL_test_common.c

@@ -482,21 +482,6 @@ static int SDLCALL SDLTest_CommonStateParseVideoArguments(void *data, char **arg
         }
         return -1;
     }
-    if (SDL_strcasecmp(argv[index], "--logical-scale-quality") == 0) {
-        ++index;
-        if (!argv[index]) {
-            return -1;
-        }
-        if (SDL_strcasecmp(argv[index], "nearest") == 0) {
-            state->logical_scale_mode = SDL_SCALEMODE_NEAREST;
-            return 2;
-        }
-        if (SDL_strcasecmp(argv[index], "linear") == 0) {
-            state->logical_scale_mode = SDL_SCALEMODE_LINEAR;
-            return 2;
-        }
-        return -1;
-    }
     if (SDL_strcasecmp(argv[index], "--scale") == 0) {
         ++index;
         if (!argv[index]) {
@@ -708,7 +693,6 @@ SDLTest_CommonState *SDLTest_CommonCreateState(char **argv, SDL_InitFlags flags)
     state->window_w = DEFAULT_WINDOW_WIDTH;
     state->window_h = DEFAULT_WINDOW_HEIGHT;
     state->logical_presentation = SDL_LOGICAL_PRESENTATION_DISABLED;
-    state->logical_scale_mode = SDL_SCALEMODE_LINEAR;
     state->num_windows = 1;
     state->audio_freq = 22050;
     state->audio_format = SDL_AUDIO_S16;
@@ -1082,21 +1066,6 @@ static void SDLTest_PrintLogicalPresentation(char *text, size_t maxlen, SDL_Rend
     }
 }
 
-static void SDLTest_PrintScaleMode(char *text, size_t maxlen, SDL_ScaleMode scale_mode)
-{
-    switch (scale_mode) {
-    case SDL_SCALEMODE_NEAREST:
-        SDL_snprintfcat(text, maxlen, "NEAREST");
-        break;
-    case SDL_SCALEMODE_LINEAR:
-        SDL_snprintfcat(text, maxlen, "LINEAR");
-        break;
-    default:
-        SDL_snprintfcat(text, maxlen, "0x%8.8x", scale_mode);
-        break;
-    }
-}
-
 static void SDLTest_PrintRenderer(SDL_Renderer *renderer)
 {
     const char *name;
@@ -1480,7 +1449,7 @@ bool SDLTest_CommonInit(SDLTest_CommonState *state)
                 if (state->render_vsync) {
                     SDL_SetRenderVSync(state->renderers[i], state->render_vsync);
                 }
-                if (!SDL_SetRenderLogicalPresentation(state->renderers[i], state->logical_w, state->logical_h, state->logical_presentation, state->logical_scale_mode)) {
+                if (!SDL_SetRenderLogicalPresentation(state->renderers[i], state->logical_w, state->logical_h, state->logical_presentation)) {
                     SDL_Log("Couldn't set logical presentation: %s\n", SDL_GetError());
                     return false;
                 }
@@ -2587,7 +2556,6 @@ void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, fl
     SDL_DisplayID windowDisplayID = SDL_GetDisplayForWindow(window);
     const char *name;
     SDL_RendererLogicalPresentation logical_presentation;
-    SDL_ScaleMode logical_scale_mode;
 
     /* Video */
 
@@ -2638,12 +2606,9 @@ void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, fl
     SDLTest_DrawString(renderer, 0.0f, textY, text);
     textY += lineHeight;
 
-    SDL_GetRenderLogicalPresentation(renderer, &w, &h, &logical_presentation, &logical_scale_mode);
+    SDL_GetRenderLogicalPresentation(renderer, &w, &h, &logical_presentation);
     (void)SDL_snprintf(text, sizeof(text), "SDL_GetRenderLogicalPresentation: %dx%d ", w, h);
     SDLTest_PrintLogicalPresentation(text, sizeof(text), logical_presentation);
-    SDL_snprintfcat(text, sizeof(text), ", ");
-    SDLTest_PrintScaleMode(text, sizeof(text), logical_scale_mode);
-    SDLTest_DrawString(renderer, 0.0f, textY, text);
     textY += lineHeight;
 
     /* Window */

+ 20 - 36
test/testautomation_render.c

@@ -1089,7 +1089,6 @@ static int SDLCALL render_testLogicalSize(void *arg)
     int w, h;
     int set_w, set_h;
     SDL_RendererLogicalPresentation set_presentation_mode;
-    SDL_ScaleMode set_scale_mode;
     SDL_FRect set_rect;
     const int factor = 2;
 
@@ -1108,16 +1107,13 @@ static int SDLCALL render_testLogicalSize(void *arg)
 
     /* Set the logical size and do a fill operation */
     CHECK_FUNC(SDL_GetCurrentRenderOutputSize, (renderer, &w, &h))
-    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, w / factor, h / factor,
-                                           SDL_LOGICAL_PRESENTATION_LETTERBOX,
-                                           SDL_SCALEMODE_NEAREST))
-    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, w / factor, h / factor, SDL_LOGICAL_PRESENTATION_LETTERBOX))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode))
     SDLTest_AssertCheck(
         set_w == (w / factor) &&
         set_h == (h / factor) &&
-        set_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX &&
-        set_scale_mode == SDL_SCALEMODE_NEAREST,
-        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d", set_w, set_h, set_presentation_mode);
     CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
     SDLTest_AssertCheck(
         set_rect.x == 0.0f &&
@@ -1131,16 +1127,13 @@ static int SDLCALL render_testLogicalSize(void *arg)
     rect.w = (float)viewport.w / factor;
     rect.h = (float)viewport.h / factor;
     CHECK_FUNC(SDL_RenderFillRect, (renderer, &rect))
-    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0,
-                                           SDL_LOGICAL_PRESENTATION_DISABLED,
-                                           SDL_SCALEMODE_NEAREST))
-    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode))
     SDLTest_AssertCheck(
         set_w == 0 &&
         set_h == 0 &&
-        set_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED &&
-        set_scale_mode == SDL_SCALEMODE_NEAREST,
-        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d", set_w, set_h, set_presentation_mode);
     CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
     SDLTest_AssertCheck(
         set_rect.x == 0.0f &&
@@ -1157,20 +1150,16 @@ static int SDLCALL render_testLogicalSize(void *arg)
 
     /* Set the logical size and viewport and do a fill operation */
     CHECK_FUNC(SDL_GetCurrentRenderOutputSize, (renderer, &w, &h))
-    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, w / factor, h / factor,
-                                           SDL_LOGICAL_PRESENTATION_LETTERBOX,
-                                           SDL_SCALEMODE_NEAREST))
+    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, w / factor, h / factor, SDL_LOGICAL_PRESENTATION_LETTERBOX))
     viewport.x = (TESTRENDER_SCREEN_W / 4) / factor;
     viewport.y = (TESTRENDER_SCREEN_H / 4) / factor;
-    viewport.w = (TESTRENDER_SCREEN_W / 2) / factor;
-    viewport.h = (TESTRENDER_SCREEN_H / 2) / factor;
+    viewport.w = TESTRENDER_SCREEN_W / factor;
+    viewport.h = TESTRENDER_SCREEN_H / factor;
     CHECK_FUNC(SDL_SetRenderViewport, (renderer, &viewport))
     CHECK_FUNC(SDL_SetRenderDrawColor, (renderer, 0, 255, 0, SDL_ALPHA_OPAQUE))
     CHECK_FUNC(SDL_RenderFillRect, (renderer, NULL))
     CHECK_FUNC(SDL_SetRenderViewport, (renderer, NULL))
-    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0,
-                                           SDL_LOGICAL_PRESENTATION_DISABLED,
-                                           SDL_SCALEMODE_NEAREST))
+    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED))
 
     /* Check to see if final image matches. */
     compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE);
@@ -1196,15 +1185,13 @@ static int SDLCALL render_testLogicalSize(void *arg)
     CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer,
                                            w - 2 * (TESTRENDER_SCREEN_W / 4),
                                            h,
-                                           SDL_LOGICAL_PRESENTATION_LETTERBOX,
-                                           SDL_SCALEMODE_LINEAR))
-    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+                                           SDL_LOGICAL_PRESENTATION_LETTERBOX))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode))
     SDLTest_AssertCheck(
         set_w == w - 2 * (TESTRENDER_SCREEN_W / 4) &&
         set_h == h &&
-        set_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX &&
-        set_scale_mode == SDL_SCALEMODE_LINEAR,
-        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d", set_w, set_h, set_presentation_mode);
     CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
     SDLTest_AssertCheck(
         set_rect.x == 20.0f &&
@@ -1214,16 +1201,13 @@ static int SDLCALL render_testLogicalSize(void *arg)
         "Validate result from SDL_GetRenderLogicalPresentationRect, got {%g, %g, %gx%g}", set_rect.x, set_rect.y, set_rect.w, set_rect.h);
     CHECK_FUNC(SDL_SetRenderDrawColor, (renderer, 0, 255, 0, SDL_ALPHA_OPAQUE))
     CHECK_FUNC(SDL_RenderFillRect, (renderer, NULL))
-    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0,
-                                           SDL_LOGICAL_PRESENTATION_DISABLED,
-                                           SDL_SCALEMODE_NEAREST))
-    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode, &set_scale_mode))
+    CHECK_FUNC(SDL_SetRenderLogicalPresentation, (renderer, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED))
+    CHECK_FUNC(SDL_GetRenderLogicalPresentation, (renderer, &set_w, &set_h, &set_presentation_mode))
     SDLTest_AssertCheck(
         set_w == 0 &&
         set_h == 0 &&
-        set_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED &&
-        set_scale_mode == SDL_SCALEMODE_NEAREST,
-        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d, %d", set_w, set_h, set_presentation_mode, set_scale_mode);
+        set_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED,
+        "Validate result from SDL_GetRenderLogicalPresentation, got %d, %d, %d", set_w, set_h, set_presentation_mode);
     CHECK_FUNC(SDL_GetRenderLogicalPresentationRect, (renderer, &set_rect))
     SDLTest_AssertCheck(
         set_rect.x == 0.0f &&

+ 1 - 2
test/testcontroller.c

@@ -2086,8 +2086,7 @@ int main(int argc, char *argv[])
 
     /* scale for platforms that don't give you the window size you asked for. */
     SDL_SetRenderLogicalPresentation(screen, (int)SCREEN_WIDTH, (int)SCREEN_HEIGHT,
-                                     SDL_LOGICAL_PRESENTATION_LETTERBOX,
-                                     SDL_SCALEMODE_LINEAR);
+                                     SDL_LOGICAL_PRESENTATION_LETTERBOX);
 
 
     title_area.w = GAMEPAD_WIDTH;

+ 1 - 1
test/testime.c

@@ -1109,7 +1109,7 @@ int main(int argc, char *argv[])
         SDL_Renderer *renderer = state->renderers[i];
         int icon_w = 0, icon_h = 0;
 
-        SDL_SetRenderLogicalPresentation(renderer, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX, SDL_SCALEMODE_LINEAR);
+        SDL_SetRenderLogicalPresentation(renderer, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX);
 
         ctx->window = window;
         ctx->renderer = renderer;

+ 3 - 1
test/testspriteminimal.c

@@ -117,11 +117,13 @@ int main(int argc, char *argv[])
         goto quit;
     }
 
-    if (!SDL_CreateWindowAndRenderer("testspriteminimal", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) {
+    if (!SDL_CreateWindowAndRenderer("testspriteminimal", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
         return_code = 2;
         goto quit;
     }
 
+    SDL_SetRenderLogicalPresentation(renderer, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX);
+
     sprite = CreateTexture(renderer, icon_bmp, icon_bmp_len, &sprite_w, &sprite_h);
 
     if (!sprite) {