software: Correctly track viewport and cliprect. Fixes Bugzilla #4457.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index 8c48201..5fe89e7 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -39,6 +39,13 @@
typedef struct
{
+ const SDL_Rect *viewport;
+ const SDL_Rect *cliprect;
+ SDL_bool surface_cliprect_dirty;
+} SW_DrawStateCache;
+
+typedef struct
+{
SDL_Surface *surface;
SDL_Surface *window;
} SW_RenderData;
@@ -568,18 +575,44 @@ PrepTextureForCopy(const SDL_RenderCommand *cmd)
SDL_SetSurfaceBlendMode(surface, blend);
}
+static void
+SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate)
+{
+ if (drawstate->surface_cliprect_dirty) {
+ const SDL_Rect *viewport = drawstate->viewport;
+ const SDL_Rect *cliprect = drawstate->cliprect;
+ SDL_assert(viewport != NULL); /* the higher level should have forced a SDL_RENDERCMD_SETVIEWPORT */
+
+ if (cliprect != NULL) {
+ SDL_Rect clip_rect;
+ clip_rect.x = cliprect->x + viewport->x;
+ clip_rect.y = cliprect->y + viewport->y;
+ clip_rect.w = cliprect->w;
+ clip_rect.h = cliprect->h;
+ SDL_IntersectRect(viewport, &clip_rect, &clip_rect);
+ SDL_SetClipRect(surface, &clip_rect);
+ } else {
+ SDL_SetClipRect(surface, drawstate->viewport);
+ }
+ drawstate->surface_cliprect_dirty = SDL_FALSE;
+ }
+}
+
static int
SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{
SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
SDL_Surface *surface = SW_ActivateRenderer(renderer);
- const SDL_Rect *viewport = NULL;
- const SDL_Rect *cliprect = NULL;
+ SW_DrawStateCache drawstate;
if (!surface) {
return -1;
}
+ drawstate.viewport = NULL;
+ drawstate.cliprect = NULL;
+ drawstate.surface_cliprect_dirty = SDL_TRUE;
+
while (cmd) {
switch (cmd->command) {
case SDL_RENDERCMD_SETDRAWCOLOR: {
@@ -587,25 +620,14 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
}
case SDL_RENDERCMD_SETVIEWPORT: {
- viewport = &cmd->data.viewport.rect;
- SDL_SetClipRect(data->surface, viewport);
+ drawstate.viewport = &cmd->data.viewport.rect;
+ drawstate.surface_cliprect_dirty = SDL_TRUE;
break;
}
case SDL_RENDERCMD_SETCLIPRECT: {
- SDL_assert(viewport != NULL);
- cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL;
- if (cliprect) {
- SDL_Rect clip_rect;
- clip_rect.x = cliprect->x + viewport->x;
- clip_rect.y = cliprect->y + viewport->y;
- clip_rect.w = cliprect->w;
- clip_rect.h = cliprect->h;
- SDL_IntersectRect(viewport, &clip_rect, &clip_rect);
- SDL_SetClipRect(surface, &clip_rect);
- } else {
- SDL_SetClipRect(surface, viewport);
- }
+ drawstate.cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL;
+ drawstate.surface_cliprect_dirty = SDL_TRUE;
break;
}
@@ -614,11 +636,10 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
const Uint8 g = cmd->data.color.g;
const Uint8 b = cmd->data.color.b;
const Uint8 a = cmd->data.color.a;
- const SDL_Rect clip_rect = surface->clip_rect;
/* By definition the clear ignores the clip rect */
SDL_SetClipRect(surface, NULL);
SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, r, g, b, a));
- SDL_SetClipRect(surface, &clip_rect);
+ drawstate.surface_cliprect_dirty = SDL_TRUE;
break;
}
@@ -630,6 +651,7 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
const int count = (int) cmd->data.draw.count;
const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
const SDL_BlendMode blend = cmd->data.draw.blend;
+ SetDrawState(surface, &drawstate);
if (blend == SDL_BLENDMODE_NONE) {
SDL_DrawPoints(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
} else {
@@ -646,6 +668,7 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
const int count = (int) cmd->data.draw.count;
const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
const SDL_BlendMode blend = cmd->data.draw.blend;
+ SetDrawState(surface, &drawstate);
if (blend == SDL_BLENDMODE_NONE) {
SDL_DrawLines(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
} else {
@@ -662,6 +685,7 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
const int count = (int) cmd->data.draw.count;
const SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first);
const SDL_BlendMode blend = cmd->data.draw.blend;
+ SetDrawState(surface, &drawstate);
if (blend == SDL_BLENDMODE_NONE) {
SDL_FillRects(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
} else {
@@ -677,6 +701,8 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
SDL_Texture *texture = cmd->data.draw.texture;
SDL_Surface *src = (SDL_Surface *) texture->driverdata;
+ SetDrawState(surface, &drawstate);
+
PrepTextureForCopy(cmd);
if ( srcrect->w == dstrect->w && srcrect->h == dstrect->h ) {
@@ -693,6 +719,7 @@ 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);
+ SetDrawState(surface, &drawstate);
PrepTextureForCopy(cmd);
SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, ©data->srcrect,
©data->dstrect, copydata->angle, ©data->center, copydata->flip);