SDL: SDL_Renderer software, D3D11: don't use "renderer->viewport" in back-ends, but use the one from SETVIEWPORT cmd

From 7828362da9bf269c76ba0a6c128a98c639bf07b2 Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Wed, 24 Nov 2021 16:45:06 +0100
Subject: [PATCH] SDL_Renderer software, D3D11: don't use "renderer->viewport"
 in back-ends, but use the one from SETVIEWPORT cmd

---
 src/render/direct3d11/SDL_render_d3d11.c |  27 +++--
 src/render/software/SDL_render_sw.c      | 142 +++++++++++++++--------
 2 files changed, 106 insertions(+), 63 deletions(-)

diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index ffae92f5f68..c03a2d051be 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -700,7 +700,10 @@ D3D11_GetRotationForCurrentRenderTarget(SDL_Renderer * renderer)
 static int
 D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRect, D3D11_RECT * outRect, BOOL includeViewportOffset)
 {
+    D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
     const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
+    const SDL_Rect *viewport = &data->currentViewport;
+
     switch (rotation) {
         case DXGI_MODE_ROTATION_IDENTITY:
             outRect->left = sdlRect->x;
@@ -708,27 +711,27 @@ D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRec
             outRect->top = sdlRect->y;
             outRect->bottom = sdlRect->y + sdlRect->h;
             if (includeViewportOffset) {
-                outRect->left += renderer->viewport.x;
-                outRect->right += renderer->viewport.x;
-                outRect->top += renderer->viewport.y;
-                outRect->bottom += renderer->viewport.y;
+                outRect->left += viewport->x;
+                outRect->right += viewport->x;
+                outRect->top += viewport->y;
+                outRect->bottom += viewport->y;
             }
             break;
         case DXGI_MODE_ROTATION_ROTATE270:
             outRect->left = sdlRect->y;
             outRect->right = sdlRect->y + sdlRect->h;
-            outRect->top = renderer->viewport.w - sdlRect->x - sdlRect->w;
-            outRect->bottom = renderer->viewport.w - sdlRect->x;
+            outRect->top = viewport->w - sdlRect->x - sdlRect->w;
+            outRect->bottom = viewport->w - sdlRect->x;
             break;
         case DXGI_MODE_ROTATION_ROTATE180:
-            outRect->left = renderer->viewport.w - sdlRect->x - sdlRect->w;
-            outRect->right = renderer->viewport.w - sdlRect->x;
-            outRect->top = renderer->viewport.h - sdlRect->y - sdlRect->h;
-            outRect->bottom = renderer->viewport.h - sdlRect->y;
+            outRect->left = viewport->w - sdlRect->x - sdlRect->w;
+            outRect->right = viewport->w - sdlRect->x;
+            outRect->top = viewport->h - sdlRect->y - sdlRect->h;
+            outRect->bottom = viewport->h - sdlRect->y;
             break;
         case DXGI_MODE_ROTATION_ROTATE90:
-            outRect->left = renderer->viewport.h - sdlRect->y - sdlRect->h;
-            outRect->right = renderer->viewport.h - sdlRect->y;
+            outRect->left = viewport->h - sdlRect->y - sdlRect->h;
+            outRect->right = viewport->h - sdlRect->y;
             outRect->top = sdlRect->x;
             outRect->bottom = sdlRect->x + sdlRect->h;
             break;
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index e8136a2f4c0..6ce921a044f 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -214,18 +214,9 @@ SW_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FP
 
     cmd->data.draw.count = count;
 
-    if (renderer->viewport.x || renderer->viewport.y) {
-        const int x = renderer->viewport.x;
-        const int y = renderer->viewport.y;
-        for (i = 0; i < count; i++, verts++, points++) {
-            verts->x = (int)(x + points->x);
-            verts->y = (int)(y + points->y);
-        }
-    } else {
-        for (i = 0; i < count; i++, verts++, points++) {
-            verts->x = (int)points->x;
-            verts->y = (int)points->y;
-        }
+    for (i = 0; i < count; i++, verts++, points++) {
+        verts->x = (int)points->x;
+        verts->y = (int)points->y;
     }
 
     return 0;
@@ -243,23 +234,11 @@ SW_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRe
 
     cmd->data.draw.count = count;
 
-    if (renderer->viewport.x || renderer->viewport.y) {
-        const int x = renderer->viewport.x;
-        const int y = renderer->viewport.y;
-
-        for (i = 0; i < count; i++, verts++, rects++) {
-            verts->x = (int)(x + rects->x);
-            verts->y = (int)(y + rects->y);
-            verts->w = SDL_max((int)rects->w, 1);
-            verts->h = SDL_max((int)rects->h, 1);
-        }
-    } else {
-        for (i = 0; i < count; i++, verts++, rects++) {
-            verts->x = (int)rects->x;
-            verts->y = (int)rects->y;
-            verts->w = SDL_max((int)rects->w, 1);
-            verts->h = SDL_max((int)rects->h, 1);
-        }
+    for (i = 0; i < count; i++, verts++, rects++) {
+        verts->x = (int)rects->x;
+        verts->y = (int)rects->y;
+        verts->w = SDL_max((int)rects->w, 1);
+        verts->h = SDL_max((int)rects->h, 1);
     }
 
     return 0;
@@ -280,13 +259,8 @@ SW_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * text
     SDL_memcpy(verts, srcrect, sizeof (SDL_Rect));
     verts++;
 
-    if (renderer->viewport.x || renderer->viewport.y) {
-        verts->x = (int)(renderer->viewport.x + dstrect->x);
-        verts->y = (int)(renderer->viewport.y + dstrect->y);
-    } else {
-        verts->x = (int)dstrect->x;
-        verts->y = (int)dstrect->y;
-    }
+    verts->x = (int)dstrect->x;
+    verts->y = (int)dstrect->y;
     verts->w = (int)dstrect->w;
     verts->h = (int)dstrect->h;
 
@@ -317,13 +291,8 @@ SW_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * te
 
     SDL_memcpy(&verts->srcrect, srcrect, sizeof (SDL_Rect));
 
-    if (renderer->viewport.x || renderer->viewport.y) {
-        verts->dstrect.x = (int)(renderer->viewport.x + dstrect->x);
-        verts->dstrect.y = (int)(renderer->viewport.y + dstrect->y);
-    } else {
-        verts->dstrect.x = (int)dstrect->x;
-        verts->dstrect.y = (int)dstrect->y;
-    }
+    verts->dstrect.x = (int)dstrect->x;
+    verts->dstrect.y = (int)dstrect->y;
     verts->dstrect.w = (int)dstrect->w;
     verts->dstrect.h = (int)dstrect->h;
     verts->angle = angle;
@@ -618,8 +587,8 @@ SW_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *te
             ptr->src.x = (int)(uv_[0] * texture->w);
             ptr->src.y = (int)(uv_[1] * texture->h);
 
-            ptr->dst.x = (int)(xy_[0] * scale_x + renderer->viewport.x);
-            ptr->dst.y = (int)(xy_[1] * scale_y + renderer->viewport.y);
+            ptr->dst.x = (int)(xy_[0] * scale_x);
+            ptr->dst.y = (int)(xy_[1] * scale_y);
             trianglepoint_2_fixedpoint(&ptr->dst);
 
             ptr->color = col_;
@@ -646,8 +615,8 @@ SW_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *te
             xy_ = (float *)((char*)xy + j * xy_stride);
             col_ = *(SDL_Color *)((char*)color + j * color_stride);
 
-            ptr->dst.x = (int)(xy_[0] * scale_x + renderer->viewport.x);
-            ptr->dst.y = (int)(xy_[1] * scale_y + renderer->viewport.y);
+            ptr->dst.x = (int)(xy_[0] * scale_x);
+            ptr->dst.y = (int)(xy_[1] * scale_y);
             trianglepoint_2_fixedpoint(&ptr->dst);
 
             ptr->color = col_;
@@ -755,9 +724,19 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
                 const Uint8 b = cmd->data.draw.b;
                 const Uint8 a = cmd->data.draw.a;
                 const int count = (int) cmd->data.draw.count;
-                const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
                 const SDL_BlendMode blend = cmd->data.draw.blend;
                 SetDrawState(surface, &drawstate);
+
+                /* Apply viewport */
+                if (drawstate.viewport->x || drawstate.viewport->y) {
+                    int i;
+                    for (i = 0; i < count; i++) {
+                        verts[i].x += drawstate.viewport->x;
+                        verts[i].y += drawstate.viewport->y;
+                    }
+                }
+
                 if (blend == SDL_BLENDMODE_NONE) {
                     SDL_DrawPoints(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
                 } else {
@@ -772,9 +751,19 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
                 const Uint8 b = cmd->data.draw.b;
                 const Uint8 a = cmd->data.draw.a;
                 const int count = (int) cmd->data.draw.count;
-                const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
                 const SDL_BlendMode blend = cmd->data.draw.blend;
                 SetDrawState(surface, &drawstate);
+
+                /* Apply viewport */
+                if (drawstate.viewport->x || drawstate.viewport->y) {
+                    int i;
+                    for (i = 0; i < count; i++) {
+                        verts[i].x += drawstate.viewport->x;
+                        verts[i].y += drawstate.viewport->y;
+                    }
+                }
+
                 if (blend == SDL_BLENDMODE_NONE) {
                     SDL_DrawLines(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
                 } else {
@@ -789,9 +778,19 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
                 const Uint8 b = cmd->data.draw.b;
                 const Uint8 a = cmd->data.draw.a;
                 const int count = (int) cmd->data.draw.count;
-                const SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first);
                 const SDL_BlendMode blend = cmd->data.draw.blend;
                 SetDrawState(surface, &drawstate);
+
+                /* Apply viewport */
+                if (drawstate.viewport->x || drawstate.viewport->y) {
+                    int i;
+                    for (i = 0; i < count; i++) {
+                        verts[i].x += drawstate.viewport->x;
+                        verts[i].y += drawstate.viewport->y;
+                    }
+                }
+
                 if (blend == SDL_BLENDMODE_NONE) {
                     SDL_FillRects(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
                 } else {
@@ -811,6 +810,12 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
 
                 PrepTextureForCopy(cmd);
 
+                /* Apply viewport */
+                if (drawstate.viewport->x || drawstate.viewport->y) {
+                    dstrect->x += drawstate.viewport->x;
+                    dstrect->y += drawstate.viewport->y;
+                }
+
                 if ( srcrect->w == dstrect->w && srcrect->h == dstrect->h ) {
                     SDL_BlitSurface(src, srcrect, surface, dstrect);
                 } else {
@@ -824,9 +829,16 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
             }
 
             case SDL_RENDERCMD_COPY_EX: {
-                const CopyExData *copydata = (CopyExData *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                CopyExData *copydata = (CopyExData *) (((Uint8 *) vertices) + cmd->data.draw.first);
                 SetDrawState(surface, &drawstate);
                 PrepTextureForCopy(cmd);
+
+                /* Apply viewport */
+                if (drawstate.viewport->x || drawstate.viewport->y) {
+                    copydata->dstrect.x += drawstate.viewport->x;
+                    copydata->dstrect.y += drawstate.viewport->y;
+                }
+
                 SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, &copydata->srcrect,
                                 &copydata->dstrect, copydata->angle, &copydata->center, copydata->flip);
                 break;
@@ -847,6 +859,20 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
                     GeometryCopyData *ptr = (GeometryCopyData *) verts;
 
                     PrepTextureForCopy(cmd);
+
+                    /* Apply viewport */
+                    if (drawstate.viewport->x || drawstate.viewport->y) {
+                        int i;
+                        SDL_Point vp;
+                        vp.x = drawstate.viewport->x;
+                        vp.y = drawstate.viewport->y;
+                        trianglepoint_2_fixedpoint(&vp);
+                        for (i = 0; i < count; i++) {
+                            ptr[i].dst.x += vp.x;
+                            ptr[i].dst.y += vp.y;
+                        }
+                    }
+
                     for (i = 0; i < count; i += 3, ptr += 3) {
                         SDL_SW_BlitTriangle(
                                 src,
@@ -857,6 +883,20 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
                     }
                 } else {
                     GeometryFillData *ptr = (GeometryFillData *) verts;
+
+                    /* Apply viewport */
+                    if (drawstate.viewport->x || drawstate.viewport->y) {
+                        int i;
+                        SDL_Point vp;
+                        vp.x = drawstate.viewport->x;
+                        vp.y = drawstate.viewport->y;
+                        trianglepoint_2_fixedpoint(&vp);
+                        for (i = 0; i < count; i++) {
+                            ptr[i].dst.x += vp.x;
+                            ptr[i].dst.y += vp.y;
+                        }
+                    }
+
                     for (i = 0; i < count; i += 3, ptr += 3) {
                         SDL_SW_FillTriangle(surface, &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), blend, ptr[0].color, ptr[1].color, ptr[2].color);
                     }