From 4c571e8fd7c1918244eae464dde0654191e2b148 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 24 Jun 2015 22:04:19 -0300 Subject: [PATCH] Prevent redundant shader uniform uploads for built-in uniforms when OpenGL ES 2 is used. As a result, the graphics primitive drawing functions (e.g. love.graphics.rectangle) are now more efficient on mobile devices. --- src/modules/graphics/opengl/OpenGL.cpp | 28 ++--- src/modules/graphics/opengl/Shader.cpp | 138 +++++++++++++------------ src/modules/graphics/opengl/Shader.h | 8 +- 3 files changed, 82 insertions(+), 92 deletions(-) diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 0d2b2550f..dd05338f3 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -321,31 +321,15 @@ void OpenGL::prepareDraw() { TempDebugGroup debuggroup("Prepare OpenGL draw"); - Shader *shader = Shader::current; + // Make sure the active shader's love-provided uniforms are up to date. + if (Shader::current != nullptr) + Shader::current->checkSetBuiltinUniforms(); - if (shader != nullptr) + if (GLAD_VERSION_1_0) { - // Make sure the active shader has the correct values for its love- - // provided uniforms. - shader->checkSetScreenParams(); - } + const Matrix &curproj = matrices.projection.back(); + const Matrix &curxform = matrices.transform.back(); - const Matrix &curproj = matrices.projection.back(); - const Matrix &curxform = matrices.transform.back(); - - if (GLAD_ES_VERSION_2_0 && shader) - { - // Send built-in uniforms to the current shader. - shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_MATRIX, 4, curxform.getElements(), 1); - shader->sendBuiltinMatrix(Shader::BUILTIN_PROJECTION_MATRIX, 4, curproj.getElements(), 1); - - Matrix tp_matrix(curproj * curxform); - shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX, 4, tp_matrix.getElements(), 1); - - shader->checkSetPointSize(state.pointSize); - } - else if (GLAD_VERSION_1_0) - { const Matrix &lastproj = state.lastProjectionMatrix; const Matrix &lastxform = state.lastTransformMatrix; diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index e3439f747..1dd57f76c 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -26,6 +26,7 @@ // C++ #include +#include namespace love { @@ -50,7 +51,7 @@ namespace ~TemporaryAttacher() { if (prevShader != nullptr) - prevShader->attach(); + prevShader->attach(true); else curShader->detach(); } @@ -217,7 +218,12 @@ bool Shader::loadVolatile() lastCanvas = (Canvas *) -1; lastViewport = OpenGL::Viewport(); - lastPointSize = 0.0f; + lastPointSize = -1.0f; + + // Invalidate the cached matrices by setting some elements to NaN. + float nan = std::numeric_limits::quiet_NaN(); + lastProjectionMatrix.setTranslation(nan, nan); + lastTransformMatrix.setTranslation(nan, nan); // zero out active texture list activeTexUnits.clear(); @@ -299,7 +305,7 @@ bool Shader::loadVolatile() // make sure glUseProgram gets called. current = nullptr; attach(); - checkSetScreenParams(); + checkSetBuiltinUniforms(); } return true; @@ -629,68 +635,6 @@ bool Shader::hasVertexAttrib(VertexAttribID attrib) const return builtinAttributes[int(attrib)] != -1; } -bool Shader::hasBuiltinUniform(BuiltinUniform builtin) const -{ - return builtinUniforms[int(builtin)] != -1; -} - -bool Shader::sendBuiltinMatrix(BuiltinUniform builtin, int size, const GLfloat *m, int count) -{ - if (!hasBuiltinUniform(builtin)) - return false; - - GLint location = builtinUniforms[GLint(builtin)]; - - TemporaryAttacher attacher(this); - - switch (size) - { - case 2: - glUniformMatrix2fv(location, count, GL_FALSE, m); - break; - case 3: - glUniformMatrix3fv(location, count, GL_FALSE, m); - break; - case 4: - glUniformMatrix4fv(location, count, GL_FALSE, m); - break; - default: - return false; - } - - return true; -} - -bool Shader::sendBuiltinFloat(BuiltinUniform builtin, int size, const GLfloat *vec, int count) -{ - if (!hasBuiltinUniform(builtin)) - return false; - - GLint location = builtinUniforms[int(builtin)]; - - TemporaryAttacher attacher(this); - - switch (size) - { - case 1: - glUniform1fv(location, count, vec); - break; - case 2: - glUniform2fv(location, count, vec); - break; - case 3: - glUniform3fv(location, count, vec); - break; - case 4: - glUniform4fv(location, count, vec); - break; - default: - return false; - } - - return true; -} - void Shader::checkSetScreenParams() { OpenGL::Viewport view = gl.getViewport(); @@ -720,7 +664,13 @@ void Shader::checkSetScreenParams() params[3] = (GLfloat) view.h; } - sendBuiltinFloat(BUILTIN_SCREEN_SIZE, 4, params, 1); + GLint location = builtinUniforms[BUILTIN_SCREEN_SIZE]; + + if (location >= 0) + { + TemporaryAttacher attacher(this); + glUniform4fv(location, 1, params); + } lastCanvas = Canvas::current; lastViewport = view; @@ -731,11 +681,65 @@ void Shader::checkSetPointSize(float size) if (size == lastPointSize) return; - sendBuiltinFloat(BUILTIN_POINT_SIZE, 1, &size, 1); + GLint location = builtinUniforms[BUILTIN_POINT_SIZE]; + + if (location >= 0) + { + TemporaryAttacher attacher(this); + glUniform1f(location, size); + } lastPointSize = size; } +void Shader::checkSetBuiltinUniforms() +{ + checkSetScreenParams(); + + if (GLAD_ES_VERSION_2_0) + { + checkSetPointSize(gl.getPointSize()); + + const Matrix &curxform = gl.matrices.transform.back(); + const Matrix &curproj = gl.matrices.projection.back(); + + TemporaryAttacher attacher(this); + + bool tpmatrixneedsupdate = false; + + // Only upload the matrices if they've changed. + if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0) + { + GLint location = builtinUniforms[BUILTIN_TRANSFORM_MATRIX]; + if (location >= 0) + glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements()); + + tpmatrixneedsupdate = true; + lastTransformMatrix = curxform; + } + + if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0) + { + GLint location = builtinUniforms[BUILTIN_PROJECTION_MATRIX]; + if (location >= 0) + glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements()); + + tpmatrixneedsupdate = true; + lastProjectionMatrix = curproj; + } + + if (tpmatrixneedsupdate) + { + GLint location = builtinUniforms[BUILTIN_TRANSFORM_PROJECTION_MATRIX]; + if (location >= 0) + { + Matrix tp_matrix(curproj * curxform); + glUniformMatrix4fv(location, 1, GL_FALSE, tp_matrix.getElements()); + } + } + } +} + const std::map &Shader::getBoundRetainables() const { return boundRetainables; diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index e07c47601..b40e2cf52 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -180,11 +180,10 @@ public: * Internal use only. **/ bool hasVertexAttrib(VertexAttribID attrib) const; - bool hasBuiltinUniform(BuiltinUniform builtin) const; - bool sendBuiltinMatrix(BuiltinUniform builtin, int size, const GLfloat *m, int count); - bool sendBuiltinFloat(BuiltinUniform builtin, int size, const GLfloat *m, int count); + void checkSetScreenParams(); void checkSetPointSize(float size); + void checkSetBuiltinUniforms(); const std::map &getBoundRetainables() const; @@ -260,6 +259,9 @@ private: float lastPointSize; + Matrix lastTransformMatrix; + Matrix lastProjectionMatrix; + // Counts total number of textures bound to each texture unit in all shaders static std::vector textureCounters;