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.
This commit is contained in:
Ryan C. Gordon 2018-09-09 15:09:38 -04:00
parent 0d3275297d
commit a2f7af9a47

View file

@ -196,6 +196,7 @@ typedef struct GLES2_RenderCommand
SDL_Texture *texture; SDL_Texture *texture;
} draw; } draw;
} data; } data;
struct GLES2_RenderCommand *next;
} GLES2_RenderCommand; } GLES2_RenderCommand;
typedef struct GLES2_DriverContext typedef struct GLES2_DriverContext
@ -220,17 +221,49 @@ typedef struct GLES2_DriverContext
GLuint vertex_buffers[4]; GLuint vertex_buffers[4];
GLsizeiptr vertex_buffer_size[4]; GLsizeiptr vertex_buffer_size[4];
int current_vertex_buffer; int current_vertex_buffer;
GLES2_RenderCommand render_commands[1024 * 10]; GLES2_RenderCommand *render_commands;
int current_render_command; GLES2_RenderCommand *render_commands_tail;
GLES2_RenderCommand *render_commands_pool;
int current_vertex_data; int current_vertex_data;
Uint32 command_generation; Uint32 command_generation;
GLfloat vertex_data[1024 * 1024 * 5]; GLfloat *vertex_data;
GLsizeiptr vertex_data_allocation;
} GLES2_DriverContext; } GLES2_DriverContext;
#define GLES2_MAX_CACHED_PROGRAMS 8 #define GLES2_MAX_CACHED_PROGRAMS 8
static const float inv255f = 1.0f / 255.0f; static const float inv255f = 1.0f / 255.0f;
static GLES2_RenderCommand *
GLES2_AllocateRenderCommand(SDL_Renderer *renderer)
{
GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
GLES2_RenderCommand *retval = NULL;
/* !!! FIXME: are there threading limitations in SDL's render API? */
retval = data->render_commands_pool;
if (retval != NULL) {
data->render_commands_pool = retval->next;
retval->next = NULL;
} else {
retval = SDL_calloc(1, sizeof (*retval));
if (!retval) {
SDL_OutOfMemory();
return NULL;
}
}
SDL_assert((data->render_commands == NULL) == (data->render_commands_tail == NULL));
if (data->render_commands_tail != NULL) {
data->render_commands_tail->next = retval;
} else {
data->render_commands = retval;
}
data->render_commands_tail = retval;
return retval;
}
static SDL_bool static SDL_bool
CompareColors(const Uint8 r1, const Uint8 g1, const Uint8 b1, const Uint8 a1, CompareColors(const Uint8 r1, const Uint8 g1, const Uint8 b1, const Uint8 a1,
const Uint8 r2, const Uint8 g2, const Uint8 b2, const Uint8 a2) const Uint8 r2, const Uint8 g2, const Uint8 b2, const Uint8 a2)
@ -481,8 +514,9 @@ GLES2_FlushCommands(SDL_Renderer *renderer)
const int vboidx = data->current_vertex_buffer; const int vboidx = data->current_vertex_buffer;
const GLuint vbo = data->vertex_buffers[vboidx]; const GLuint vbo = data->vertex_buffers[vboidx];
const GLsizeiptr dataSizeInBytes = data->current_vertex_data * sizeof (float); const GLsizeiptr dataSizeInBytes = data->current_vertex_data * sizeof (float);
const int totalcmds = data->current_render_command;
Uint8 enabled_attrs = (1 << GLES2_ATTRIBUTE_POSITION); Uint8 enabled_attrs = (1 << GLES2_ATTRIBUTE_POSITION);
GLES2_RenderCommand *cmd;
GLES2_RenderCommand *next;
SDL_Rect viewport; SDL_Rect viewport;
SDL_Texture *bound_texture = NULL; SDL_Texture *bound_texture = NULL;
SDL_BlendMode blend = SDL_BLENDMODE_INVALID; SDL_BlendMode blend = SDL_BLENDMODE_INVALID;
@ -491,11 +525,10 @@ GLES2_FlushCommands(SDL_Renderer *renderer)
GLfloat projection[4][4]; GLfloat projection[4][4];
SDL_bool cliprect_enabled = SDL_FALSE; SDL_bool cliprect_enabled = SDL_FALSE;
SDL_Rect cliprect; SDL_Rect cliprect;
int i;
GLES2_ActivateRenderer(renderer); GLES2_ActivateRenderer(renderer);
if (totalcmds == 0) { /* nothing to do! */ if (data->render_commands == NULL) { /* nothing to do! */
SDL_assert(data->current_vertex_data == 0); SDL_assert(data->current_vertex_data == 0);
return 0; return 0;
} }
@ -506,7 +539,9 @@ GLES2_FlushCommands(SDL_Renderer *renderer)
data->current_vertex_buffer = 0; data->current_vertex_buffer = 0;
} }
data->current_vertex_data = 0; /* start next VBO at start. */ data->current_vertex_data = 0; /* start next VBO at start. */
data->current_render_command = 0; cmd = data->render_commands;
data->render_commands = NULL;
data->render_commands_tail = NULL;
SDL_zero(projection); SDL_zero(projection);
projection[3][0] = -1.0f; projection[3][0] = -1.0f;
@ -555,8 +590,7 @@ GLES2_FlushCommands(SDL_Renderer *renderer)
data->glScissor(viewport.x + cliprect.x, drawableh - viewport.y - cliprect.y - cliprect.h, cliprect.w, cliprect.h); data->glScissor(viewport.x + cliprect.x, drawableh - viewport.y - cliprect.y - cliprect.h, cliprect.w, cliprect.h);
} }
for (i = 0; i < totalcmds; i++) { while (cmd != NULL) {
const GLES2_RenderCommand *cmd = &data->render_commands[i];
switch (cmd->cmd) { switch (cmd->cmd) {
case GLES2_RENDERCMD_VIEWPORT: case GLES2_RENDERCMD_VIEWPORT:
if (SDL_memcmp(&cmd->data.viewport, &viewport, sizeof (SDL_Rect)) != 0) { if (SDL_memcmp(&cmd->data.viewport, &viewport, sizeof (SDL_Rect)) != 0) {
@ -713,6 +747,12 @@ GLES2_FlushCommands(SDL_Renderer *renderer)
default: SDL_assert(!"Unknown rendering command"); break; default: SDL_assert(!"Unknown rendering command"); break;
} }
/* put this command in the pool for reuse, move on to next one. */
next = cmd->next;
cmd->next = data->render_commands_pool;
data->render_commands_pool = cmd;
cmd = next;
} }
data->command_generation++; data->command_generation++;
@ -734,8 +774,10 @@ GLES2_FlushCommandsIfTextureNeeded(SDL_Renderer *renderer, SDL_Texture *texture)
static int static int
GLES2_UpdateViewport(SDL_Renderer * renderer) GLES2_UpdateViewport(SDL_Renderer * renderer)
{ {
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++]; if (cmd == NULL) {
return -1;
}
cmd->cmd = GLES2_RENDERCMD_VIEWPORT; cmd->cmd = GLES2_RENDERCMD_VIEWPORT;
SDL_memcpy(&cmd->data.viewport, &renderer->viewport, sizeof (SDL_Rect)); SDL_memcpy(&cmd->data.viewport, &renderer->viewport, sizeof (SDL_Rect));
return 0; return 0;
@ -744,8 +786,10 @@ GLES2_UpdateViewport(SDL_Renderer * renderer)
static int static int
GLES2_UpdateClipRect(SDL_Renderer * renderer) GLES2_UpdateClipRect(SDL_Renderer * renderer)
{ {
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++]; if (cmd == NULL) {
return -1;
}
cmd->cmd = GLES2_RENDERCMD_CLIPRECT; cmd->cmd = GLES2_RENDERCMD_CLIPRECT;
cmd->data.cliprect.enabled = renderer->clipping_enabled; cmd->data.cliprect.enabled = renderer->clipping_enabled;
SDL_memcpy(&cmd->data.cliprect.rect, &renderer->clip_rect, sizeof (SDL_Rect)); SDL_memcpy(&cmd->data.cliprect.rect, &renderer->clip_rect, sizeof (SDL_Rect));
@ -759,8 +803,25 @@ GLES2_DestroyRenderer(SDL_Renderer *renderer)
/* Deallocate everything */ /* Deallocate everything */
if (data) { if (data) {
GLES2_RenderCommand *cmd;
GLES2_ActivateRenderer(renderer); GLES2_ActivateRenderer(renderer);
if (data->render_commands_tail != NULL) {
data->render_commands_tail->next = data->render_commands_pool;
} else {
data->render_commands = data->render_commands_pool;
}
cmd = data->render_commands;
while (cmd != NULL) {
GLES2_RenderCommand *next = cmd->next;
SDL_free(cmd);
cmd = next;
}
SDL_free(data->vertex_data);
{ {
GLES2_ShaderCacheEntry *entry; GLES2_ShaderCacheEntry *entry;
GLES2_ShaderCacheEntry *next; GLES2_ShaderCacheEntry *next;
@ -1625,8 +1686,10 @@ static void GLES2_RenderPresent(SDL_Renderer *renderer);
static int static int
GLES2_RenderClear(SDL_Renderer * renderer) GLES2_RenderClear(SDL_Renderer * renderer)
{ {
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++]; if (cmd == NULL) {
return -1;
}
cmd->cmd = GLES2_RENDERCMD_CLEAR; cmd->cmd = GLES2_RENDERCMD_CLEAR;
cmd->data.clear.r = renderer->r; cmd->data.clear.r = renderer->r;
cmd->data.clear.g = renderer->g; cmd->data.clear.g = renderer->g;
@ -1635,25 +1698,48 @@ GLES2_RenderClear(SDL_Renderer * renderer)
return 0; return 0;
} }
static void static int
GLES2_AddVertices(SDL_Renderer *renderer, const GLES2_Attribute attr, const float *vertexData, size_t dataSizeInElements) GLES2_AddVertices(SDL_Renderer *renderer, const GLES2_Attribute attr, const float *vertexData, size_t dataSizeInElements)
{ {
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++]; const GLsizeiptr needed = data->current_vertex_data + dataSizeInElements;
GLfloat *vdata = &data->vertex_data[data->current_vertex_data]; GLES2_RenderCommand *cmd;
GLfloat *vdata;
if (needed > data->vertex_data_allocation) {
const GLsizeiptr newsize = data->vertex_data_allocation * 2;
printf("realloc'ing %p to %d\n", data->vertex_data, (int) newsize);
void *ptr = SDL_realloc(data->vertex_data, newsize * sizeof (GLfloat));
if (ptr == NULL) {
SDL_OutOfMemory();
return -1;
}
data->vertex_data = (GLfloat *) ptr;
data->vertex_data_allocation = newsize;
}
cmd = GLES2_AllocateRenderCommand(renderer);
if (cmd == NULL) {
return -1;
}
vdata = &data->vertex_data[data->current_vertex_data];
SDL_memcpy(vdata, vertexData, dataSizeInElements * sizeof (GLfloat)); SDL_memcpy(vdata, vertexData, dataSizeInElements * sizeof (GLfloat));
cmd->cmd = GLES2_RENDERCMD_ATTR; cmd->cmd = GLES2_RENDERCMD_ATTR;
cmd->data.attr.attr = attr; cmd->data.attr.attr = attr;
cmd->data.attr.offset = data->current_vertex_data * sizeof (GLfloat); cmd->data.attr.offset = data->current_vertex_data * sizeof (GLfloat);
cmd->data.attr.count = dataSizeInElements; cmd->data.attr.count = dataSizeInElements;
data->current_vertex_data += dataSizeInElements; data->current_vertex_data += dataSizeInElements;
return 0;
} }
static GLES2_RenderCommand * static int
GLES2_InitSolidDrawCommand(SDL_Renderer *renderer, const GLenum mode, const GLint first, const GLsizei count) GLES2_AddSolidDrawCommand(SDL_Renderer *renderer, const GLenum mode, const GLint first, const GLsizei count)
{ {
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLES2_RenderCommand *cmd = GLES2_AllocateRenderCommand(renderer);
GLES2_RenderCommand *cmd = &data->render_commands[data->current_render_command++]; if (cmd == NULL) {
return -1;
}
cmd->cmd = GLES2_RENDERCMD_DRAW; cmd->cmd = GLES2_RENDERCMD_DRAW;
cmd->data.draw.mode = mode; cmd->data.draw.mode = mode;
cmd->data.draw.first = first; cmd->data.draw.first = first;
@ -1666,7 +1752,7 @@ GLES2_InitSolidDrawCommand(SDL_Renderer *renderer, const GLenum mode, const GLin
cmd->data.draw.blend = renderer->blendMode; cmd->data.draw.blend = renderer->blendMode;
cmd->data.draw.imgsrc = GLES2_IMAGESOURCE_SOLID; cmd->data.draw.imgsrc = GLES2_IMAGESOURCE_SOLID;
cmd->data.draw.texture = NULL; cmd->data.draw.texture = NULL;
return cmd; return 0;
} }
static int static int
@ -1674,6 +1760,7 @@ GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int cou
{ {
GLfloat *vertices = SDL_stack_alloc(GLfloat, count * 2); /* !!! FIXME: We could do this without a stack_alloc... */ GLfloat *vertices = SDL_stack_alloc(GLfloat, count * 2); /* !!! FIXME: We could do this without a stack_alloc... */
int idx; int idx;
int rc;
/* Emit the specified vertices as points */ /* Emit the specified vertices as points */
for (idx = 0; idx < count; ++idx) { for (idx = 0; idx < count; ++idx) {
@ -1681,10 +1768,14 @@ GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int cou
vertices[(idx * 2) + 1] = points[idx].y + 0.5f; vertices[(idx * 2) + 1] = points[idx].y + 0.5f;
} }
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2); rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2);
GLES2_InitSolidDrawCommand(renderer, GL_POINTS, 0, count);
SDL_stack_free(vertices); SDL_stack_free(vertices);
return 0;
if (rc == 0) {
rc = GLES2_AddSolidDrawCommand(renderer, GL_POINTS, 0, count);
}
return rc;
} }
static int static int
@ -1692,6 +1783,7 @@ GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int coun
{ {
GLfloat *vertices = SDL_stack_alloc(GLfloat, count * 2); /* !!! FIXME: We could do this without a stack_alloc... */ GLfloat *vertices = SDL_stack_alloc(GLfloat, count * 2); /* !!! FIXME: We could do this without a stack_alloc... */
int idx; int idx;
int rc;
/* Emit a line strip including the specified vertices */ /* Emit a line strip including the specified vertices */
for (idx = 0; idx < count; ++idx) { for (idx = 0; idx < count; ++idx) {
@ -1699,8 +1791,10 @@ GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int coun
vertices[(idx * 2) + 1] = points[idx].y + 0.5f; vertices[(idx * 2) + 1] = points[idx].y + 0.5f;
} }
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2); rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2);
GLES2_InitSolidDrawCommand(renderer, GL_LINE_STRIP, 0, count); if (rc == 0) {
rc = GLES2_AddSolidDrawCommand(renderer, GL_LINE_STRIP, 0, count);
}
#if 0 /* !!! FIXME: ugh */ #if 0 /* !!! FIXME: ugh */
/* We need to close the endpoint of the line */ /* We need to close the endpoint of the line */
@ -1711,7 +1805,7 @@ GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int coun
#endif #endif
SDL_stack_free(vertices); SDL_stack_free(vertices);
return 0; return rc;
} }
static int static int
@ -1719,9 +1813,10 @@ GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
{ {
GLfloat vertices[8]; GLfloat vertices[8];
int idx; int idx;
int rc = 0;
/* Emit a line loop for each rectangle */ /* Emit a line loop for each rectangle */
for (idx = 0; idx < count; ++idx) { for (idx = 0; (rc == 0) && (idx < count); ++idx) {
const SDL_FRect *rect = &rects[idx]; const SDL_FRect *rect = &rects[idx];
GLfloat xMin = rect->x; GLfloat xMin = rect->x;
@ -1738,16 +1833,18 @@ GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
vertices[6] = xMax; vertices[6] = xMax;
vertices[7] = yMax; vertices[7] = yMax;
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8); rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
GLES2_InitSolidDrawCommand(renderer, GL_TRIANGLE_STRIP, 0, 4); if (rc == 0) {
rc = GLES2_AddSolidDrawCommand(renderer, GL_TRIANGLE_STRIP, 0, 4);
}
} }
return 0; return 0;
} }
static GLES2_RenderCommand * static int
GLES2_InitCopyDrawCommand(SDL_Renderer *renderer, SDL_Texture *texture, const Uint8 attrs) GLES2_AddCopyDrawCommand(SDL_Renderer *renderer, SDL_Texture *texture, const Uint8 attrs)
{ {
GLES2_RenderCommand *cmd = NULL; GLES2_RenderCommand *cmd = NULL;
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
@ -1820,8 +1917,7 @@ GLES2_InitCopyDrawCommand(SDL_Renderer *renderer, SDL_Texture *texture, const Ui
sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES; sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
break; break;
default: default:
SDL_SetError("Unsupported texture format"); return SDL_SetError("Unsupported texture format");
return NULL;
} }
} else { } else {
sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */ sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
@ -1854,14 +1950,16 @@ GLES2_InitCopyDrawCommand(SDL_Renderer *renderer, SDL_Texture *texture, const Ui
sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES; sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
break; break;
default: default:
SDL_SetError("Unsupported texture format"); return SDL_SetError("Unsupported texture format");
return NULL;
} }
} }
((GLES2_TextureData *)texture->driverdata)->last_cmd_generation = data->command_generation; ((GLES2_TextureData *)texture->driverdata)->last_cmd_generation = data->command_generation;
cmd = &data->render_commands[data->current_render_command++]; cmd = GLES2_AllocateRenderCommand(renderer);
if (cmd == NULL) {
return -1;
}
cmd->cmd = GLES2_RENDERCMD_DRAW; cmd->cmd = GLES2_RENDERCMD_DRAW;
cmd->data.draw.mode = GL_TRIANGLE_STRIP; cmd->data.draw.mode = GL_TRIANGLE_STRIP;
cmd->data.draw.first = 0; cmd->data.draw.first = 0;
@ -1875,7 +1973,7 @@ GLES2_InitCopyDrawCommand(SDL_Renderer *renderer, SDL_Texture *texture, const Ui
cmd->data.draw.imgsrc = sourceType; cmd->data.draw.imgsrc = sourceType;
cmd->data.draw.texture = texture; cmd->data.draw.texture = texture;
return cmd; return 0;
} }
static int static int
@ -1883,6 +1981,7 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s
const SDL_FRect *dstrect) const SDL_FRect *dstrect)
{ {
GLfloat vertices[8]; GLfloat vertices[8];
int rc;
/* Emit the textured quad */ /* Emit the textured quad */
vertices[0] = dstrect->x; vertices[0] = dstrect->x;
@ -1893,20 +1992,25 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s
vertices[5] = (dstrect->y + dstrect->h); vertices[5] = (dstrect->y + dstrect->h);
vertices[6] = (dstrect->x + dstrect->w); vertices[6] = (dstrect->x + dstrect->w);
vertices[7] = (dstrect->y + dstrect->h); vertices[7] = (dstrect->y + dstrect->h);
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8); rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
vertices[0] = srcrect->x / (GLfloat)texture->w; if (rc == 0) {
vertices[1] = srcrect->y / (GLfloat)texture->h; vertices[0] = srcrect->x / (GLfloat)texture->w;
vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; vertices[1] = srcrect->y / (GLfloat)texture->h;
vertices[3] = srcrect->y / (GLfloat)texture->h; vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
vertices[4] = srcrect->x / (GLfloat)texture->w; vertices[3] = srcrect->y / (GLfloat)texture->h;
vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; vertices[4] = srcrect->x / (GLfloat)texture->w;
vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8); vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8);
GLES2_InitCopyDrawCommand(renderer, texture, 0); if (rc == 0) {
return 0; rc = GLES2_AddCopyDrawCommand(renderer, texture, 0);
}
}
return rc;
} }
static int static int
@ -1915,50 +2019,60 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
{ {
const float radian_angle = (float)(M_PI * (360.0 - angle) / 180.0); const float radian_angle = (float)(M_PI * (360.0 - angle) / 180.0);
GLfloat vertices[8]; GLfloat vertices[8];
int rc;
vertices[0] = vertices[2] = vertices[4] = vertices[6] = (GLfloat)SDL_sin(radian_angle); vertices[0] = vertices[2] = vertices[4] = vertices[6] = (GLfloat)SDL_sin(radian_angle);
/* render expects cos value - 1 (see GLES2_VertexSrc_Default_) */ /* render expects cos value - 1 (see GLES2_VertexSrc_Default_) */
vertices[1] = vertices[3] = vertices[5] = vertices[7] = (GLfloat)SDL_cos(radian_angle) - 1.0f; vertices[1] = vertices[3] = vertices[5] = vertices[7] = (GLfloat)SDL_cos(radian_angle) - 1.0f;
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_ANGLE, vertices, 8); rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_ANGLE, vertices, 8);
/* Calculate the center of rotation */ /* Calculate the center of rotation */
vertices[0] = vertices[2] = vertices[4] = vertices[6] = (center->x + dstrect->x); if (rc == 0) {
vertices[1] = vertices[3] = vertices[5] = vertices[7] = (center->y + dstrect->y); vertices[0] = vertices[2] = vertices[4] = vertices[6] = (center->x + dstrect->x);
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_CENTER, vertices, 8); vertices[1] = vertices[3] = vertices[5] = vertices[7] = (center->y + dstrect->y);
rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_CENTER, vertices, 8);
if (rc == 0) {
/* Emit the textured quad */
vertices[0] = dstrect->x;
vertices[1] = dstrect->y;
vertices[2] = (dstrect->x + dstrect->w);
vertices[3] = dstrect->y;
vertices[4] = dstrect->x;
vertices[5] = (dstrect->y + dstrect->h);
vertices[6] = (dstrect->x + dstrect->w);
vertices[7] = (dstrect->y + dstrect->h);
if (flip & SDL_FLIP_HORIZONTAL) {
const GLfloat tmp = vertices[0];
vertices[0] = vertices[4] = vertices[2];
vertices[2] = vertices[6] = tmp;
}
if (flip & SDL_FLIP_VERTICAL) {
const GLfloat tmp = vertices[1];
vertices[1] = vertices[3] = vertices[5];
vertices[5] = vertices[7] = tmp;
}
rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
/* Emit the textured quad */ if (rc == 0) {
vertices[0] = dstrect->x; vertices[0] = srcrect->x / (GLfloat)texture->w;
vertices[1] = dstrect->y; vertices[1] = srcrect->y / (GLfloat)texture->h;
vertices[2] = (dstrect->x + dstrect->w); vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
vertices[3] = dstrect->y; vertices[3] = srcrect->y / (GLfloat)texture->h;
vertices[4] = dstrect->x; vertices[4] = srcrect->x / (GLfloat)texture->w;
vertices[5] = (dstrect->y + dstrect->h); vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
vertices[6] = (dstrect->x + dstrect->w); vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
vertices[7] = (dstrect->y + dstrect->h); vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
if (flip & SDL_FLIP_HORIZONTAL) { rc = GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8);
const GLfloat tmp = vertices[0];
vertices[0] = vertices[4] = vertices[2]; if (rc == 0) {
vertices[2] = vertices[6] = tmp; GLES2_AddCopyDrawCommand(renderer, texture, (1 << GLES2_ATTRIBUTE_CENTER) | (1 << GLES2_ATTRIBUTE_ANGLE));
}
}
}
} }
if (flip & SDL_FLIP_VERTICAL) {
const GLfloat tmp = vertices[1];
vertices[1] = vertices[3] = vertices[5];
vertices[5] = vertices[7] = tmp;
}
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8);
vertices[0] = srcrect->x / (GLfloat)texture->w; return rc;
vertices[1] = srcrect->y / (GLfloat)texture->h;
vertices[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
vertices[3] = srcrect->y / (GLfloat)texture->h;
vertices[4] = srcrect->x / (GLfloat)texture->w;
vertices[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
vertices[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
vertices[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
GLES2_AddVertices(renderer, GLES2_ATTRIBUTE_TEXCOORD, vertices, 8);
GLES2_InitCopyDrawCommand(renderer, texture, (1 << GLES2_ATTRIBUTE_CENTER) | (1 << GLES2_ATTRIBUTE_ANGLE));
return 0;
} }
static int static int
@ -2158,6 +2272,15 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
renderer->driverdata = data; renderer->driverdata = data;
renderer->window = window; renderer->window = window;
data->vertex_data_allocation = 512;
data->vertex_data = (GLfloat *) SDL_malloc(data->vertex_data_allocation * sizeof (GLfloat));
if (data->vertex_data == NULL) {
GLES2_DestroyRenderer(renderer);
SDL_OutOfMemory();
goto error;
}
printf("malloc'd %p\n", data->vertex_data);
/* Create an OpenGL ES 2.0 context */ /* Create an OpenGL ES 2.0 context */
data->context = SDL_GL_CreateContext(window); data->context = SDL_GL_CreateContext(window);
if (!data->context) { if (!data->context) {