From 5607cc45c507b18d08b0a770bfd5cfc5bbf77c47 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 5 Oct 2013 00:29:57 -0400 Subject: [PATCH] Avoid redundant state changes in the GLES2 renderer. --- src/render/opengles2/SDL_render_gles2.c | 175 +++++++++++++++--------- src/video/uikit/SDL_uikitopenglview.m | 8 +- 2 files changed, 119 insertions(+), 64 deletions(-) diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index 6f798022ec35d..536fec90b6466 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -81,6 +81,7 @@ typedef struct GLES2_ShaderCacheEntry GLES2_ShaderType type; const GLES2_ShaderInstance *instance; int references; + Uint8 modulation_r, modulation_g, modulation_b, modulation_a; struct GLES2_ShaderCacheEntry *prev; struct GLES2_ShaderCacheEntry *next; } GLES2_ShaderCacheEntry; @@ -98,6 +99,9 @@ typedef struct GLES2_ProgramCacheEntry GLES2_ShaderCacheEntry *vertex_shader; GLES2_ShaderCacheEntry *fragment_shader; GLuint uniform_locations[16]; + Uint8 color_r, color_g, color_b, color_a; + Uint8 modulation_r, modulation_g, modulation_b, modulation_a; + GLfloat projection[4][4]; struct GLES2_ProgramCacheEntry *prev; struct GLES2_ProgramCacheEntry *next; } GLES2_ProgramCacheEntry; @@ -156,6 +160,7 @@ typedef struct GLES2_DriverContext GLES2_ShaderCache shader_cache; GLES2_ProgramCache program_cache; GLES2_ProgramCacheEntry *current_program; + Uint8 clear_r, clear_g, clear_b, clear_a; } GLES2_DriverContext; #define GLES2_MAX_CACHED_PROGRAMS 8 @@ -492,8 +497,6 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return -1; } texture->driverdata = data; - - renderdata->glActiveTexture(GL_TEXTURE0); renderdata->glBindTexture(data->texture_type, data->texture); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); @@ -549,9 +552,7 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect } /* Create a texture subimage with the supplied data */ - data->glActiveTexture(GL_TEXTURE0); data->glBindTexture(tdata->texture_type, tdata->texture); - data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); data->glTexSubImage2D(tdata->texture_type, 0, rect->x, @@ -720,7 +721,16 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, entry->uniform_locations[GLES2_UNIFORM_MODULATION] = data->glGetUniformLocation(entry->id, "u_modulation"); entry->uniform_locations[GLES2_UNIFORM_COLOR] = - rdata->glGetUniformLocation(entry->id, "u_color"); + data->glGetUniformLocation(entry->id, "u_color"); + + entry->modulation_r = entry->modulation_g = entry->modulation_b = entry->modulation_a = 1.0f; + entry->color_r = entry->color_g = entry->color_b = entry->color_a = 1.0f; + + data->glUseProgram(entry->id); + data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection); + data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */ + data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_MODULATION], 1.0f, 1.0f, 1.0f, 1.0f); + data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f); /* Cache the linked program */ if (data->program_cache.head) @@ -959,7 +969,6 @@ GLES2_SetOrthographicProjection(SDL_Renderer *renderer) { GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLfloat projection[4][4]; - GLuint locProjection; if (!renderer->viewport.w || !renderer->viewport.h) { return 0; @@ -992,8 +1001,12 @@ GLES2_SetOrthographicProjection(SDL_Renderer *renderer) projection[3][3] = 1.0f; /* Set the projection matrix */ - locProjection = data->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION]; - data->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection); + if (SDL_memcmp(data->current_program->projection, projection, sizeof (projection)) != 0) { + const GLuint locProjection = data->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION]; + data->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection); + SDL_memcpy(data->current_program->projection, projection, sizeof (projection)); + } + return 0; } @@ -1024,10 +1037,18 @@ GLES2_RenderClear(SDL_Renderer * renderer) GLES2_ActivateRenderer(renderer); - data->glClearColor((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); + /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */ + if ( (data->clear_r != renderer->r) || (data->clear_g != renderer->g) || + (data->clear_b != renderer->b) || (data->clear_a != renderer->a) ) { + data->glClearColor((GLfloat) renderer->r * inv255f, + (GLfloat) renderer->g * inv255f, + (GLfloat) renderer->b * inv255f, + (GLfloat) renderer->a * inv255f); + data->clear_r = renderer->r; + data->clear_g = renderer->g; + data->clear_b = renderer->b; + data->clear_a = renderer->a; + } data->glClear(GL_COLOR_BUFFER_BIT); @@ -1077,8 +1098,9 @@ static int GLES2_SetDrawingState(SDL_Renderer * renderer) { GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; - int blendMode = renderer->blendMode; - GLuint locColor; + const int blendMode = renderer->blendMode; + GLES2_ProgramCacheEntry *program; + Uint8 r, g, b, a; GLES2_ActivateRenderer(renderer); @@ -1087,26 +1109,35 @@ GLES2_SetDrawingState(SDL_Renderer * renderer) GLES2_SetTexCoords(data, SDL_FALSE); /* Activate an appropriate shader and set the projection matrix */ - if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) + if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) { return -1; + } /* Select the color to draw with */ - locColor = data->current_program->uniform_locations[GLES2_UNIFORM_COLOR]; + g = renderer->g; + a = renderer->a; + if (renderer->target && - (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || + (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888)) { - data->glUniform4f(locColor, - renderer->b * inv255f, - renderer->g * inv255f, - renderer->r * inv255f, - renderer->a * inv255f); - } else { - data->glUniform4f(locColor, - renderer->r * inv255f, - renderer->g * inv255f, - renderer->b * inv255f, - renderer->a * inv255f); + r = renderer->b; + b = renderer->r; + } else { + r = renderer->r; + b = renderer->b; + } + + program = data->current_program; + /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */ + if ( (program->color_r != r) || (program->color_g != g) || (program->color_b != b) || (program->color_a != a) ) { + /* Select the color to draw with */ + data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f); + program->color_r = r; + program->color_g = g; + program->color_b = b; + program->color_a = a; } + return 0; } @@ -1213,8 +1244,8 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s SDL_BlendMode blendMode; GLfloat vertices[8]; GLfloat texCoords[8]; - GLuint locTexture; - GLuint locModulation; + GLES2_ProgramCacheEntry *program; + Uint8 r, g, b, a; GLES2_ActivateRenderer(renderer); @@ -1300,31 +1331,37 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s return -1; } } - if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0) + + if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0) { return -1; + } /* Select the target texture */ - locTexture = data->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE]; - data->glActiveTexture(GL_TEXTURE0); data->glBindTexture(tdata->texture_type, tdata->texture); - data->glUniform1i(locTexture, 0); /* Configure color modulation */ - locModulation = data->current_program->uniform_locations[GLES2_UNIFORM_MODULATION]; + g = texture->g; + a = texture->a; + if (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888)) { - data->glUniform4f(locModulation, - texture->b * inv255f, - texture->g * inv255f, - texture->r * inv255f, - texture->a * inv255f); + r = texture->b; + b = texture->r; } else { - data->glUniform4f(locModulation, - texture->r * inv255f, - texture->g * inv255f, - texture->b * inv255f, - texture->a * inv255f); + r = texture->r; + b = texture->b; + } + + program = data->current_program; + + /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */ + if ( (program->modulation_r != r) || (program->modulation_g != g) || (program->modulation_b != b) || (program->modulation_a != a) ) { + data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f); + program->modulation_r = r; + program->modulation_g = g; + program->modulation_b = b; + program->modulation_a = a; } /* Configure texture blending */ @@ -1363,11 +1400,11 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; + GLES2_ProgramCacheEntry *program; + Uint8 r, g, b, a; SDL_BlendMode blendMode; GLfloat vertices[8]; GLfloat texCoords[8]; - GLuint locTexture; - GLuint locModulation; GLfloat translate[8]; GLfloat fAngle[4]; GLfloat tmp; @@ -1467,27 +1504,32 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect return -1; /* Select the target texture */ - locTexture = data->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE]; - data->glActiveTexture(GL_TEXTURE0); data->glBindTexture(tdata->texture_type, tdata->texture); - data->glUniform1i(locTexture, 0); /* Configure color modulation */ - locModulation = data->current_program->uniform_locations[GLES2_UNIFORM_MODULATION]; + /* !!! FIXME: grep for glUniform4f(), move that stuff to a subroutine, it's a lot of copy/paste. */ + g = texture->g; + a = texture->a; + if (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888)) { - data->glUniform4f(locModulation, - texture->b * inv255f, - texture->g * inv255f, - texture->r * inv255f, - texture->a * inv255f); + r = texture->b; + b = texture->r; } else { - data->glUniform4f(locModulation, - texture->r * inv255f, - texture->g * inv255f, - texture->b * inv255f, - texture->a * inv255f); + r = texture->r; + b = texture->b; + } + + program = data->current_program; + + /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */ + if ( (program->modulation_r != r) || (program->modulation_g != g) || (program->modulation_b != b) || (program->modulation_a != a) ) { + data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f); + program->modulation_r = r; + program->modulation_g = g; + program->modulation_b = b; + program->modulation_a = a; } /* Configure texture blending */ @@ -1557,8 +1599,6 @@ GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, SDL_GetRendererOutputSize(renderer, &w, &h); - data->glPixelStorei(GL_PACK_ALIGNMENT, 1); - data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); if (GL_CheckError("glReadPixels()", renderer) < 0) { @@ -1650,6 +1690,15 @@ GLES2_ResetState(SDL_Renderer *renderer) data->current.blendMode = -1; data->current.tex_coords = SDL_FALSE; + data->glActiveTexture(GL_TEXTURE0); + data->glPixelStorei(GL_PACK_ALIGNMENT, 1); + data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + data->glClearColor((GLfloat) data->clear_r * inv255f, + (GLfloat) data->clear_g * inv255f, + (GLfloat) data->clear_b * inv255f, + (GLfloat) data->clear_a * inv255f); + data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD); diff --git a/src/video/uikit/SDL_uikitopenglview.m b/src/video/uikit/SDL_uikitopenglview.m index 9f3dc136a71a8..b43f3455f5649 100644 --- a/src/video/uikit/SDL_uikitopenglview.m +++ b/src/video/uikit/SDL_uikitopenglview.m @@ -121,6 +121,8 @@ - (id)initWithFrame:(CGRect)frame if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { return NO; } + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); /* end create buffers */ self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); @@ -148,6 +150,8 @@ - (void)updateFrame glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight); } + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); } - (void)setAnimationCallback:(int)interval @@ -197,7 +201,9 @@ - (void)setCurrentContext - (void)swapBuffers { - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); + /* viewRenderbuffer should always be bound here. Code that binds something + else is responsible for rebinding viewRenderbuffer, to reduce + duplicate state changes. */ [context presentRenderbuffer:GL_RENDERBUFFER_OES]; }