From b389c9ea1f6ec7c36fd4a6f3a9831b1c7c753d24 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 29 Nov 2017 20:19:40 +0100 Subject: [PATCH] [d3d11] Experimental implementation of OMSetRenderTargets and ClearRenderTargetView --- src/d3d11/d3d11_context.cpp | 96 ++++++++++++++++++++- src/d3d11/d3d11_context.h | 5 +- src/d3d11/d3d11_context_state.h | 18 ++++ src/d3d11/d3d11_device.cpp | 146 +++++++++++++++++++++++++++++--- src/d3d11/d3d11_interfaces.h | 45 ++++++++++ src/d3d11/d3d11_texture.cpp | 6 ++ src/d3d11/d3d11_texture.h | 4 +- src/d3d11/d3d11_view.cpp | 16 +++- src/d3d11/d3d11_view.h | 11 ++- src/dxvk/dxvk_context.cpp | 2 + src/dxvk/dxvk_device.cpp | 1 + src/util/com/com_guid.cpp | 16 ++-- 12 files changed, 336 insertions(+), 30 deletions(-) create mode 100644 src/d3d11/d3d11_context_state.h diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index ab9df7be..23c40359 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -1,3 +1,5 @@ +#include + #include "d3d11_context.h" #include "d3d11_device.h" @@ -168,7 +170,53 @@ namespace dxvk { void D3D11DeviceContext::ClearRenderTargetView( ID3D11RenderTargetView* pRenderTargetView, const FLOAT ColorRGBA[4]) { - Logger::err("D3D11DeviceContext::ClearRenderTargetView: Not implemented"); + Com rtv; + pRenderTargetView->QueryInterface( + __uuidof(ID3D11RenderTargetViewPrivate), + reinterpret_cast(&rtv)); + + // Find out whether the given attachment is currently bound + // or not, and if it is, which attachment index it has. + int32_t attachmentIndex = -1; + + for (uint32_t i = 0; i < m_state.omRenderTargetViews.size(); i++) { + if (rtv.ptr() == m_state.omRenderTargetViews.at(i).ptr()) + attachmentIndex = static_cast(i); + } + + if (attachmentIndex < 0) { + // FIXME bind render target, then restore framebuffer or mark dirty + Logger::err("D3D11DeviceContext::ClearRenderTargetView: Render target not bound. This is currently not supported."); + return; + } + + // Retrieve image info, which we will need in + // order to determine the size of the clear area + const Rc image = rtv->GetDXVKImageView()->image(); + + // Set up attachment info and copy the clear color + VkClearAttachment clearInfo; + clearInfo.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clearInfo.colorAttachment = static_cast(attachmentIndex); + + std::memcpy(clearInfo.clearValue.color.float32, ColorRGBA, + sizeof(clearInfo.clearValue.color.float32)); + + // Clear the full area. On FL 9.x, only the first array + // layer will be cleared, rather than all array layers. + VkClearRect clearRect; + clearRect.rect.offset.x = 0; + clearRect.rect.offset.y = 0; + clearRect.rect.extent.width = image->info().extent.width; + clearRect.rect.extent.height = image->info().extent.height; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = image->info().numLayers; + + if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) + clearRect.layerCount = 1; + + // Record the clear operation + m_context->clearRenderTarget(clearInfo, clearRect); } @@ -780,7 +828,37 @@ namespace dxvk { UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView) { - Logger::err("D3D11DeviceContext::OMSetRenderTargets: Not implemented"); + // Update state vector for OMGetRenderTargets + for (UINT i = 0; i < m_state.omRenderTargetViews.size(); i++) { + Com view = nullptr; + + if ((i < NumViews) && (ppRenderTargetViews[i] != nullptr)) { + ppRenderTargetViews[i]->QueryInterface( + __uuidof(ID3D11RenderTargetViewPrivate), + reinterpret_cast(&view)); + } + + m_state.omRenderTargetViews.at(i) = view; + } + + // TODO unbind overlapping shader resource views + + // D3D11 doesn't have the concept of a framebuffer object, + // so we'll just create a new one every time the render + // target bindings are updated. Set up the attachments. + DxvkRenderTargets attachments; + + for (UINT i = 0; i < m_state.omRenderTargetViews.size(); i++) { + if (m_state.omRenderTargetViews.at(i) != nullptr) + attachments.setColorTarget(i, m_state.omRenderTargetViews.at(i)->GetDXVKImageView()); + } + + // TODO implement depth-stencil views + if (pDepthStencilView != nullptr) + Logger::err("D3D11DeviceContext::OMSetRenderTargets: Depth-stencil view not supported"); + + // Create and bind the framebuffer object using the given attachments + m_context->bindFramebuffer(m_device->createFramebuffer(attachments)); } @@ -791,7 +869,7 @@ namespace dxvk { UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, - const UINT* pUAVInitialCounts) { + const UINT* pUAVInitialCounts) { Logger::err("D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews: Not implemented"); } @@ -815,7 +893,17 @@ namespace dxvk { UINT NumViews, ID3D11RenderTargetView** ppRenderTargetViews, ID3D11DepthStencilView** ppDepthStencilView) { - Logger::err("D3D11DeviceContext::OMGetRenderTargets: Not implemented"); + if (ppRenderTargetViews != nullptr) { + for (UINT i = 0; i < NumViews; i++) + ppRenderTargetViews[i] = i < m_state.omRenderTargetViews.size() + ? m_state.omRenderTargetViews.at(i).ref() + : nullptr; + } + + if (ppDepthStencilView != nullptr) { + Logger::err("D3D11DeviceContext::OMGetRenderTargets: Stencil view not supported"); + *ppDepthStencilView = nullptr; + } } diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 1c52d5ff..778f233e 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -1,5 +1,6 @@ #pragma once +#include "d3d11_context_state.h" #include "d3d11_device_child.h" #include @@ -471,7 +472,7 @@ namespace dxvk { UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, - const UINT* pUAVInitialCounts) final; + const UINT* pUAVInitialCounts) final; void OMSetBlendState( ID3D11BlendState* pBlendState, @@ -546,6 +547,8 @@ namespace dxvk { Rc m_context; Rc m_cmdList; + D3D11ContextState m_state; + }; } diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h new file mode 100644 index 00000000..e81546c5 --- /dev/null +++ b/src/d3d11/d3d11_context_state.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "d3d11_interfaces.h" + +namespace dxvk { + + /** + * \brief Context state + */ + struct D3D11ContextState { + std::array< + Com, + D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT> omRenderTargetViews; + }; + +} \ No newline at end of file diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index aae53126..7bd3322b 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -106,19 +106,6 @@ namespace dxvk { ID3D11Resource* pResource, const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, ID3D11RenderTargetView** ppRTView) { - // TODO fill desc - // TODO create view - D3D11_RENDER_TARGET_VIEW_DESC desc; - - *ppRTView = ref(new D3D11RenderTargetView(this, desc)); - return S_OK; - } - - - HRESULT D3D11Device::CreateDepthStencilView( - ID3D11Resource* pResource, - const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, - ID3D11DepthStencilView** ppDepthStencilView) { D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; pResource->GetType(&resourceDim); @@ -128,9 +115,140 @@ namespace dxvk { return E_INVALIDARG; } + // Make sure we can retrieve the image object + Com texture = nullptr; + if (FAILED(pResource->QueryInterface(__uuidof(ID3D11Texture2DPrivate), + reinterpret_cast(&texture)))) { + Logger::err("D3D11Device::CreateRenderTargetView: Invalid texture"); + return E_INVALIDARG; + } - Logger::err("D3D11Device::CreateRenderTargetView: Not implemented"); + // Image that we are going to create the view for + const Rc image = texture->GetDXVKImage(); + + // The view description is optional. If not defined, it + // will use the resource's format and all subresources. + D3D11_RENDER_TARGET_VIEW_DESC desc; + + if (pDesc != nullptr) { + desc = *pDesc; + } else { + D3D11_TEXTURE2D_DESC texDesc; + texture->GetDesc(&texDesc); + + // Select the view dimension based on the + // texture's array size and sample count. + const std::array viewDims = { + D3D11_RTV_DIMENSION_TEXTURE2D, + D3D11_RTV_DIMENSION_TEXTURE2DARRAY, + D3D11_RTV_DIMENSION_TEXTURE2DMS, + D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY, + }; + + uint32_t viewDimIndex = 0; + + if (texDesc.ArraySize > 1) + viewDimIndex |= 0x1; + + if (texDesc.SampleDesc.Count > 1) + viewDimIndex |= 0x2; + + // Fill the correct union member + desc.ViewDimension = viewDims.at(viewDimIndex); + desc.Format = texDesc.Format; + + switch (desc.ViewDimension) { + case D3D11_RTV_DIMENSION_TEXTURE2D: + desc.Texture2D.MipSlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + desc.Texture2DArray.MipSlice = 0; + desc.Texture2DArray.FirstArraySlice = 0; + desc.Texture2DArray.ArraySize = texDesc.ArraySize; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + desc.Texture2DMSArray.FirstArraySlice = 0; + desc.Texture2DMSArray.ArraySize = texDesc.ArraySize; + break; + + default: + Logger::err("D3D11Device::CreateRenderTargetView: Internal error"); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + } + + // Fill in Vulkan image view info + DxvkImageViewCreateInfo viewInfo; + // FIXME look up Vulkan format for DXGI format + viewInfo.format = image->info().format; + viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT; + + switch (desc.ViewDimension) { + case D3D11_RTV_DIMENSION_TEXTURE2D: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = desc.Texture2D.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = desc.Texture2DArray.MipSlice; + viewInfo.numLevels = 1; + viewInfo.minLayer = desc.Texture2DArray.FirstArraySlice; + viewInfo.numLayers = desc.Texture2DArray.ArraySize; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = 1; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = desc.Texture2DArray.FirstArraySlice; + viewInfo.numLayers = desc.Texture2DArray.ArraySize; + break; + + default: + Logger::err(str::format( + "D3D11Device::CreateRenderTargetView: pDesc->ViewDimension not supported: ", + desc.ViewDimension)); + return E_INVALIDARG; + } + + // Create the actual image view if requested + if (ppRTView == nullptr) + return S_OK; + + try { + Rc view = m_dxvkDevice->createImageView(image, viewInfo); + *ppRTView = ref(new D3D11RenderTargetView(this, pResource, desc, view)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + } + + + HRESULT D3D11Device::CreateDepthStencilView( + ID3D11Resource* pResource, + const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, + ID3D11DepthStencilView** ppDepthStencilView) { + Logger::err("D3D11Device::CreateDepthStencilView: Not implemented"); return E_NOTIMPL; } diff --git a/src/d3d11/d3d11_interfaces.h b/src/d3d11/d3d11_interfaces.h index 82ccb797..445bfefc 100644 --- a/src/d3d11/d3d11_interfaces.h +++ b/src/d3d11/d3d11_interfaces.h @@ -6,3 +6,48 @@ #include "../dxvk/dxvk_device.h" +MIDL_INTERFACE("776fc4de-9cd9-4a4d-936a-7837d20ec5d9") +ID3D11BufferPrivate : public ID3D11Buffer { + static const GUID guid; + + virtual dxvk::Rc GetDXVKBuffer() = 0; +}; + + +MIDL_INTERFACE("cc62022f-eb7c-473c-b58c-c621bc27b405") +ID3D11Texture1DPrivate : public ID3D11Texture1D { + static const GUID guid; + + virtual dxvk::Rc GetDXVKImage() = 0; +}; + + +MIDL_INTERFACE("0ca9d5af-96e6-41f2-a2c0-6b43d4dc837d") +ID3D11Texture2DPrivate : public ID3D11Texture2D { + static const GUID guid; + + virtual dxvk::Rc GetDXVKImage() = 0; +}; + + +MIDL_INTERFACE("b0f7d56e-761e-46c0-8fca-d465b742b2f8") +ID3D11Texture3DPrivate : public ID3D11Texture3D { + static const GUID guid; + + virtual dxvk::Rc GetDXVKImage() = 0; +}; + + +MIDL_INTERFACE("175a9e94-115c-416a-967d-afabadfa0ea8") +ID3D11RenderTargetViewPrivate : public ID3D11RenderTargetView { + static const GUID guid; + + virtual dxvk::Rc GetDXVKImageView() = 0; +}; + + +DXVK_DEFINE_GUID(ID3D11BufferPrivate); +DXVK_DEFINE_GUID(ID3D11Texture1DPrivate); +DXVK_DEFINE_GUID(ID3D11Texture2DPrivate); +DXVK_DEFINE_GUID(ID3D11Texture3DPrivate); +DXVK_DEFINE_GUID(ID3D11RenderTargetViewPrivate); \ No newline at end of file diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index 2ff51837..d4f38d99 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -24,6 +24,7 @@ namespace dxvk { COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); COM_QUERY_IFACE(riid, ppvObject, ID3D11Resource); COM_QUERY_IFACE(riid, ppvObject, ID3D11Texture2D); + COM_QUERY_IFACE(riid, ppvObject, ID3D11Texture2DPrivate); if (riid == __uuidof(IDXGIResource) || riid == __uuidof(IDXGIImageResourcePrivate)) @@ -60,4 +61,9 @@ namespace dxvk { *pDesc = m_desc; } + + Rc D3D11Texture2D::GetDXVKImage() { + return m_resource->GetDXVKImage(); + } + } diff --git a/src/d3d11/d3d11_texture.h b/src/d3d11/d3d11_texture.h index e323b858..e253f6cd 100644 --- a/src/d3d11/d3d11_texture.h +++ b/src/d3d11/d3d11_texture.h @@ -10,7 +10,7 @@ namespace dxvk { class D3D11Device; - class D3D11Texture2D : public D3D11DeviceChild { + class D3D11Texture2D : public D3D11DeviceChild { public: @@ -37,6 +37,8 @@ namespace dxvk { void GetDesc( D3D11_TEXTURE2D_DESC *pDesc) final; + Rc GetDXVKImage() final; + private: Com m_device; diff --git a/src/d3d11/d3d11_view.cpp b/src/d3d11/d3d11_view.cpp index 7b1fabe8..7c5778d1 100644 --- a/src/d3d11/d3d11_view.cpp +++ b/src/d3d11/d3d11_view.cpp @@ -5,9 +5,13 @@ namespace dxvk { D3D11RenderTargetView::D3D11RenderTargetView( D3D11Device* device, - const D3D11_RENDER_TARGET_VIEW_DESC& desc) + ID3D11Resource* resource, + const D3D11_RENDER_TARGET_VIEW_DESC& desc, + Rc view) : m_device (device), - m_desc (desc) { + m_resource(resource), + m_desc (desc), + m_view (view) { } @@ -22,6 +26,7 @@ namespace dxvk { COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); COM_QUERY_IFACE(riid, ppvObject, ID3D11View); COM_QUERY_IFACE(riid, ppvObject, ID3D11RenderTargetView); + COM_QUERY_IFACE(riid, ppvObject, ID3D11RenderTargetViewPrivate); Logger::warn("D3D11RenderTargetView::QueryInterface: Unknown interface query"); return E_NOINTERFACE; @@ -34,7 +39,7 @@ namespace dxvk { void D3D11RenderTargetView::GetResource(ID3D11Resource **ppResource) { - + *ppResource = m_resource.ref(); } @@ -42,4 +47,9 @@ namespace dxvk { *pDesc = m_desc; } + + Rc D3D11RenderTargetView::GetDXVKImageView() { + return m_view; + } + } diff --git a/src/d3d11/d3d11_view.h b/src/d3d11/d3d11_view.h index b9b84d19..30dcc46e 100644 --- a/src/d3d11/d3d11_view.h +++ b/src/d3d11/d3d11_view.h @@ -8,13 +8,15 @@ namespace dxvk { class D3D11Device; - class D3D11RenderTargetView : public D3D11DeviceChild { + class D3D11RenderTargetView : public D3D11DeviceChild { public: D3D11RenderTargetView( D3D11Device* device, - const D3D11_RENDER_TARGET_VIEW_DESC& desc); + ID3D11Resource* resource, + const D3D11_RENDER_TARGET_VIEW_DESC& desc, + Rc view); ~D3D11RenderTargetView(); HRESULT QueryInterface( @@ -30,10 +32,15 @@ namespace dxvk { void GetDesc( D3D11_RENDER_TARGET_VIEW_DESC* pDesc) final; + Rc GetDXVKImageView() final; + private: Com m_device; + Com m_resource; + D3D11_RENDER_TARGET_VIEW_DESC m_desc; + Rc m_view; }; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index ed65c492..15c066b1 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -282,6 +282,8 @@ namespace dxvk { m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE); + m_cmd->trackResource( + m_state.om.framebuffer); } } diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 60923d21..ed606fa2 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -67,6 +67,7 @@ namespace dxvk { Rc DxvkDevice::createImage( const DxvkImageCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) { + // TODO record image initialization commands return new DxvkImage(m_vkd, createInfo, *m_memory, memoryType); } diff --git a/src/util/com/com_guid.cpp b/src/util/com/com_guid.cpp index d2145f9e..476b308f 100644 --- a/src/util/com/com_guid.cpp +++ b/src/util/com/com_guid.cpp @@ -4,11 +4,17 @@ #include "../../dxgi/dxgi_interfaces.h" -const GUID IDXGIAdapterPrivate::guid = {0x907bf281,0xea3c,0x43b4,{0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff}}; -const GUID IDXGIDevicePrivate::guid = {0x7a622cf6,0x627a,0x46b2,{0xb5,0x2f,0x36,0x0e,0xf3,0xda,0x83,0x1c}}; -const GUID IDXGIPresentDevicePrivate::guid = {0x79352328,0x16f2,0x4f81,{0x97,0x46,0x9c,0x2e,0x2c,0xcd,0x43,0xcf}}; -const GUID IDXGIBufferResourcePrivate::guid = {0x5679becd,0x8547,0x4d93,{0x96,0xa1,0xe6,0x1a,0x1c,0xe7,0xef,0x37}}; -const GUID IDXGIImageResourcePrivate::guid = {0x1cfe6592,0x7de0,0x4a07,{0x8d,0xcb,0x45,0x43,0xcb,0xbc,0x6a,0x7d}}; +const GUID IDXGIAdapterPrivate::guid = {0x907bf281,0xea3c,0x43b4,{0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff}}; +const GUID IDXGIDevicePrivate::guid = {0x7a622cf6,0x627a,0x46b2,{0xb5,0x2f,0x36,0x0e,0xf3,0xda,0x83,0x1c}}; +const GUID IDXGIPresentDevicePrivate::guid = {0x79352328,0x16f2,0x4f81,{0x97,0x46,0x9c,0x2e,0x2c,0xcd,0x43,0xcf}}; +const GUID IDXGIBufferResourcePrivate::guid = {0x5679becd,0x8547,0x4d93,{0x96,0xa1,0xe6,0x1a,0x1c,0xe7,0xef,0x37}}; +const GUID IDXGIImageResourcePrivate::guid = {0x1cfe6592,0x7de0,0x4a07,{0x8d,0xcb,0x45,0x43,0xcb,0xbc,0x6a,0x7d}}; + +const GUID ID3D11BufferPrivate::guid = {0x776fc4de,0x9cd9,0x4a4d,{0x93,0x6a,0x78,0x37,0xd2,0x0e,0xc5,0xd9}}; +const GUID ID3D11Texture1DPrivate::guid = {0xcc62022f,0xeb7c,0x473c,{0xb5,0x8c,0xc6,0x21,0xbc,0x27,0xb4,0x05}}; +const GUID ID3D11Texture2DPrivate::guid = {0x0ca9d5af,0x96e6,0x41f2,{0xa2,0xc0,0x6b,0x43,0xd4,0xdc,0x83,0x7d}}; +const GUID ID3D11Texture3DPrivate::guid = {0xb0f7d56e,0x761e,0x46c0,{0x8f,0xca,0xd4,0x65,0xb7,0x42,0xb2,0xf8}}; +const GUID ID3D11RenderTargetViewPrivate::guid = {0x175a9e94,0x115c,0x416a,{0x96,0x7d,0xaf,0xab,0xad,0xfa,0x0e,0xa8}}; std::ostream& operator << (std::ostream& os, REFIID guid) { os.width(8);