فهرست منبع

D3D11 rendertarget and initial shadow (directional & spot light) support. Fix creating too many rasterizer states for depth bias by quantizing. Fix crash on exit if states failed to create.

Lasse Öörni 10 سال پیش
والد
کامیت
17cf79ab82

+ 21 - 5
Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.cpp

@@ -275,15 +275,24 @@ Graphics::~Graphics()
     constantBuffers_.Clear();
     
     for (HashMap<unsigned, ID3D11BlendState*>::Iterator i = impl_->blendStates_.Begin(); i != impl_->blendStates_.End(); ++i)
-        i->second_->Release();
+    {
+        if (i->second_)
+            i->second_->Release();
+    }
     impl_->blendStates_.Clear();
     
     for (HashMap<unsigned, ID3D11DepthStencilState*>::Iterator i = impl_->depthStates_.Begin(); i != impl_->depthStates_.End(); ++i)
-        i->second_->Release();
+    {
+        if (i->second_)
+            i->second_->Release();
+    }
     impl_->depthStates_.Clear();
 
     for (HashMap<unsigned, ID3D11RasterizerState*>::Iterator i = impl_->rasterizerStates_.Begin(); i != impl_->rasterizerStates_.End(); ++i)
-        i->second_->Release();
+    {
+        if (i->second_)
+            i->second_->Release();
+    }
     impl_->rasterizerStates_.Clear();
 
     if (impl_->defaultRenderTargetView_)
@@ -1373,6 +1382,8 @@ void Graphics::SetDepthStencil(Texture2D* texture)
         depthStencil = texture->GetRenderSurface();
     
     SetDepthStencil(depthStencil);
+    // Constant depth bias depends on the bitdepth
+    rasterizerStateDirty_ = true;
 }
 
 void Graphics::SetViewport(const IntRect& rect)
@@ -2551,8 +2562,13 @@ void Graphics::PrepareDraw()
 
     if (rasterizerStateDirty_)
     {
+        unsigned depthBits = 24;
+        if (depthStencil_ && depthStencil_->GetParentTexture()->GetFormat() == DXGI_FORMAT_R16_TYPELESS)
+            depthBits = 16;
+        int scaledDepthBias = (int)(constantDepthBias_ * (1 << depthBits));
+
         unsigned newRasterizerStateHash = (scissorTest_ ? 1 : 0) | (fillMode_ << 1) | (cullMode_ << 3) |
-            ((*((unsigned*)&constantDepthBias_) & 0x1fff) << 5) | ((*((unsigned*)&slopeScaledDepthBias_) & 0x1fff) << 18);
+            ((scaledDepthBias & 0x1fff) << 5) | ((*((unsigned*)&slopeScaledDepthBias_) & 0x1fff) << 18);
         if (newRasterizerStateHash != rasterizerStateHash_)
         {
             HashMap<unsigned, ID3D11RasterizerState*>::Iterator i = impl_->rasterizerStates_.Find(newRasterizerStateHash);
@@ -2565,7 +2581,7 @@ void Graphics::PrepareDraw()
                 stateDesc.FillMode = d3dFillMode[fillMode_];
                 stateDesc.CullMode = d3dCullMode[cullMode_];
                 stateDesc.FrontCounterClockwise = FALSE;
-                stateDesc.DepthBias = (int)(16777216.0f * constantDepthBias_); /// \todo Verify that bias is same as on D3D9
+                stateDesc.DepthBias = scaledDepthBias;
                 stateDesc.DepthBiasClamp = M_INFINITY;
                 stateDesc.SlopeScaledDepthBias = slopeScaledDepthBias_;
                 stateDesc.DepthClipEnable = TRUE;

+ 16 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11Texture.cpp

@@ -60,7 +60,11 @@ static const D3D11_FILTER d3dFilterMode[] =
     D3D11_FILTER_MIN_MAG_MIP_POINT,
     D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT,
     D3D11_FILTER_MIN_MAG_MIP_LINEAR,
-    D3D11_FILTER_ANISOTROPIC
+    D3D11_FILTER_ANISOTROPIC,
+    D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT,
+    D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT,
+    D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR,
+    D3D11_FILTER_COMPARISON_ANISOTROPIC
 };
 
 static const D3D11_TEXTURE_ADDRESS_MODE d3dAddressMode[] = 
@@ -83,6 +87,7 @@ Texture::Texture(Context* context) :
     width_(0),
     height_(0),
     depth_(0),
+    shadowCompare_(false),
     filterMode_(FILTER_DEFAULT),
     sRGB_(false),
     parametersDirty_(true)
@@ -117,6 +122,12 @@ void Texture::SetAddressMode(TextureCoordinate coord, TextureAddressMode mode)
     parametersDirty_ = true;
 }
 
+void Texture::SetShadowCompare(bool enable)
+{
+    shadowCompare_ = enable;
+    parametersDirty_ = true;
+}
+
 void Texture::SetBorderColor(const Color& color)
 {
     borderColor_ = color;
@@ -314,7 +325,10 @@ void Texture::UpdateParameters()
 
     D3D11_SAMPLER_DESC samplerDesc;
     memset(&samplerDesc, 0, sizeof samplerDesc);
-    samplerDesc.Filter = d3dFilterMode[filterMode_ != FILTER_DEFAULT ? filterMode_ : graphics_->GetDefaultTextureFilterMode()];
+    unsigned filterModeIndex = filterMode_ != FILTER_DEFAULT ? filterMode_ : graphics_->GetDefaultTextureFilterMode();
+    if (shadowCompare_)
+        filterModeIndex += 4;
+    samplerDesc.Filter = d3dFilterMode[filterModeIndex];
     samplerDesc.AddressU = d3dAddressMode[addressMode_[0]];
     samplerDesc.AddressV = d3dAddressMode[addressMode_[1]];
     samplerDesc.AddressW = d3dAddressMode[addressMode_[2]];

+ 6 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11Texture.h

@@ -51,6 +51,8 @@ public:
     void SetFilterMode(TextureFilterMode filter);
     /// Set addressing mode by texture coordinate.
     void SetAddressMode(TextureCoordinate coord, TextureAddressMode address);
+    /// Set shadow compare mode.
+    void SetShadowCompare(bool enable);
     /// Set border color for border addressing mode.
     void SetBorderColor(const Color& color);
     /// Set sRGB sampling and writing mode.
@@ -76,6 +78,8 @@ public:
     TextureFilterMode GetFilterMode() const { return filterMode_; }
     /// Return addressing mode by texture coordinate.
     TextureAddressMode GetAddressMode(TextureCoordinate coord) const { return addressMode_[coord]; }
+    /// Return whether shadow compare is enabled.
+    bool GetShadowCompare() const { return shadowCompare_; }
     /// Return border color.
     const Color& GetBorderColor() const { return borderColor_; }
     /// Return whether is using sRGB sampling and writing.
@@ -141,6 +145,8 @@ protected:
     int height_;
     /// Texture depth.
     int depth_;
+    /// Shadow compare mode.
+    bool shadowCompare_;
     /// Filtering mode.
     TextureFilterMode filterMode_;
     /// Addressing mode.

+ 53 - 0
Source/Urho3D/Graphics/Direct3D11/D3D11Texture2D.cpp

@@ -444,6 +444,17 @@ bool Texture2D::Create()
 
     D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
     memset(&resourceViewDesc, 0, sizeof resourceViewDesc);
+    if (usage_ != TEXTURE_DEPTHSTENCIL)
+        resourceViewDesc.Format = textureDesc.Format;
+    else
+    {
+        if (textureDesc.Format == DXGI_FORMAT_R24G8_TYPELESS)
+            resourceViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
+        else if (textureDesc.Format == DXGI_FORMAT_R16_TYPELESS)
+            resourceViewDesc.Format = DXGI_FORMAT_R16_UNORM;
+        else if (textureDesc.Format == DXGI_FORMAT_R32_TYPELESS)
+            resourceViewDesc.Format = DXGI_FORMAT_R32_FLOAT;
+    }
     resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
     resourceViewDesc.Texture2D.MipLevels = (unsigned)levels_;
     resourceViewDesc.Texture2D.MostDetailedMip = 0;
@@ -456,6 +467,48 @@ bool Texture2D::Create()
         return false;
     }
 
+    if (usage_ == TEXTURE_RENDERTARGET)
+    {
+        renderSurface_ = new RenderSurface(this);
+
+        D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
+        memset(&renderTargetViewDesc, 0, sizeof renderTargetViewDesc);
+        renderTargetViewDesc.Format = textureDesc.Format;
+        renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+
+        graphics_->GetImpl()->GetDevice()->CreateRenderTargetView((ID3D11Resource*)object_, &renderTargetViewDesc,
+            (ID3D11RenderTargetView**)&renderSurface_->renderTargetView_);
+
+        if (!renderSurface_->renderTargetView_)
+        {
+            LOGERROR("Failed to create rendertarget view for texture");
+            return false;
+        }
+    }
+    else if (usage_ == TEXTURE_DEPTHSTENCIL)
+    {
+        renderSurface_ = new RenderSurface(this);
+
+        D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
+        memset(&depthStencilViewDesc, 0, sizeof depthStencilViewDesc);
+        if (textureDesc.Format == DXGI_FORMAT_R24G8_TYPELESS)
+            depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
+        else if (textureDesc.Format == DXGI_FORMAT_R16_TYPELESS)
+            depthStencilViewDesc.Format = DXGI_FORMAT_D16_UNORM;
+        else if (textureDesc.Format == DXGI_FORMAT_R32_TYPELESS)
+            depthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT;
+        depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+
+        graphics_->GetImpl()->GetDevice()->CreateDepthStencilView((ID3D11Resource*)object_, &depthStencilViewDesc,
+            (ID3D11DepthStencilView**)&renderSurface_->renderTargetView_);
+
+        if (!renderSurface_->renderTargetView_)
+        {
+            LOGERROR("Failed to create depth-stencil view for texture");
+            return false;
+        }
+    }
+
     return true;
 }
 

+ 4 - 0
Source/Urho3D/Graphics/Direct3D9/D3D9Texture.h

@@ -50,6 +50,8 @@ public:
     void SetFilterMode(TextureFilterMode filter);
     /// Set addressing mode by texture coordinate.
     void SetAddressMode(TextureCoordinate coord, TextureAddressMode address);
+    /// Set shadow compare mode. No-op on D3D9.
+    void SetShadowCompare(bool enable) {}
     /// Set border color for border addressing mode.
     void SetBorderColor(const Color& color);
     /// Set sRGB sampling and writing mode.
@@ -75,6 +77,8 @@ public:
     TextureFilterMode GetFilterMode() const { return filterMode_; }
     /// Return addressing mode by texture coordinate.
     TextureAddressMode GetAddressMode(TextureCoordinate coord) const { return addressMode_[coord]; }
+    /// Return whether shadow compare is enabled. Always false on D3D9.
+    bool GetShadowCompare() const { return false; }
     /// Return border color.
     const Color& GetBorderColor() const { return borderColor_; }
     /// Return whether is using sRGB sampling and writing.

+ 3 - 3
Source/Urho3D/Graphics/OpenGL/OGLTexture.h

@@ -50,7 +50,7 @@ public:
     void SetFilterMode(TextureFilterMode filter);
     /// Set addressing mode by texture coordinate.
     void SetAddressMode(TextureCoordinate coord, TextureAddressMode address);
-    /// Set shadow compare mode, OpenGL only.
+    /// Set shadow compare mode.
     void SetShadowCompare(bool enable);
     /// Set border color for border addressing mode.
     void SetBorderColor(const Color& color);
@@ -85,7 +85,7 @@ public:
     TextureFilterMode GetFilterMode() const { return filterMode_; }
     /// Return addressing mode by texture coordinate.
     TextureAddressMode GetAddressMode(TextureCoordinate coord) const { return addressMode_[coord]; }
-    /// Return whether shadow compare is enabled, OpenGL only.
+    /// Return whether shadow compare is enabled.
     bool GetShadowCompare() const { return shadowCompare_; }
      /// Return border color.
     const Color& GetBorderColor() const { return borderColor_; }
@@ -143,7 +143,7 @@ protected:
     int height_;
     /// Texture depth.
     int depth_;
-    /// Shadow compare mode, OpenGL only.
+    /// Shadow compare mode.
     bool shadowCompare_;
     /// Parameters dirty flag.
     bool parametersDirty_;

+ 2 - 3
Source/Urho3D/Graphics/Renderer.cpp

@@ -885,13 +885,12 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
         }
         else
         {
-            #ifdef URHO3D_OPENGL
             #ifndef GL_ES_VERSION_2_0
-            // OpenGL (desktop): shadow compare mode needs to be specifically enabled for the shadow map
+            // OpenGL (desktop) and D3D11: shadow compare mode needs to be specifically enabled for the shadow map
             newShadowMap->SetFilterMode(FILTER_BILINEAR);
             newShadowMap->SetShadowCompare(true);
             #endif
-            #else
+            #ifndef URHO3D_OPENGL
             // Direct3D9: when shadow compare must be done manually, use nearest filtering so that the filtering of point lights
             // and other shadowed lights matches
             newShadowMap->SetFilterMode(graphics_->GetHardwareShadowSupport() ? FILTER_BILINEAR : FILTER_NEAREST);

+ 2 - 0
Source/Urho3D/Graphics/View.cpp

@@ -2918,6 +2918,8 @@ void View::RenderShadowMap(const LightBatchQueue& queue)
         {
             multiplier = Max(queue.shadowSplits_[i].shadowCamera_->GetFarClip() / queue.shadowSplits_[0].shadowCamera_->GetFarClip(), 1.0f);
             multiplier = 1.0f + (multiplier - 1.0f) * queue.light_->GetShadowCascade().biasAutoAdjust_;
+            // Quantize multiplier to prevent creation of too many rasterizer states on D3D11
+            multiplier = (int)(multiplier * 10.0f) / 10.0f;
         }
         
         // Perform further modification of depth bias on OpenGL ES, as shadow calculations' precision is limited

+ 16 - 8
bin/CoreData/Shaders/HLSL/Lighting.hlsl

@@ -133,19 +133,27 @@ float GetIntensity(float3 color)
 
 float GetShadow(float4 shadowPos)
 {
+    #ifdef D3D11
+        shadowPos.xyz /= shadowPos.w;
+    #endif
+
     #ifndef LQSHADOW
         // Take four samples and average them
         // Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
-        #ifndef POINTLIGHT
+        #if !defined(POINTLIGHT) && !defined(D3D11)
             float2 offsets = cShadowMapInvSize * shadowPos.w;
         #else
             float2 offsets = cShadowMapInvSize;
         #endif
+        float4 shadowPos2 = float4(shadowPos.x + offsets.x, shadowPos.yzw);
+        float4 shadowPos3 = float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw);
+        float4 shadowPos4 = float4(shadowPos.xy + offsets.xy, shadowPos.zw);
+
         float4 inLight = float4(
-            tex2Dproj(sShadowMap, shadowPos).r,
-            tex2Dproj(sShadowMap, float4(shadowPos.x + offsets.x, shadowPos.yzw)).r,
-            tex2Dproj(sShadowMap, float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r,
-            tex2Dproj(sShadowMap, float4(shadowPos.xy + offsets.xy, shadowPos.zw)).r
+            SampleShadow(ShadowMap, shadowPos).r,
+            SampleShadow(ShadowMap, shadowPos2).r,
+            SampleShadow(ShadowMap, shadowPos3).r,
+            SampleShadow(ShadowMap, shadowPos4).r
         );
         #ifndef SHADOWCMP
             return cShadowIntensity.y + dot(inLight, cShadowIntensity.x);
@@ -158,7 +166,7 @@ float GetShadow(float4 shadowPos)
         #endif
     #else
         // Take one sample
-        float inLight = tex2Dproj(sShadowMap, shadowPos).r;
+        float inLight = SampleShadow(ShadowMap, shadowPos).r;
         #ifndef SHADOWCMP
             return cShadowIntensity.y + cShadowIntensity.x * inLight;
         #else
@@ -174,7 +182,7 @@ float GetShadow(float4 shadowPos)
 #ifdef POINTLIGHT
 float GetPointShadow(float3 lightVec)
 {
-    float3 axis = texCUBE(sFaceSelectCubeMap, lightVec).rgb;
+    float3 axis = SampleCube(FaceSelectCubeMap, lightVec).rgb;
     float depth = abs(dot(lightVec, axis));
 
     // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
@@ -184,7 +192,7 @@ float GetPointShadow(float3 lightVec)
     lightVec += factor * axis * lightVec;
 
     // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
-    float4 indirectPos = texCUBE(sIndirectionCubeMap, lightVec);
+    float4 indirectPos = SampleCube(IndirectionCubeMap, lightVec);
     indirectPos.xy *= cShadowCubeAdjust.xy;
     indirectPos.xy += float2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
 

+ 4 - 2
bin/CoreData/Shaders/HLSL/Samplers.hlsl

@@ -27,7 +27,8 @@ sampler3D sZoneVolumeMap : register(s15);
 #define Sample2D(tex, uv) tex2D(s##tex, uv)
 #define Sample2DProj(tex, uv) tex2Dproj(s##tex, uv)
 #define Sample2DLod0(tex, uv) tex2Dlod(s##tex, float4(uv, 0.0, 0.0))
-#define SampleCube(tex, uv) texCUBE(S##tex, uv)
+#define SampleCube(tex, uv) texCUBE(s##tex, uv)
+#define SampleShadow(tex, uv) tex2Dproj(s##tex, uv)
 
 #else
 
@@ -67,7 +68,7 @@ SamplerState sEnvCubeMap : register(s4);
 SamplerState sLightRampMap : register(s8);
 SamplerState sLightSpotMap : register(s9);
 SamplerState sLightCubeMap : register(s9);
-SamplerState sShadowMap : register(s10);
+SamplerComparisonState sShadowMap : register(s10);
 SamplerState sFaceSelectCubeMap : register(s11);
 SamplerState sIndirectionCubeMap : register(s12);
 SamplerState sDepthBuffer : register(s13);
@@ -79,6 +80,7 @@ SamplerState sZoneVolumeMap : register(s15);
 #define Sample2DProj(tex, uv) t##tex.Sample(s##tex, uv.xy / uv.w)
 #define Sample2DLod0(tex, uv) t##tex.Sample(s##tex, uv)
 #define SampleCube(tex, uv) t##tex.Sample(s##tex, uv)
+#define SampleShadow(tex, uv) t##tex.SampleCmpLevelZero(s##tex, uv.xy, uv.z)
 
 #endif