Avoid redundant state changes in the GLES2 renderer.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 05 Oct 2013 00:29:57 -0400
changeset 778470b305e09b4e
parent 7783 e6f43a80eff1
child 7785 d01823d85840
Avoid redundant state changes in the GLES2 renderer.
src/render/opengles2/SDL_render_gles2.c
src/video/uikit/SDL_uikitopenglview.m
     1.1 --- a/src/render/opengles2/SDL_render_gles2.c	Fri Oct 04 11:25:14 2013 -0400
     1.2 +++ b/src/render/opengles2/SDL_render_gles2.c	Sat Oct 05 00:29:57 2013 -0400
     1.3 @@ -81,6 +81,7 @@
     1.4      GLES2_ShaderType type;
     1.5      const GLES2_ShaderInstance *instance;
     1.6      int references;
     1.7 +    Uint8 modulation_r, modulation_g, modulation_b, modulation_a;
     1.8      struct GLES2_ShaderCacheEntry *prev;
     1.9      struct GLES2_ShaderCacheEntry *next;
    1.10  } GLES2_ShaderCacheEntry;
    1.11 @@ -98,6 +99,9 @@
    1.12      GLES2_ShaderCacheEntry *vertex_shader;
    1.13      GLES2_ShaderCacheEntry *fragment_shader;
    1.14      GLuint uniform_locations[16];
    1.15 +    Uint8 color_r, color_g, color_b, color_a;
    1.16 +    Uint8 modulation_r, modulation_g, modulation_b, modulation_a;
    1.17 +    GLfloat projection[4][4];
    1.18      struct GLES2_ProgramCacheEntry *prev;
    1.19      struct GLES2_ProgramCacheEntry *next;
    1.20  } GLES2_ProgramCacheEntry;
    1.21 @@ -156,6 +160,7 @@
    1.22      GLES2_ShaderCache shader_cache;
    1.23      GLES2_ProgramCache program_cache;
    1.24      GLES2_ProgramCacheEntry *current_program;
    1.25 +    Uint8 clear_r, clear_g, clear_b, clear_a;
    1.26  } GLES2_DriverContext;
    1.27  
    1.28  #define GLES2_MAX_CACHED_PROGRAMS 8
    1.29 @@ -492,8 +497,6 @@
    1.30          return -1;
    1.31      }
    1.32      texture->driverdata = data;
    1.33 -
    1.34 -    renderdata->glActiveTexture(GL_TEXTURE0);
    1.35      renderdata->glBindTexture(data->texture_type, data->texture);
    1.36      renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
    1.37      renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
    1.38 @@ -549,9 +552,7 @@
    1.39      }
    1.40  
    1.41      /* Create a texture subimage with the supplied data */
    1.42 -    data->glActiveTexture(GL_TEXTURE0);
    1.43      data->glBindTexture(tdata->texture_type, tdata->texture);
    1.44 -    data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    1.45      data->glTexSubImage2D(tdata->texture_type,
    1.46                      0,
    1.47                      rect->x,
    1.48 @@ -720,7 +721,16 @@
    1.49      entry->uniform_locations[GLES2_UNIFORM_MODULATION] =
    1.50          data->glGetUniformLocation(entry->id, "u_modulation");
    1.51      entry->uniform_locations[GLES2_UNIFORM_COLOR] =
    1.52 -        rdata->glGetUniformLocation(entry->id, "u_color");
    1.53 +        data->glGetUniformLocation(entry->id, "u_color");
    1.54 +
    1.55 +    entry->modulation_r = entry->modulation_g = entry->modulation_b = entry->modulation_a = 1.0f;
    1.56 +    entry->color_r = entry->color_g = entry->color_b = entry->color_a = 1.0f;
    1.57 +
    1.58 +    data->glUseProgram(entry->id);
    1.59 +    data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
    1.60 +    data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0);  /* always texture unit 0. */
    1.61 +    data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_MODULATION], 1.0f, 1.0f, 1.0f, 1.0f);
    1.62 +    data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f);
    1.63  
    1.64      /* Cache the linked program */
    1.65      if (data->program_cache.head)
    1.66 @@ -959,7 +969,6 @@
    1.67  {
    1.68      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
    1.69      GLfloat projection[4][4];
    1.70 -    GLuint locProjection;
    1.71  
    1.72      if (!renderer->viewport.w || !renderer->viewport.h) {
    1.73          return 0;
    1.74 @@ -992,8 +1001,12 @@
    1.75      projection[3][3] = 1.0f;
    1.76  
    1.77      /* Set the projection matrix */
    1.78 -    locProjection = data->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION];
    1.79 -    data->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection);
    1.80 +    if (SDL_memcmp(data->current_program->projection, projection, sizeof (projection)) != 0) {
    1.81 +        const GLuint locProjection = data->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION];
    1.82 +        data->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection);
    1.83 +        SDL_memcpy(data->current_program->projection, projection, sizeof (projection));
    1.84 +    }
    1.85 +
    1.86      return 0;
    1.87  }
    1.88  
    1.89 @@ -1024,10 +1037,18 @@
    1.90  
    1.91      GLES2_ActivateRenderer(renderer);
    1.92  
    1.93 -    data->glClearColor((GLfloat) renderer->r * inv255f,
    1.94 -                 (GLfloat) renderer->g * inv255f,
    1.95 -                 (GLfloat) renderer->b * inv255f,
    1.96 -                 (GLfloat) renderer->a * inv255f);
    1.97 +    /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */
    1.98 +    if ( (data->clear_r != renderer->r) || (data->clear_g != renderer->g) ||
    1.99 +         (data->clear_b != renderer->b) || (data->clear_a != renderer->a) ) {
   1.100 +        data->glClearColor((GLfloat) renderer->r * inv255f,
   1.101 +                     (GLfloat) renderer->g * inv255f,
   1.102 +                     (GLfloat) renderer->b * inv255f,
   1.103 +                     (GLfloat) renderer->a * inv255f);
   1.104 +        data->clear_r = renderer->r;
   1.105 +        data->clear_g = renderer->g;
   1.106 +        data->clear_b = renderer->b;
   1.107 +        data->clear_a = renderer->a;
   1.108 +    }
   1.109  
   1.110      data->glClear(GL_COLOR_BUFFER_BIT);
   1.111  
   1.112 @@ -1077,8 +1098,9 @@
   1.113  GLES2_SetDrawingState(SDL_Renderer * renderer)
   1.114  {
   1.115      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.116 -    int blendMode = renderer->blendMode;
   1.117 -    GLuint locColor;
   1.118 +    const int blendMode = renderer->blendMode;
   1.119 +    GLES2_ProgramCacheEntry *program;
   1.120 +    Uint8 r, g, b, a;
   1.121  
   1.122      GLES2_ActivateRenderer(renderer);
   1.123  
   1.124 @@ -1087,26 +1109,35 @@
   1.125      GLES2_SetTexCoords(data, SDL_FALSE);
   1.126  
   1.127      /* Activate an appropriate shader and set the projection matrix */
   1.128 -    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
   1.129 +    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) {
   1.130          return -1;
   1.131 +    }
   1.132  
   1.133      /* Select the color to draw with */
   1.134 -    locColor = data->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
   1.135 +    g = renderer->g;
   1.136 +    a = renderer->a;
   1.137 +
   1.138      if (renderer->target &&
   1.139 -        (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
   1.140 +         (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
   1.141           renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
   1.142 -        data->glUniform4f(locColor,
   1.143 -                    renderer->b * inv255f,
   1.144 -                    renderer->g * inv255f,
   1.145 -                    renderer->r * inv255f,
   1.146 -                    renderer->a * inv255f);
   1.147 -    } else {
   1.148 -        data->glUniform4f(locColor,
   1.149 -                    renderer->r * inv255f,
   1.150 -                    renderer->g * inv255f,
   1.151 -                    renderer->b * inv255f,
   1.152 -                    renderer->a * inv255f);
   1.153 +        r = renderer->b;
   1.154 +        b = renderer->r;
   1.155 +     } else {
   1.156 +        r = renderer->r;
   1.157 +        b = renderer->b;
   1.158 +     }
   1.159 +
   1.160 +    program = data->current_program;
   1.161 +    /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */
   1.162 +    if ( (program->color_r != r) || (program->color_g != g) || (program->color_b != b) || (program->color_a != a) ) {
   1.163 +        /* Select the color to draw with */
   1.164 +        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
   1.165 +        program->color_r = r;
   1.166 +        program->color_g = g;
   1.167 +        program->color_b = b;
   1.168 +        program->color_a = a;
   1.169      }
   1.170 +
   1.171      return 0;
   1.172  }
   1.173  
   1.174 @@ -1213,8 +1244,8 @@
   1.175      SDL_BlendMode blendMode;
   1.176      GLfloat vertices[8];
   1.177      GLfloat texCoords[8];
   1.178 -    GLuint locTexture;
   1.179 -    GLuint locModulation;
   1.180 +    GLES2_ProgramCacheEntry *program;
   1.181 +    Uint8 r, g, b, a;
   1.182  
   1.183      GLES2_ActivateRenderer(renderer);
   1.184  
   1.185 @@ -1300,31 +1331,37 @@
   1.186                  return -1;
   1.187          }
   1.188      }
   1.189 -    if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
   1.190 +
   1.191 +    if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0) {
   1.192          return -1;
   1.193 +    }
   1.194  
   1.195      /* Select the target texture */
   1.196 -    locTexture = data->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE];
   1.197 -    data->glActiveTexture(GL_TEXTURE0);
   1.198      data->glBindTexture(tdata->texture_type, tdata->texture);
   1.199 -    data->glUniform1i(locTexture, 0);
   1.200  
   1.201      /* Configure color modulation */
   1.202 -    locModulation = data->current_program->uniform_locations[GLES2_UNIFORM_MODULATION];
   1.203 +    g = texture->g;
   1.204 +    a = texture->a;
   1.205 +
   1.206      if (renderer->target &&
   1.207          (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
   1.208           renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
   1.209 -        data->glUniform4f(locModulation,
   1.210 -                    texture->b * inv255f,
   1.211 -                    texture->g * inv255f,
   1.212 -                    texture->r * inv255f,
   1.213 -                    texture->a * inv255f);
   1.214 +        r = texture->b;
   1.215 +        b = texture->r;
   1.216      } else {
   1.217 -        data->glUniform4f(locModulation,
   1.218 -                    texture->r * inv255f,
   1.219 -                    texture->g * inv255f,
   1.220 -                    texture->b * inv255f,
   1.221 -                    texture->a * inv255f);
   1.222 +        r = texture->r;
   1.223 +        b = texture->b;
   1.224 +    }
   1.225 +
   1.226 +    program = data->current_program;
   1.227 +
   1.228 +    /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */
   1.229 +    if ( (program->modulation_r != r) || (program->modulation_g != g) || (program->modulation_b != b) || (program->modulation_a != a) ) {
   1.230 +        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
   1.231 +        program->modulation_r = r;
   1.232 +        program->modulation_g = g;
   1.233 +        program->modulation_b = b;
   1.234 +        program->modulation_a = a;
   1.235      }
   1.236  
   1.237      /* Configure texture blending */
   1.238 @@ -1363,11 +1400,11 @@
   1.239      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   1.240      GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   1.241      GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   1.242 +    GLES2_ProgramCacheEntry *program;
   1.243 +    Uint8 r, g, b, a;
   1.244      SDL_BlendMode blendMode;
   1.245      GLfloat vertices[8];
   1.246      GLfloat texCoords[8];
   1.247 -    GLuint locTexture;
   1.248 -    GLuint locModulation;
   1.249      GLfloat translate[8];
   1.250      GLfloat fAngle[4];
   1.251      GLfloat tmp;
   1.252 @@ -1467,27 +1504,32 @@
   1.253          return -1;
   1.254  
   1.255      /* Select the target texture */
   1.256 -    locTexture = data->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE];
   1.257 -    data->glActiveTexture(GL_TEXTURE0);
   1.258      data->glBindTexture(tdata->texture_type, tdata->texture);
   1.259 -    data->glUniform1i(locTexture, 0);
   1.260  
   1.261      /* Configure color modulation */
   1.262 -    locModulation = data->current_program->uniform_locations[GLES2_UNIFORM_MODULATION];
   1.263 +    /* !!! FIXME: grep for glUniform4f(), move that stuff to a subroutine, it's a lot of copy/paste. */
   1.264 +    g = texture->g;
   1.265 +    a = texture->a;
   1.266 +
   1.267      if (renderer->target &&
   1.268          (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
   1.269           renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
   1.270 -        data->glUniform4f(locModulation,
   1.271 -                    texture->b * inv255f,
   1.272 -                    texture->g * inv255f,
   1.273 -                    texture->r * inv255f,
   1.274 -                    texture->a * inv255f);
   1.275 +        r = texture->b;
   1.276 +        b = texture->r;
   1.277      } else {
   1.278 -        data->glUniform4f(locModulation,
   1.279 -                    texture->r * inv255f,
   1.280 -                    texture->g * inv255f,
   1.281 -                    texture->b * inv255f,
   1.282 -                    texture->a * inv255f);
   1.283 +        r = texture->r;
   1.284 +        b = texture->b;
   1.285 +    }
   1.286 +
   1.287 +    program = data->current_program;
   1.288 +
   1.289 +    /* !!! FIXME: it'd be nice to do a single 32-bit compare here. */
   1.290 +    if ( (program->modulation_r != r) || (program->modulation_g != g) || (program->modulation_b != b) || (program->modulation_a != a) ) {
   1.291 +        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
   1.292 +        program->modulation_r = r;
   1.293 +        program->modulation_g = g;
   1.294 +        program->modulation_b = b;
   1.295 +        program->modulation_a = a;
   1.296      }
   1.297  
   1.298      /* Configure texture blending */
   1.299 @@ -1557,8 +1599,6 @@
   1.300  
   1.301      SDL_GetRendererOutputSize(renderer, &w, &h);
   1.302  
   1.303 -    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
   1.304 -
   1.305      data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
   1.306                         GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
   1.307      if (GL_CheckError("glReadPixels()", renderer) < 0) {
   1.308 @@ -1650,6 +1690,15 @@
   1.309      data->current.blendMode = -1;
   1.310      data->current.tex_coords = SDL_FALSE;
   1.311  
   1.312 +    data->glActiveTexture(GL_TEXTURE0);
   1.313 +    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
   1.314 +    data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   1.315 +
   1.316 +    data->glClearColor((GLfloat) data->clear_r * inv255f,
   1.317 +                        (GLfloat) data->clear_g * inv255f,
   1.318 +                        (GLfloat) data->clear_b * inv255f,
   1.319 +                        (GLfloat) data->clear_a * inv255f);
   1.320 +
   1.321      data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
   1.322      data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
   1.323  
     2.1 --- a/src/video/uikit/SDL_uikitopenglview.m	Fri Oct 04 11:25:14 2013 -0400
     2.2 +++ b/src/video/uikit/SDL_uikitopenglview.m	Sat Oct 05 00:29:57 2013 -0400
     2.3 @@ -121,6 +121,8 @@
     2.4          if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
     2.5              return NO;
     2.6          }
     2.7 +
     2.8 +        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
     2.9          /* end create buffers */
    2.10  
    2.11          self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
    2.12 @@ -148,6 +150,8 @@
    2.13          glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
    2.14          glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
    2.15      }
    2.16 +
    2.17 +    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    2.18  }
    2.19  
    2.20  - (void)setAnimationCallback:(int)interval
    2.21 @@ -197,7 +201,9 @@
    2.22  
    2.23  - (void)swapBuffers
    2.24  {
    2.25 -    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    2.26 +    /* viewRenderbuffer should always be bound here. Code that binds something
    2.27 +        else is responsible for rebinding viewRenderbuffer, to reduce
    2.28 +        duplicate state changes. */
    2.29      [context presentRenderbuffer:GL_RENDERBUFFER_OES];
    2.30  }
    2.31