Pārlūkot izejas kodu

Simplified shader register mapping code.

Lasse Öörni 14 gadi atpakaļ
vecāks
revīzija
7f09ddcb14

+ 2 - 2
Docs/Reference.dox

@@ -425,11 +425,11 @@ For details on how Direct3D9 and OpenGL rendering differs, see \ref APIDifferenc
 
 \page APIDifferences Differences between Direct3D9 and OpenGL
 
-- On Direct3D9 shader uniform parameters are global. On OpenGL they are shader-specific. To ensure correct operation also on OpenGL, first set the shaders, then query Graphics whether each shader parameter is needed, and set the corresponding parameter if needed. This includes also frame-global parameters, which on Direct3D9 need to be set only once per frame.
+- On Direct3D9 shader uniform parameters are global. On OpenGL they are shader-specific. To ensure correct operation also on OpenGL, first set the shaders, then query Graphics whether each shader parameter is needed, and set the corresponding parameter if needed. This includes also frame-global parameters, which on Direct3D9 need to be set only once per frame, if the uniform register assignments are fixed.
 
 - On OpenGL vertex attribute bindings also depend on the currently set shaders. To ensure correct operation, first set the shaders, then the vertex buffers.
 
-- On Direct3D9 the depth stencil surface can be equal size or larger than the color render target. On OpenGL the sizes must always match. Furthermore, OpenGL can not use the system depth stencil buffer when rendering to a texture. To overcome these limitations, Graphics will create correctly sized depth stencil buffers on demand whenever a texture is set as a color render target, and a null depth stencil is specified.
+- On Direct3D9 the depth stencil surface can be equal or larger in size than the color render target. On OpenGL the sizes must always match. Furthermore, OpenGL can not use the system depth stencil buffer when rendering to a texture. To overcome these limitations, Graphics will create correctly sized depth stencil buffers on demand whenever a texture is set as a color render target, and a null depth stencil is specified.
 
 - On Direct3D9 setting the first color render target resets the viewport dimensions. On OpenGL there is no such mechanism, but as sometimes (for example in shadow rendering) only a depth stencil buffer is set for rendering, Graphics will instead reset the viewport when the depth stencil buffer is set. To ensure correct operation on both APIs, first set the render targets, then the depth stencil buffer, and finally the viewport, if you need it to be less than the whole render target.
 

+ 88 - 166
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -866,6 +866,17 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
 {
     if (vs != vertexShader_)
     {
+        // Clear all previous register mappings. If shader parameters overlap, also clear remembered sources
+        for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
+        {
+            if (i->second_.type_ == VS)
+            {
+                i->second_.register_ = M_MAX_UNSIGNED;
+                if (shaderParametersOverlap_)
+                    i->second_.lastSource_ = (void*)M_MAX_UNSIGNED;
+            }
+        }
+        
         // Create the shader now if not yet created. If already attempted, do not retry
         if (vs && !vs->IsCreated())
         {
@@ -887,7 +898,18 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
         }
         
         if (vs && vs->GetShaderType() == VS)
+        {
             impl_->device_->SetVertexShader((IDirect3DVertexShader9*)vs->GetGPUObject());
+            
+            // Update the parameter-to-register mappings
+            const HashMap<StringHash, ShaderParameter>& parameters = vs->GetParameters();
+            for (HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+            {
+                HashMap<StringHash, ShaderParameter>::Iterator j = shaderParameters_.Find(i->first_);
+                if (j != parameters.End())
+                    j->second_.register_ = i->second_.register_;
+            }
+        }
         else
         {
             impl_->device_->SetVertexShader(0);
@@ -899,6 +921,16 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
     
     if (ps != pixelShader_)
     {
+        for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
+        {
+            if (i->second_.type_ == PS)
+            {
+                i->second_.register_ = M_MAX_UNSIGNED;
+                if (shaderParametersOverlap_)
+                    i->second_.lastSource_ = (void*)M_MAX_UNSIGNED;
+            }
+        }
+        
         if (ps && !ps->IsCreated())
         {
             if (!ps->IsFailed())
@@ -919,7 +951,17 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
         }
         
         if (ps && ps->GetShaderType() == PS)
+        {
             impl_->device_->SetPixelShader((IDirect3DPixelShader9*)ps->GetGPUObject());
+            
+            const HashMap<StringHash, ShaderParameter>& parameters = ps->GetParameters();
+            for (HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+            {
+                HashMap<StringHash, ShaderParameter>::Iterator j = shaderParameters_.Find(i->first_);
+                if (j != parameters.End())
+                    j->second_.register_ = i->second_.register_;
+            }
+        }
         else
         {
             impl_->device_->SetPixelShader(0);
@@ -933,23 +975,19 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
 void Graphics::SetShaderParameter(StringHash param, const float* data, unsigned count)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
-    unsigned reg = GetParameterRegister(i, count / 4);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, data, count / 4);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, data, count / 4);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, data, count / 4);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, data, count / 4);
 }
 
 void Graphics::SetShaderParameter(StringHash param, float value)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
     float data[4];
@@ -959,36 +997,28 @@ void Graphics::SetShaderParameter(StringHash param, float value)
     data[2] = 0.0f;
     data[3] = 0.0f;
     
-    unsigned reg = GetParameterRegister(i, 1);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, &data[0], 1);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, &data[0], 1);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, &data[0], 1);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, &data[0], 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Color& color)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
-    unsigned reg = GetParameterRegister(i, 1);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, color.GetData(), 1);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, color.GetData(), 1);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, color.GetData(), 1);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, color.GetData(), 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
     float data[12];
@@ -1006,20 +1036,16 @@ void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
     data[10] = matrix.m22_;
     data[11] = 0.0f;
     
-    unsigned reg = GetParameterRegister(i, 3);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, &data[0], 3);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, &data[0], 3);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, &data[0], 3);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, &data[0], 3);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Vector3& vector)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
     float data[4];
@@ -1029,62 +1055,46 @@ void Graphics::SetShaderParameter(StringHash param, const Vector3& vector)
     data[2] = vector.z_;
     data[3] = 0.0f;
     
-    unsigned reg = GetParameterRegister(i, 1);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, &data[0], 1);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, &data[0], 1);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, &data[0], 1);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, &data[0], 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix4& matrix)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
-    unsigned reg = GetParameterRegister(i, 4);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, matrix.GetData(), 4);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, matrix.GetData(), 4);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, matrix.GetData(), 4);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, matrix.GetData(), 4);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Vector4& vector)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
-    unsigned reg = GetParameterRegister(i, 1);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, vector.GetData(), 1);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, vector.GetData(), 1);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, vector.GetData(), 1);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, vector.GetData(), 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix3x4& matrix)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return;
     
-    unsigned reg = GetParameterRegister(i, 3);
-    if (reg < MAX_CONSTANT_REGISTERS)
-    {
-        if (i->second_.type_ == VS)
-            impl_->device_->SetVertexShaderConstantF(reg, matrix.GetData(), 3);
-        else
-            impl_->device_->SetPixelShaderConstantF(reg, matrix.GetData(), 3);
-    }
+    if (i->second_.type_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.register_, matrix.GetData(), 3);
+    else
+        impl_->device_->SetPixelShaderConstantF(i->second_.register_, matrix.GetData(), 3);
 }
 
 void Graphics::RegisterShaderParameter(StringHash param, const ShaderParameter& definition)
@@ -1113,7 +1123,7 @@ void Graphics::RegisterShaderParameter(StringHash param, const ShaderParameter&
             i->second_.regCount_ = definition.regCount_;
     }
     
-    // Check if parameter overlaps any other parameters, and activate overlapping check in that case
+    // Check if parameter overlaps any other parameters
     if (definition.type_ == VS)
     {
         for (unsigned j = definition.register_; j < definition.register_ + definition.regCount_; ++j)
@@ -1145,48 +1155,16 @@ void Graphics::RegisterShaderParameter(StringHash param, const ShaderParameter&
 bool Graphics::NeedParameterUpdate(StringHash param, const void* source)
 {
     HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End())
+    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
         return false;
     
-    ShaderParameter& globalParam = i->second_;
-    if (globalParam.type_ == VS)
+    if (i->second_.lastSource_ != source)
     {
-        if (!vertexShader_)
-            return false;
-        
-        const ShaderParameter& localParam = vertexShader_->GetParameter(param);
-        // Check that parameter exists
-        if (!localParam.regCount_)
-            return false;
-        
-        // If source is different, or the current register does not match, need to update
-        if (globalParam.lastSource_ != source || globalParam.register_ != localParam.register_)
-        {
-            globalParam.lastSource_ = source;
-            return true;
-        }
-        else
-            return false;
+        i->second_.lastSource_ = source;
+        return true;
     }
     else
-    {
-        if (!pixelShader_)
-            return false;
-        
-        const ShaderParameter& localParam = pixelShader_->GetParameter(param);
-        if (!localParam.regCount_)
-            return false;
-        
-        if (globalParam.lastSource_ != source || globalParam.register_ != localParam.register_)
-        {
-            globalParam.lastSource_ = source;
-            return true;
-        }
-        else
-            return false;
-    }
-    
-    return false;
+        return false;
 }
 
 bool Graphics::NeedTextureUnit(TextureUnit unit)
@@ -2360,62 +2338,6 @@ void Graphics::SetTextureUnitMappings()
     textureUnits_["IndirectionCubeMap"] = TU_INDIRECTION;
 }
 
-unsigned Graphics::GetParameterRegister(HashMap<StringHash, ShaderParameter>::Iterator i, unsigned regCount)
-{
-    ShaderParameter& globalParam = i->second_;
-    
-    if (globalParam.type_ == VS)
-    {
-        if (!vertexShader_)
-            return M_MAX_UNSIGNED;
-        
-        const ShaderParameter& localParam = vertexShader_->GetParameter(i->first_);
-        // Check that parameter exists
-        if (!localParam.regCount_)
-            return M_MAX_UNSIGNED;
-        
-        globalParam.register_ = localParam.register_;
-        
-        // Check if this parameter overwrites other parameters, and clear their register assignments
-        if (shaderParametersOverlap_)
-        {
-            for (HashMap<StringHash, ShaderParameter>::Iterator j = shaderParameters_.Begin(); j != shaderParameters_.End(); ++j)
-            {
-                ShaderParameter& otherGlobalParam = j->second_;
-                if (j != i && otherGlobalParam.type_ == VS && otherGlobalParam.register_ < localParam.register_ + regCount &&
-                    localParam.register_ < otherGlobalParam.register_ + otherGlobalParam.regCount_)
-                    otherGlobalParam.register_ = M_MAX_UNSIGNED;
-            }
-        }
-        
-        return globalParam.register_;
-    }
-    else
-    {
-        if (!pixelShader_)
-            return M_MAX_UNSIGNED;
-        
-        const ShaderParameter& localParam = pixelShader_->GetParameter(i->first_);
-        if (!localParam.regCount_)
-            return M_MAX_UNSIGNED;
-        
-        globalParam.register_ = localParam.register_;
-        
-        if (shaderParametersOverlap_)
-        {
-            for (HashMap<StringHash, ShaderParameter>::Iterator j = shaderParameters_.Begin(); j != shaderParameters_.End(); ++j)
-            {
-                ShaderParameter& otherGlobalParam = j->second_;
-                if (j != i && otherGlobalParam.type_ == PS && otherGlobalParam.register_ < localParam.register_ + regCount &&
-                    localParam.register_ < otherGlobalParam.register_ + otherGlobalParam.regCount_)
-                    otherGlobalParam.register_ = M_MAX_UNSIGNED;
-            }
-        }
-        
-        return globalParam.register_;
-    }
-}
-
 void Graphics::HandleWindowMessage(StringHash eventType, VariantMap& eventData)
 {
     using namespace WindowMessage;

+ 0 - 2
Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -352,8 +352,6 @@ private:
     void ResetCachedState();
     /// Initialize texture unit mappings.
     void SetTextureUnitMappings();
-    /// Return the hardware register index of a shader parameter in the current shader and update the register assignments.
-    unsigned GetParameterRegister(HashMap<StringHash, ShaderParameter>::Iterator i, unsigned regCount);
     /// Handle operating system window message.
     void HandleWindowMessage(StringHash eventType, VariantMap& eventData);
 

+ 0 - 8
Engine/Graphics/Direct3D9/D3D9ShaderVariation.cpp

@@ -31,8 +31,6 @@
 
 #include "DebugNew.h"
 
-static ShaderParameter emptyShaderParameter;
-
 ShaderVariation::ShaderVariation(Shader* shader, ShaderType type, bool isSM3) :
     GPUObject(shader->GetSubsystem<Graphics>()),
     shaderType_(type),
@@ -141,9 +139,3 @@ bool ShaderVariation::IsCreated() const
 {
     return object_ != 0;
 }
-
-const ShaderParameter& ShaderVariation::GetParameter(StringHash param) const
-{
-    HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters_.Find(param);
-    return i != parameters_.End() ? i->second_ : emptyShaderParameter;
-}

+ 2 - 2
Engine/Graphics/Direct3D9/D3D9ShaderVariation.h

@@ -103,8 +103,8 @@ public:
     bool HasParameter(StringHash param) const { return parameters_.Contains(param); }
     /// Return whether uses a texture unit (only for pixel shaders.)
     bool HasTextureUnit(TextureUnit unit) const { return useTextureUnit_[unit]; }
-    /// Return the parameter definition.
-    const ShaderParameter& GetParameter(StringHash param) const;
+    /// Return all parameter definitions.
+    const HashMap<StringHash, ShaderParameter>& GetParameters() const { return parameters_; }
     
 private:
     /// Shader type.