From 4aadf46465d066f916ef9a0bc17139d58eb55ff1 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 4 Sep 2014 21:12:27 +0200 Subject: [PATCH] Don't set redundant GL state (glBindTexture, glStencilFunc, glStencilMask) --- src/nanovg_gl.h | 90 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 16 deletions(-) diff --git a/src/nanovg_gl.h b/src/nanovg_gl.h index 5ed5ef9..57683c6 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -49,6 +49,7 @@ enum NVGcreateFlags { # define NANOVG_GL_IMPLEMENTATION 1 #endif +#define NANOVG_GL_USE_STATE_FILTER (1) // Creates NanoVG contexts for different OpenGL (ES) versions. // Flags should be combination of the create flags above. @@ -231,6 +232,15 @@ struct GLNVGcontext { unsigned char* uniforms; int cuniforms; int nuniforms; + + // cached state + #if NANOVG_GL_USE_STATE_FILTER + GLuint boundTexture; + GLuint stencilMask; + GLenum stencilFunc; + GLint stencilFuncRef; + GLuint stencilFuncMask; + #endif }; typedef struct GLNVGcontext GLNVGcontext; @@ -250,6 +260,47 @@ static unsigned int glnvg__nearestPow2(unsigned int num) } #endif +static void glnvg__bindTexture(GLNVGcontext* gl, GLuint tex) +{ +#if NANOVG_GL_USE_STATE_FILTER + if (gl->boundTexture != tex) { + gl->boundTexture = tex; + glBindTexture(GL_TEXTURE_2D, tex); + } +#else + glBindTexture(GL_TEXTURE_2D, tex); +#endif +} + +static void glnvg__stencilMask(GLNVGcontext* gl, GLuint mask) +{ +#if NANOVG_GL_USE_STATE_FILTER + if (gl->stencilMask != mask) { + gl->stencilMask = mask; + glStencilMask(mask); + } +#else + glStencilMask(mask); +#endif +} + +static void glnvg__stencilFunc(GLNVGcontext* gl, GLenum func, GLint ref, GLuint mask) +{ +#if NANOVG_GL_USE_STATE_FILTER + if ((gl->stencilFunc != func) || + (gl->stencilFuncRef != ref) || + (gl->stencilFuncMask != mask)) { + + gl->stencilFunc = func; + gl->stencilFuncRef = ref; + gl->stencilFuncMask = mask; + glStencilFunc(func, ref, mask); + } +#else + glStencilFunc(func, ref, mask); +#endif +} + static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) { GLNVGtexture* tex = NULL; @@ -661,7 +712,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im tex->height = h; tex->type = type; tex->flags = imageFlags; - glBindTexture(GL_TEXTURE_2D, tex->tex); + glnvg__bindTexture(gl, tex->tex); glPixelStorei(GL_UNPACK_ALIGNMENT,1); #ifndef NANOVG_GLES2 @@ -720,8 +771,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im #endif glnvg__checkError(gl, "create tex"); - - glBindTexture(GL_TEXTURE_2D, 0); + glnvg__bindTexture(gl, 0); return tex->id; } @@ -739,7 +789,7 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w GLNVGtexture* tex = glnvg__findTexture(gl, image); if (tex == NULL) return 0; - glBindTexture(GL_TEXTURE_2D, tex->tex); + glnvg__bindTexture(gl, tex->tex); glPixelStorei(GL_UNPACK_ALIGNMENT,1); @@ -773,7 +823,7 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); #endif - glBindTexture(GL_TEXTURE_2D, 0); + glnvg__bindTexture(gl, 0); return 1; } @@ -917,10 +967,10 @@ static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image) if (image != 0) { GLNVGtexture* tex = glnvg__findTexture(gl, image); - glBindTexture(GL_TEXTURE_2D, tex != NULL ? tex->tex : 0); + glnvg__bindTexture(gl, tex != NULL ? tex->tex : 0); glnvg__checkError(gl, "tex paint tex"); } else { - glBindTexture(GL_TEXTURE_2D, 0); + glnvg__bindTexture(gl, 0); } } @@ -938,8 +988,8 @@ static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call) // Draw shapes glEnable(GL_STENCIL_TEST); - glStencilMask(0xff); - glStencilFunc(GL_ALWAYS, 0, 0xff); + glnvg__stencilMask(gl, 0xff); + glnvg__stencilFunc(gl, GL_ALWAYS, 0, 0xff); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // set bindpoint for solid loc @@ -960,7 +1010,7 @@ static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call) glnvg__checkError(gl, "fill fill"); if (gl->flags & NVG_ANTIALIAS) { - glStencilFunc(GL_EQUAL, 0x00, 0xff); + glnvg__stencilFunc(gl, GL_EQUAL, 0x00, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Draw fringes for (i = 0; i < npaths; i++) @@ -968,7 +1018,7 @@ static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call) } // Draw fill - glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); + glnvg__stencilFunc(gl, GL_NOTEQUAL, 0x0, 0xff); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); @@ -1000,10 +1050,10 @@ static void glnvg__stroke(GLNVGcontext* gl, GLNVGcall* call) if (gl->flags & NVG_STENCIL_STROKES) { glEnable(GL_STENCIL_TEST); - glStencilMask(0xff); + glnvg__stencilMask(gl, 0xff); // Fill the stroke base without overlap - glStencilFunc(GL_EQUAL, 0x0, 0xff); + glnvg__stencilFunc(gl, GL_EQUAL, 0x0, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glnvg__setUniforms(gl, call->uniformOffset + gl->fragSize, call->image); glnvg__checkError(gl, "stroke fill 0"); @@ -1012,14 +1062,14 @@ static void glnvg__stroke(GLNVGcontext* gl, GLNVGcall* call) // Draw anti-aliased pixels. glnvg__setUniforms(gl, call->uniformOffset, call->image); - glStencilFunc(GL_EQUAL, 0x00, 0xff); + glnvg__stencilFunc(gl, GL_EQUAL, 0x00, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); for (i = 0; i < npaths; i++) glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); // Clear stencil buffer. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - glStencilFunc(GL_ALWAYS, 0x0, 0xff); + glnvg__stencilFunc(gl, GL_ALWAYS, 0x0, 0xff); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); glnvg__checkError(gl, "stroke fill 1"); for (i = 0; i < npaths; i++) @@ -1069,6 +1119,14 @@ static void glnvg__renderFlush(void* uptr) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc(GL_ALWAYS, 0, 0xffffffff); glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + #if NANOVG_GL_USE_STATE_FILTER + gl->boundTexture = 0; + gl->stencilMask = 0xffffffff; + gl->stencilFunc = GL_ALWAYS; + gl->stencilFuncRef = 0; + gl->stencilFuncMask = 0xffffffff; + #endif #if NANOVG_GL_USE_UNIFORMBUFFER // Upload ubo for frag shaders @@ -1115,7 +1173,7 @@ static void glnvg__renderFlush(void* uptr) glDisable(GL_CULL_FACE); glBindBuffer(GL_ARRAY_BUFFER, 0); glUseProgram(0); - glBindTexture(GL_TEXTURE_2D, 0); + glnvg__bindTexture(gl, 0); } // Reset calls