From dbd4dad095f4f7c1b435402d130ab7c26c8565fb Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 22 Feb 2022 04:58:42 +0100 Subject: [PATCH] [d3d11] Introduce d3d11.maxDynamicImageBufferSize option --- src/d3d11/d3d11_options.cpp | 5 +++++ src/d3d11/d3d11_options.h | 3 +++ src/d3d11/d3d11_texture.cpp | 40 +++++++++++++++++++++---------------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/d3d11/d3d11_options.cpp b/src/d3d11/d3d11_options.cpp index 2fb14557..09db0159 100644 --- a/src/d3d11/d3d11_options.cpp +++ b/src/d3d11/d3d11_options.cpp @@ -30,6 +30,11 @@ namespace dxvk { ? VkDeviceSize(maxImplicitDiscardSize) << 10 : VkDeviceSize(~0ull); + int32_t maxDynamicImageBufferSize = config.getOption("d3d11.maxDynamicImageBufferSize", -1); + this->maxDynamicImageBufferSize = maxDynamicImageBufferSize >= 0 + ? VkDeviceSize(maxDynamicImageBufferSize) << 10 + : VkDeviceSize(~0ull); + this->constantBufferRangeCheck = config.getOption("d3d11.constantBufferRangeCheck", false) && DxvkGpuVendor(devInfo.core.properties.vendorID) != DxvkGpuVendor::Amd; diff --git a/src/d3d11/d3d11_options.h b/src/d3d11/d3d11_options.h index d931f5f9..6ec0b5a3 100644 --- a/src/d3d11/d3d11_options.h +++ b/src/d3d11/d3d11_options.h @@ -95,6 +95,9 @@ namespace dxvk { /// Limit discardable resource size VkDeviceSize maxImplicitDiscardSize; + /// Limit size of buffer-mapped images + VkDeviceSize maxDynamicImageBufferSize; + /// Defer surface creation until first present call. This /// fixes issues with games that create multiple swap chains /// for a single window that may interfere with each other. diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index 4bf7c1cb..1f8f978c 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -553,16 +553,6 @@ namespace dxvk { if (!m_desc.BindFlags && m_desc.Usage != D3D11_USAGE_DEFAULT) return D3D11_COMMON_TEXTURE_MAP_MODE_STAGING; - // Write-only images should go through a buffer for multiple reasons: - // 1. Some games do not respect the row and depth pitch that is returned - // by the Map() method, which leads to incorrect rendering (e.g. Nier) - // 2. Since the image will most likely be read for rendering by the GPU, - // writing the image to device-local image may be more efficient than - // reading its contents from host memory. - if (m_desc.Usage == D3D11_USAGE_DYNAMIC - && m_desc.TextureLayout != D3D11_TEXTURE_LAYOUT_ROW_MAJOR) - return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; - // Depth-stencil formats in D3D11 can be mapped and follow special // packing rules, so we need to copy that data into a buffer first if (GetPackedDepthStencilFormat(m_desc.Format)) @@ -572,13 +562,29 @@ namespace dxvk { if (imageFormatInfo(pImageInfo->format)->flags.test(DxvkFormatFlag::MultiPlane)) return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; - // Images that can be read by the host should be mapped directly in - // order to avoid expensive synchronization with the GPU. This does - // however require linear tiling, which may not be supported for all - // combinations of image parameters. - return this->CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR) - ? D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT - : D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + // If we can't use linear tiling for this image, we have to use a buffer + if (!this->CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR)) + return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + + // If supported and requested, create a linear image. Default images + // can be used for resolves and other operations regardless of bind + // flags, so we need to use a proper image for those. + if (m_desc.TextureLayout == D3D11_TEXTURE_LAYOUT_ROW_MAJOR + || m_desc.Usage == D3D11_USAGE_DEFAULT) + return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT; + + // The overhead of frequently uploading large dynamic images may outweigh + // the benefit of linear tiling, so use a linear image in those cases. + VkDeviceSize threshold = m_device->GetOptions()->maxDynamicImageBufferSize; + VkDeviceSize size = util::computeImageDataSize(pImageInfo->format, pImageInfo->extent); + + if (size > threshold) + return D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT; + + // Dynamic images that can be sampled by a shader should generally go + // through a buffer to allow optimal tiling and to avoid running into + // bugs where games ignore the pitch when mapping the image. + return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; }