From 0c2e10dce4596aa114be06a5e56521638d4bf8e5 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Oct 2018 22:53:45 -0400 Subject: [PATCH] render: Make the GL backends cache and defer more state changes. --- src/render/opengl/SDL_render_gl.c | 84 +++++++++++------- src/render/opengles/SDL_render_gles.c | 113 +++++++++++++++--------- src/render/opengles2/SDL_render_gles2.c | 84 +++++++++++------- 3 files changed, 174 insertions(+), 107 deletions(-) diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 529c67088..ef8507ebf 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -62,11 +62,17 @@ struct GL_FBOList typedef struct { + SDL_bool viewport_dirty; SDL_Rect viewport; SDL_Texture *texture; + SDL_Texture *target; + int drawablew; + int drawableh; SDL_BlendMode blend; GL_Shader shader; + SDL_bool cliprect_enabled_dirty; SDL_bool cliprect_enabled; + SDL_bool cliprect_dirty; SDL_Rect cliprect; SDL_bool texturing; Uint32 color; @@ -934,6 +940,42 @@ SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader { const SDL_BlendMode blend = cmd->data.draw.blend; + if (data->drawstate.viewport_dirty) { + const SDL_bool istarget = data->drawstate.target != NULL; + const SDL_Rect *viewport = &data->drawstate.viewport; + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); + data->glViewport(viewport->x, + istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h), + viewport->w, viewport->h); + if (viewport->w && viewport->h) { + data->glOrtho((GLdouble) 0, (GLdouble) viewport->w, + (GLdouble) istarget ? 0 : viewport->h, + (GLdouble) istarget ? viewport->h : 0, + 0.0, 1.0); + } + data->glMatrixMode(GL_MODELVIEW); + data->drawstate.viewport_dirty = SDL_FALSE; + } + + if (data->drawstate.cliprect_enabled_dirty) { + if (!data->drawstate.cliprect_enabled) { + data->glDisable(GL_SCISSOR_TEST); + } else { + data->glEnable(GL_SCISSOR_TEST); + } + data->drawstate.cliprect_enabled_dirty = SDL_FALSE; + } + + if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) { + const SDL_Rect *viewport = &data->drawstate.viewport; + const SDL_Rect *rect = &data->drawstate.cliprect; + data->glScissor(viewport->x + rect->x, + data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h, + rect->w, rect->h); + data->drawstate.cliprect_dirty = SDL_FALSE; + } + if (blend != data->drawstate.blend) { if (blend == SDL_BLENDMODE_NONE) { data->glDisable(GL_BLEND); @@ -1035,18 +1077,18 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic { /* !!! FIXME: it'd be nice to use a vertex buffer instead of immediate mode... */ GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - int drawablew = 0, drawableh = 0; - const SDL_bool istarget = renderer->target != NULL; size_t i; if (GL_ActivateRenderer(renderer) < 0) { return -1; } - if (!istarget) { - SDL_GL_GetDrawableSize(renderer->window, &drawablew, &drawableh); + data->drawstate.target = renderer->target; + if (!data->drawstate.target) { + SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh); } + while (cmd) { switch (cmd->command) { case SDL_RENDERCMD_SETDRAWCOLOR: { @@ -1069,18 +1111,7 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic SDL_Rect *viewport = &data->drawstate.viewport; if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) { SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)); - data->glMatrixMode(GL_PROJECTION); - data->glLoadIdentity(); - data->glViewport(viewport->x, - istarget ? viewport->y : (drawableh - viewport->y - viewport->h), - viewport->w, viewport->h); - if (viewport->w && viewport->h) { - data->glOrtho((GLdouble) 0, (GLdouble) viewport->w, - (GLdouble) istarget ? 0 : viewport->h, - (GLdouble) istarget ? viewport->h : 0, - 0.0, 1.0); - } - data->glMatrixMode(GL_MODELVIEW); + data->drawstate.viewport_dirty = SDL_TRUE; } break; } @@ -1089,18 +1120,11 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic const SDL_Rect *rect = &cmd->data.cliprect.rect; if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; - if (!data->drawstate.cliprect_enabled) { - data->glDisable(GL_SCISSOR_TEST); - } else { - const SDL_Rect *viewport = &data->drawstate.viewport; - data->glEnable(GL_SCISSOR_TEST); - if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { - data->glScissor(viewport->x + rect->x, - istarget ? viewport->y + rect->y : drawableh - viewport->y - rect->y - rect->h, - rect->w, rect->h); - SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); - } - } + data->drawstate.cliprect_enabled_dirty = SDL_TRUE; + } + if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { + SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); + data->drawstate.cliprect_dirty = SDL_TRUE; } break; } @@ -1122,13 +1146,11 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic if (data->drawstate.cliprect_enabled) { data->glDisable(GL_SCISSOR_TEST); + data->drawstate.cliprect_enabled_dirty = SDL_TRUE; } data->glClear(GL_COLOR_BUFFER_BIT); - if (data->drawstate.cliprect_enabled) { - data->glEnable(GL_SCISSOR_TEST); - } break; } diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c index 64801db73..6f662afa9 100644 --- a/src/render/opengles/SDL_render_gles.c +++ b/src/render/opengles/SDL_render_gles.c @@ -64,9 +64,15 @@ struct GLES_FBOList typedef struct { SDL_Rect viewport; + SDL_bool viewport_dirty; SDL_Texture *texture; + SDL_Texture *target; + int drawablew; + int drawableh; SDL_BlendMode blend; + SDL_bool cliprect_enabled_dirty; SDL_bool cliprect_enabled; + SDL_bool cliprect_dirty; SDL_Rect cliprect; SDL_bool texturing; Uint32 color; @@ -692,6 +698,57 @@ static void SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd) { const SDL_BlendMode blend = cmd->data.draw.blend; + const Uint8 r = cmd->data.color.r; + const Uint8 g = cmd->data.color.g; + const Uint8 b = cmd->data.color.b; + const Uint8 a = cmd->data.color.a; + const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b); + + if (color != data->drawstate.color) { + const GLfloat fr = ((GLfloat) r) * inv255f; + const GLfloat fg = ((GLfloat) g) * inv255f; + const GLfloat fb = ((GLfloat) b) * inv255f; + const GLfloat fa = ((GLfloat) a) * inv255f; + data->glColor4f(fr, fg, fb, fa); + data->drawstate.color = color; + } + + if (data->drawstate.viewport_dirty) { + const SDL_Rect *viewport = &data->drawstate.viewport; + const SDL_bool istarget = (data->drawstate.target != NULL); + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); + data->glViewport(viewport->x, + istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h), + viewport->w, viewport->h); + if (viewport->w && viewport->h) { + data->glOrthof((GLfloat) 0, (GLfloat) viewport->w, + (GLfloat) istarget ? 0 : viewport->h, + (GLfloat) istarget ? viewport->h : 0, + 0.0, 1.0); + } + data->glMatrixMode(GL_MODELVIEW); + data->drawstate.viewport_dirty = SDL_FALSE; + } + + if (data->drawstate.cliprect_enabled_dirty) { + if (data->drawstate.cliprect_enabled) { + data->glEnable(GL_SCISSOR_TEST); + } else { + data->glDisable(GL_SCISSOR_TEST); + } + data->drawstate.cliprect_enabled_dirty = SDL_FALSE; + } + + if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) { + const SDL_Rect *viewport = &data->drawstate.viewport; + const SDL_Rect *rect = &data->drawstate.cliprect; + const SDL_bool istarget = (data->drawstate.target != NULL); + data->glScissor(viewport->x + rect->x, + istarget ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h, + rect->w, rect->h); + data->drawstate.cliprect_dirty = SDL_FALSE; + } if (blend != data->drawstate.blend) { if (blend == SDL_BLENDMODE_NONE) { @@ -747,52 +804,29 @@ static int GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - int drawablew = 0, drawableh = 0; - const SDL_bool istarget = renderer->target != NULL; size_t i; if (GLES_ActivateRenderer(renderer) < 0) { return -1; } - if (!istarget) { - SDL_GL_GetDrawableSize(renderer->window, &drawablew, &drawableh); + data->drawstate.target = renderer->target; + + if (!renderer->target) { + SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh); } while (cmd) { switch (cmd->command) { case SDL_RENDERCMD_SETDRAWCOLOR: { - const Uint8 r = cmd->data.color.r; - const Uint8 g = cmd->data.color.g; - const Uint8 b = cmd->data.color.b; - const Uint8 a = cmd->data.color.a; - const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b); - if (color != data->drawstate.color) { - data->glColor4f((GLfloat) r * inv255f, - (GLfloat) g * inv255f, - (GLfloat) b * inv255f, - (GLfloat) a * inv255f); - data->drawstate.color = color; - } - break; + break; /* not used in this render backend. */ } case SDL_RENDERCMD_SETVIEWPORT: { SDL_Rect *viewport = &data->drawstate.viewport; if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) { SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)); - data->glMatrixMode(GL_PROJECTION); - data->glLoadIdentity(); - data->glViewport(viewport->x, - istarget ? viewport->y : (drawableh - viewport->y - viewport->h), - viewport->w, viewport->h); - if (viewport->w && viewport->h) { - data->glOrthof((GLfloat) 0, (GLfloat) viewport->w, - (GLfloat) istarget ? 0 : viewport->h, - (GLfloat) istarget ? viewport->h : 0, - 0.0, 1.0); - } - data->glMatrixMode(GL_MODELVIEW); + data->drawstate.viewport_dirty = SDL_TRUE; } break; } @@ -801,18 +835,11 @@ GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vert const SDL_Rect *rect = &cmd->data.cliprect.rect; if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; - if (!data->drawstate.cliprect_enabled) { - data->glDisable(GL_SCISSOR_TEST); - } else { - const SDL_Rect *viewport = &data->drawstate.viewport; - data->glEnable(GL_SCISSOR_TEST); - if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { - data->glScissor(viewport->x + rect->x, - istarget ? viewport->y + rect->y : drawableh - viewport->y - rect->y - rect->h, - rect->w, rect->h); - SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); - } - } + data->drawstate.cliprect_enabled_dirty = SDL_TRUE; + } + if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { + SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); + data->drawstate.cliprect_dirty = SDL_TRUE; } break; } @@ -834,13 +861,11 @@ GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vert if (data->drawstate.cliprect_enabled) { data->glDisable(GL_SCISSOR_TEST); + data->drawstate.cliprect_enabled_dirty = SDL_TRUE; } data->glClear(GL_COLOR_BUFFER_BIT); - if (data->drawstate.cliprect_enabled) { - data->glEnable(GL_SCISSOR_TEST); - } break; } diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index ff2bce2a0..1acc25e7c 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -136,14 +136,20 @@ typedef enum typedef struct { SDL_Rect viewport; + SDL_bool viewport_dirty; SDL_Texture *texture; + SDL_Texture *target; SDL_BlendMode blend; + SDL_bool cliprect_enabled_dirty; SDL_bool cliprect_enabled; + SDL_bool cliprect_dirty; SDL_Rect cliprect; SDL_bool texturing; SDL_bool is_copy_ex; Uint32 color; Uint32 clear_color; + int drawablew; + int drawableh; GLES2_ProgramCacheEntry *program; GLfloat projection[4][4]; } GLES2_DrawStateCache; @@ -944,6 +950,37 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I SDL_assert((texture != NULL) == (imgsrc != GLES2_IMAGESOURCE_SOLID)); + if (data->drawstate.viewport_dirty) { + const SDL_Rect *viewport = &data->drawstate.viewport; + data->glViewport(viewport->x, + data->drawstate.target ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h), + viewport->w, viewport->h); + if (viewport->w && viewport->h) { + data->drawstate.projection[0][0] = 2.0f / viewport->w; + data->drawstate.projection[1][1] = (data->drawstate.target ? 2.0f : -2.0f) / viewport->h; + data->drawstate.projection[3][1] = data->drawstate.target ? -1.0f : 1.0f; + } + data->drawstate.viewport_dirty = SDL_FALSE; + } + + if (data->drawstate.cliprect_enabled_dirty) { + if (!data->drawstate.cliprect_enabled) { + data->glDisable(GL_SCISSOR_TEST); + } else { + data->glEnable(GL_SCISSOR_TEST); + } + data->drawstate.cliprect_enabled_dirty = SDL_TRUE; + } + + if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) { + const SDL_Rect *viewport = &data->drawstate.viewport; + const SDL_Rect *rect = &data->drawstate.cliprect; + data->glScissor(viewport->x + rect->x, + data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h, + rect->w, rect->h); + SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); + } + if (texture != data->drawstate.texture) { if ((texture != NULL) != data->drawstate.texturing) { if (texture == NULL) { @@ -1157,16 +1194,15 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver const SDL_bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888)); const int vboidx = data->current_vertex_buffer; const GLuint vbo = data->vertex_buffers[vboidx]; - int drawablew = 0, drawableh = 0; - const SDL_bool istarget = renderer->target != NULL; size_t i; if (GLES2_ActivateRenderer(renderer) < 0) { return -1; } - if (!istarget) { - SDL_GL_GetDrawableSize(renderer->window, &drawablew, &drawableh); + data->drawstate.target = renderer->target; + if (!data->drawstate.target) { + SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh); } /* upload the new VBO data for this set of commands. */ @@ -1199,14 +1235,7 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver SDL_Rect *viewport = &data->drawstate.viewport; if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) { SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)); - data->glViewport(viewport->x, - istarget ? viewport->y : (drawableh - viewport->y - viewport->h), - viewport->w, viewport->h); - if (viewport->w && viewport->h) { - data->drawstate.projection[0][0] = 2.0f / viewport->w; - data->drawstate.projection[1][1] = (renderer->target ? 2.0f : -2.0f) / viewport->h; - data->drawstate.projection[3][1] = renderer->target ? -1.0f : 1.0f; - } + data->drawstate.viewport_dirty = SDL_TRUE; } break; } @@ -1215,32 +1244,26 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver const SDL_Rect *rect = &cmd->data.cliprect.rect; if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; - if (!data->drawstate.cliprect_enabled) { - data->glDisable(GL_SCISSOR_TEST); - } else { - const SDL_Rect *viewport = &data->drawstate.viewport; - data->glEnable(GL_SCISSOR_TEST); - if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { - data->glScissor(viewport->x + rect->x, - istarget ? viewport->y + rect->y : drawableh - viewport->y - rect->y - rect->h, - rect->w, rect->h); - SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); - } - } + data->drawstate.cliprect_enabled_dirty = SDL_TRUE; + } + + if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { + SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); + data->drawstate.cliprect_dirty = SDL_TRUE; } break; } case SDL_RENDERCMD_CLEAR: { - const Uint8 r = cmd->data.color.r; + const Uint8 r = colorswap ? cmd->data.color.b : cmd->data.color.r; const Uint8 g = cmd->data.color.g; - const Uint8 b = cmd->data.color.b; + const Uint8 b = colorswap ? cmd->data.color.r : cmd->data.color.b; const Uint8 a = cmd->data.color.a; const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b); if (color != data->drawstate.clear_color) { - const GLfloat fr = ((GLfloat) colorswap ? b : r) * inv255f; + const GLfloat fr = ((GLfloat) r) * inv255f; const GLfloat fg = ((GLfloat) g) * inv255f; - const GLfloat fb = ((GLfloat) colorswap ? r : b) * inv255f; + const GLfloat fb = ((GLfloat) b) * inv255f; const GLfloat fa = ((GLfloat) a) * inv255f; data->glClearColor(fr, fg, fb, fa); data->drawstate.clear_color = color; @@ -1248,13 +1271,10 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver if (data->drawstate.cliprect_enabled) { data->glDisable(GL_SCISSOR_TEST); + data->drawstate.cliprect_enabled_dirty = SDL_TRUE; } data->glClear(GL_COLOR_BUFFER_BIT); - - if (data->drawstate.cliprect_enabled) { - data->glEnable(GL_SCISSOR_TEST); - } break; }