Browse Source

Initial D3D11 constant buffer handling. If URHO3D_D3D11 option given, disable OpenGL, but error out on non-Windows platforms.

Lasse Öörni 10 years ago
parent
commit
a936eab7c7

+ 9 - 5
CMake/Modules/Urho3D-CMake-common.cmake

@@ -234,16 +234,20 @@ if (NOT WIN32)
     set (URHO3D_OPENGL 1)
     set (URHO3D_OPENGL 1)
 endif ()
 endif ()
 
 
-# Add definition for OpenGL
-if (URHO3D_OPENGL)
-    add_definitions (-DURHO3D_OPENGL)
-endif ()
-
 # Add definition for Direct3D11
 # Add definition for Direct3D11
 if (URHO3D_D3D11)
 if (URHO3D_D3D11)
+    if (NOT WIN32)
+        message(FATAL_ERROR "Direct3D 11 can only be used on Windows platform")
+    endif ()
+    set (URHO3D_OPENGL 0)
     add_definitions (-DURHO3D_D3D11)
     add_definitions (-DURHO3D_D3D11)
 endif ()
 endif ()
 
 
+# Add definition for OpenGL
+if (URHO3D_OPENGL)
+    add_definitions (-DURHO3D_OPENGL)
+endif ()
+
 # Add definitions for GLEW
 # Add definitions for GLEW
 if (NOT IOS AND NOT ANDROID AND NOT RPI AND URHO3D_OPENGL)
 if (NOT IOS AND NOT ANDROID AND NOT RPI AND URHO3D_OPENGL)
     add_definitions (-DGLEW_STATIC -DGLEW_NO_GLU)
     add_definitions (-DGLEW_STATIC -DGLEW_NO_GLU)

+ 85 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11ConstantBuffer.cpp

@@ -44,6 +44,91 @@ ConstantBuffer::~ConstantBuffer()
 
 
 void ConstantBuffer::Release()
 void ConstantBuffer::Release()
 {
 {
+    if (object_)
+    {
+        if (!graphics_)
+            return;
+
+        ((ID3D11Buffer*)object_)->Release();
+        object_ = 0;
+    }
+
+    shadowData_.Reset();
+    size_ = 0;
+}
+
+bool ConstantBuffer::SetSize(unsigned size)
+{
+    Release();
+
+    if (!size)
+    {
+        LOGERROR("Can not create zero-sized constant buffer");
+        return false;
+    }
+
+    size_ = size;
+    dirty_ = false;
+    shadowData_ = new unsigned char[size_];
+    memset(shadowData_.Get(), 0, size_);
+
+    if (graphics_)
+    {
+        D3D11_BUFFER_DESC bufferDesc;
+        memset(&bufferDesc, 0, sizeof bufferDesc);
+
+        bufferDesc.ByteWidth = size_;
+        bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+        bufferDesc.CPUAccessFlags = 0;
+        bufferDesc.Usage = D3D11_USAGE_DEFAULT;
+
+        graphics_->GetImpl()->GetDevice()->CreateBuffer(&bufferDesc, 0, (ID3D11Buffer**)&object_);
+
+        if (!object_)
+        {
+            LOGERROR("Failed to create constant buffer");
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void ConstantBuffer::SetParameter(unsigned offset, unsigned size, const void* data)
+{
+    if (offset + size > size_)
+        return; // Would overflow the buffer
+
+    memcpy(&shadowData_[offset], data, size);
+    dirty_ = true;
+}
+
+void ConstantBuffer::SetVector3ArrayParameter(unsigned offset, unsigned rows, const void* data)
+{
+    if (offset + rows * 4 * sizeof(float) > size_)
+        return; // Would overflow the buffer
+
+    float* dest = (float*)&shadowData_[offset];
+    float* src = (float*)data;
+
+    while (rows--)
+    {
+        dest[0] = src[0];
+        dest[1] = src[1];
+        dest[2] = src[2];
+        ++dest; // Skip over the w coordinate
+    }
+
+    dirty_ = true;
+}
+
+void ConstantBuffer::Apply()
+{
+    if (dirty_ && object_)
+    {
+        graphics_->GetImpl()->GetDeviceContext()->UpdateSubresource((ID3D11Buffer*)object_, 0, 0, shadowData_.Get(), 0, 0);
+        dirty_ = false;
+    }
 }
 }
 
 
 }
 }

+ 22 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11ConstantBuffer.h

@@ -25,6 +25,7 @@
 #include "../../Graphics/GPUObject.h"
 #include "../../Graphics/GPUObject.h"
 #include "../../Graphics/GraphicsDefs.h"
 #include "../../Graphics/GraphicsDefs.h"
 #include "../../Container/ArrayPtr.h"
 #include "../../Container/ArrayPtr.h"
+#include "../../Core/Object.h"
 
 
 namespace Urho3D
 namespace Urho3D
 {
 {
@@ -43,9 +44,30 @@ public:
     /// Release buffer.
     /// Release buffer.
     virtual void Release();
     virtual void Release();
     
     
+    /// Set size and create GPU-side buffer. Return true on success.
+    bool SetSize(unsigned size);
+    /// Set a generic parameter and mark buffer dirty.
+    void SetParameter(unsigned offset, unsigned size, const void* data);
+    /// Set a Vector3 array parameter and mark buffer dirty.
+    void SetVector3ArrayParameter(unsigned offset, unsigned rows, const void* data);
+    /// Apply to GPU.
+    void Apply();
+
+    /// Return size.
+    unsigned GetSize() const { return size_; }
+    /// Return whether has unapplied data.
+    bool IsDirty() const { return dirty_; }
+
 private:
 private:
     /// Create buffer.
     /// Create buffer.
     bool Create();
     bool Create();
+
+    /// Shadow data.
+    SharedArrayPtr<unsigned char> shadowData_;
+    /// Buffer byte size.
+    unsigned size_;
+    /// Dirty flag.
+    bool dirty_;
 };
 };
 
 
 }
 }

+ 156 - 61
Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.cpp

@@ -24,6 +24,7 @@
 #include "../../Graphics/Animation.h"
 #include "../../Graphics/Animation.h"
 #include "../../Graphics/AnimationController.h"
 #include "../../Graphics/AnimationController.h"
 #include "../../Graphics/Camera.h"
 #include "../../Graphics/Camera.h"
+#include "../../Graphics/ConstantBuffer.h"
 #include "../../Core/Context.h"
 #include "../../Core/Context.h"
 #include "../../Graphics/CustomGeometry.h"
 #include "../../Graphics/CustomGeometry.h"
 #include "../../Graphics/DebugRenderer.h"
 #include "../../Graphics/DebugRenderer.h"
@@ -43,6 +44,7 @@
 #include "../../Resource/ResourceCache.h"
 #include "../../Resource/ResourceCache.h"
 #include "../../Graphics/Shader.h"
 #include "../../Graphics/Shader.h"
 #include "../../Graphics/ShaderPrecache.h"
 #include "../../Graphics/ShaderPrecache.h"
+#include "../../Graphics/ShaderProgram.h"
 #include "../../Graphics/ShaderVariation.h"
 #include "../../Graphics/ShaderVariation.h"
 #include "../../Graphics/Skybox.h"
 #include "../../Graphics/Skybox.h"
 #include "../../Graphics/StaticModelGroup.h"
 #include "../../Graphics/StaticModelGroup.h"
@@ -242,7 +244,7 @@ Graphics::Graphics(Context* context) :
     numBatches_(0),
     numBatches_(0),
     maxScratchBufferRequest_(0),
     maxScratchBufferRequest_(0),
     defaultTextureFilterMode_(FILTER_TRILINEAR),
     defaultTextureFilterMode_(FILTER_TRILINEAR),
-    currentShaderParameters_(0),
+    shaderProgram_(0),
     shaderPath_("Shaders/HLSL/"),
     shaderPath_("Shaders/HLSL/"),
     shaderExtension_(".hlsl"),
     shaderExtension_(".hlsl"),
     orientations_("LandscapeLeft LandscapeRight"),
     orientations_("LandscapeLeft LandscapeRight"),
@@ -270,6 +272,7 @@ Graphics::~Graphics()
     }
     }
 
 
     vertexDeclarations_.Clear();
     vertexDeclarations_.Clear();
+    constantBuffers_.Clear();
     
     
     for (HashMap<unsigned, ID3D11BlendState*>::Iterator i = impl_->blendStates_.Begin(); i != impl_->blendStates_.End(); ++i)
     for (HashMap<unsigned, ID3D11BlendState*>::Iterator i = impl_->blendStates_.Begin(); i != impl_->blendStates_.End(); ++i)
         i->second_->Release();
         i->second_->Release();
@@ -808,7 +811,7 @@ void Graphics::SetIndexBuffer(IndexBuffer* buffer)
                 sizeof(unsigned short) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
                 sizeof(unsigned short) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
         }
         }
         else
         else
-            impl_->deviceContext_->IASetIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0);
+            impl_->deviceContext_->IASetIndexBuffer(0, DXGI_FORMAT_UNKNOWN, 0);
 
 
         indexBuffer_ = buffer;
         indexBuffer_ = buffer;
     }
     }
@@ -867,7 +870,51 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
         pixelShader_ = ps;
         pixelShader_ = ps;
     }
     }
     
     
-    /// \todo Update the parameters / constant buffers used by the shaders
+    // Update current shader parameters & constant buffers
+    if (vertexShader_ && pixelShader_)
+    {
+        Pair<ShaderVariation*, ShaderVariation*> key = MakePair(vertexShader_, pixelShader_);
+        ShaderProgramMap::Iterator i = shaderPrograms_.Find(key);
+        if (i != shaderPrograms_.End())
+            shaderProgram_ = i->second_.Get();
+        else
+        {
+            ShaderProgram* newProgram = shaderPrograms_[key] = new ShaderProgram(this, vertexShader_, pixelShader_);
+            shaderProgram_ = newProgram;
+        }
+
+        bool vsBuffersChanged = false;
+        bool psBuffersChanged = false;
+
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        {
+            ID3D11Buffer* vsBuffer = shaderProgram_->vsConstantBuffers_[i] ? (ID3D11Buffer*)shaderProgram_->vsConstantBuffers_[i]->
+                GetGPUObject() : 0;
+            if (vsBuffer != impl_->constantBuffers_[VS][i])
+            {
+                impl_->constantBuffers_[VS][i] = vsBuffer;
+                vsBuffersChanged = true;
+            }
+
+            ID3D11Buffer* psBuffer = shaderProgram_->psConstantBuffers_[i] ? (ID3D11Buffer*)shaderProgram_->psConstantBuffers_[i]->
+                GetGPUObject() : 0;
+            if (psBuffer != impl_->constantBuffers_[PS][i])
+            {
+                impl_->constantBuffers_[PS][i] = psBuffer;
+                psBuffersChanged = true;
+            }
+        }
+
+        if (vsBuffersChanged)
+            impl_->deviceContext_->VSSetConstantBuffers(0, MAX_SHADER_PARAMETER_GROUPS, &impl_->constantBuffers_[VS][0]);
+        if (psBuffersChanged)
+            impl_->deviceContext_->PSSetConstantBuffers(0, MAX_SHADER_PARAMETER_GROUPS, &impl_->constantBuffers_[PS][0]);
+
+        /// \todo When shaders use constant buffers properly, need only reset a parameter source when/if a buffer in slot changes
+        ClearParameterSources();
+    }
+    else
+        shaderProgram_ = 0;
 
 
     // Store shader combination if shader dumping in progress
     // Store shader combination if shader dumping in progress
     if (shaderPrecache_)
     if (shaderPrecache_)
@@ -877,109 +924,121 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
 void Graphics::SetShaderParameter(StringHash param, const float* data, unsigned count)
 void Graphics::SetShaderParameter(StringHash param, const float* data, unsigned count)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, count * sizeof(float), data);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, count * sizeof(float), data);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, float value)
 void Graphics::SetShaderParameter(StringHash param, float value)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
-    
-    float data[4];
-    
-    data[0] = value;
-    data[1] = 0.0f;
-    data[2] = 0.0f;
-    data[3] = 0.0f;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(float), &value);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(float), &value);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, bool value)
 void Graphics::SetShaderParameter(StringHash param, bool value)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
 
 
-    BOOL data = value;
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(bool), &value);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(bool), &value);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Color& color)
 void Graphics::SetShaderParameter(StringHash param, const Color& color)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Color), &color);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Color), &color);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Vector2& vector)
 void Graphics::SetShaderParameter(StringHash param, const Vector2& vector)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
-    
-    float data[4];
-    
-    data[0] = vector.x_;
-    data[1] = vector.y_;
-    data[2] = 0.0f;
-    data[3] = 0.0f;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Vector2), &vector);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Vector2), &vector);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
 void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
-    
-    float data[12];
-    
-    data[0] = matrix.m00_;
-    data[1] = matrix.m01_;
-    data[2] = matrix.m02_;
-    data[3] = 0.0f;
-    data[4] = matrix.m10_;
-    data[5] = matrix.m11_;
-    data[6] = matrix.m12_;
-    data[7] = 0.0f;
-    data[8] = matrix.m20_;
-    data[9] = matrix.m21_;
-    data[10] = matrix.m22_;
-    data[11] = 0.0f;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetVector3ArrayParameter(i->second_.offset_, 3, &matrix);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetVector3ArrayParameter(i->second_.offset_, 3, &matrix);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Vector3& vector)
 void Graphics::SetShaderParameter(StringHash param, const Vector3& vector)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
-    
-    float data[4];
-    
-    data[0] = vector.x_;
-    data[1] = vector.y_;
-    data[2] = vector.z_;
-    data[3] = 0.0f;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Vector3), &vector);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Vector3), &vector);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix4& matrix)
 void Graphics::SetShaderParameter(StringHash param, const Matrix4& matrix)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Matrix4), &matrix);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Matrix4), &matrix);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Vector4& vector)
 void Graphics::SetShaderParameter(StringHash param, const Vector4& vector)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Vector4), &vector);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Vector4), &vector);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix3x4& matrix)
 void Graphics::SetShaderParameter(StringHash param, const Matrix3x4& matrix)
 {
 {
     HashMap<StringHash, ShaderParameter>::Iterator i;
     HashMap<StringHash, ShaderParameter>::Iterator i;
-    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
+    if (!shaderProgram_ || (i = shaderProgram_->parameters_.Find(param)) == shaderProgram_->parameters_.End())
         return;
         return;
+
+    if (i->second_.type_ == VS)
+        shaderProgram_->vsConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Matrix3x4), &matrix);
+    else
+        shaderProgram_->psConstantBuffers_[i->second_.buffer_]->SetParameter(i->second_.offset_, sizeof(Matrix3x4), &matrix);
 }
 }
 
 
 void Graphics::SetShaderParameter(StringHash param, const Variant& value)
 void Graphics::SetShaderParameter(StringHash param, const Variant& value)
@@ -1041,7 +1100,7 @@ bool Graphics::NeedParameterUpdate(ShaderParameterGroup group, const void* sourc
 
 
 bool Graphics::HasShaderParameter(StringHash param)
 bool Graphics::HasShaderParameter(StringHash param)
 {
 {
-    return currentShaderParameters_ && currentShaderParameters_->Find(param) != currentShaderParameters_->End();
+    return shaderProgram_ && shaderProgram_->parameters_.Find(param) != shaderProgram_->parameters_.End();
 }
 }
 
 
 bool Graphics::HasTextureUnit(TextureUnit unit)
 bool Graphics::HasTextureUnit(TextureUnit unit)
@@ -1751,19 +1810,34 @@ void Graphics::CleanupScratchBuffers()
     maxScratchBufferRequest_ = 0;
     maxScratchBufferRequest_ = 0;
 }
 }
 
 
-void Graphics::CleanupShaderParameters(ShaderVariation* variation)
+void Graphics::CleanUpShaderPrograms(ShaderVariation* variation)
 {
 {
-    for (HashMap<Pair<ShaderVariation*, ShaderVariation*>, HashMap<StringHash, ShaderParameter> >::Iterator i =
-        shaderParameters_.Begin(); i != shaderParameters_.End();)
+    for (ShaderProgramMap::Iterator i = shaderPrograms_.Begin(); i != shaderPrograms_.End();)
     {
     {
         if (i->first_.first_ == variation || i->first_.second_ == variation)
         if (i->first_.first_ == variation || i->first_.second_ == variation)
-            i = shaderParameters_.Erase(i);
+            i = shaderPrograms_.Erase(i);
         else
         else
             ++i;
             ++i;
     }
     }
 
 
     if (vertexShader_ == variation || pixelShader_ == variation)
     if (vertexShader_ == variation || pixelShader_ == variation)
-        currentShaderParameters_ = 0;
+        shaderProgram_ = 0;
+}
+
+ConstantBuffer* Graphics::GetOrCreateConstantBuffer(ShaderType type, unsigned index, unsigned size)
+{
+    // Ensure that different shader types and index slots get unique buffers, even if the size is same
+    unsigned key = type | (index << 1) | (size << 4);
+    HashMap<unsigned, SharedPtr<ConstantBuffer> >::Iterator i = constantBuffers_.Find(key);
+    if (i != constantBuffers_.End())
+        return i->second_.Get();
+    else
+    {
+        SharedPtr<ConstantBuffer> newConstantBuffer(new ConstantBuffer(context_));
+        newConstantBuffer->SetSize(size);
+        constantBuffers_[key] = newConstantBuffer;
+        return newConstantBuffer.Get();
+    }
 }
 }
 
 
 unsigned Graphics::GetAlphaFormat()
 unsigned Graphics::GetAlphaFormat()
@@ -2028,22 +2102,22 @@ bool Graphics::UpdateSwapChain(int width, int height)
 {
 {
     bool success = true;
     bool success = true;
 
 
-    ID3D11RenderTargetView* nullView = nullptr;
-    impl_->deviceContext_->OMSetRenderTargets(1, &nullView, nullptr);
+    ID3D11RenderTargetView* nullView = 0;
+    impl_->deviceContext_->OMSetRenderTargets(1, &nullView, 0);
     if (impl_->defaultRenderTargetView_)
     if (impl_->defaultRenderTargetView_)
     {
     {
         impl_->defaultRenderTargetView_->Release();
         impl_->defaultRenderTargetView_->Release();
-        impl_->defaultRenderTargetView_ = nullptr;
+        impl_->defaultRenderTargetView_ = 0;
     }
     }
     if (impl_->defaultDepthStencilView_)
     if (impl_->defaultDepthStencilView_)
     {
     {
         impl_->defaultDepthStencilView_->Release();
         impl_->defaultDepthStencilView_->Release();
-        impl_->defaultDepthStencilView_ = nullptr;
+        impl_->defaultDepthStencilView_ = 0;
     }
     }
     if (impl_->defaultDepthTexture_)
     if (impl_->defaultDepthTexture_)
     {
     {
         impl_->defaultDepthTexture_->Release();
         impl_->defaultDepthTexture_->Release();
-        impl_->defaultDepthTexture_ = nullptr;
+        impl_->defaultDepthTexture_ = 0;
     }
     }
 
 
     impl_->swapChain_->ResizeBuffers(1, width, height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
     impl_->swapChain_->ResizeBuffers(1, width, height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
@@ -2130,6 +2204,12 @@ void Graphics::ResetCachedState()
         renderTargets_[i] = 0;
         renderTargets_[i] = 0;
         impl_->renderTargetViews_[i] = 0;
         impl_->renderTargetViews_[i] = 0;
     }
     }
+
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+    {
+        impl_->constantBuffers_[VS][i] = 0;
+        impl_->constantBuffers_[PS][i] = 0;
+    }
     
     
     depthStencil_ = 0;
     depthStencil_ = 0;
     impl_->depthStencilView_ = 0;
     impl_->depthStencilView_ = 0;
@@ -2140,6 +2220,7 @@ void Graphics::ResetCachedState()
     primitiveType_ = 0;
     primitiveType_ = 0;
     vertexShader_ = 0;
     vertexShader_ = 0;
     pixelShader_ = 0;
     pixelShader_ = 0;
+    shaderProgram_ = 0;
     blendMode_ = BLEND_REPLACE;
     blendMode_ = BLEND_REPLACE;
     textureAnisotropy_ = 1;
     textureAnisotropy_ = 1;
     colorWrite_ = true;
     colorWrite_ = true;
@@ -2361,6 +2442,20 @@ void Graphics::PrepareDraw()
         impl_->deviceContext_->RSSetScissorRects(1, &d3dRect);
         impl_->deviceContext_->RSSetScissorRects(1, &d3dRect);
         scissorRectDirty_ = false;
         scissorRectDirty_ = false;
     }
     }
+
+    if (shaderProgram_)
+    {
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        {
+            ConstantBuffer* cb = shaderProgram_->vsConstantBuffers_[i];
+            if (cb && cb->IsDirty())
+                cb->Apply();
+
+            cb = shaderProgram_->psConstantBuffers_[i];
+            if (cb && cb->IsDirty())
+                cb->Apply();
+        }
+    }
 }
 }
 
 
 void Graphics::SetTextureUnitMappings()
 void Graphics::SetTextureUnitMappings()

+ 13 - 5
Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.h

@@ -36,6 +36,7 @@
 namespace Urho3D
 namespace Urho3D
 {
 {
 
 
+class ConstantBuffer;
 class File;
 class File;
 class Image;
 class Image;
 class IndexBuffer;
 class IndexBuffer;
@@ -44,6 +45,7 @@ class GraphicsImpl;
 class RenderSurface;
 class RenderSurface;
 class Shader;
 class Shader;
 class ShaderPrecache;
 class ShaderPrecache;
+class ShaderProgram;
 class ShaderVariation;
 class ShaderVariation;
 class Texture;
 class Texture;
 class Texture2D;
 class Texture2D;
@@ -72,6 +74,8 @@ struct ScratchBuffer
     bool reserved_;
     bool reserved_;
 };
 };
 
 
+typedef HashMap<Pair<ShaderVariation*, ShaderVariation*>, SharedPtr<ShaderProgram> > ShaderProgramMap;
+
 /// %Graphics subsystem. Manages the application window, rendering state and GPU resources.
 /// %Graphics subsystem. Manages the application window, rendering state and GPU resources.
 class URHO3D_API Graphics : public Object
 class URHO3D_API Graphics : public Object
 {
 {
@@ -378,7 +382,9 @@ public:
     /// Clean up too large scratch buffers.
     /// Clean up too large scratch buffers.
     void CleanupScratchBuffers();
     void CleanupScratchBuffers();
     /// Clean up shader parameters when a shader variation is released or destroyed.
     /// Clean up shader parameters when a shader variation is released or destroyed.
-    void CleanupShaderParameters(ShaderVariation* variation);
+    void CleanUpShaderPrograms(ShaderVariation* variation);
+    /// Get or create a constant buffer. Will be shared between shaders if possible.
+    ConstantBuffer* GetOrCreateConstantBuffer(ShaderType type, unsigned index, unsigned size);
 
 
     /// Return the API-specific alpha texture format.
     /// Return the API-specific alpha texture format.
     static unsigned GetAlphaFormat();
     static unsigned GetAlphaFormat();
@@ -591,12 +597,14 @@ private:
     unsigned lastDirtyTexture_;
     unsigned lastDirtyTexture_;
     /// Default texture filtering mode.
     /// Default texture filtering mode.
     TextureFilterMode defaultTextureFilterMode_;
     TextureFilterMode defaultTextureFilterMode_;
-    /// Shader parameters for all vertex/pixel shader combinations.
-    HashMap<Pair<ShaderVariation*, ShaderVariation*>, HashMap<StringHash, ShaderParameter> > shaderParameters_;
-    /// Current active shader parameters.
-    HashMap<StringHash, ShaderParameter>* currentShaderParameters_;
     /// Vertex declarations.
     /// Vertex declarations.
     HashMap<unsigned long long, SharedPtr<VertexDeclaration> > vertexDeclarations_;
     HashMap<unsigned long long, SharedPtr<VertexDeclaration> > vertexDeclarations_;
+    /// Constant buffers.
+    HashMap<unsigned, SharedPtr<ConstantBuffer> > constantBuffers_;
+    /// Shader programs.
+    ShaderProgramMap shaderPrograms_;
+    /// Shader program in use.
+    ShaderProgram* shaderProgram_;
     /// Remembered shader parameter sources.
     /// Remembered shader parameter sources.
     const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     /// Base directory for shaders.
     /// Base directory for shaders.

+ 6 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11GraphicsImpl.cpp

@@ -51,6 +51,12 @@ GraphicsImpl::GraphicsImpl() :
         vertexSizes_[i] = 0;
         vertexSizes_[i] = 0;
         vertexOffsets_[i] = 0;
         vertexOffsets_[i] = 0;
     }
     }
+
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+    {
+        constantBuffers_[VS][i] = 0;
+        constantBuffers_[PS][i] = 0;
+    }
 }
 }
 
 
 }
 }

+ 2 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11GraphicsImpl.h

@@ -79,6 +79,8 @@ private:
     ID3D11ShaderResourceView* shaderResourceViews_[MAX_TEXTURE_UNITS];
     ID3D11ShaderResourceView* shaderResourceViews_[MAX_TEXTURE_UNITS];
     /// Bound vertex buffers.
     /// Bound vertex buffers.
     ID3D11Buffer* vertexBuffers_[MAX_VERTEX_STREAMS];
     ID3D11Buffer* vertexBuffers_[MAX_VERTEX_STREAMS];
+    /// Bound constant buffers.
+    ID3D11Buffer* constantBuffers_[2][MAX_SHADER_PARAMETER_GROUPS];
     /// Vertex sizes per buffer.
     /// Vertex sizes per buffer.
     unsigned vertexSizes_[MAX_VERTEX_STREAMS];
     unsigned vertexSizes_[MAX_VERTEX_STREAMS];
     /// Vertex stream offsets per buffer.
     /// Vertex stream offsets per buffer.

+ 26 - 1
Source/Urho3D/Graphics/Direct3D11/D3D11ShaderProgram.h

@@ -23,6 +23,8 @@
 #pragma once
 #pragma once
 
 
 #include "../../Container/HashMap.h"
 #include "../../Container/HashMap.h"
+#include "../../Graphics/ConstantBuffer.h"
+#include "../../Graphics/Graphics.h"
 #include "../../Graphics/ShaderVariation.h"
 #include "../../Graphics/ShaderVariation.h"
 
 
 namespace Urho3D
 namespace Urho3D
@@ -33,7 +35,7 @@ class ShaderProgram : public RefCounted
 {
 {
 public:
 public:
     /// Construct.
     /// Construct.
-    ShaderProgram(ShaderVariation* vertexShader, ShaderVariation* pixelShader)
+    ShaderProgram(Graphics* graphics, ShaderVariation* vertexShader, ShaderVariation* pixelShader)
     {
     {
         const HashMap<StringHash, ShaderParameter>& vsParams = vertexShader->GetParameters();
         const HashMap<StringHash, ShaderParameter>& vsParams = vertexShader->GetParameters();
         for (HashMap<StringHash, ShaderParameter>::ConstIterator i = vsParams.Begin(); i != vsParams.End(); ++i)
         for (HashMap<StringHash, ShaderParameter>::ConstIterator i = vsParams.Begin(); i != vsParams.End(); ++i)
@@ -45,10 +47,33 @@ public:
 
 
         // Optimize shader parameter lookup by rehashing to next power of two
         // Optimize shader parameter lookup by rehashing to next power of two
         parameters_.Rehash(NextPowerOfTwo(parameters_.Size()));
         parameters_.Rehash(NextPowerOfTwo(parameters_.Size()));
+
+        const unsigned* vsBufferSizes = vertexShader->GetConstantBufferSizes();
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        {
+            if (vsBufferSizes[i])
+                vsConstantBuffers_[i] = graphics->GetOrCreateConstantBuffer(VS, i, vsBufferSizes[i]);
+        }
+
+        const unsigned* psBufferSizes = pixelShader->GetConstantBufferSizes();
+        for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        {
+            if (psBufferSizes[i])
+                psConstantBuffers_[i] = graphics->GetOrCreateConstantBuffer(PS, i, psBufferSizes[i]);
+        }
+    }
+
+    /// Destruct.
+    ~ShaderProgram()
+    {
     }
     }
 
 
     /// Combined parameters from the vertex and pixel shader.
     /// Combined parameters from the vertex and pixel shader.
     HashMap<StringHash, ShaderParameter> parameters_;
     HashMap<StringHash, ShaderParameter> parameters_;
+    /// Vertex shader constant buffers.
+    SharedPtr<ConstantBuffer> vsConstantBuffers_[MAX_SHADER_PARAMETER_GROUPS];
+    /// Pixel shader constant buffers.
+    SharedPtr<ConstantBuffer> psConstantBuffers_[MAX_SHADER_PARAMETER_GROUPS];
 };
 };
 
 
 }
 }

+ 25 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11ShaderVariation.cpp

@@ -46,6 +46,8 @@ ShaderVariation::ShaderVariation(Shader* owner, ShaderType type) :
 {
 {
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         useTextureUnit_[i] = false;
         useTextureUnit_[i] = false;
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        constantBufferSizes_[i] = 0;
 }
 }
 
 
 ShaderVariation::~ShaderVariation()
 ShaderVariation::~ShaderVariation()
@@ -110,7 +112,7 @@ void ShaderVariation::Release()
         if (!graphics_)
         if (!graphics_)
             return;
             return;
         
         
-        graphics_->CleanupShaderParameters(this);
+        graphics_->CleanUpShaderPrograms(this);
 
 
         if (type_ == VS)
         if (type_ == VS)
         {
         {
@@ -134,6 +136,8 @@ void ShaderVariation::Release()
     
     
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         useTextureUnit_[i] = false;
         useTextureUnit_[i] = false;
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        constantBufferSizes_[i] = 0;
     parameters_.Clear();
     parameters_.Clear();
     byteCode_.Clear();
     byteCode_.Clear();
     elementMask_ = 0;
     elementMask_ = 0;
@@ -213,6 +217,7 @@ bool ShaderVariation::LoadByteCode(const String& binaryShaderName)
         else
         else
             LOGDEBUG("Loaded cached pixel shader " + GetFullName());
             LOGDEBUG("Loaded cached pixel shader " + GetFullName());
         
         
+        CalculateConstantBufferSizes();
         return true;
         return true;
     }
     }
     else
     else
@@ -299,6 +304,7 @@ bool ShaderVariation::Compile()
         byteCode_.Resize(bufSize);
         byteCode_.Resize(bufSize);
         memcpy(&byteCode_[0], bufData, bufSize);
         memcpy(&byteCode_[0], bufData, bufSize);
         ParseParameters();
         ParseParameters();
+        CalculateConstantBufferSizes();
     }
     }
 
 
     if (shaderCode)
     if (shaderCode)
@@ -314,7 +320,7 @@ void ShaderVariation::ParseParameters()
     if (byteCode_.Empty())
     if (byteCode_.Empty())
         return;
         return;
 
 
-    ID3D11ShaderReflection* reflection = nullptr;
+    ID3D11ShaderReflection* reflection = 0;
     D3D11_SHADER_DESC shaderDesc;
     D3D11_SHADER_DESC shaderDesc;
 
 
     D3DReflect(&byteCode_[0], byteCode_.Size(), IID_ID3D11ShaderReflection, (void**)&reflection);
     D3DReflect(&byteCode_[0], byteCode_.Size(), IID_ID3D11ShaderReflection, (void**)&reflection);
@@ -435,4 +441,21 @@ void ShaderVariation::SaveByteCode(const String& binaryShaderName)
         file->Write(&byteCode_[0], byteCode_.Size());
         file->Write(&byteCode_[0], byteCode_.Size());
 }
 }
 
 
+void ShaderVariation::CalculateConstantBufferSizes()
+{
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
+        constantBufferSizes_[i] = 0;
+    
+    for (HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters_.Begin(); i != parameters_.End(); ++i)
+    {
+        if (i->second_.buffer_ < MAX_SHADER_PARAMETER_GROUPS)
+        {
+            unsigned oldSize = constantBufferSizes_[i->second_.buffer_];
+            unsigned paramEnd = i->second_.offset_ + i->second_.size_;
+            if (paramEnd > oldSize)
+                constantBufferSizes_[i->second_.buffer_] = paramEnd;
+        }
+    }
+}
+
 }
 }

+ 7 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11ShaderVariation.h

@@ -108,6 +108,9 @@ public:
     const String& GetDefines() const { return defines_; }
     const String& GetDefines() const { return defines_; }
     /// Return compile error/warning string.
     /// Return compile error/warning string.
     const String& GetCompilerOutput() const { return compilerOutput_; }
     const String& GetCompilerOutput() const { return compilerOutput_; }
+    /// Return constant buffer data sizes.
+    const unsigned* GetConstantBufferSizes() const { return &constantBufferSizes_[0]; }
+
 private:
 private:
     /// Load bytecode from a file. Return true if successful.
     /// Load bytecode from a file. Return true if successful.
     bool LoadByteCode(const String& binaryShaderName);
     bool LoadByteCode(const String& binaryShaderName);
@@ -117,6 +120,8 @@ private:
     void ParseParameters();
     void ParseParameters();
     /// Save bytecode to a file.
     /// Save bytecode to a file.
     void SaveByteCode(const String& binaryShaderName);
     void SaveByteCode(const String& binaryShaderName);
+    /// Calculate constant buffer sizes from parameters.
+    void CalculateConstantBufferSizes();
     
     
     /// Shader this variation belongs to.
     /// Shader this variation belongs to.
     WeakPtr<Shader> owner_;
     WeakPtr<Shader> owner_;
@@ -128,6 +133,8 @@ private:
     HashMap<StringHash, ShaderParameter> parameters_;
     HashMap<StringHash, ShaderParameter> parameters_;
     /// Texture unit use flags.
     /// Texture unit use flags.
     bool useTextureUnit_[MAX_TEXTURE_UNITS];
     bool useTextureUnit_[MAX_TEXTURE_UNITS];
+    /// Constant buffer sizes. 0 if a constant buffer slot is not in use.
+    unsigned constantBufferSizes_[MAX_SHADER_PARAMETER_GROUPS];
     /// Bytecode. Needed for inspecting the input signature and parameters.
     /// Bytecode. Needed for inspecting the input signature and parameters.
     PODVector<unsigned char> byteCode_;
     PODVector<unsigned char> byteCode_;
     /// Shader name.
     /// Shader name.

+ 1 - 2
Source/Urho3D/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -2272,8 +2272,7 @@ void Graphics::CleanupScratchBuffers()
 
 
 void Graphics::CleanupShaderPrograms(ShaderVariation* variation)
 void Graphics::CleanupShaderPrograms(ShaderVariation* variation)
 {
 {
-    for (ShaderProgramMap::Iterator i =
-        shaderPrograms_.Begin(); i != shaderPrograms_.End();)
+    for (ShaderProgramMap::Iterator i = shaderPrograms_.Begin(); i != shaderPrograms_.End();)
     {
     {
         if (i->first_.first_ == variation || i->first_.second_ == variation)
         if (i->first_.first_ == variation || i->first_.second_ == variation)
             i = shaderPrograms_.Erase(i);
             i = shaderPrograms_.Erase(i);