From 61c595dd6270b9a839ec1bde64a291ed4165aaff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 2 Nov 2015 21:30:01 +0200 Subject: [PATCH] Model Renderer|libgui: Don't try to bind uniforms that don't exist The variables defined in the render block, outside any passes, apply to all passes. However, if a pass uses a different shader, it may not have the same variables. --- .../client/include/render/modelrenderer.h | 18 +++++++++++++ .../apps/client/src/render/modelrenderer.cpp | 12 +++++++++ .../apps/client/src/render/stateanimator.cpp | 27 +++++++++++++++++-- .../libgui/include/de/graphics/glprogram.h | 4 ++- .../sdk/libgui/src/graphics/glprogram.cpp | 13 +++++---- 5 files changed, 64 insertions(+), 10 deletions(-) diff --git a/doomsday/apps/client/include/render/modelrenderer.h b/doomsday/apps/client/include/render/modelrenderer.h index 39962cb0b4..460aaace6c 100644 --- a/doomsday/apps/client/include/render/modelrenderer.h +++ b/doomsday/apps/client/include/render/modelrenderer.h @@ -87,6 +87,24 @@ class ModelRenderer */ void render(vispsprite_t const &pspr); + /** + * Looks up the name of a shader based on a GLProgram instance. + * + * @param program Shader program. Must be a shader program + * created and owned by ModelRenderer. + * @return Name of the shader (in the shader bank). + */ + de::String shaderName(de::GLProgram const &program) const; + + /** + * Looks up the definition of a shader based on a GLProgram instance. + * + * @param program Shader program. Must be a shader program + * created and owned by ModelRenderer. + * @return Shader definition record. + */ + de::Record const &shaderDefinition(de::GLProgram const &program) const; + public: static void initBindings(de::Binder &binder, de::Record &module); diff --git a/doomsday/apps/client/src/render/modelrenderer.cpp b/doomsday/apps/client/src/render/modelrenderer.cpp index ad840ce8aa..634571d765 100644 --- a/doomsday/apps/client/src/render/modelrenderer.cpp +++ b/doomsday/apps/client/src/render/modelrenderer.cpp @@ -70,6 +70,7 @@ DENG2_PIMPL(ModelRenderer) struct Program : public GLProgram { String shaderName; + Record const *def = nullptr; int useCount = 1; ///< Number of models using the program. }; @@ -217,6 +218,7 @@ DENG2_PIMPL(ModelRenderer) std::unique_ptr prog(new Program); prog->shaderName = name; + prog->def = &ClientApp::shaders()[name].valueAsRecord(); // for lookups later LOG_RES_VERBOSE("Loading model shader \"%s\"") << name; @@ -722,6 +724,16 @@ void ModelRenderer::render(vispsprite_t const &pspr) GLState::current().setCull(gl::Back).apply(); } +String ModelRenderer::shaderName(GLProgram const &program) const +{ + return static_cast(program).shaderName; +} + +Record const &ModelRenderer::shaderDefinition(GLProgram const &program) const +{ + return *static_cast(program).def; +} + int ModelRenderer::identifierFromText(String const &text, std::function resolver) // static { diff --git a/doomsday/apps/client/src/render/stateanimator.cpp b/doomsday/apps/client/src/render/stateanimator.cpp index ea28fa8507..a285ca6a83 100644 --- a/doomsday/apps/client/src/render/stateanimator.cpp +++ b/doomsday/apps/client/src/render/stateanimator.cpp @@ -126,6 +126,8 @@ DENG2_PIMPL(StateAnimator) Record names; ///< Local context for scripts, i.e., per-object model state. ModelDrawable::Appearance appearance; + + // Lookups used when drawing or updating state: QHash indexForPassName; QHash passForMaterialVariable; @@ -221,7 +223,7 @@ DENG2_PIMPL(StateAnimator) initVariables(); - // Set up the appearance. + // Set up the model drawing parameters. if(!self.model().passes.isEmpty()) { appearance.drawPasses = &self.model().passes; @@ -258,7 +260,10 @@ DENG2_PIMPL(StateAnimator) } else { - for(int i = 0; i < passCount; ++i) appearance.passMaterial << 0; + for(int i = 0; i < passCount; ++i) + { + appearance.passMaterial << 0; + } } appearance.passMask.resize(passCount); @@ -499,6 +504,18 @@ DENG2_PIMPL(StateAnimator) } } + /** + * Checks if a shader definition has a declaration for a variable. + * + * @param program Shader definition. + * @param uniform Uniform. + * @return @c true, if a variable exists matching @a uniform. + */ + static bool hasDeclaredVariable(Record const &shaderDef, GLUniform const &uniform) + { + return shaderDef.hasMember(String::fromUtf8(uniform.name())); + } + /** * Binds or unbinds uniforms that apply to all rendering passes. * @@ -522,11 +539,17 @@ DENG2_PIMPL(StateAnimator) de::String const &passName, BindOperation operation) const { + auto const &modelRenderer = ClientApp::renderSystem().modelRenderer(); + auto const vars = passVars.constFind(passName); if(vars != passVars.constEnd()) { for(auto i : vars.value()) { + if(!hasDeclaredVariable(modelRenderer.shaderDefinition(program), + *i->uniform)) + continue; + if(operation == Bind) { i->updateUniform(); diff --git a/doomsday/sdk/libgui/include/de/graphics/glprogram.h b/doomsday/sdk/libgui/include/de/graphics/glprogram.h index cdfcca2a46..e287199675 100644 --- a/doomsday/sdk/libgui/include/de/graphics/glprogram.h +++ b/doomsday/sdk/libgui/include/de/graphics/glprogram.h @@ -13,7 +13,7 @@ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy of * the GNU Lesser General Public License along with this program; if not, see: - * http://www.gnu.org/licenses + * http://www.gnu.org/licenses */ #ifndef LIBGUI_GLPROGRAM_H @@ -106,6 +106,8 @@ class LIBGUI_PUBLIC GLProgram : public Asset int glUniformLocation(char const *uniformName) const; + bool glHasUniform(char const *uniformName) const; + /** * Determines which attribute location is used for a particular attribute semantic. * These locations are available after the program has been successfully built diff --git a/doomsday/sdk/libgui/src/graphics/glprogram.cpp b/doomsday/sdk/libgui/src/graphics/glprogram.cpp index 07131e36aa..a98de253d7 100644 --- a/doomsday/sdk/libgui/src/graphics/glprogram.cpp +++ b/doomsday/sdk/libgui/src/graphics/glprogram.cpp @@ -494,13 +494,12 @@ GLuint GLProgram::glName() const int GLProgram::glUniformLocation(char const *uniformName) const { - GLint loc = glGetUniformLocation(d->name, uniformName); - if(loc < 0) - { - LOG_AS("GLProgram"); - LOGDEV_GL_WARNING("Could not find uniform '%s'") << uniformName; - } - return loc; + return glGetUniformLocation(d->name, uniformName); +} + +bool GLProgram::glHasUniform(char const *uniformName) const +{ + return glUniformLocation(uniformName) >= 0; } int GLProgram::attributeLocation(AttribSpec::Semantic semantic) const