From 04fedce0e8f3a7ee8cb00d16d40518a18975516f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 11 Jun 2019 14:09:53 -0400 Subject: [PATCH] software: Correctly track viewport and cliprect. Fixes Bugzilla #4457. --- src/render/software/SDL_render_sw.c | 65 ++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c index 8c4820128a204..5fe89e7c9e28f 100644 --- a/src/render/software/SDL_render_sw.c +++ b/src/render/software/SDL_render_sw.c @@ -37,6 +37,13 @@ /* SDL surface based renderer implementation */ +typedef struct +{ + const SDL_Rect *viewport; + const SDL_Rect *cliprect; + SDL_bool surface_cliprect_dirty; +} SW_DrawStateCache; + typedef struct { SDL_Surface *surface; @@ -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);