software: Correctly track viewport and cliprect.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 11 Jun 2019 14:09:53 -0400
changeset 1283632839175c0e4
parent 12835 706e38de05c9
child 12837 e319b798dc2d
software: Correctly track viewport and cliprect.

Fixes Bugzilla #4457.
src/render/software/SDL_render_sw.c
     1.1 --- a/src/render/software/SDL_render_sw.c	Tue Jun 11 13:02:56 2019 -0400
     1.2 +++ b/src/render/software/SDL_render_sw.c	Tue Jun 11 14:09:53 2019 -0400
     1.3 @@ -39,6 +39,13 @@
     1.4  
     1.5  typedef struct
     1.6  {
     1.7 +    const SDL_Rect *viewport;
     1.8 +    const SDL_Rect *cliprect;
     1.9 +    SDL_bool surface_cliprect_dirty;
    1.10 +} SW_DrawStateCache;
    1.11 +
    1.12 +typedef struct
    1.13 +{
    1.14      SDL_Surface *surface;
    1.15      SDL_Surface *window;
    1.16  } SW_RenderData;
    1.17 @@ -568,18 +575,44 @@
    1.18      SDL_SetSurfaceBlendMode(surface, blend);
    1.19  }
    1.20  
    1.21 +static void
    1.22 +SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate)
    1.23 +{
    1.24 +    if (drawstate->surface_cliprect_dirty) {
    1.25 +        const SDL_Rect *viewport = drawstate->viewport;
    1.26 +        const SDL_Rect *cliprect = drawstate->cliprect;
    1.27 +        SDL_assert(viewport != NULL);  /* the higher level should have forced a SDL_RENDERCMD_SETVIEWPORT */
    1.28 +
    1.29 +        if (cliprect != NULL) {
    1.30 +            SDL_Rect clip_rect;
    1.31 +            clip_rect.x = cliprect->x + viewport->x;
    1.32 +            clip_rect.y = cliprect->y + viewport->y;
    1.33 +            clip_rect.w = cliprect->w;
    1.34 +            clip_rect.h = cliprect->h;
    1.35 +            SDL_IntersectRect(viewport, &clip_rect, &clip_rect);
    1.36 +            SDL_SetClipRect(surface, &clip_rect);
    1.37 +        } else {
    1.38 +            SDL_SetClipRect(surface, drawstate->viewport);
    1.39 +        }
    1.40 +        drawstate->surface_cliprect_dirty = SDL_FALSE;
    1.41 +    }
    1.42 +}
    1.43 +
    1.44  static int
    1.45  SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
    1.46  {
    1.47      SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
    1.48      SDL_Surface *surface = SW_ActivateRenderer(renderer);
    1.49 -    const SDL_Rect *viewport = NULL;
    1.50 -    const SDL_Rect *cliprect = NULL;
    1.51 +    SW_DrawStateCache drawstate;
    1.52  
    1.53      if (!surface) {
    1.54          return -1;
    1.55      }
    1.56  
    1.57 +    drawstate.viewport = NULL;
    1.58 +    drawstate.cliprect = NULL;
    1.59 +    drawstate.surface_cliprect_dirty = SDL_TRUE;
    1.60 +
    1.61      while (cmd) {
    1.62          switch (cmd->command) {
    1.63              case SDL_RENDERCMD_SETDRAWCOLOR: {
    1.64 @@ -587,25 +620,14 @@
    1.65              }
    1.66  
    1.67              case SDL_RENDERCMD_SETVIEWPORT: {
    1.68 -                viewport = &cmd->data.viewport.rect;
    1.69 -                SDL_SetClipRect(data->surface, viewport);
    1.70 +                drawstate.viewport = &cmd->data.viewport.rect;
    1.71 +                drawstate.surface_cliprect_dirty = SDL_TRUE;
    1.72                  break;
    1.73              }
    1.74  
    1.75              case SDL_RENDERCMD_SETCLIPRECT: {
    1.76 -                SDL_assert(viewport != NULL);
    1.77 -                cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL;
    1.78 -                if (cliprect) {
    1.79 -                    SDL_Rect clip_rect;
    1.80 -                    clip_rect.x = cliprect->x + viewport->x;
    1.81 -                    clip_rect.y = cliprect->y + viewport->y;
    1.82 -                    clip_rect.w = cliprect->w;
    1.83 -                    clip_rect.h = cliprect->h;
    1.84 -                    SDL_IntersectRect(viewport, &clip_rect, &clip_rect);
    1.85 -                    SDL_SetClipRect(surface, &clip_rect);
    1.86 -                } else {
    1.87 -                    SDL_SetClipRect(surface, viewport);
    1.88 -                }
    1.89 +                drawstate.cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL;                
    1.90 +                drawstate.surface_cliprect_dirty = SDL_TRUE;
    1.91                  break;
    1.92              }
    1.93  
    1.94 @@ -614,11 +636,10 @@
    1.95                  const Uint8 g = cmd->data.color.g;
    1.96                  const Uint8 b = cmd->data.color.b;
    1.97                  const Uint8 a = cmd->data.color.a;
    1.98 -                const SDL_Rect clip_rect = surface->clip_rect;
    1.99                  /* By definition the clear ignores the clip rect */
   1.100                  SDL_SetClipRect(surface, NULL);
   1.101                  SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, r, g, b, a));
   1.102 -                SDL_SetClipRect(surface, &clip_rect);
   1.103 +                drawstate.surface_cliprect_dirty = SDL_TRUE;
   1.104                  break;
   1.105              }
   1.106  
   1.107 @@ -630,6 +651,7 @@
   1.108                  const int count = (int) cmd->data.draw.count;
   1.109                  const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
   1.110                  const SDL_BlendMode blend = cmd->data.draw.blend;
   1.111 +                SetDrawState(surface, &drawstate);
   1.112                  if (blend == SDL_BLENDMODE_NONE) {
   1.113                      SDL_DrawPoints(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
   1.114                  } else {
   1.115 @@ -646,6 +668,7 @@
   1.116                  const int count = (int) cmd->data.draw.count;
   1.117                  const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
   1.118                  const SDL_BlendMode blend = cmd->data.draw.blend;
   1.119 +                SetDrawState(surface, &drawstate);
   1.120                  if (blend == SDL_BLENDMODE_NONE) {
   1.121                      SDL_DrawLines(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
   1.122                  } else {
   1.123 @@ -662,6 +685,7 @@
   1.124                  const int count = (int) cmd->data.draw.count;
   1.125                  const SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first);
   1.126                  const SDL_BlendMode blend = cmd->data.draw.blend;
   1.127 +                SetDrawState(surface, &drawstate);
   1.128                  if (blend == SDL_BLENDMODE_NONE) {
   1.129                      SDL_FillRects(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
   1.130                  } else {
   1.131 @@ -677,6 +701,8 @@
   1.132                  SDL_Texture *texture = cmd->data.draw.texture;
   1.133                  SDL_Surface *src = (SDL_Surface *) texture->driverdata;
   1.134  
   1.135 +                SetDrawState(surface, &drawstate);
   1.136 +
   1.137                  PrepTextureForCopy(cmd);
   1.138  
   1.139                  if ( srcrect->w == dstrect->w && srcrect->h == dstrect->h ) {
   1.140 @@ -693,6 +719,7 @@
   1.141  
   1.142              case SDL_RENDERCMD_COPY_EX: {
   1.143                  const CopyExData *copydata = (CopyExData *) (((Uint8 *) vertices) + cmd->data.draw.first);
   1.144 +                SetDrawState(surface, &drawstate);
   1.145                  PrepTextureForCopy(cmd);
   1.146                  SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, &copydata->srcrect,
   1.147                                  &copydata->dstrect, copydata->angle, &copydata->center, copydata->flip);