Browse Source

Fix multisample quality handling on D3D11 feature level 10.0. Closes #1792.

Lasse Öörni 8 years ago
parent
commit
0cc2bf595e

+ 3 - 6
Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.cpp

@@ -1708,10 +1708,7 @@ PODVector<int> Graphics::GetMultiSampleLevels() const
     {
         for (unsigned i = 2; i <= 16; ++i)
         {
-            unsigned levels = 0;
-            impl_->device_->CheckMultisampleQualityLevels(sRGB_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM,
-                i, &levels);
-            if (levels)
+            if (impl_->CheckMultiSampleSupport(sRGB_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM, i))
                 ret.Push(i);
         }
     }
@@ -2163,7 +2160,7 @@ bool Graphics::CreateDevice(int width, int height, int multiSample)
     swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
     swapChainDesc.OutputWindow = GetWindowHandle(window_);
     swapChainDesc.SampleDesc.Count = (UINT)multiSample;
-    swapChainDesc.SampleDesc.Quality = multiSample > 1 ? 0xffffffff : 0;
+    swapChainDesc.SampleDesc.Quality = impl_->GetMultiSampleQuality(swapChainDesc.BufferDesc.Format, multiSample);
     swapChainDesc.Windowed = TRUE;
     swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
 
@@ -2257,7 +2254,7 @@ bool Graphics::UpdateSwapChain(int width, int height)
     depthDesc.ArraySize = 1;
     depthDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
     depthDesc.SampleDesc.Count = (UINT)multiSample_;
-    depthDesc.SampleDesc.Quality = multiSample_ > 1 ? 0xffffffff : 0;
+    depthDesc.SampleDesc.Quality = impl_->GetMultiSampleQuality(depthDesc.Format, multiSample_);
     depthDesc.Usage = D3D11_USAGE_DEFAULT;
     depthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
     depthDesc.CPUAccessFlags = 0;

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

@@ -64,4 +64,31 @@ GraphicsImpl::GraphicsImpl() :
     }
 }
 
+bool GraphicsImpl::CheckMultiSampleSupport(DXGI_FORMAT format, unsigned sampleCount) const
+{
+    if (sampleCount < 2)
+        return true; // Not multisampled
+
+    UINT numLevels = 0;
+    if (FAILED(device_->CheckMultisampleQualityLevels(format, sampleCount, &numLevels)))
+        return false;
+    else
+        return numLevels > 0;
+}
+
+unsigned GraphicsImpl::GetMultiSampleQuality(DXGI_FORMAT format, unsigned sampleCount) const
+{
+    if (sampleCount < 2)
+        return 0; // Not multisampled, should use quality 0
+
+    if (device_->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_1)
+        return 0xffffffff; // D3D10.1+ standard level
+
+    UINT numLevels = 0;
+    if (FAILED(device_->CheckMultisampleQualityLevels(format, sampleCount, &numLevels)) || !numLevels)
+        return 0; // Errored or sample count not supported
+    else
+        return numLevels - 1; // D3D10.0 and below: use the best quality
+}
+
 }

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

@@ -60,6 +60,12 @@ public:
     /// Return swapchain.
     IDXGISwapChain* GetSwapChain() const { return swapChain_; }
 
+    /// Return whether multisampling is supported for a given texture format and sample count.
+    bool CheckMultiSampleSupport(DXGI_FORMAT format, unsigned sampleCount) const;
+
+    /// Return multisample quality level for a given texture format and sample count. The sample count must be supported. On D3D feature level 10.1+, uses the standard level. Below that uses the best quality.
+    unsigned GetMultiSampleQuality(DXGI_FORMAT format, unsigned sampleCount) const;
+
 private:
     /// Graphics device.
     ID3D11Device* device_;

+ 42 - 23
Source/Urho3D/Graphics/Direct3D11/D3D11Texture2D.cpp

@@ -378,6 +378,14 @@ bool Texture2D::Create()
 
     D3D11_TEXTURE2D_DESC textureDesc;
     memset(&textureDesc, 0, sizeof textureDesc);
+    textureDesc.Format = (DXGI_FORMAT)(sRGB_ ? GetSRGBFormat(format_) : format_);
+
+    // Disable multisampling if not supported
+    if (multiSample_ > 1 && !graphics_->GetImpl()->CheckMultiSampleSupport(textureDesc.Format, multiSample_))
+    {
+        multiSample_ = 1;
+        autoResolve_ = false;
+    }
 
     // Set mipmapping
     if (usage_ == TEXTURE_DEPTHSTENCIL)
@@ -390,9 +398,9 @@ bool Texture2D::Create()
     // Disable mip levels from the multisample texture. Rather create them to the resolve texture
     textureDesc.MipLevels = multiSample_ == 1 ? levels_ : 1;
     textureDesc.ArraySize = 1;
-    textureDesc.Format = (DXGI_FORMAT)(sRGB_ ? GetSRGBFormat(format_) : format_);
     textureDesc.SampleDesc.Count = (UINT)multiSample_;
-    textureDesc.SampleDesc.Quality = multiSample_ > 1 ? 0xffffffff : 0;
+    textureDesc.SampleDesc.Quality = graphics_->GetImpl()->GetMultiSampleQuality(textureDesc.Format, multiSample_);
+
     textureDesc.Usage = usage_ == TEXTURE_DYNAMIC ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
     textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
     if (usage_ == TEXTURE_RENDERTARGET)
@@ -401,6 +409,10 @@ bool Texture2D::Create()
         textureDesc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
     textureDesc.CPUAccessFlags = usage_ == TEXTURE_DYNAMIC ? D3D11_CPU_ACCESS_WRITE : 0;
 
+    // D3D feature level 10.0 or below does not support readable depth when multisampled
+    if (usage_ == TEXTURE_DEPTHSTENCIL && multiSample_ > 1 && graphics_->GetImpl()->GetDevice()->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_1)
+        textureDesc.BindFlags &= ~D3D11_BIND_SHADER_RESOURCE;
+
     HRESULT hr = graphics_->GetImpl()->GetDevice()->CreateTexture2D(&textureDesc, 0, (ID3D11Texture2D**)&object_);
     if (FAILED(hr))
     {
@@ -427,22 +439,25 @@ bool Texture2D::Create()
         }
     }
 
-    D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
-    memset(&resourceViewDesc, 0, sizeof resourceViewDesc);
-    resourceViewDesc.Format = (DXGI_FORMAT)GetSRVFormat(textureDesc.Format);
-    resourceViewDesc.ViewDimension = (multiSample_ > 1 && !autoResolve_) ? D3D11_SRV_DIMENSION_TEXTURE2DMS :
-        D3D11_SRV_DIMENSION_TEXTURE2D;
-    resourceViewDesc.Texture2D.MipLevels = (UINT)levels_;
-
-    // Sample the resolve texture if created, otherwise the original
-    ID3D11Resource* viewObject = resolveTexture_ ? (ID3D11Resource*)resolveTexture_ : (ID3D11Resource*)object_.ptr_;
-    hr = graphics_->GetImpl()->GetDevice()->CreateShaderResourceView(viewObject, &resourceViewDesc,
-        (ID3D11ShaderResourceView**)&shaderResourceView_);
-    if (FAILED(hr))
+    if (textureDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
     {
-        URHO3D_LOGD3DERROR("Failed to create shader resource view for texture", hr);
-        URHO3D_SAFE_RELEASE(shaderResourceView_);
-        return false;
+        D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
+        memset(&resourceViewDesc, 0, sizeof resourceViewDesc);
+        resourceViewDesc.Format = (DXGI_FORMAT)GetSRVFormat(textureDesc.Format);
+        resourceViewDesc.ViewDimension = (multiSample_ > 1 && !autoResolve_) ? D3D11_SRV_DIMENSION_TEXTURE2DMS :
+            D3D11_SRV_DIMENSION_TEXTURE2D;
+        resourceViewDesc.Texture2D.MipLevels = (UINT)levels_;
+
+        // Sample the resolve texture if created, otherwise the original
+        ID3D11Resource* viewObject = resolveTexture_ ? (ID3D11Resource*)resolveTexture_ : (ID3D11Resource*)object_.ptr_;
+        hr = graphics_->GetImpl()->GetDevice()->CreateShaderResourceView(viewObject, &resourceViewDesc,
+            (ID3D11ShaderResourceView**)&shaderResourceView_);
+        if (FAILED(hr))
+        {
+            URHO3D_LOGD3DERROR("Failed to create shader resource view for texture", hr);
+            URHO3D_SAFE_RELEASE(shaderResourceView_);
+            return false;
+        }
     }
 
     if (usage_ == TEXTURE_RENDERTARGET)
@@ -478,13 +493,17 @@ bool Texture2D::Create()
         }
 
         // Create also a read-only version of the view for simultaneous depth testing and sampling in shader
-        depthStencilViewDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
-        hr = graphics_->GetImpl()->GetDevice()->CreateDepthStencilView((ID3D11Resource*)object_.ptr_, &depthStencilViewDesc,
-            (ID3D11DepthStencilView**)&renderSurface_->readOnlyView_);
-        if (FAILED(hr))
+        // Requires feature level 11
+        if (graphics_->GetImpl()->GetDevice()->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_0)
         {
-            URHO3D_LOGD3DERROR("Failed to create read-only depth-stencil view for texture", hr);
-            URHO3D_SAFE_RELEASE(renderSurface_->readOnlyView_);
+            depthStencilViewDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
+            hr = graphics_->GetImpl()->GetDevice()->CreateDepthStencilView((ID3D11Resource*)object_.ptr_, &depthStencilViewDesc,
+                (ID3D11DepthStencilView**)&renderSurface_->readOnlyView_);
+            if (FAILED(hr))
+            {
+                URHO3D_LOGD3DERROR("Failed to create read-only depth-stencil view for texture", hr);
+                URHO3D_SAFE_RELEASE(renderSurface_->readOnlyView_);
+            }
         }
     }
 

+ 9 - 2
Source/Urho3D/Graphics/Direct3D11/D3D11TextureCube.cpp

@@ -445,6 +445,14 @@ bool TextureCube::Create()
 
     D3D11_TEXTURE2D_DESC textureDesc;
     memset(&textureDesc, 0, sizeof textureDesc);
+    textureDesc.Format = (DXGI_FORMAT)(sRGB_ ? GetSRGBFormat(format_) : format_);
+
+    // Disable multisampling if not supported
+    if (multiSample_ > 1 && !graphics_->GetImpl()->CheckMultiSampleSupport(textureDesc.Format, multiSample_))
+    {
+        multiSample_ = 1;
+        autoResolve_ = false;
+    }
 
     // Set mipmapping
     if (usage_ == TEXTURE_RENDERTARGET && levels_ != 1 && multiSample_ == 1)
@@ -455,9 +463,8 @@ bool TextureCube::Create()
     // Disable mip levels from the multisample texture. Rather create them to the resolve texture
     textureDesc.MipLevels = multiSample_ == 1 ? levels_ : 1;
     textureDesc.ArraySize = MAX_CUBEMAP_FACES;
-    textureDesc.Format = (DXGI_FORMAT)(sRGB_ ? GetSRGBFormat(format_) : format_);
     textureDesc.SampleDesc.Count = (UINT)multiSample_;
-    textureDesc.SampleDesc.Quality = multiSample_ > 1 ? 0xffffffff : 0;
+    textureDesc.SampleDesc.Quality = graphics_->GetImpl()->GetMultiSampleQuality(textureDesc.Format, multiSample_);
     textureDesc.Usage = usage_ == TEXTURE_DYNAMIC ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
     textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
     if (usage_ == TEXTURE_RENDERTARGET)