gles2: Make render command queue dynamic. SDL-ryan-batching-renderer
authorRyan C. Gordon <icculus@icculus.org>
Sun, 09 Sep 2018 15:09:38 -0400
branchSDL-ryan-batching-renderer
changeset 12209042096b6e332
parent 12208 abf1ced78a16
child 12210 9f9dbcce30b3
gles2: Make render command queue dynamic.

It now uses a growable linked list that keeps a pool of allocated items for
reuse, and reallocs the vertex array as necessary. Testsprite2 can scale to
20,000 (or more!) draws now without drama.
src/render/opengles2/SDL_render_gles2.c
     1.1 --- a/src/render/opengles2/SDL_render_gles2.c	Sat Sep 08 18:26:11 2018 -0400
     1.2 +++ b/src/render/opengles2/SDL_render_gles2.c	Sun Sep 09 15:09:38 2018 -0400
     1.3 @@ -196,6 +196,7 @@
     1.4              SDL_Texture *texture;
     1.5          } draw;
     1.6      } data;
     1.7 +    struct GLES2_RenderCommand *next;
     1.8  } GLES2_RenderCommand;
     1.9  
    1.10  typedef struct GLES2_DriverContext
    1.11 @@ -220,17 +221,49 @@
    1.12      GLuint vertex_buffers[4];
    1.13      GLsizeiptr vertex_buffer_size[4];
    1.14      int current_vertex_buffer;
    1.15 -    GLES2_RenderCommand render_commands[1024 * 10];
    1.16 -    int current_render_command;
    1.17 +    GLES2_RenderCommand *render_commands;
    1.18 +    GLES2_RenderCommand *render_commands_tail;
    1.19 +    GLES2_RenderCommand *render_commands_pool;
    1.20      int current_vertex_data;
    1.21      Uint32 command_generation;
    1.22 -    GLfloat vertex_data[1024 * 1024 * 5];
    1.23 +    GLfloat *vertex_data;
    1.24 +    GLsizeiptr vertex_data_allocation;
    1.25  } GLES2_DriverContext;
    1.26  
    1.27  #define GLES2_MAX_CACHED_PROGRAMS 8
    1.28  
    1.29  static const float inv255f = 1.0f / 255.0f;
    1.30  
    1.31 +static GLES2_RenderCommand *
    1.32 +GLES2_AllocateRenderCommand(SDL_Renderer *renderer)
    1.33 +{
    1.34 +    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
    1.35 +    GLES2_RenderCommand *retval = NULL;
    1.36 +
    1.37 +    /* !!! FIXME: are there threading limitations in SDL's render API? */
    1.38 +    retval = data->render_commands_pool;
    1.39 +    if (retval != NULL) {
    1.40 +        data->render_commands_pool = retval->next;
    1.41 +        retval->next = NULL;
    1.42 +    } else {
    1.43 +        retval = SDL_calloc(1, sizeof (*retval));
    1.44 +        if (!retval) {
    1.45 +            SDL_OutOfMemory();
    1.46 +            return NULL;
    1.47 +        }
    1.48 +    }
    1.49 +
    1.50 +    SDL_assert((data->render_commands == NULL) == (data->render_commands_tail == NULL));
    1.51 +    if (data->render_commands_tail != NULL) {
    1.52 +        data->render_commands_tail->next = retval;
    1.53 +    } else {
    1.54 +        data->render_commands = retval;
    1.55 +    }
    1.56 +    data->render_commands_tail = retval;
    1.57 +
    1.58 +    return retval;
    1.59 +}
    1.60 +
    1.61  static SDL_bool
    1.62  CompareColors(const Uint8 r1, const Uint8 g1, const Uint8 b1, const Uint8 a1,
    1.63                const Uint8 r2, const Uint8 g2, const Uint8 b2, const Uint8 a2)
    1.64 @@ -481,8 +514,9 @@
    1.65      const int vboidx = data->current_vertex_buffer;
    1.66      const GLuint vbo = data->vertex_buffers[vboidx];
    1.67      const GLsizeiptr dataSizeInBytes = data->current_vertex_data * sizeof (float);
    1.68 -    const int totalcmds = data->current_render_command;
    1.69      Uint8 enabled_attrs = (1 << GLES2_ATTRIBUTE_POSITION);
    1.70 +    GLES2_RenderCommand *cmd;
    1.71 +    GLES2_RenderCommand *next;
    1.72      SDL_Rect viewport;
    1.73      SDL_Texture *bound_texture = NULL;
    1.74      SDL_BlendMode blend = SDL_BLENDMODE_INVALID;
    1.75 @@ -491,11 +525,10 @@
    1.76      GLfloat projection[4][4];
    1.77      SDL_bool cliprect_enabled = SDL_FALSE;
    1.78      SDL_Rect cliprect;
    1.79 -    int i;
    1.80  
    1.81      GLES2_ActivateRenderer(renderer);
    1.82  
    1.83 -    if (totalcmds == 0) {  /* nothing to do! */
    1.84 +    if (data->render_commands == NULL) {  /* nothing to do! */
    1.85          SDL_assert(data->current_vertex_data == 0);
    1.86          return 0;
    1.87      }
    1.88 @@ -506,7 +539,9 @@
    1.89          data->current_vertex_buffer = 0;
    1.90      }
    1.91      data->current_vertex_data = 0;  /* start next VBO at start. */
    1.92 -    data->current_render_command = 0;
    1.93 +    cmd = data->render_commands;
    1.94 +    data->render_commands = NULL;
    1.95 +    data->render_commands_tail = NULL;
    1.96  
    1.97      SDL_zero(projection);
    1.98      projection[3][0] = -1.0f;
    1.99 @@ -555,8 +590,7 @@
   1.100          data->glScissor(viewport.x + cliprect.x, drawableh - viewport.y - cliprect.y - cliprect.h, cliprect.w, cliprect.h);
   1.101      }
   1.102  
   1.103 -    for (i = 0; i < totalcmds; i++) {
   1.104 -        const GLES2_RenderCommand *cmd = &data->render_commands[i];
   1.105 +    while (cmd != NULL) {
   1.106          switch (cmd->cmd) {
   1.107              case GLES2_RENDERCMD_VIEWPORT:
   1.108                  if (SDL_memcmp(&cmd->data.viewport, &viewport, sizeof (SDL_Rect)) != 0) {
   1.109 @@ -713,6 +747,12 @@
   1.110  
   1.111              default: SDL_assert(!"Unknown rendering command"); break;
   1.112          }
   1.113 +
   1.114 +        /* put this command in the pool for reuse, move on to next one. */
   1.115 +        next = cmd->next;
   1.116 +        cmd->next = data->render_commands_pool;
   1.117 +        data->render_commands_pool = cmd;
   1.118 +        cmd = next;
   1.119      }
   1.120  
   1.121      data->command_generation++;
   1.122 @@ -734,8 +774,10 @@
   1.123  static int
   1.124  GLES2_UpdateViewport(SDL_Renderer * renderer)
   1.125  {
   1.126 -    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.127 -    GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++];
   1.128 +    GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
   1.129 +    if (cmd == NULL) {
   1.130 +        return -1;
   1.131 +    }
   1.132      cmd->cmd = GLES2_RENDERCMD_VIEWPORT;
   1.133      SDL_memcpy(&cmd->data.viewport, &renderer->viewport, sizeof (SDL_Rect));
   1.134      return 0;
   1.135 @@ -744,8 +786,10 @@
   1.136  static int
   1.137  GLES2_UpdateClipRect(SDL_Renderer * renderer)
   1.138  {
   1.139 -    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.140 -    GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++];
   1.141 +    GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
   1.142 +    if (cmd == NULL) {
   1.143 +        return -1;
   1.144 +    }
   1.145      cmd->cmd = GLES2_RENDERCMD_CLIPRECT;
   1.146      cmd->data.cliprect.enabled = renderer->clipping_enabled;
   1.147      SDL_memcpy(&cmd->data.cliprect.rect, &renderer->clip_rect, sizeof (SDL_Rect));
   1.148 @@ -759,8 +803,25 @@
   1.149  
   1.150      /* Deallocate everything */
   1.151      if (data) {
   1.152 +        GLES2_RenderCommand *cmd;
   1.153 +
   1.154          GLES2_ActivateRenderer(renderer);
   1.155  
   1.156 +        if (data->render_commands_tail != NULL) {
   1.157 +            data->render_commands_tail->next = data->render_commands_pool;
   1.158 +        } else {
   1.159 +            data->render_commands = data->render_commands_pool;
   1.160 +        }
   1.161 +
   1.162 +        cmd = data->render_commands;
   1.163 +        while (cmd != NULL) {
   1.164 +            GLES2_RenderCommand *next = cmd->next;
   1.165 +            SDL_free(cmd);
   1.166 +            cmd = next;
   1.167 +        }
   1.168 +
   1.169 +        SDL_free(data->vertex_data);
   1.170 +
   1.171          {
   1.172              GLES2_ShaderCacheEntry *entry;
   1.173              GLES2_ShaderCacheEntry *next;
   1.174 @@ -1625,8 +1686,10 @@
   1.175  static int
   1.176  GLES2_RenderClear(SDL_Renderer * renderer)
   1.177  {
   1.178 -    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.179 -    GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++];
   1.180 +    GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
   1.181 +    if (cmd == NULL) {
   1.182 +        return -1;
   1.183 +    }
   1.184      cmd->cmd = GLES2_RENDERCMD_CLEAR;
   1.185      cmd->data.clear.r = renderer->r;
   1.186      cmd->data.clear.g = renderer->g;
   1.187 @@ -1635,25 +1698,48 @@
   1.188      return 0;
   1.189  }
   1.190  
   1.191 -static void
   1.192 +static int
   1.193  GLES2_AddVertices(SDL_Renderer *renderer, const GLES2_Attribute attr, const float *vertexData, size_t dataSizeInElements)
   1.194  {
   1.195      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.196 -    GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++];
   1.197 -    GLfloat *vdata = &data->vertex_data[data->current_vertex_data];
   1.198 +    const GLsizeiptr needed = data->current_vertex_data + dataSizeInElements;
   1.199 +    GLES2_RenderCommand *cmd;
   1.200 +    GLfloat *vdata;
   1.201 +
   1.202 +    if (needed > data->vertex_data_allocation) {
   1.203 +        const GLsizeiptr newsize = data->vertex_data_allocation * 2;
   1.204 +printf("realloc'ing %p to %d\n", data->vertex_data, (int) newsize);
   1.205 +        void *ptr = SDL_realloc(data->vertex_data, newsize * sizeof (GLfloat));
   1.206 +        if (ptr == NULL) {
   1.207 +            SDL_OutOfMemory();
   1.208 +            return -1;
   1.209 +        }
   1.210 +        data->vertex_data = (GLfloat *) ptr;
   1.211 +        data->vertex_data_allocation = newsize;
   1.212 +    }
   1.213 +
   1.214 +    cmd = GLES2_AllocateRenderCommand(renderer);
   1.215 +    if (cmd == NULL) {
   1.216 +        return -1;
   1.217 +    }
   1.218 +
   1.219 +    vdata = &data->vertex_data[data->current_vertex_data];
   1.220      SDL_memcpy(vdata, vertexData, dataSizeInElements * sizeof (GLfloat));
   1.221      cmd->cmd = GLES2_RENDERCMD_ATTR;
   1.222      cmd->data.attr.attr = attr;
   1.223      cmd->data.attr.offset = data->current_vertex_data * sizeof (GLfloat);
   1.224      cmd->data.attr.count = dataSizeInElements;
   1.225      data->current_vertex_data += dataSizeInElements;
   1.226 +    return 0;
   1.227  }
   1.228  
   1.229 -static GLES2_RenderCommand *
   1.230 -GLES2_InitSolidDrawCommand(SDL_Renderer *renderer, const GLenum mode, const GLint first, const GLsizei count)
   1.231 +static int
   1.232 +GLES2_AddSolidDrawCommand(SDL_Renderer *renderer, const GLenum mode, const GLint first, const GLsizei count)
   1.233  {
   1.234 -    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.235 -    GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++];
   1.236 +    GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
   1.237 +    if (cmd == NULL) {
   1.238 +        return -1;
   1.239 +    }
   1.240      cmd->cmd = GLES2_RENDERCMD_DRAW;
   1.241      cmd->data.draw.mode = mode;
   1.242      cmd->data.draw.first = first;
   1.243 @@ -1666,7 +1752,7 @@
   1.244      cmd->data.draw.blend = renderer->blendMode;
   1.245      cmd->data.draw.imgsrc = GLES2_IMAGESOURCE_SOLID;
   1.246      cmd->data.draw.texture = NULL;
   1.247 -    return cmd;
   1.248 +    return 0;
   1.249  }
   1.250  
   1.251  static int
   1.252 @@ -1674,6 +1760,7 @@
   1.253  {
   1.254      GLfloat *vertices = SDL_stack_alloc(GLfloat, count * 2);  /* !!! FIXME: We could do this without a stack_alloc... */
   1.255      int idx;
   1.256 +    int rc;
   1.257  
   1.258      /* Emit the specified vertices as points */
   1.259      for (idx = 0; idx < count; ++idx) {
   1.260 @@ -1681,10 +1768,14 @@
   1.261          vertices[(idx * 2) + 1] = points[idx].y + 0.5f;
   1.262      }
   1.263  
   1.264 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2);
   1.265 -    GLES2_InitSolidDrawCommand(renderer, GL_POINTS, 0, count);
   1.266 +    rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2);
   1.267      SDL_stack_free(vertices);
   1.268 -    return 0;
   1.269 +
   1.270 +    if (rc == 0) {
   1.271 +        rc = GLES2_AddSolidDrawCommand(renderer, GL_POINTS, 0, count);
   1.272 +    }
   1.273 +
   1.274 +    return rc;
   1.275  }
   1.276  
   1.277  static int
   1.278 @@ -1692,6 +1783,7 @@
   1.279  {
   1.280      GLfloat *vertices = SDL_stack_alloc(GLfloat, count * 2);  /* !!! FIXME: We could do this without a stack_alloc... */
   1.281      int idx;
   1.282 +    int rc;
   1.283  
   1.284      /* Emit a line strip including the specified vertices */
   1.285      for (idx = 0; idx < count; ++idx) {
   1.286 @@ -1699,8 +1791,10 @@
   1.287          vertices[(idx * 2) + 1] = points[idx].y + 0.5f;
   1.288      }
   1.289  
   1.290 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2);
   1.291 -    GLES2_InitSolidDrawCommand(renderer, GL_LINE_STRIP, 0, count);
   1.292 +    rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2);
   1.293 +    if (rc == 0) {
   1.294 +        rc = GLES2_AddSolidDrawCommand(renderer, GL_LINE_STRIP, 0, count);
   1.295 +    }
   1.296  
   1.297  #if 0  /* !!! FIXME: ugh */
   1.298      /* We need to close the endpoint of the line */
   1.299 @@ -1711,7 +1805,7 @@
   1.300  #endif
   1.301  
   1.302      SDL_stack_free(vertices);
   1.303 -    return 0;
   1.304 +    return rc;
   1.305  }
   1.306  
   1.307  static int
   1.308 @@ -1719,9 +1813,10 @@
   1.309  {
   1.310      GLfloat vertices[8];
   1.311      int idx;
   1.312 +    int rc = 0;
   1.313  
   1.314      /* Emit a line loop for each rectangle */
   1.315 -    for (idx = 0; idx < count; ++idx) {
   1.316 +    for (idx = 0; (rc == 0) && (idx < count); ++idx) {
   1.317          const SDL_FRect *rect = &rects[idx];
   1.318  
   1.319          GLfloat xMin = rect->x;
   1.320 @@ -1738,16 +1833,18 @@
   1.321          vertices[6] = xMax;
   1.322          vertices[7] = yMax;
   1.323  
   1.324 -        GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
   1.325 -        GLES2_InitSolidDrawCommand(renderer, GL_TRIANGLE_STRIP, 0, 4);
   1.326 +        rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
   1.327 +        if (rc == 0) {
   1.328 +            rc = GLES2_AddSolidDrawCommand(renderer, GL_TRIANGLE_STRIP, 0, 4);
   1.329 +        }
   1.330      }
   1.331  
   1.332      return 0;
   1.333  }
   1.334  
   1.335  
   1.336 -static GLES2_RenderCommand *
   1.337 -GLES2_InitCopyDrawCommand(SDL_Renderer *renderer, SDL_Texture *texture, const Uint8 attrs)
   1.338 +static int
   1.339 +GLES2_AddCopyDrawCommand(SDL_Renderer *renderer, SDL_Texture *texture, const Uint8 attrs)
   1.340  {
   1.341      GLES2_RenderCommand *cmd = NULL;
   1.342      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.343 @@ -1820,8 +1917,7 @@
   1.344                  sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
   1.345                  break;
   1.346              default:
   1.347 -                SDL_SetError("Unsupported texture format");
   1.348 -                return NULL;
   1.349 +                return SDL_SetError("Unsupported texture format");
   1.350              }
   1.351          } else {
   1.352              sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;   /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
   1.353 @@ -1854,14 +1950,16 @@
   1.354                  sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
   1.355                  break;
   1.356              default:
   1.357 -                SDL_SetError("Unsupported texture format");
   1.358 -                return NULL;
   1.359 +                return SDL_SetError("Unsupported texture format");
   1.360          }
   1.361      }
   1.362  
   1.363      ((GLES2_TextureData *)texture->driverdata)->last_cmd_generation = data->command_generation;
   1.364  
   1.365 -    cmd = &data->render_commands[data->current_render_command++];
   1.366 +    cmd = GLES2_AllocateRenderCommand(renderer);
   1.367 +    if (cmd == NULL) {
   1.368 +        return -1;
   1.369 +    }
   1.370      cmd->cmd = GLES2_RENDERCMD_DRAW;
   1.371      cmd->data.draw.mode = GL_TRIANGLE_STRIP;
   1.372      cmd->data.draw.first = 0;
   1.373 @@ -1875,7 +1973,7 @@
   1.374      cmd->data.draw.imgsrc = sourceType;
   1.375      cmd->data.draw.texture = texture;
   1.376  
   1.377 -    return cmd;
   1.378 +    return 0;
   1.379  }
   1.380  
   1.381  static int
   1.382 @@ -1883,6 +1981,7 @@
   1.383                   const SDL_FRect *dstrect)
   1.384  {
   1.385      GLfloat vertices[8];
   1.386 +    int rc;
   1.387  
   1.388      /* Emit the textured quad */
   1.389      vertices[0] = dstrect->x;
   1.390 @@ -1893,20 +1992,25 @@
   1.391      vertices[5] = (dstrect->y + dstrect->h);
   1.392      vertices[6] = (dstrect->x + dstrect->w);
   1.393      vertices[7] = (dstrect->y + dstrect->h);
   1.394 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
   1.395 +    rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
   1.396  
   1.397 -    vertices[0] = srcrect->x / (GLfloat)texture->w;
   1.398 -    vertices[1] = srcrect->y / (GLfloat)texture->h;
   1.399 -    vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.400 -    vertices[3] = srcrect->y / (GLfloat)texture->h;
   1.401 -    vertices[4] = srcrect->x / (GLfloat)texture->w;
   1.402 -    vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.403 -    vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.404 -    vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.405 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8);
   1.406 +    if (rc == 0) {
   1.407 +        vertices[0] = srcrect->x / (GLfloat)texture->w;
   1.408 +        vertices[1] = srcrect->y / (GLfloat)texture->h;
   1.409 +        vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.410 +        vertices[3] = srcrect->y / (GLfloat)texture->h;
   1.411 +        vertices[4] = srcrect->x / (GLfloat)texture->w;
   1.412 +        vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.413 +        vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.414 +        vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.415 +        rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8);
   1.416  
   1.417 -    GLES2_InitCopyDrawCommand(renderer, texture, 0);
   1.418 -    return 0;
   1.419 +        if (rc == 0) {
   1.420 +            rc = GLES2_AddCopyDrawCommand(renderer, texture, 0);
   1.421 +        }
   1.422 +    }
   1.423 +
   1.424 +    return rc;
   1.425  }
   1.426  
   1.427  static int
   1.428 @@ -1915,50 +2019,60 @@
   1.429  {
   1.430      const float radian_angle = (float)(M_PI * (360.0 - angle) / 180.0);
   1.431      GLfloat vertices[8];
   1.432 +    int rc;
   1.433  
   1.434      vertices[0] = vertices[2] = vertices[4] = vertices[6] = (GLfloat)SDL_sin(radian_angle);
   1.435      /* render expects cos value - 1 (see GLES2_VertexSrc_Default_) */
   1.436      vertices[1] = vertices[3] = vertices[5] = vertices[7] = (GLfloat)SDL_cos(radian_angle) - 1.0f;
   1.437 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_ANGLE, vertices, 8);
   1.438 +    rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_ANGLE, vertices, 8);
   1.439  
   1.440      /* Calculate the center of rotation */
   1.441 -    vertices[0] = vertices[2] = vertices[4] = vertices[6] = (center->x + dstrect->x);
   1.442 -    vertices[1] = vertices[3] = vertices[5] = vertices[7] = (center->y + dstrect->y);
   1.443 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_CENTER, vertices, 8);
   1.444 +    if (rc == 0) {
   1.445 +        vertices[0] = vertices[2] = vertices[4] = vertices[6] = (center->x + dstrect->x);
   1.446 +        vertices[1] = vertices[3] = vertices[5] = vertices[7] = (center->y + dstrect->y);
   1.447 +        rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_CENTER, vertices, 8);
   1.448 +    
   1.449 +        if (rc == 0) {
   1.450 +            /* Emit the textured quad */
   1.451 +            vertices[0] = dstrect->x;
   1.452 +            vertices[1] = dstrect->y;
   1.453 +            vertices[2] = (dstrect->x + dstrect->w);
   1.454 +            vertices[3] = dstrect->y;
   1.455 +            vertices[4] = dstrect->x;
   1.456 +            vertices[5] = (dstrect->y + dstrect->h);
   1.457 +            vertices[6] = (dstrect->x + dstrect->w);
   1.458 +            vertices[7] = (dstrect->y + dstrect->h);
   1.459 +            if (flip & SDL_FLIP_HORIZONTAL) {
   1.460 +                const GLfloat tmp = vertices[0];
   1.461 +                vertices[0] = vertices[4] = vertices[2];
   1.462 +                vertices[2] = vertices[6] = tmp;
   1.463 +            }
   1.464 +            if (flip & SDL_FLIP_VERTICAL) {
   1.465 +                const GLfloat tmp = vertices[1];
   1.466 +                vertices[1] = vertices[3] = vertices[5];
   1.467 +                vertices[5] = vertices[7] = tmp;
   1.468 +            }
   1.469 +            rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
   1.470  
   1.471 -    /* Emit the textured quad */
   1.472 -    vertices[0] = dstrect->x;
   1.473 -    vertices[1] = dstrect->y;
   1.474 -    vertices[2] = (dstrect->x + dstrect->w);
   1.475 -    vertices[3] = dstrect->y;
   1.476 -    vertices[4] = dstrect->x;
   1.477 -    vertices[5] = (dstrect->y + dstrect->h);
   1.478 -    vertices[6] = (dstrect->x + dstrect->w);
   1.479 -    vertices[7] = (dstrect->y + dstrect->h);
   1.480 -    if (flip & SDL_FLIP_HORIZONTAL) {
   1.481 -        const GLfloat tmp = vertices[0];
   1.482 -        vertices[0] = vertices[4] = vertices[2];
   1.483 -        vertices[2] = vertices[6] = tmp;
   1.484 +            if (rc == 0) {
   1.485 +                vertices[0] = srcrect->x / (GLfloat)texture->w;
   1.486 +                vertices[1] = srcrect->y / (GLfloat)texture->h;
   1.487 +                vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.488 +                vertices[3] = srcrect->y / (GLfloat)texture->h;
   1.489 +                vertices[4] = srcrect->x / (GLfloat)texture->w;
   1.490 +                vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.491 +                vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.492 +                vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.493 +                rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8);
   1.494 +
   1.495 +                if (rc == 0) {
   1.496 +                    GLES2_AddCopyDrawCommand(renderer, texture, (1 << GLES2_ATTRIBUTE_CENTER) | (1 << GLES2_ATTRIBUTE_ANGLE));
   1.497 +                }
   1.498 +            }
   1.499 +        }
   1.500      }
   1.501 -    if (flip & SDL_FLIP_VERTICAL) {
   1.502 -        const GLfloat tmp = vertices[1];
   1.503 -        vertices[1] = vertices[3] = vertices[5];
   1.504 -        vertices[5] = vertices[7] = tmp;
   1.505 -    }
   1.506 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
   1.507  
   1.508 -    vertices[0] = srcrect->x / (GLfloat)texture->w;
   1.509 -    vertices[1] = srcrect->y / (GLfloat)texture->h;
   1.510 -    vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.511 -    vertices[3] = srcrect->y / (GLfloat)texture->h;
   1.512 -    vertices[4] = srcrect->x / (GLfloat)texture->w;
   1.513 -    vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.514 -    vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   1.515 -    vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
   1.516 -    GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8);
   1.517 -
   1.518 -    GLES2_InitCopyDrawCommand(renderer, texture, (1 << GLES2_ATTRIBUTE_CENTER) | (1 << GLES2_ATTRIBUTE_ANGLE));
   1.519 -    return 0;
   1.520 +    return rc;
   1.521  }
   1.522  
   1.523  static int
   1.524 @@ -2158,6 +2272,15 @@
   1.525      renderer->driverdata = data;
   1.526      renderer->window = window;
   1.527  
   1.528 +    data->vertex_data_allocation = 512;
   1.529 +    data->vertex_data = (GLfloat *) SDL_malloc(data->vertex_data_allocation * sizeof (GLfloat));
   1.530 +    if (data->vertex_data == NULL) {
   1.531 +        GLES2_DestroyRenderer(renderer);
   1.532 +        SDL_OutOfMemory();
   1.533 +        goto error;
   1.534 +    }
   1.535 +printf("malloc'd %p\n", data->vertex_data);
   1.536 +
   1.537      /* Create an OpenGL ES 2.0 context */
   1.538      data->context = SDL_GL_CreateContext(window);
   1.539      if (!data->context) {