Browse Source

Divided shader parameters into groups for less checking of whether individual parameters need update.

Lasse Öörni 13 years ago
parent
commit
6f55d9c24e

+ 157 - 218
Engine/Graphics/Batch.cpp

@@ -185,15 +185,12 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
     // Set shaders
     graphics->SetShaders(vertexShader_, pixelShader_);
     
-    // Set viewport and camera shader parameters
-    if (graphics->NeedParameterUpdate(VSP_CAMERAPOS, camera_))
+    // Set camera shader parameters
+    void* cameraSource = (void*)(overrideView_ ? (unsigned)camera_ + 4 : (unsigned)camera_);
+    if (graphics->NeedParameterUpdate(SPG_CAMERA, cameraSource))
+    {
         graphics->SetShaderParameter(VSP_CAMERAPOS, cameraNode->GetWorldPosition());
-    
-    if (graphics->NeedParameterUpdate(VSP_CAMERAROT, camera_))
         graphics->SetShaderParameter(VSP_CAMERAROT, cameraNode->GetWorldTransform().RotationMatrix());
-    
-    if (graphics->NeedParameterUpdate(VSP_DEPTHMODE, camera_))
-    {
         Vector4 depthMode = Vector4::ZERO;
         if (camera_->IsOrthographic())
         {
@@ -209,24 +206,35 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             depthMode.w_ = 1.0f / camera_->GetFarClip();
         
         graphics->SetShaderParameter(VSP_DEPTHMODE, depthMode);
-    }
-    
-    if (graphics->NeedParameterUpdate(VSP_FRUSTUMSIZE, camera_))
-    {
+        
         Vector3 nearVector, farVector;
         camera_->GetFrustumSize(nearVector, farVector);
         Vector4 viewportParams(farVector.x_, farVector.y_, farVector.z_, 0.0f);
-        
         graphics->SetShaderParameter(VSP_FRUSTUMSIZE, viewportParams);
+        
+        if (overrideView_)
+            graphics->SetShaderParameter(VSP_VIEWPROJ, camera_->GetProjection());
+        else
+            graphics->SetShaderParameter(VSP_VIEWPROJ, camera_->GetProjection() * camera_->GetInverseWorldTransform());
+        
+        graphics->SetShaderParameter(VSP_VIEWRIGHTVECTOR, camera_->GetRightVector());
+        graphics->SetShaderParameter(VSP_VIEWUPVECTOR, camera_->GetUpVector());
+        
+        float farClip = camera_->GetFarClip();
+        float nearClip = camera_->GetNearClip();
+        Vector4 depthReconstruct(farClip / (farClip - nearClip), -nearClip / (farClip - nearClip), 0.0f, 0.0f);
+        graphics->SetShaderParameter(PSP_DEPTHRECONSTRUCT, depthReconstruct);
     }
     
+    // Set viewport shader parameters
     IntVector2 rtSize = graphics->GetRenderTargetDimensions();
     IntRect viewport = graphics->GetViewport();
     unsigned viewportHash = (viewport.left_) | (viewport.top_ << 8) | (viewport.right_ << 16) | (viewport.bottom_ << 24);
-    float rtWidth = (float)rtSize.x_;
-    float rtHeight = (float)rtSize.y_;
-    if (graphics->NeedParameterUpdate(VSP_GBUFFEROFFSETS, (const void*)viewportHash))
+    
+    if (graphics->NeedParameterUpdate(SPG_VIEWPORT, (void*)viewportHash))
     {
+        float rtWidth = (float)rtSize.x_;
+        float rtHeight = (float)rtSize.y_;
         float widthRange = 0.5f * (viewport.right_ - viewport.left_) / rtWidth;
         float heightRange = 0.5f * (viewport.bottom_ - viewport.top_) / rtHeight;
         
@@ -237,96 +245,52 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         Vector4 bufferUVOffset((0.5f + (float)viewport.left_) / rtWidth + widthRange,
             (0.5f + (float)viewport.top_) / rtHeight + heightRange, widthRange, heightRange);
         #endif
-        
         graphics->SetShaderParameter(VSP_GBUFFEROFFSETS, bufferUVOffset);
-    }
-    if (graphics->NeedParameterUpdate(PSP_GBUFFERINVSIZE, (const void*)viewportHash))
-    {
+        
         float sizeX = 1.0f / rtWidth;
         float sizeY = 1.0f / rtHeight;
         graphics->SetShaderParameter(PSP_GBUFFERINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
     }
     
-    if (overrideView_)
-    {
-        if (graphics->NeedParameterUpdate(VSP_VIEWPROJ, ((unsigned char*)camera_) + 4))
-            graphics->SetShaderParameter(VSP_VIEWPROJ, camera_->GetProjection());
-    }
-    else
-    {
-        if (graphics->NeedParameterUpdate(VSP_VIEWPROJ, camera_))
-            graphics->SetShaderParameter(VSP_VIEWPROJ, camera_->GetProjection() *
-                camera_->GetInverseWorldTransform());
-    }
-    
-    if (graphics->NeedParameterUpdate(VSP_VIEWRIGHTVECTOR, camera_))
-        graphics->SetShaderParameter(VSP_VIEWRIGHTVECTOR, camera_->GetRightVector());
-    
-    if (graphics->NeedParameterUpdate(VSP_VIEWUPVECTOR, camera_))
-        graphics->SetShaderParameter(VSP_VIEWUPVECTOR, camera_->GetUpVector());
-    
     // Set model transform
-    if (setModelTransform && graphics->NeedParameterUpdate(VSP_MODEL, worldTransform_))
+    if (setModelTransform && graphics->NeedParameterUpdate(SPG_OBJECTTRANSFORM, worldTransform_))
         graphics->SetShaderParameter(VSP_MODEL, *worldTransform_);
     
     // Set skinning transforms
-    if (shaderData_ && shaderDataSize_)
-    {
-        if (graphics->NeedParameterUpdate(VSP_SKINMATRICES, shaderData_))
-            graphics->SetShaderParameter(VSP_SKINMATRICES, shaderData_, shaderDataSize_);
-    }
+    if (shaderData_ && shaderDataSize_ && graphics->NeedParameterUpdate(SPG_OBJECTDATA, shaderData_))
+        graphics->SetShaderParameter(VSP_SKINMATRICES, shaderData_, shaderDataSize_);
     
     // Set zone-related shader parameters
-    if (zone_)
+    BlendMode blend = graphics->GetBlendMode();
+    Zone* fogColorZone = (blend == BLEND_ADD || blend == BLEND_ADDALPHA) ? renderer->GetDefaultZone() : zone_;
+    unsigned zoneHash = (unsigned)zone_ + (unsigned)fogColorZone;
+    if (zone_ && graphics->NeedParameterUpdate(SPG_ZONE, (void*)zoneHash))
     {
-        if (graphics->NeedParameterUpdate(VSP_AMBIENTSTARTCOLOR, zone_))
-            graphics->SetShaderParameter(VSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor());
-        if (graphics->NeedParameterUpdate(VSP_AMBIENTENDCOLOR, zone_))
-            graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
+        graphics->SetShaderParameter(VSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor());
+        graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
         
-        if (graphics->NeedParameterUpdate(VSP_ZONE, zone_))
-        {
-            const BoundingBox& box = zone_->GetBoundingBox();
-            Vector3 boxSize = box.Size();
-            Matrix3x4 adjust(Matrix3x4::IDENTITY);
-            adjust.SetScale(Vector3(1.0f / boxSize.x_, 1.0f / boxSize.y_, 1.0f / boxSize.z_));
-            adjust.SetTranslation(Vector3(0.5f, 0.5f, 0.5f));
-            Matrix3x4 zoneTransform = adjust * zone_->GetInverseWorldTransform();
-            
-            graphics->SetShaderParameter(VSP_ZONE, zoneTransform);
-        }
+        const BoundingBox& box = zone_->GetBoundingBox();
+        Vector3 boxSize = box.Size();
+        Matrix3x4 adjust(Matrix3x4::IDENTITY);
+        adjust.SetScale(Vector3(1.0f / boxSize.x_, 1.0f / boxSize.y_, 1.0f / boxSize.z_));
+        adjust.SetTranslation(Vector3(0.5f, 0.5f, 0.5f));
+        Matrix3x4 zoneTransform = adjust * zone_->GetInverseWorldTransform();
+        graphics->SetShaderParameter(VSP_ZONE, zoneTransform);
         
-        if (graphics->NeedParameterUpdate(PSP_AMBIENTCOLOR, zone_))
-            graphics->SetShaderParameter(PSP_AMBIENTCOLOR, zone_->GetAmbientColor());
+        graphics->SetShaderParameter(PSP_AMBIENTCOLOR, zone_->GetAmbientColor());
         
         // If the pass is additive, override fog color to black so that shaders do not need a separate additive path
-        BlendMode blend = pass_->GetBlendMode();
-        Zone* fogColorZone = (blend == BLEND_ADD || blend == BLEND_ADDALPHA) ? renderer->GetDefaultZone() : zone_;
-        if (graphics->NeedParameterUpdate(PSP_FOGCOLOR, fogColorZone))
-            graphics->SetShaderParameter(PSP_FOGCOLOR, fogColorZone->GetFogColor());
+        graphics->SetShaderParameter(PSP_FOGCOLOR, fogColorZone->GetFogColor());
         
-        if (graphics->NeedParameterUpdate(PSP_FOGPARAMS, zone_))
-        {
-            float farClip = camera_->GetFarClip();
-            float nearClip = camera_->GetNearClip();
-            float fogStart = Min(zone_->GetFogStart(), farClip);
-            float fogEnd = Min(zone_->GetFogEnd(), farClip);
-            if (fogStart >= fogEnd * (1.0f - M_LARGE_EPSILON))
-                fogStart = fogEnd * (1.0f - M_LARGE_EPSILON);
-            float fogRange = Max(fogEnd - fogStart, M_EPSILON);
-            Vector4 fogParams(fogEnd / farClip, farClip / fogRange, 0.0f, 0.0f);
-            
-            graphics->SetShaderParameter(PSP_FOGPARAMS, fogParams);
-        }
-    }
-    
-    if (graphics->NeedParameterUpdate(PSP_DEPTHRECONSTRUCT, camera_))
-    {
         float farClip = camera_->GetFarClip();
         float nearClip = camera_->GetNearClip();
-        Vector4 depthReconstruct(farClip / (farClip - nearClip), -nearClip / (farClip - nearClip), 0.0f, 0.0f);
-        
-        graphics->SetShaderParameter(PSP_DEPTHRECONSTRUCT, depthReconstruct);
+        float fogStart = Min(zone_->GetFogStart(), farClip);
+        float fogEnd = Min(zone_->GetFogEnd(), farClip);
+        if (fogStart >= fogEnd * (1.0f - M_LARGE_EPSILON))
+            fogStart = fogEnd * (1.0f - M_LARGE_EPSILON);
+        float fogRange = Max(fogEnd - fogStart, M_EPSILON);
+        Vector4 fogParams(fogEnd / farClip, farClip / fogRange, 0.0f, 0.0f);
+        graphics->SetShaderParameter(PSP_FOGPARAMS, fogParams);
     }
     
     // Set light-related shader parameters
@@ -337,7 +301,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         light = lightQueue_->light_;
         shadowMap = lightQueue_->shadowMap_;
         
-        if (graphics->NeedParameterUpdate(VSP_VERTEXLIGHTS, lightQueue_))
+        if (graphics->NeedParameterUpdate(SPG_VERTEXLIGHTS, lightQueue_) && vertexShader_->HasParameter(VSP_VERTEXLIGHTS))
         {
             Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
             const PODVector<Light*>& lights = lightQueue_->vertexLights_;
@@ -387,135 +351,118 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             if (lights.Size())
                 graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].Data(), lights.Size() * 3 * 4);
         }
+    }
+    
+    if (light && graphics->NeedParameterUpdate(SPG_LIGHT, light))
+    {
+        Node* lightNode = light->GetNode();
+        
+        graphics->SetShaderParameter(VSP_LIGHTDIR, lightNode->GetWorldRotation() * Vector3::BACK);
         
-        if (light)
+        float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
+        graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition(), atten));
+        
+        if (vertexShader_->HasParameter(VSP_LIGHTMATRICES))
         {
-            Node* lightNode = light->GetNode();
-            
-            if (graphics->NeedParameterUpdate(VSP_LIGHTDIR, light))
-                graphics->SetShaderParameter(VSP_LIGHTDIR, lightNode->GetWorldRotation() * Vector3::BACK);
-            
-            if (graphics->NeedParameterUpdate(VSP_LIGHTPOS, light))
-            {
-                float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
-                graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition(), atten));
-            }
-            
-            if (graphics->NeedParameterUpdate(VSP_LIGHTMATRICES, light))
+            switch (light->GetLightType())
             {
-                switch (light->GetLightType())
+            case LIGHT_DIRECTIONAL:
                 {
-                case LIGHT_DIRECTIONAL:
-                    {
-                        Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
-                        unsigned numSplits = lightQueue_->shadowSplits_.Size();
-                        for (unsigned i = 0; i < numSplits; ++i)
-                            CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
-                        
-                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
-                    }
-                    break;
+                    Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
+                    unsigned numSplits = lightQueue_->shadowSplits_.Size();
+                    for (unsigned i = 0; i < numSplits; ++i)
+                        CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
                     
-                case LIGHT_SPOT:
-                    {
-                        Matrix4 shadowMatrices[2];
-                        
-                        CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
-                        bool isShadowed = shadowMap && graphics->NeedTextureUnit(TU_SHADOWMAP);
-                        if (isShadowed)
-                            CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
-                        
-                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
-                    }
-                    break;
-                    
-                case LIGHT_POINT:
-                    {
-                        Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
-                        // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
-                        // the next parameter
-                        #ifdef USE_OPENGL
-                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 16);
-                        #else
-                        graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 12);
-                        #endif
-                    }
-                    break;
+                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
                 }
-            }
-            
-            if (graphics->NeedParameterUpdate(PSP_LIGHTCOLOR, light))
-            {
-                float fade = 1.0f;
-                float fadeEnd = light->GetDrawDistance();
-                float fadeStart = light->GetFadeDistance();
+                break;
                 
-                // Do fade calculation for light if both fade & draw distance defined
-                if (light->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
-                    fade = Min(1.0f - (light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
+            case LIGHT_SPOT:
+                {
+                    Matrix4 shadowMatrices[2];
+                    
+                    CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
+                    bool isShadowed = shadowMap && graphics->NeedTextureUnit(TU_SHADOWMAP);
+                    if (isShadowed)
+                        CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
+                    
+                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
+                }
+                break;
                 
-                graphics->SetShaderParameter(PSP_LIGHTCOLOR, Vector4(light->GetColor().RGBValues(),
-                    light->GetSpecularIntensity()) * fade);
-            }
-            
-            if (graphics->NeedParameterUpdate(PSP_LIGHTDIR, light))
-                graphics->SetShaderParameter(PSP_LIGHTDIR, lightNode->GetWorldRotation() * Vector3::BACK);
-            
-            if (graphics->NeedParameterUpdate(PSP_LIGHTPOS, light))
-            {
-                float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
-                graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition() -
-                    cameraNode->GetWorldPosition(), atten));
+            case LIGHT_POINT:
+                {
+                    Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
+                    // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
+                    // the next parameter
+                    #ifdef USE_OPENGL
+                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 16);
+                    #else
+                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 12);
+                    #endif
+                }
+                break;
             }
-            
-            if (graphics->NeedParameterUpdate(PSP_LIGHTMATRICES, light))
+        }
+        
+        float fade = 1.0f;
+        float fadeEnd = light->GetDrawDistance();
+        float fadeStart = light->GetFadeDistance();
+        
+        // Do fade calculation for light if both fade & draw distance defined
+        if (light->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
+            fade = Min(1.0f - (light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
+        
+        graphics->SetShaderParameter(PSP_LIGHTCOLOR, Vector4(light->GetColor().RGBValues(), light->GetSpecularIntensity()) * fade);
+        graphics->SetShaderParameter(PSP_LIGHTDIR, lightNode->GetWorldRotation() * Vector3::BACK);
+        graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition() - cameraNode->GetWorldPosition(), atten));
+        
+        if (pixelShader_->HasParameter(PSP_LIGHTMATRICES))
+        {
+            switch (light->GetLightType())
             {
-                switch (light->GetLightType())
+            case LIGHT_DIRECTIONAL:
+                {
+                    Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
+                    unsigned numSplits = lightQueue_->shadowSplits_.Size();
+                    for (unsigned i = 0; i < numSplits; ++i)
+                        CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, cameraNode->GetWorldPosition());
+                    
+                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
+                }
+                break;
+                
+            case LIGHT_SPOT:
                 {
-                case LIGHT_DIRECTIONAL:
-                    {
-                        Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
-                        unsigned numSplits = lightQueue_->shadowSplits_.Size();
-                        for (unsigned i = 0; i < numSplits; ++i)
-                            CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, cameraNode->GetWorldPosition());
-                        
-                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
-                    }
-                    break;
+                    Matrix4 shadowMatrices[2];
                     
-                case LIGHT_SPOT:
-                    {
-                        Matrix4 shadowMatrices[2];
-                        
-                        CalculateSpotMatrix(shadowMatrices[0], light, cameraNode->GetWorldPosition());
-                        bool isShadowed = lightQueue_->shadowMap_ != 0;
-                        if (isShadowed)
-                            CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, cameraNode->GetWorldPosition());
-                        
-                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
-                    }
-                    break;
+                    CalculateSpotMatrix(shadowMatrices[0], light, cameraNode->GetWorldPosition());
+                    bool isShadowed = lightQueue_->shadowMap_ != 0;
+                    if (isShadowed)
+                        CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, cameraNode->GetWorldPosition());
                     
-                case LIGHT_POINT:
-                    {
-                        Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
-                        // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
-                        // the next parameter
-                        #ifdef USE_OPENGL
-                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 16);
-                        #else
-                        graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 12);
-                        #endif
-                    }
-                    break;
+                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
+                }
+                break;
+                
+            case LIGHT_POINT:
+                {
+                    Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
+                    // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
+                    // the next parameter
+                    #ifdef USE_OPENGL
+                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 16);
+                    #else
+                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 12);
+                    #endif
                 }
+                break;
             }
         }
         
         // Set shadow mapping shader parameters
         if (shadowMap)
         {
-            if (graphics->NeedParameterUpdate(PSP_SHADOWCUBEADJUST, light))
             {
                 unsigned faceWidth = shadowMap->GetWidth() / 2;
                 unsigned faceHeight = shadowMap->GetHeight() / 3;
@@ -541,7 +488,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                 graphics->SetShaderParameter(PSP_SHADOWCUBEADJUST, Vector4(mulX, mulY, addX, addY));
             }
             
-            if (graphics->NeedParameterUpdate(PSP_SHADOWDEPTHFADE, light))
             {
                 Camera* shadowCamera = lightQueue_->shadowSplits_[0].shadowCamera_;
                 float nearClip = shadowCamera->GetNearClip();
@@ -559,7 +505,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                 graphics->SetShaderParameter(PSP_SHADOWDEPTHFADE, Vector4(q, r, fadeStart, 1.0f / fadeRange));
             }
             
-            if (graphics->NeedParameterUpdate(PSP_SHADOWINTENSITY, light))
             {
                 float intensity = light->GetShadowIntensity();
                 float fadeStart = light->GetShadowFadeDistance();
@@ -571,35 +516,29 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                 graphics->SetShaderParameter(PSP_SHADOWINTENSITY, Vector4(pcfValues / samples, intensity, 0.0f, 0.0f));
             }
             
-            if (graphics->NeedParameterUpdate(PSP_SHADOWMAPINVSIZE, shadowMap))
-            {
-                float sizeX = 1.0f / (float)shadowMap->GetWidth();
-                float sizeY = 1.0f / (float)shadowMap->GetHeight();
-                graphics->SetShaderParameter(PSP_SHADOWMAPINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
-            }
+            float sizeX = 1.0f / (float)shadowMap->GetWidth();
+            float sizeY = 1.0f / (float)shadowMap->GetHeight();
+            graphics->SetShaderParameter(PSP_SHADOWMAPINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
             
-            if (graphics->NeedParameterUpdate(PSP_SHADOWSPLITS, light))
-            {
-                Vector4 lightSplits(M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE);
-                if (lightQueue_->shadowSplits_.Size() > 1)
-                    lightSplits.x_ = lightQueue_->shadowSplits_[0].farSplit_ / camera_->GetFarClip();
-                if (lightQueue_->shadowSplits_.Size() > 2)
-                    lightSplits.y_ = lightQueue_->shadowSplits_[1].farSplit_ / camera_->GetFarClip();
-                if (lightQueue_->shadowSplits_.Size() > 3)
-                    lightSplits.z_ = lightQueue_->shadowSplits_[2].farSplit_ / camera_->GetFarClip();
-                
-                graphics->SetShaderParameter(PSP_SHADOWSPLITS, lightSplits);
-            }
+            Vector4 lightSplits(M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE);
+            if (lightQueue_->shadowSplits_.Size() > 1)
+                lightSplits.x_ = lightQueue_->shadowSplits_[0].farSplit_ / camera_->GetFarClip();
+            if (lightQueue_->shadowSplits_.Size() > 2)
+                lightSplits.y_ = lightQueue_->shadowSplits_[1].farSplit_ / camera_->GetFarClip();
+            if (lightQueue_->shadowSplits_.Size() > 3)
+                lightSplits.z_ = lightQueue_->shadowSplits_[2].farSplit_ / camera_->GetFarClip();
+            
+            graphics->SetShaderParameter(PSP_SHADOWSPLITS, lightSplits);
         }
     }
     
     // Set material-specific shader parameters and textures
     if (material_)
     {
-        const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
-        for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+        if (graphics->NeedParameterUpdate(SPG_MATERIAL, material_))
         {
-            if (graphics->NeedParameterUpdate(i->first_, material_))
+            const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
+            for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
                 graphics->SetShaderParameter(i->first_, i->second_.value_);
         }
         

+ 14 - 19
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -862,16 +862,18 @@ void Graphics::SetIndexBuffer(IndexBuffer* buffer)
 
 void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
 {
+    if (vs == vertexShader_ && ps == pixelShader_)
+        return;
+    
+    ClearParameterSources();
+    
     if (vs != vertexShader_)
     {
         // Clear all previous vertex shader register mappings
         for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
         {
             if (i->second_.type_ == VS)
-            {
                 i->second_.register_ = M_MAX_UNSIGNED;
-                i->second_.lastSource_ = (void*)M_MAX_UNSIGNED;
-            }
         }
         
         // Create the shader now if not yet created. If already attempted, do not retry
@@ -917,10 +919,7 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
         for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
         {
             if (i->second_.type_ == PS)
-            {
                 i->second_.register_ = M_MAX_UNSIGNED;
-                i->second_.lastSource_ = (void*)M_MAX_UNSIGNED;
-            }
         }
         
         if (ps && !ps->IsCreated())
@@ -1110,15 +1109,11 @@ void Graphics::RegisterShaderParameter(StringHash param, const ShaderParameter&
     }
 }
 
-bool Graphics::NeedParameterUpdate(StringHash param, const void* source)
+bool Graphics::NeedParameterUpdate(ShaderParameterGroup group, const void* source)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
-        return false;
-    
-    if (i->second_.lastSource_ != source)
+    if ((unsigned)shaderParameterSources_[group] == M_MAX_UNSIGNED || shaderParameterSources_[group] != source)
     {
-        i->second_.lastSource_ = source;
+        shaderParameterSources_[group] = source;
         return true;
     }
     else
@@ -1130,21 +1125,21 @@ bool Graphics::NeedTextureUnit(TextureUnit unit)
     return pixelShader_ && pixelShader_->HasTextureUnit(unit);
 }
 
-void Graphics::ClearParameterSource(StringHash param)
+void Graphics::ClearParameterSource(ShaderParameterGroup group)
 {
-    shaderParameters_[param].lastSource_ = (const void*)M_MAX_UNSIGNED;
+    shaderParameterSources_[group] = (const void*)M_MAX_UNSIGNED;
 }
 
 void Graphics::ClearParameterSources()
 {
-    for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
-        i->second_.lastSource_ = (const void*)M_MAX_UNSIGNED;
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        shaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
 }
 
 void Graphics::ClearTransformSources()
 {
-    shaderParameters_[VSP_MODEL].lastSource_ = (const void*)M_MAX_UNSIGNED;
-    shaderParameters_[VSP_VIEWPROJ].lastSource_ = (const void*)M_MAX_UNSIGNED;
+    shaderParameterSources_[SPG_CAMERA] = (const void*)M_MAX_UNSIGNED;
+    shaderParameterSources_[SPG_OBJECTTRANSFORM] = (const void*)M_MAX_UNSIGNED;
 }
 
 void Graphics::SetTexture(unsigned index, Texture* texture)

+ 5 - 3
Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -114,11 +114,11 @@ public:
     /// Register a shader parameter globally. Called by Shader.
     void RegisterShaderParameter(StringHash param, const ShaderParameter& definition);
     /// Check whether a shader parameter in the currently set shaders needs update.
-    bool NeedParameterUpdate(StringHash param, const void* source);
+    bool NeedParameterUpdate(ShaderParameterGroup group, const void* source);
     /// Check whether the current pixel shader uses a texture unit.
     bool NeedTextureUnit(TextureUnit unit);
-    /// Clear remembered shader parameter source.
-    void ClearParameterSource(StringHash param);
+    /// Clear remembered shader parameter source group.
+    void ClearParameterSource(ShaderParameterGroup group);
     /// Clear remembered shader parameter sources.
     void ClearParameterSources();
     /// Clear remembered transform shader parameter sources.
@@ -479,6 +479,8 @@ private:
     unsigned stencilWriteMask_;
     /// Default texture filtering mode.
     TextureFilterMode defaultTextureFilterMode_;
+    /// Remembered shader parameter sources.
+    const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
 };
 
 /// Register Graphics library objects.

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

@@ -38,8 +38,7 @@ struct ShaderParameter
     ShaderParameter() :
         type_(VS),
         register_(M_MAX_UNSIGNED),
-        regCount_(0),
-        lastSource_((void*)M_MAX_UNSIGNED)
+        regCount_(0)
     {
     }
     
@@ -47,8 +46,7 @@ struct ShaderParameter
     ShaderParameter(ShaderType type, unsigned reg, unsigned regCount) :
         type_(type),
         register_(reg),
-        regCount_(regCount),
-        lastSource_((void*)M_MAX_UNSIGNED)
+        regCount_(regCount)
     {
     }
     
@@ -58,8 +56,6 @@ struct ShaderParameter
     unsigned register_;
     /// Number of registers.
     unsigned regCount_;
-    /// Last data source.
-    const void* lastSource_;
 };
 
 /// Vertex or pixel shader on the GPU.

+ 15 - 0
Engine/Graphics/GraphicsDefs.h

@@ -265,6 +265,21 @@ enum TextureUnit
     MAX_TEXTURE_UNITS = 16
 };
 
+/// Shader parameter groups for determining need to update
+enum ShaderParameterGroup
+{
+    SPG_FRAME = 0,
+    SPG_CAMERA,
+    SPG_VIEWPORT,
+    SPG_ZONE,
+    SPG_LIGHT,
+    SPG_VERTEXLIGHTS,
+    SPG_MATERIAL,
+    SPG_OBJECTTRANSFORM,
+    SPG_OBJECTDATA,
+    MAX_SHADER_PARAMETER_GROUPS
+};
+
 static const int QUALITY_LOW = 0;
 static const int QUALITY_MEDIUM = 1;
 static const int QUALITY_HIGH = 2;

+ 2 - 2
Engine/Graphics/View.cpp

@@ -1219,7 +1219,7 @@ void View::RenderBatchesForward()
     graphics_->SetStencilTest(false);
     graphics_->SetShaders(renderer_->GetVertexShader("Basic"), renderer_->GetPixelShader("Basic"));
     graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, farClipZone_->GetFogColor());
-    graphics_->ClearParameterSource(PSP_MATDIFFCOLOR);
+    graphics_->ClearParameterSource(SPG_MATERIAL);
     DrawFullscreenQuad(camera_, false);
     
     // Render pre-alpha custom pass
@@ -1370,7 +1370,7 @@ void View::RenderBatchesDeferred()
     graphics_->SetStencilTest(true, CMP_EQUAL, OP_KEEP, OP_KEEP, OP_KEEP, 0);
     graphics_->SetShaders(renderer_->GetVertexShader("Basic"), renderer_->GetPixelShader("Basic"));
     graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, farClipZone_->GetFogColor());
-    graphics_->ClearParameterSource(PSP_MATDIFFCOLOR);
+    graphics_->ClearParameterSource(SPG_MATERIAL);
     DrawFullscreenQuad(camera_, false);
     
     // Render opaque objects with deferred lighting result (light pre-pass only)

+ 3 - 3
Engine/UI/UI.cpp

@@ -299,11 +299,11 @@ void UI::Render()
         }
         
         graphics_->SetShaders(vs, ps);
-        if (graphics_->NeedParameterUpdate(VSP_MODEL, this))
+        if (graphics_->NeedParameterUpdate(SPG_OBJECTTRANSFORM, this))
             graphics_->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
-        if (graphics_->NeedParameterUpdate(VSP_VIEWPROJ, this))
+        if (graphics_->NeedParameterUpdate(SPG_CAMERA, this))
             graphics_->SetShaderParameter(VSP_VIEWPROJ, projection);
-        if (graphics_->NeedParameterUpdate(PSP_MATDIFFCOLOR, this))
+        if (graphics_->NeedParameterUpdate(SPG_MATERIAL, this))
             graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
         
         // Use alpha test if not alpha blending