From 24ad9e730cd62f2319f0b67a399ec0b36e6e2859 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 8 Jan 2018 10:17:52 +0100 Subject: [PATCH] [d3d11] Added dummy resoruce binding for buffers Fixes crashes when a D3D11 application uses unbound resources in shaders. Allows Nier:Automata to play back cutscenes. --- src/d3d11/d3d11_context.cpp | 16 +++++--- src/d3d11/d3d11_context.h | 12 ++++-- src/d3d11/d3d11_device.cpp | 4 +- src/d3d11/d3d11_device.h | 2 + src/d3d11/d3d11_dummy_resource.cpp | 64 ++++++++++++++++++++++++++++++ src/d3d11/d3d11_dummy_resource.h | 37 +++++++++++++++++ src/d3d11/meson.build | 1 + 7 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 src/d3d11/d3d11_dummy_resource.cpp create mode 100644 src/d3d11/d3d11_dummy_resource.h diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index ea8fde98..07ccaca0 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -10,13 +10,17 @@ namespace dxvk { D3D11DeviceContext::D3D11DeviceContext( - D3D11Device* parent, - Rc device) - : m_parent(parent), - m_device(device) { + D3D11Device* parent, + const Rc& device, + const Rc& dummyResources) + : m_parent(parent), m_device(device), + m_dummyResources(dummyResources) { + // Create and initialize underlying context so that the + // application can use it for rendering immediately m_context = m_device->createContext(); m_context->beginRecording( m_device->createCommandList()); + // Create default state objects. We won't ever return them // to the application, but we'll use them to apply state. Com defaultBlendState; @@ -1808,7 +1812,7 @@ namespace dxvk { slotId + i, newBuffer->GetBufferSlice(0)); } else { m_context->bindResourceBuffer( - slotId + i, DxvkBufferSlice()); + slotId + i, DxvkBufferSlice(m_dummyResources->buffer)); } } } @@ -1836,7 +1840,7 @@ namespace dxvk { slotId + i, sampler->GetDXVKSampler()); } else { m_context->bindResourceSampler( - slotId + i, nullptr); + slotId + i, m_dummyResources->sampler); } } } diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 6f2b2d29..ff9d9e10 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -4,6 +4,7 @@ #include "../dxvk/dxvk_device.h" #include "d3d11_context_state.h" +#include "d3d11_dummy_resource.h" #include "d3d11_device_child.h" #include "d3d11_view.h" @@ -16,8 +17,9 @@ namespace dxvk { public: D3D11DeviceContext( - D3D11Device* parent, - Rc device); + D3D11Device* parent, + const Rc& device, + const Rc& dummyResources); ~D3D11DeviceContext(); ULONG STDMETHODCALLTYPE AddRef() final; @@ -554,8 +556,10 @@ namespace dxvk { const D3D11_DEVICE_CONTEXT_TYPE m_type = D3D11_DEVICE_CONTEXT_IMMEDIATE; const UINT m_flags = 0; - Rc m_device; - Rc m_context; + Rc m_device; + Rc m_context; + + Rc m_dummyResources; Com m_defaultBlendState; Com m_defaultDepthStencilState; diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index d135345a..f11a3a9e 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -24,6 +24,8 @@ namespace dxvk { m_featureFlags (featureFlags), m_dxvkDevice (m_dxgiDevice->GetDXVKDevice()), m_dxvkAdapter (m_dxvkDevice->adapter()), + m_dummyResources(new D3D11DummyResources( + m_dxvkDevice, GetEnabledShaderStages())), m_dxbcOptions (m_dxvkDevice) { Com adapter; @@ -35,7 +37,7 @@ namespace dxvk { m_dxgiDevice->SetDeviceLayer(this); m_presentDevice->SetDeviceLayer(this); - m_context = new D3D11DeviceContext(this, m_dxvkDevice); + m_context = new D3D11DeviceContext(this, m_dxvkDevice, m_dummyResources); m_resourceInitContext = m_dxvkDevice->createContext(); } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 668dea5b..64103bc1 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -6,6 +6,7 @@ #include "../util/com/com_private_data.h" +#include "d3d11_dummy_resource.h" #include "d3d11_interfaces.h" #include "d3d11_state.h" #include "d3d11_util.h" @@ -256,6 +257,7 @@ namespace dxvk { const Rc m_dxvkDevice; const Rc m_dxvkAdapter; + const Rc m_dummyResources; const DxbcOptions m_dxbcOptions; diff --git a/src/d3d11/d3d11_dummy_resource.cpp b/src/d3d11/d3d11_dummy_resource.cpp new file mode 100644 index 00000000..2d6c2707 --- /dev/null +++ b/src/d3d11/d3d11_dummy_resource.cpp @@ -0,0 +1,64 @@ +#include "d3d11_dummy_resource.h" + +namespace dxvk { + + D3D11DummyResources::D3D11DummyResources( + const Rc& device, + VkPipelineStageFlags enabledShaderStages) { + // Create a sampler to use with dummy textures. Parameters + // are the same as the default D3D11 sampling parameters. + DxvkSamplerCreateInfo samplerInfo; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipmapLodBias = 0.0f; + samplerInfo.mipmapLodMin = 0.0f; + samplerInfo.mipmapLodMax = 256.0f; + samplerInfo.useAnisotropy = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.compareToDepth = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_NEVER; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + samplerInfo.usePixelCoord = VK_FALSE; + + this->sampler = device->createSampler(samplerInfo); + + // Create a dummy buffer. We'll use this for both texel buffers + // and uniform buffers. The contents will be initialized to zero. + DxvkBufferCreateInfo bufferInfo; + bufferInfo.size = 0x10000; // Max constant buffer size + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + bufferInfo.stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT + | VK_PIPELINE_STAGE_TRANSFER_BIT + | enabledShaderStages; + bufferInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT + | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT + | VK_ACCESS_UNIFORM_READ_BIT; + + this->buffer = device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + // Create buffer view to use for texel buffer bindings. + DxvkBufferViewCreateInfo bufferViewInfo; + bufferViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + bufferViewInfo.rangeOffset = 0; + bufferViewInfo.rangeLength = bufferInfo.size; + + this->bufferView = device->createBufferView(this->buffer, bufferViewInfo); + + // TODO images and image views + // TODO initialize resources + } + + + D3D11DummyResources::~D3D11DummyResources() { + + } + +} \ No newline at end of file diff --git a/src/d3d11/d3d11_dummy_resource.h b/src/d3d11/d3d11_dummy_resource.h new file mode 100644 index 00000000..9211e158 --- /dev/null +++ b/src/d3d11/d3d11_dummy_resource.h @@ -0,0 +1,37 @@ +#pragma once + +#include "../dxvk/dxvk_device.h" + +namespace dxvk { + + /** + * \brief D3D11 dummy resources + * + * Binding dummy resources to resource slots is + * required in cases where the application binds + * \c nullptr in order to keep the backend alive. + */ + struct D3D11DummyResources : public RcObject { + D3D11DummyResources( + const Rc& device, + VkPipelineStageFlags enabledShaderStages); + ~D3D11DummyResources(); + + Rc sampler; ///< Dummy texture sampler + Rc buffer; ///< Dummy constant/vertex buffer + Rc bufferView; ///< Dummy buffer SRV or UAV + + Rc image1D; ///< Dummy 1D image, used to back 1D and 1D Array views + Rc image2D; ///< Dummy 2D image, used to back 2D, 2D Array and Cube views + Rc image3D; ///< Dummy 3D image, used to back the 3D view + + Rc imageView1D; ///< 1D view + Rc imageView1DArray; ///< 1D array view + Rc imageView2D; ///< 2D view + Rc imageView2DArray; ///< 2D array view + Rc imageViewCube; ///< 2D cube view + Rc imageViewCubeArray; ///< 2D cube array view + Rc imageView3D; ///< 3D view + }; + +} \ No newline at end of file diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 51de23ec..8a2737c3 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -5,6 +5,7 @@ d3d11_src = [ 'd3d11_context.cpp', 'd3d11_depth_stencil.cpp', 'd3d11_device.cpp', + 'd3d11_dummy_resource.cpp', 'd3d11_enums.cpp', 'd3d11_input_layout.cpp', 'd3d11_main.cpp',