From a01bbfc5ee614725066fd80dd95396405dcfcaf7 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 19 Feb 2011 21:51:21 -0800 Subject: [PATCH] Added OpenGL state caching for decent speed improvement. --- src/render/opengl/SDL_render_gl.c | 191 ++++++++++++++--------- src/render/opengl/SDL_shaders_gl.c | 12 -- src/render/opengles/SDL_render_gles.c | 174 +++++++++++++-------- src/render/opengles2/SDL_render_gles2.c | 193 +++++++++++++----------- 4 files changed, 336 insertions(+), 234 deletions(-) diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 0490a5819..0df0f50aa 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -87,7 +87,12 @@ typedef struct { 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 @@ typedef struct GLenum formattype; void *pixels; int pitch; + int scaleMode; SDL_Rect locked_rect; /* YV12 texture support */ @@ -202,6 +208,32 @@ GL_ActivateRenderer(SDL_Renderer * renderer) 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 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) } /* 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 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 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 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 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 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 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, @@ -631,10 +646,33 @@ GL_UpdateViewport(SDL_Renderer * renderer) return 0; } +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 @@ GL_SetBlendMode(GL_RenderData * data, int blendMode) 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_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, 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_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, 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_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count) 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,46 +842,66 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, GL_ActivateRenderer(renderer); - minx = dstrect->x; - miny = dstrect->y; - maxx = dstrect->x + dstrect->w; - maxy = dstrect->y + dstrect->h; - - minu = (GLfloat) srcrect->x / texture->w; - minu *= texturedata->texw; - maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; - maxu *= texturedata->texw; - minv = (GLfloat) srcrect->y / texture->h; - minv *= texturedata->texh; - 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); + 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) { - data->glColor4f((GLfloat) texture->r * inv255f, - (GLfloat) texture->g * inv255f, - (GLfloat) texture->b * inv255f, - (GLfloat) texture->a * inv255f); + GL_SetColor(data, texture->r, texture->g, texture->b, texture->a); } else { - data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL_SetColor(data, 255, 255, 255, 255); } GL_SetBlendMode(data, texture->blendMode); + if (texturedata->yuv) { - GL_SelectShader(data->shaders, SHADER_YV12); + GL_SetShader(data, SHADER_YV12); } else { - GL_SelectShader(data->shaders, SHADER_RGB); + GL_SetShader(data, SHADER_RGB); } + minx = dstrect->x; + miny = dstrect->y; + maxx = dstrect->x + dstrect->w; + maxy = dstrect->y + dstrect->h; + + minu = (GLfloat) srcrect->x / texture->w; + minu *= texturedata->texw; + maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; + maxu *= texturedata->texw; + minv = (GLfloat) srcrect->y / texture->h; + minv *= texturedata->texh; + maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; + maxv *= texturedata->texh; + data->glBegin(GL_TRIANGLE_STRIP); data->glTexCoord2f(minu, minv); data->glVertex2f((GLfloat) minx, (GLfloat) miny); diff --git a/src/render/opengl/SDL_shaders_gl.c b/src/render/opengl/SDL_shaders_gl.c index 763cb277e..b9713e9d9 100755 --- a/src/render/opengl/SDL_shaders_gl.c +++ b/src/render/opengl/SDL_shaders_gl.c @@ -60,7 +60,6 @@ struct GL_ShaderContext SDL_bool GL_ARB_texture_rectangle_supported; - GL_Shader current_shader; GL_ShaderData shaders[NUM_SHADERS]; }; @@ -341,18 +340,7 @@ GL_CreateShaderContext() 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 diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c index 3967c6c24..a5db53b7f 100644 --- a/src/render/opengles/SDL_render_gles.c +++ b/src/render/opengles/SDL_render_gles.c @@ -84,7 +84,12 @@ SDL_RenderDriver GLES_RenderDriver = { 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 @@ typedef struct GLenum formattype; void *pixels; int pitch; + GLenum scaleMode; } GLES_TextureData; static void @@ -154,6 +160,33 @@ GLES_ActivateRenderer(SDL_Renderer * renderer) 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 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags) 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 @@ GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 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 @@ GLES_UpdateViewport(SDL_Renderer * renderer) 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); - - glClearColor((GLfloat) renderer->r * inv255f, - (GLfloat) renderer->g * inv255f, - (GLfloat) renderer->b * inv255f, - (GLfloat) renderer->a * inv255f); - - glClear(GL_COLOR_BUFFER_BIT); - - return 0; + Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b); + + 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 @@ GLES_SetBlendMode(GLES_RenderData * data, int blendMode) 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 @@ GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, 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 @@ GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, 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_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, 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_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 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 @@ GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } - - glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); return 0; diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index b4dc4c03e..6d7d42eb1 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -58,6 +58,7 @@ typedef struct GLES2_TextureData GLenum pixel_type; void *pixel_data; size_t pitch; + GLenum scaleMode; } GLES2_TextureData; typedef struct GLES2_ShaderCacheEntry @@ -118,6 +119,12 @@ typedef enum 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 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) 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,43 +795,58 @@ GLES2_RenderClear(SDL_Renderer * renderer) } static void -GLES2_SetBlendMode(int blendMode) +GLES2_SetBlendMode(GLES2_DriverContext *rdata, int blendMode) { - 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 (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) +{ + 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_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count) +GLES2_SetDrawingState(SDL_Renderer * renderer) { GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; - GLfloat *vertices; - SDL_BlendMode blendMode; - int alpha; + int blendMode = renderer->blendMode; GLuint locColor; - int idx; + + glGetError(); GLES2_ActivateRenderer(renderer); - blendMode = renderer->blendMode; - alpha = renderer->a; + 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) @@ -831,15 +854,24 @@ GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int coun /* 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); + renderer->a * inv255f); + return 0; +} - /* Configure the correct blend mode */ - GLES2_SetBlendMode(blendMode); +static int +GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count) +{ + GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; + GLfloat *vertices; + int idx; + + if (GLES2_SetDrawingState(renderer) < 0) { + return -1; + } /* Emit the specified vertices as points */ vertices = SDL_stack_alloc(GLfloat, count * 2); @@ -851,10 +883,9 @@ GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int coun 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_RenderDrawLines(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 a line strip including the specified vertices */ vertices = SDL_stack_alloc(GLfloat, count * 2); @@ -905,10 +916,9 @@ GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count 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_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count) { 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 @@ GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count) 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_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s 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 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s /* 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 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s 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 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s 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 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s 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 @@ GLES2_RenderPresent(SDL_Renderer *renderer) #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 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) renderer->RenderPresent = &GLES2_RenderPresent; renderer->DestroyTexture = &GLES2_DestroyTexture; renderer->DestroyRenderer = &GLES2_DestroyRenderer; + + GLES2_ResetState(renderer); + return renderer; }