From a3fe40051fb4496f0b27a855c3215bfb9d0d112c Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 28 Dec 2017 19:05:53 +0100 Subject: [PATCH] [d3d11] Initial support for unordered access views Currently restricted to buffers on the API side. Typed UAVs are not yet supported by the shader compiler. This is enough to run very simple compute shaders. --- src/d3d11/d3d11_buffer.cpp | 2 +- src/d3d11/d3d11_context.cpp | 83 +++++++++++++++++++++++++++++++++++-- src/d3d11/d3d11_context.h | 7 ++++ src/d3d11/d3d11_device.cpp | 65 ++++++++++++++++++++++++++++- 4 files changed, 151 insertions(+), 6 deletions(-) diff --git a/src/d3d11/d3d11_buffer.cpp b/src/d3d11/d3d11_buffer.cpp index b0540683..e0809dde 100644 --- a/src/d3d11/d3d11_buffer.cpp +++ b/src/d3d11/d3d11_buffer.cpp @@ -62,7 +62,7 @@ namespace dxvk { const D3D11_BUFFER_DESC* pDesc) const { DxvkBufferCreateInfo info; info.size = pDesc->ByteWidth; - info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT; info.access = VK_ACCESS_TRANSFER_READ_BIT diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index d6d5098e..b44dabf8 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -138,6 +138,12 @@ namespace dxvk { this->CSSetSamplers(i, 1, &sampler); } + for (uint32_t i = 0; i < D3D11_1_UAV_SLOT_COUNT; i++) { + ID3D11UnorderedAccessView* uav = nullptr; + + this->CSSetUnorderedAccessViews(i, 1, &uav, nullptr); + } + this->OMSetRenderTargets(0, nullptr, nullptr); this->OMSetBlendState(nullptr, nullptr, D3D11_DEFAULT_SAMPLE_MASK); this->OMSetDepthStencilState(nullptr, 0); @@ -328,7 +334,35 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11DeviceContext::CopyResource( ID3D11Resource* pDstResource, ID3D11Resource* pSrcResource) { - Logger::err("D3D11DeviceContext::CopyResource: Not implemented"); + D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + + pDstResource->GetType(&dstResourceDim); + pSrcResource->GetType(&srcResourceDim); + + if (dstResourceDim != srcResourceDim) { + Logger::err("D3D11DeviceContext: CopyResource: Mismatched resource types"); + return; + } + + if (dstResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) { + auto dstBuffer = static_cast(pDstResource)->GetBufferSlice(); + auto srcBuffer = static_cast(pSrcResource)->GetBufferSlice(); + + if (dstBuffer.length() != srcBuffer.length()) { + Logger::err("D3D11DeviceContext: CopyResource: Mismatched buffer size"); + return; + } + + m_context->copyBuffer( + dstBuffer.buffer(), + dstBuffer.offset(), + srcBuffer.buffer(), + srcBuffer.offset(), + srcBuffer.length()); + } else { + Logger::err("D3D11DeviceContext::CopyResource: Images not supported"); + } } @@ -1299,7 +1333,15 @@ namespace dxvk { UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, const UINT* pUAVInitialCounts) { - Logger::err("D3D11DeviceContext::CSSetUnorderedAccessViews: Not implemented"); + // TODO implement append-consume buffers + if (pUAVInitialCounts != nullptr) + Logger::err("D3D11DeviceContext: pUAVInitialCounts not supported"); + + this->BindUnorderedAccessViews( + DxbcProgramType::ComputeShader, + m_state.cs.unorderedAccessViews, + StartSlot, NumUAVs, + ppUnorderedAccessViews); } @@ -1696,7 +1738,6 @@ namespace dxvk { if (resView != nullptr) { // Figure out what we have to bind based on the resource type if (resView->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) { - // TODO support raw and structured buffers m_context->bindResourceTexelBuffer( slotId + i, resView->GetDXVKBufferView()); } else { @@ -1714,6 +1755,42 @@ namespace dxvk { } + void D3D11DeviceContext::BindUnorderedAccessViews( + DxbcProgramType ShaderStage, + D3D11UnorderedAccessBindings& Bindings, + UINT StartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews) { + const uint32_t slotId = computeResourceSlotId( + ShaderStage, DxbcBindingType::UnorderedAccessView, + StartSlot); + + for (uint32_t i = 0; i < NumUAVs; i++) { + auto uav = static_cast(ppUnorderedAccessViews[i]); + + if (Bindings[StartSlot + i] != uav) { + Bindings[StartSlot + i] = uav; + + if (uav != nullptr) { + // Figure out what we have to bind based on the resource type + if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) { + m_context->bindResourceTexelBuffer( + slotId + i, uav->GetDXVKBufferView()); + } else { + m_context->bindResourceImage( + slotId + i, uav->GetDXVKImageView()); + } + } else { + // When unbinding a resource, it doesn't really matter if + // the resource type is correct, so we'll just bind a null + // image to the given resource slot + m_context->bindResourceImage(slotId + i, nullptr); + } + } + } + } + + void D3D11DeviceContext::ApplyViewportState() { // We cannot set less than one viewport in Vulkan, and // rendering with no active viewport is illegal anyway. diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index e228641b..6f2b2d29 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -584,6 +584,13 @@ namespace dxvk { UINT NumResources, ID3D11ShaderResourceView* const* ppResources); + void BindUnorderedAccessViews( + DxbcProgramType ShaderStage, + D3D11UnorderedAccessBindings& Bindings, + UINT StartSlot, + UINT NumUAVs, + ID3D11UnorderedAccessView* const* ppUnorderedAccessViews); + void ApplyViewportState(); }; diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 89c36325..1fc43cae 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -314,8 +314,68 @@ namespace dxvk { ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAView) { - Logger::err("D3D11Device::CreateUnorderedAccessView: Not implemented"); - return E_NOTIMPL; + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + // The description is optional. If omitted, we'll create + // a view that covers all subresources of the image. + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + + if (pDesc == nullptr) { + if (FAILED(GetUnorderedAccessViewDescFromResource(pResource, &desc))) + return E_INVALIDARG; + } else { + desc = *pDesc; + } + + if (resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) { + auto resource = static_cast(pResource); + + D3D11_BUFFER_DESC resourceDesc; + resource->GetDesc(&resourceDesc); + + DxvkBufferViewCreateInfo viewInfo; + + if (desc.Buffer.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) { + viewInfo.format = VK_FORMAT_R32_UINT; + viewInfo.rangeOffset = sizeof(uint32_t) * desc.Buffer.FirstElement; + viewInfo.rangeLength = sizeof(uint32_t) * desc.Buffer.NumElements; + } else if (desc.Format == DXGI_FORMAT_UNKNOWN) { + viewInfo.format = VK_FORMAT_R32_UINT; + viewInfo.rangeOffset = resourceDesc.StructureByteStride * desc.Buffer.FirstElement; + viewInfo.rangeLength = resourceDesc.StructureByteStride * desc.Buffer.NumElements; + } else { + // Typed buffer view - must use an uncompressed color format + viewInfo.format = m_dxgiAdapter->LookupFormat( + desc.Format, DxgiFormatMode::Color).format; + + const DxvkFormatInfo* formatInfo = imageFormatInfo(viewInfo.format); + viewInfo.rangeOffset = formatInfo->elementSize * desc.Buffer.FirstElement; + viewInfo.rangeLength = formatInfo->elementSize * desc.Buffer.NumElements; + + if (formatInfo->flags.test(DxvkFormatFlag::BlockCompressed)) { + Logger::err("D3D11Device: Compressed formats for buffer views not supported"); + return E_INVALIDARG; + } + } + + if (ppUAView == nullptr) + return S_FALSE; + + try { + *ppUAView = ref(new D3D11UnorderedAccessView( + this, pResource, desc, + m_dxvkDevice->createBufferView( + resource->GetBufferSlice().buffer(), viewInfo))); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_FAIL; + } + } else { + Logger::err("D3D11Device::CreateUnorderedAccessView: Images not supported yet"); + return E_NOTIMPL; + } } @@ -1352,6 +1412,7 @@ namespace dxvk { HRESULT D3D11Device::GetUnorderedAccessViewDescFromResource( ID3D11Resource* pResource, D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc) { + Logger::err("D3D11Device::GetUnorderedAccessViewDescFromResource: Not implemented"); return E_NOTIMPL; }