Browse Source

Remember shader parameter sources inside individual ShaderPrograms to reduce redundant uniform assignments.

Lasse Öörni 10 years ago
parent
commit
88b05c738f

+ 12 - 18
Source/Urho3D/Graphics/OpenGL/OGLGraphics.cpp

@@ -1231,8 +1231,8 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
                 glBindBufferBase(GL_UNIFORM_BUFFER, i, object);
                 // Calling glBindBufferBase also affects the generic buffer binding point
                 impl_->boundUBO_ = object;
-                shaderParameterSources_[i % MAX_SHADER_PARAMETER_GROUPS] = (const void*)M_MAX_UNSIGNED;
                 currentConstantBuffers_[i] = buffer;
+                ShaderProgram::ClearGlobalParameterSource((ShaderParameterGroup)(i % MAX_SHADER_PARAMETER_GROUPS));
             }
         }
 
@@ -1240,10 +1240,6 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
     }
     #endif
     
-    // If shader has uniforms outside constant buffers, reset all parameter sources now, as those uniforms are per-program
-    if (shaderProgram_ && shaderProgram_->HasIndividualUniforms())
-        ClearParameterSources();
-
     // Store shader combination if shader dumping in progress
     if (shaderPrecache_)
         shaderPrecache_->StoreShaders(vertexShader_, pixelShader_);
@@ -1552,13 +1548,7 @@ void Graphics::SetShaderParameter(StringHash param, const Variant& value)
 
 bool Graphics::NeedParameterUpdate(ShaderParameterGroup group, const void* source)
 {
-    if ((unsigned)(size_t)shaderParameterSources_[group] == M_MAX_UNSIGNED || shaderParameterSources_[group] != source)
-    {
-        shaderParameterSources_[group] = source;
-        return true;
-    }
-    else
-        return false;
+    return shaderProgram_ ? shaderProgram_->NeedParameterUpdate(group, source) : false;
 }
 
 bool Graphics::HasShaderParameter(StringHash param)
@@ -1573,19 +1563,22 @@ bool Graphics::HasTextureUnit(TextureUnit unit)
 
 void Graphics::ClearParameterSource(ShaderParameterGroup group)
 {
-    shaderParameterSources_[group] = (const void*)M_MAX_UNSIGNED;
+    if (shaderProgram_)
+        shaderProgram_->ClearParameterSource(group);
 }
 
 void Graphics::ClearParameterSources()
 {
-    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
-        shaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
+    ShaderProgram::ClearParameterSources();
 }
 
 void Graphics::ClearTransformSources()
 {
-    shaderParameterSources_[SP_CAMERA] = (const void*)M_MAX_UNSIGNED;
-    shaderParameterSources_[SP_OBJECT] = (const void*)M_MAX_UNSIGNED;
+    if (shaderProgram_)
+    {
+        shaderProgram_->ClearParameterSource(SP_CAMERA);
+        shaderProgram_->ClearParameterSource(SP_OBJECT);
+    }
 }
 
 void Graphics::SetTexture(unsigned index, Texture* texture)
@@ -1880,7 +1873,8 @@ void Graphics::SetDepthBias(float constantBias, float slopeScaledBias)
         
         constantDepthBias_ = constantBias;
         slopeScaledDepthBias_ = slopeScaledBias;
-        shaderParameterSources_[SP_CAMERA] = (const void*)M_MAX_UNSIGNED;
+        // Force update of the projection matrix shader parameter
+        ClearParameterSource(SP_CAMERA);
     }
 }
 

+ 0 - 2
Source/Urho3D/Graphics/OpenGL/OGLGraphics.h

@@ -616,8 +616,6 @@ private:
     TextureFilterMode defaultTextureFilterMode_;
     /// Map for additional depth textures, to emulate Direct3D9 ability to mix render texture and backbuffer rendering.
     HashMap<int, SharedPtr<Texture2D> > depthTextures_;
-    /// Remembered shader parameter sources.
-    const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     /// Base directory for shaders.
     String shaderPath_;
     /// File extension for shaders.

+ 79 - 6
Source/Urho3D/Graphics/OpenGL/OGLShaderProgram.cpp

@@ -42,14 +42,19 @@ const char* shaderParameterGroups[] = {
     "custom"
 };
 
+unsigned ShaderProgram::globalFrameNumber = 0;
+const void* ShaderProgram::globalParameterSources[MAX_SHADER_PARAMETER_GROUPS];
+
 ShaderProgram::ShaderProgram(Graphics* graphics, ShaderVariation* vertexShader, ShaderVariation* pixelShader) :
     GPUObject(graphics),
     vertexShader_(vertexShader),
     pixelShader_(pixelShader),
-    individualUniforms_(false)
+    frameNumber_(0)
 {
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         useTextureUnit_[i] = false;
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        parameterSources_[i] = (const void*)M_MAX_UNSIGNED;
 }
 
 ShaderProgram::~ShaderProgram()
@@ -90,7 +95,6 @@ void ShaderProgram::Release()
             useTextureUnit_[i] = false;
         for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
             constantBuffers_[i].Reset();
-        individualUniforms_ = false;
     }
 }
 
@@ -225,7 +229,6 @@ bool ShaderProgram::Link()
     #endif
 
     // Check for shader parameters and texture units
-    individualUniforms_ = false;
     for (int i = 0; i < uniformCount; ++i)
     {
         unsigned type;
@@ -269,9 +272,6 @@ bool ShaderProgram::Link()
             }
             #endif
 
-            if (!newParam.bufferPtr_)
-                individualUniforms_ = true;
-
             if (newParam.location_ >= 0)
                 shaderParameters_[StringHash(paramName)] = newParam;
         }
@@ -330,4 +330,77 @@ const ShaderParameter* ShaderProgram::GetParameter(StringHash param) const
         return 0;
 }
 
+bool ShaderProgram::NeedParameterUpdate(ShaderParameterGroup group, const void* source)
+{
+    // If global framenumber has changed, invalidate all per-program parameter sources now
+    if (globalFrameNumber != frameNumber_)
+    {
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+            parameterSources_[i] = (const void*)M_MAX_UNSIGNED;
+        frameNumber_ = globalFrameNumber;
+    }
+
+    // The shader program may use a mixture of constant buffers and individual uniforms even in the same group
+    #ifndef GL_ES_VERSION_2_0
+    bool useBuffer = constantBuffers_[group].Get() || constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+    bool useIndividual = !constantBuffers_[group].Get() || !constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+    bool needUpdate = false;
+
+    if (useBuffer && globalParameterSources[group] != source)
+    {
+        globalParameterSources[group] = source;
+        needUpdate = true;
+    }
+
+    if (useIndividual && parameterSources_[group] != source)
+    {
+        parameterSources_[group] = source;
+        needUpdate = true;
+    }
+
+    return needUpdate;
+    #else
+    if (parameterSources_[group] != source)
+    {
+        parameterSources_[group] = source;
+        return true;
+    }
+    else
+        return false;
+    #endif
+}
+
+void ShaderProgram::ClearParameterSource(ShaderParameterGroup group)
+{
+    // The shader program may use a mixture of constant buffers and individual uniforms even in the same group
+    #ifndef GL_ES_VERSION_2_0
+    bool useBuffer = constantBuffers_[group].Get() || constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+    bool useIndividual = !constantBuffers_[group].Get() || !constantBuffers_[group + MAX_SHADER_PARAMETER_GROUPS].Get();
+
+    if (useBuffer)
+        globalParameterSources[group] = (const void*)M_MAX_UNSIGNED;
+    if (useIndividual)
+        parameterSources_[group] = (const void*)M_MAX_UNSIGNED;
+    #else
+    parameterSources_[group] = (const void*)M_MAX_UNSIGNED;
+    #endif
+}
+
+void ShaderProgram::ClearParameterSources()
+{
+    ++globalFrameNumber;
+    if (!globalFrameNumber)
+        ++globalFrameNumber;
+
+    #ifndef GL_ES_VERSION_2_0
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        globalParameterSources[i] = (const void*)M_MAX_UNSIGNED;
+    #endif
+}
+
+void ShaderProgram::ClearGlobalParameterSource(ShaderParameterGroup group)
+{
+    globalParameterSources[group] = (const void*)M_MAX_UNSIGNED;
+}
+
 }

+ 19 - 4
Source/Urho3D/Graphics/OpenGL/OGLShaderProgram.h

@@ -80,11 +80,19 @@ public:
     const ShaderParameter* GetParameter(StringHash param) const;
     /// Return linker output.
     const String& GetLinkerOutput() const { return linkerOutput_; }
-    /// Return whether has uniforms outside constant buffers.
-    bool HasIndividualUniforms() const { return individualUniforms_; }
     /// Return all constant buffers.
     const SharedPtr<ConstantBuffer>* GetConstantBuffers() const { return &constantBuffers_[0]; }
     
+    /// Check whether a shader parameter group needs update. Does not actually check whether parameters exist in the shaders.
+    bool NeedParameterUpdate(ShaderParameterGroup group, const void* source);
+    /// Clear a parameter source. Affects only the current shader program if appropriate.
+    void ClearParameterSource(ShaderParameterGroup group);
+
+    /// Clear all parameter sources from all shader programs by incrementing the global parameter source framenumber.
+    static void ClearParameterSources();
+    /// Clear a global parameter source when constant buffers change.
+    static void ClearGlobalParameterSource(ShaderParameterGroup group);
+
 private:
     /// Vertex shader.
     WeakPtr<ShaderVariation> vertexShader_;
@@ -96,10 +104,17 @@ private:
     bool useTextureUnit_[MAX_TEXTURE_UNITS];
     /// Constant buffers by binding index.
     SharedPtr<ConstantBuffer> constantBuffers_[MAX_SHADER_PARAMETER_GROUPS * 2];
+    /// Remembered shader parameter sources for individual uniform mode.
+    const void* parameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     /// Shader link error string.
     String linkerOutput_;
-    /// Uniforms outside buffers flag.
-    bool individualUniforms_;
+    /// Shader parameter source framenumber.
+    unsigned frameNumber_;
+
+    /// Global shader parameter source framenumber.
+    static unsigned globalFrameNumber;
+    /// Remembered global shader parameter sources for constant buffer mode.
+    static const void* globalParameterSources[MAX_SHADER_PARAMETER_GROUPS];
 };
 
 }

+ 0 - 1
Source/Urho3D/Graphics/Renderer.cpp

@@ -655,7 +655,6 @@ void Renderer::Render()
     
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
     graphics_->SetTextureAnisotropy(textureAnisotropy_);
-    graphics_->ClearParameterSources();
     
     // If no views, just clear the screen
     if (views_.Empty())