Added OpenGL state caching for decent speed improvement.
authorSam Lantinga <slouken@libsdl.org>
Sat, 19 Feb 2011 21:51:21 -0800
changeset 5355 cc2215cda170
parent 5354 a606515be168
child 5356 dc48dd5129a5
Added OpenGL state caching for decent speed improvement.
src/render/opengl/SDL_render_gl.c
src/render/opengl/SDL_shaders_gl.c
src/render/opengles/SDL_render_gles.c
src/render/opengles2/SDL_render_gles2.c
--- a/src/render/opengl/SDL_render_gl.c	Sat Feb 19 21:51:03 2011 -0800
+++ b/src/render/opengl/SDL_render_gl.c	Sat Feb 19 21:51:21 2011 -0800
@@ -87,7 +87,12 @@
 {
     SDL_GLContext context;
     SDL_bool GL_ARB_texture_rectangle_supported;
-    int blendMode;
+    struct {
+        GL_Shader shader;
+        Uint32 color;
+        int blendMode;
+        GLenum scaleMode;
+    } current;
 
     /* OpenGL functions */
 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
@@ -117,6 +122,7 @@
     GLenum formattype;
     void *pixels;
     int pitch;
+    int scaleMode;
     SDL_Rect locked_rect;
 
     /* YV12 texture support */
@@ -202,6 +208,32 @@
     return 0;
 }
 
+/* This is called if we need to invalidate all of the SDL OpenGL state */
+static void
+GL_ResetState(SDL_Renderer *renderer)
+{
+    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
+
+    if (SDL_CurrentContext == data->context) {
+        GL_UpdateViewport(renderer);
+    } else {
+        GL_ActivateRenderer(renderer);
+    }
+
+    data->current.shader = SHADER_NONE;
+    data->current.color = 0;
+    data->current.blendMode = -1;
+    data->current.scaleMode = 0;
+
+    data->glDisable(GL_DEPTH_TEST);
+    data->glDisable(GL_CULL_FACE);
+    /* This ended up causing video discrepancies between OpenGL and Direct3D */
+    /*data->glEnable(GL_LINE_SMOOTH);*/
+
+    data->glMatrixMode(GL_MODELVIEW);
+    data->glLoadIdentity();
+}
+
 SDL_Renderer *
 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
 {
@@ -320,13 +352,7 @@
     }
 
     /* Set up parameters for rendering */
-    data->blendMode = -1;
-    data->glDisable(GL_DEPTH_TEST);
-    data->glDisable(GL_CULL_FACE);
-    /* This ended up causing video discrepancies between OpenGL and Direct3D */
-    /*data->glEnable(GL_LINE_SMOOTH);*/
-    data->glMatrixMode(GL_MODELVIEW);
-    data->glLoadIdentity();
+    GL_ResetState(renderer);
 
     return renderer;
 }
@@ -437,12 +463,9 @@
 
     data->format = format;
     data->formattype = type;
+    data->scaleMode = GL_LINEAR;
     renderdata->glEnable(data->type);
     renderdata->glBindTexture(data->type, data->texture);
-    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
-                                GL_LINEAR);
-    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
-                                GL_LINEAR);
     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
                                 GL_CLAMP_TO_EDGE);
     renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
@@ -492,10 +515,6 @@
         renderdata->glEnable(data->type);
 
         renderdata->glBindTexture(data->type, data->utexture);
-        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
-                                    GL_LINEAR);
-        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
-                                    GL_LINEAR);
         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
                                     GL_CLAMP_TO_EDGE);
         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
@@ -504,10 +523,6 @@
                                  texture_h/2, 0, format, type, NULL);
 
         renderdata->glBindTexture(data->type, data->vtexture);
-        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
-                                    GL_LINEAR);
-        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
-                                    GL_LINEAR);
         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
                                     GL_CLAMP_TO_EDGE);
         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
@@ -632,9 +647,32 @@
 }
 
 static void
+GL_SetShader(GL_RenderData * data, GL_Shader shader)
+{
+    if (data->shaders && shader != data->current.shader) {
+        GL_SelectShader(data->shaders, shader);
+        data->current.shader = shader;
+    }
+}
+
+static void
+GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
+{
+    Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
+
+    if (color != data->current.color) {
+        data->glColor4f((GLfloat) r * inv255f,
+                        (GLfloat) g * inv255f,
+                        (GLfloat) b * inv255f,
+                        (GLfloat) a * inv255f);
+        data->current.color = color;
+    }
+}
+
+static void
 GL_SetBlendMode(GL_RenderData * data, int blendMode)
 {
-    if (blendMode != data->blendMode) {
+    if (blendMode != data->current.blendMode) {
         switch (blendMode) {
         case SDL_BLENDMODE_NONE:
             data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
@@ -656,10 +694,27 @@
             data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
             break;
         }
-        data->blendMode = blendMode;
+        data->current.blendMode = blendMode;
     }
 }
 
+static void
+GL_SetDrawingState(SDL_Renderer * renderer)
+{
+    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
+
+    GL_ActivateRenderer(renderer);
+
+    GL_SetColor(data, (GLfloat) renderer->r,
+                      (GLfloat) renderer->g,
+                      (GLfloat) renderer->b,
+                      (GLfloat) renderer->a);
+
+    GL_SetBlendMode(data, renderer->blendMode);
+
+    GL_SetShader(data, SHADER_SOLID);
+}
+
 static int
 GL_RenderClear(SDL_Renderer * renderer)
 {
@@ -684,15 +739,7 @@
     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
     int i;
 
-    GL_ActivateRenderer(renderer);
-
-    GL_SetBlendMode(data, renderer->blendMode);
-    GL_SelectShader(data->shaders, SHADER_SOLID);
-
-    data->glColor4f((GLfloat) renderer->r * inv255f,
-                    (GLfloat) renderer->g * inv255f,
-                    (GLfloat) renderer->b * inv255f,
-                    (GLfloat) renderer->a * inv255f);
+    GL_SetDrawingState(renderer);
 
     data->glBegin(GL_POINTS);
     for (i = 0; i < count; ++i) {
@@ -710,15 +757,7 @@
     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
     int i;
 
-    GL_ActivateRenderer(renderer);
-
-    GL_SetBlendMode(data, renderer->blendMode);
-    GL_SelectShader(data->shaders, SHADER_SOLID);
-
-    data->glColor4f((GLfloat) renderer->r * inv255f,
-                    (GLfloat) renderer->g * inv255f,
-                    (GLfloat) renderer->b * inv255f,
-                    (GLfloat) renderer->a * inv255f);
+    GL_SetDrawingState(renderer);
 
     if (count > 2 && 
         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
@@ -781,15 +820,7 @@
     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
     int i;
 
-    GL_ActivateRenderer(renderer);
-
-    GL_SetBlendMode(data, renderer->blendMode);
-    GL_SelectShader(data->shaders, SHADER_SOLID);
-
-    data->glColor4f((GLfloat) renderer->r * inv255f,
-                    (GLfloat) renderer->g * inv255f,
-                    (GLfloat) renderer->b * inv255f,
-                    (GLfloat) renderer->a * inv255f);
+    GL_SetDrawingState(renderer);
 
     for (i = 0; i < count; ++i) {
         const SDL_Rect *rect = &rects[i];
@@ -811,6 +842,52 @@
 
     GL_ActivateRenderer(renderer);
 
+    data->glEnable(texturedata->type);
+    if (texturedata->yuv) {
+        data->glActiveTextureARB(GL_TEXTURE2_ARB);
+        data->glBindTexture(texturedata->type, texturedata->vtexture);
+        if (texturedata->scaleMode != data->current.scaleMode) {
+            data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
+                                  texturedata->scaleMode);
+            data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
+                                  texturedata->scaleMode);
+        }
+
+        data->glActiveTextureARB(GL_TEXTURE1_ARB);
+        data->glBindTexture(texturedata->type, texturedata->utexture);
+        if (texturedata->scaleMode != data->current.scaleMode) {
+            data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
+                                  texturedata->scaleMode);
+            data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
+                                  texturedata->scaleMode);
+        }
+
+        data->glActiveTextureARB(GL_TEXTURE0_ARB);
+    }
+    data->glBindTexture(texturedata->type, texturedata->texture);
+
+    if (texturedata->scaleMode != data->current.scaleMode) {
+        data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
+                              texturedata->scaleMode);
+        data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
+                              texturedata->scaleMode);
+        data->current.scaleMode = texturedata->scaleMode;
+    }
+
+    if (texture->modMode) {
+        GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
+    } else {
+        GL_SetColor(data, 255, 255, 255, 255);
+    }
+
+    GL_SetBlendMode(data, texture->blendMode);
+
+    if (texturedata->yuv) {
+        GL_SetShader(data, SHADER_YV12);
+    } else {
+        GL_SetShader(data, SHADER_RGB);
+    }
+
     minx = dstrect->x;
     miny = dstrect->y;
     maxx = dstrect->x + dstrect->w;
@@ -825,32 +902,6 @@
     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
     maxv *= texturedata->texh;
 
-    data->glEnable(texturedata->type);
-    if (texturedata->yuv) {
-        data->glActiveTextureARB(GL_TEXTURE2_ARB);
-        data->glBindTexture(texturedata->type, texturedata->vtexture);
-        data->glActiveTextureARB(GL_TEXTURE1_ARB);
-        data->glBindTexture(texturedata->type, texturedata->utexture);
-        data->glActiveTextureARB(GL_TEXTURE0_ARB);
-    }
-    data->glBindTexture(texturedata->type, texturedata->texture);
-
-    if (texture->modMode) {
-        data->glColor4f((GLfloat) texture->r * inv255f,
-                        (GLfloat) texture->g * inv255f,
-                        (GLfloat) texture->b * inv255f,
-                        (GLfloat) texture->a * inv255f);
-    } else {
-        data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
-    }
-
-    GL_SetBlendMode(data, texture->blendMode);
-    if (texturedata->yuv) {
-        GL_SelectShader(data->shaders, SHADER_YV12);
-    } else {
-        GL_SelectShader(data->shaders, SHADER_RGB);
-    }
-
     data->glBegin(GL_TRIANGLE_STRIP);
     data->glTexCoord2f(minu, minv);
     data->glVertex2f((GLfloat) minx, (GLfloat) miny);
--- a/src/render/opengl/SDL_shaders_gl.c	Sat Feb 19 21:51:03 2011 -0800
+++ b/src/render/opengl/SDL_shaders_gl.c	Sat Feb 19 21:51:21 2011 -0800
@@ -60,7 +60,6 @@
 
     SDL_bool GL_ARB_texture_rectangle_supported;
 
-    GL_Shader current_shader;
     GL_ShaderData shaders[NUM_SHADERS];
 };
 
@@ -341,18 +340,7 @@
 void
 GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader)
 {
-    /* Nothing to do if there's no shader support */
-    if (!ctx) {
-        return;
-    }
-
-    /* Nothing to do if there's no shader change */
-    if (shader == ctx->current_shader) {
-        return;
-    }
-
     ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
-    ctx->current_shader = shader;
 }
 
 void
--- a/src/render/opengles/SDL_render_gles.c	Sat Feb 19 21:51:03 2011 -0800
+++ b/src/render/opengles/SDL_render_gles.c	Sat Feb 19 21:51:21 2011 -0800
@@ -84,7 +84,12 @@
 typedef struct
 {
     SDL_GLContext context;
-    int blendMode;
+    struct {
+        Uint32 color;
+        int blendMode;
+        GLenum scaleMode;
+        SDL_bool tex_coords;
+    } current;
 
     SDL_bool useDrawTexture;
     SDL_bool GL_OES_draw_texture_supported;
@@ -100,6 +105,7 @@
     GLenum formattype;
     void *pixels;
     int pitch;
+    GLenum scaleMode;
 } GLES_TextureData;
 
 static void
@@ -154,6 +160,33 @@
     return 0;
 }
 
+/* This is called if we need to invalidate all of the SDL OpenGL state */
+static void
+GLES_ResetState(SDL_Renderer *renderer)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+
+    if (SDL_CurrentContext == data->context) {
+        GLES_UpdateViewport(renderer);
+    } else {
+        GLES_ActivateRenderer(renderer);
+    }
+
+    data->current.color = 0;
+    data->current.blendMode = -1;
+    data->current.scaleMode = 0;
+    data->current.tex_coords = SDL_FALSE;
+
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_CULL_FACE);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
 SDL_Renderer *
 GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
 {
@@ -234,15 +267,8 @@
     renderer->info.max_texture_height = value;
 
     /* Set up parameters for rendering */
-    data->blendMode = -1;
-    glDisable(GL_DEPTH_TEST);
-    glDisable(GL_CULL_FACE);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
+    GLES_ResetState(renderer);
 
-    glEnableClientState(GL_VERTEX_ARRAY);
-    //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-    
     return renderer;
 }
 
@@ -319,15 +345,10 @@
 
     data->format = format;
     data->formattype = type;
+    data->scaleMode = GL_LINEAR;
     glBindTexture(data->type, data->texture);
-    glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
-                                GL_LINEAR);
-    glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
-                                GL_LINEAR);
-    glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
-                                GL_CLAMP_TO_EDGE);
-    glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
-                                GL_CLAMP_TO_EDGE);
+    glTexParameteri(data->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     glTexImage2D(data->type, 0, internalFormat, texture_w,
                              texture_h, 0, format, type, NULL);
@@ -453,25 +474,24 @@
     return 0;
 }
 
-static int
-GLES_RenderClear(SDL_Renderer * renderer)
+static void
+GLES_SetColor(GLES_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
 {
-    GLES_ActivateRenderer(renderer);
+    Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
 
-    glClearColor((GLfloat) renderer->r * inv255f,
-                 (GLfloat) renderer->g * inv255f,
-                 (GLfloat) renderer->b * inv255f,
-                 (GLfloat) renderer->a * inv255f);
-
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    return 0;
+    if (color != data->current.color) {
+        glColor4f((GLfloat) r * inv255f,
+                        (GLfloat) g * inv255f,
+                        (GLfloat) b * inv255f,
+                        (GLfloat) a * inv255f);
+        data->current.color = color;
+    }
 }
 
 static void
 GLES_SetBlendMode(GLES_RenderData * data, int blendMode)
 {
-    if (blendMode != data->blendMode) {
+    if (blendMode != data->current.blendMode) {
         switch (blendMode) {
         case SDL_BLENDMODE_NONE:
             glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
@@ -493,10 +513,55 @@
             glBlendFunc(GL_ZERO, GL_SRC_COLOR);
             break;
         }
-        data->blendMode = blendMode;
+        data->current.blendMode = blendMode;
+    }
+}
+
+static void
+GLES_SetTexCoords(GLES_RenderData * data, SDL_bool enabled)
+{
+    if (enabled != data->current.tex_coords) {
+        if (enabled) {
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        } else {
+            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        }
+        data->current.tex_coords = enabled;
     }
 }
 
+static void
+GLES_SetDrawingState(SDL_Renderer * renderer)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+
+    GLES_ActivateRenderer(renderer);
+
+    GLES_SetColor(data, (GLfloat) renderer->r,
+                        (GLfloat) renderer->g,
+                        (GLfloat) renderer->b,
+                        (GLfloat) renderer->a);
+
+    GLES_SetBlendMode(data, renderer->blendMode);
+
+    GLES_SetTexCoords(data, SDL_FALSE);
+}
+
+static int
+GLES_RenderClear(SDL_Renderer * renderer)
+{
+    GLES_ActivateRenderer(renderer);
+
+    glClearColor((GLfloat) renderer->r * inv255f,
+                 (GLfloat) renderer->g * inv255f,
+                 (GLfloat) renderer->b * inv255f,
+                 (GLfloat) renderer->a * inv255f);
+
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    return 0;
+}
+
 static int
 GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
                       int count)
@@ -505,14 +570,7 @@
     int i;
     GLshort *vertices;
 
-    GLES_ActivateRenderer(renderer);
-
-    GLES_SetBlendMode(data, renderer->blendMode);
-
-    glColor4f((GLfloat) renderer->r * inv255f,
-                    (GLfloat) renderer->g * inv255f,
-                    (GLfloat) renderer->b * inv255f,
-                    (GLfloat) renderer->a * inv255f);
+    GLES_SetDrawingState(renderer);
 
     vertices = SDL_stack_alloc(GLshort, count*2);
     for (i = 0; i < count; ++i) {
@@ -534,14 +592,7 @@
     int i;
     GLshort *vertices;
 
-    GLES_ActivateRenderer(renderer);
-
-    GLES_SetBlendMode(data, renderer->blendMode);
-
-    glColor4f((GLfloat) renderer->r * inv255f,
-                    (GLfloat) renderer->g * inv255f,
-                    (GLfloat) renderer->b * inv255f,
-                    (GLfloat) renderer->a * inv255f);
+    GLES_SetDrawingState(renderer);
 
     vertices = SDL_stack_alloc(GLshort, count*2);
     for (i = 0; i < count; ++i) {
@@ -569,14 +620,7 @@
     GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
     int i;
 
-    GLES_ActivateRenderer(renderer);
-
-    GLES_SetBlendMode(data, renderer->blendMode);
-
-    glColor4f((GLfloat) renderer->r * inv255f,
-                    (GLfloat) renderer->g * inv255f,
-                    (GLfloat) renderer->b * inv255f,
-                    (GLfloat) renderer->a * inv255f);
+    GLES_SetDrawingState(renderer);
 
     for (i = 0; i < count; ++i) {
         const SDL_Rect *rect = &rects[i];
@@ -614,21 +658,27 @@
     GLES_ActivateRenderer(renderer);
 
     glEnable(GL_TEXTURE_2D);
-    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
     glBindTexture(texturedata->type, texturedata->texture);
 
+    if (texturedata->scaleMode != data->current.scaleMode) {
+        glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
+                        texturedata->scaleMode);
+        glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
+                        texturedata->scaleMode);
+        data->current.scaleMode = texturedata->scaleMode;
+    }
+
     if (texture->modMode) {
-        glColor4f((GLfloat) texture->r * inv255f,
-                        (GLfloat) texture->g * inv255f,
-                        (GLfloat) texture->b * inv255f,
-                        (GLfloat) texture->a * inv255f);
+        GLES_SetColor(data, texture->r, texture->g, texture->b, texture->a);
     } else {
-        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+        GLES_SetColor(data, 255, 255, 255, 255);
     }
 
     GLES_SetBlendMode(data, texture->blendMode);
 
+    GLES_SetTexCoords(data, SDL_TRUE);
+
     if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
         /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */
         GLint cropRect[4];
@@ -685,8 +735,6 @@
         glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
     }
-	
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDisable(GL_TEXTURE_2D);
 
     return 0;
--- a/src/render/opengles2/SDL_render_gles2.c	Sat Feb 19 21:51:03 2011 -0800
+++ b/src/render/opengles2/SDL_render_gles2.c	Sat Feb 19 21:51:21 2011 -0800
@@ -58,6 +58,7 @@
     GLenum pixel_type;
     void *pixel_data;
     size_t pitch;
+    GLenum scaleMode;
 } GLES2_TextureData;
 
 typedef struct GLES2_ShaderCacheEntry
@@ -118,6 +119,12 @@
 typedef struct GLES2_DriverContext
 {
     SDL_GLContext *context;
+    struct {
+        int blendMode;
+        GLenum scaleMode;
+        SDL_bool tex_coords;
+    } current;
+
     int shader_format_count;
     GLenum *shader_formats;
     GLES2_ShaderCache shader_cache;
@@ -259,6 +266,7 @@
     tdata->texture_type = GL_TEXTURE_2D;
     tdata->pixel_format = format;
     tdata->pixel_type = type;
+    tdata->scaleMode = GL_LINEAR;
 
     /* Allocate a blob for image data */
     if (texture->access == SDL_TEXTUREACCESS_STREAMING)
@@ -787,59 +795,83 @@
 }
 
 static void
-GLES2_SetBlendMode(int blendMode)
+GLES2_SetBlendMode(GLES2_DriverContext *rdata, int blendMode)
+{
+    if (blendMode != rdata->current.blendMode) {
+        switch (blendMode) {
+        default:
+        case SDL_BLENDMODE_NONE:
+            glDisable(GL_BLEND);
+            break;
+        case SDL_BLENDMODE_BLEND:
+            glEnable(GL_BLEND);
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            break;
+        case SDL_BLENDMODE_ADD:
+            glEnable(GL_BLEND);
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+            break;
+        case SDL_BLENDMODE_MOD:
+            glEnable(GL_BLEND);
+            glBlendFunc(GL_ZERO, GL_SRC_COLOR);
+            break;
+        }
+        rdata->current.blendMode = blendMode;
+    }
+}
+
+static void
+GLES2_SetTexCoords(GLES2_DriverContext * rdata, SDL_bool enabled)
 {
-    switch (blendMode)
-    {
-    case SDL_BLENDMODE_NONE:
-    default:
-        glDisable(GL_BLEND);
-        break;
-    case SDL_BLENDMODE_BLEND:
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        break;
-    case SDL_BLENDMODE_ADD:
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-        break;
-    case SDL_BLENDMODE_MOD:
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_ZERO, GL_SRC_COLOR);
-        break;
+    if (enabled != rdata->current.tex_coords) {
+        if (enabled) {
+            glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
+        } else {
+            glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
+        }
+        rdata->current.tex_coords = enabled;
     }
 }
 
 static int
+GLES2_SetDrawingState(SDL_Renderer * renderer)
+{
+    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
+    int blendMode = renderer->blendMode;
+    GLuint locColor;
+
+    glGetError();
+
+    GLES2_ActivateRenderer(renderer);
+
+    GLES2_SetBlendMode(rdata, blendMode);
+
+    GLES2_SetTexCoords(rdata, SDL_FALSE);
+
+    /* Activate an appropriate shader and set the projection matrix */
+    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
+        return -1;
+
+    /* Select the color to draw with */
+    locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
+    glUniform4f(locColor,
+                renderer->r * inv255f,
+                renderer->g * inv255f,
+                renderer->b * inv255f,
+                renderer->a * inv255f);
+    return 0;
+}
+
+static int
 GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count)
 {
     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
     GLfloat *vertices;
-    SDL_BlendMode blendMode;
-    int alpha;
-    GLuint locColor;
     int idx;
 
-    GLES2_ActivateRenderer(renderer);
-
-    blendMode = renderer->blendMode;
-    alpha = renderer->a;
-
-    /* Activate an appropriate shader and set the projection matrix */
-    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
+    if (GLES2_SetDrawingState(renderer) < 0) {
         return -1;
-
-    /* Select the color to draw with */
-    locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
-    glGetError();
-    glUniform4f(locColor,
-                renderer->r * inv255f,
-                renderer->g * inv255f,
-                renderer->b * inv255f,
-                alpha * inv255f);
-
-    /* Configure the correct blend mode */
-    GLES2_SetBlendMode(blendMode);
+    }
 
     /* Emit the specified vertices as points */
     vertices = SDL_stack_alloc(GLfloat, count * 2);
@@ -851,10 +883,9 @@
         vertices[idx * 2] = x;
         vertices[(idx * 2) + 1] = y;
     }
-    glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
+    glGetError();
     glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
     glDrawArrays(GL_POINTS, 0, count);
-    glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
     SDL_stack_free(vertices);
     if (glGetError() != GL_NO_ERROR)
     {
@@ -869,31 +900,11 @@
 {
     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
     GLfloat *vertices;
-    SDL_BlendMode blendMode;
-    int alpha;
-    GLuint locColor;
     int idx;
 
-    GLES2_ActivateRenderer(renderer);
-
-    blendMode = renderer->blendMode;
-    alpha = renderer->a;
-
-    /* Activate an appropriate shader and set the projection matrix */
-    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
+    if (GLES2_SetDrawingState(renderer) < 0) {
         return -1;
-
-    /* Select the color to draw with */
-    locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
-    glGetError();
-    glUniform4f(locColor,
-                renderer->r * inv255f,
-                renderer->g * inv255f,
-                renderer->b * inv255f,
-                alpha * inv255f);
-
-    /* Configure the correct blend mode */
-    GLES2_SetBlendMode(blendMode);
+    }
 
     /* Emit a line strip including the specified vertices */
     vertices = SDL_stack_alloc(GLfloat, count * 2);
@@ -905,10 +916,9 @@
         vertices[idx * 2] = x;
         vertices[(idx * 2) + 1] = y;
     }
-    glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
+    glGetError();
     glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
     glDrawArrays(GL_LINE_STRIP, 0, count);
-    glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
     SDL_stack_free(vertices);
     if (glGetError() != GL_NO_ERROR)
     {
@@ -923,34 +933,14 @@
 {
     GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
     GLfloat vertices[8];
-    SDL_BlendMode blendMode;
-    int alpha;
-    GLuint locColor;
     int idx;
 
-    GLES2_ActivateRenderer(renderer);
-
-    blendMode = renderer->blendMode;
-    alpha = renderer->a;
-
-    /* Activate an appropriate shader and set the projection matrix */
-    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
+    if (GLES2_SetDrawingState(renderer) < 0) {
         return -1;
-
-    /* Select the color to draw with */
-    locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
-    glGetError();
-    glUniform4f(locColor,
-                renderer->r * inv255f,
-                renderer->g * inv255f,
-                renderer->b * inv255f,
-                alpha * inv255f);
-
-    /* Configure the correct blend mode */
-    GLES2_SetBlendMode(blendMode);
+    }
 
     /* Emit a line loop for each rectangle */
-    glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
+    glGetError();
     for (idx = 0; idx < count; ++idx) {
         const SDL_Rect *rect = &rects[idx];
 
@@ -970,7 +960,6 @@
         glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
     }
-    glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
     if (glGetError() != GL_NO_ERROR)
     {
         SDL_SetError("Failed to render lines");
@@ -987,7 +976,6 @@
     GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
     GLES2_ImageSource sourceType;
     SDL_BlendMode blendMode;
-    int alpha;
     GLfloat vertices[8];
     GLfloat texCoords[8];
     GLuint locTexture;
@@ -997,7 +985,6 @@
 
     /* Activate an appropriate shader and set the projection matrix */
     blendMode = texture->blendMode;
-    alpha = texture->a;
     sourceType = GLES2_IMAGESOURCE_TEXTURE;
     if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
         return -1;
@@ -1009,8 +996,13 @@
     glBindTexture(tdata->texture_type, tdata->texture);
     glUniform1i(locTexture, 0);
 
-    /* Configure texture blending */
-    GLES2_SetBlendMode(blendMode);
+    if (tdata->scaleMode != rdata->current.scaleMode) {
+        glTexParameteri(tdata->texture_type, GL_TEXTURE_MIN_FILTER,
+                        tdata->scaleMode);
+        glTexParameteri(tdata->texture_type, GL_TEXTURE_MAG_FILTER,
+                        tdata->scaleMode);
+        rdata->current.scaleMode = tdata->scaleMode;
+    }
 
     /* Configure color modulation */
     locModulation = rdata->current_program->uniform_locations[GLES2_UNIFORM_MODULATION];
@@ -1018,11 +1010,14 @@
                 texture->r * inv255f,
                 texture->g * inv255f,
                 texture->b * inv255f,
-                alpha * inv255f);
+                texture->a * inv255f);
+
+    /* Configure texture blending */
+    GLES2_SetBlendMode(rdata, blendMode);
+
+    GLES2_SetTexCoords(rdata, SDL_TRUE);
 
     /* Emit the textured quad */
-    glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
-    glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
     vertices[0] = (GLfloat)dstrect->x;
     vertices[1] = (GLfloat)dstrect->y;
     vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
@@ -1042,8 +1037,6 @@
     texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
     glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
-    glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
     if (glGetError() != GL_NO_ERROR)
     {
         SDL_SetError("Failed to render texture");
@@ -1067,6 +1060,25 @@
 
 #define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
 
+static void
+GLES2_ResetState(SDL_Renderer *renderer)
+{
+    GLES2_DriverContext *rdata = (GLES2_DriverContext *) renderer->driverdata;
+
+    if (SDL_CurrentContext == rdata->context) {
+        GLES2_UpdateViewport(renderer);
+    } else {
+        GLES2_ActivateRenderer(renderer);
+    }
+
+    rdata->current.blendMode = -1;
+    rdata->current.scaleMode = 0;
+    rdata->current.tex_coords = SDL_FALSE;
+
+    glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
+    glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
+}
+
 static SDL_Renderer *
 GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
 {
@@ -1166,6 +1178,9 @@
     renderer->RenderPresent       = &GLES2_RenderPresent;
     renderer->DestroyTexture      = &GLES2_DestroyTexture;
     renderer->DestroyRenderer     = &GLES2_DestroyRenderer;
+
+    GLES2_ResetState(renderer);
+
     return renderer;
 }