summaryrefslogtreecommitdiff
path: root/tools/gfx/d3d12/d3d12-resource-views.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-04-15 23:28:28 -0700
committerGitHub <noreply@github.com>2024-04-15 23:28:28 -0700
commit3192f34f57abd3245995342a0a5971ebbbbd945c (patch)
treedc139be9fe9f4995bac96513571cc9e0526ce547 /tools/gfx/d3d12/d3d12-resource-views.cpp
parent030d7f45726187b5b23a3cfb9743166aa60fae30 (diff)
[GFX] Fix d3d12 buffer view creation logic for StructuredBuffers. (#3954)
Diffstat (limited to 'tools/gfx/d3d12/d3d12-resource-views.cpp')
-rw-r--r--tools/gfx/d3d12/d3d12-resource-views.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/tools/gfx/d3d12/d3d12-resource-views.cpp b/tools/gfx/d3d12/d3d12-resource-views.cpp
index 5a044dd3b..b0b441f87 100644
--- a/tools/gfx/d3d12/d3d12-resource-views.cpp
+++ b/tools/gfx/d3d12/d3d12-resource-views.cpp
@@ -1,5 +1,6 @@
// d3d12-resource-views.cpp
#include "d3d12-resource-views.h"
+#include "d3d12-device.h"
namespace gfx
{
@@ -12,6 +13,208 @@ ResourceViewInternalImpl::~ResourceViewInternalImpl()
{
if (m_descriptor.cpuHandle.ptr)
m_allocator->free(m_descriptor);
+ for (auto desc : m_mapBufferStrideToDescriptor)
+ {
+ m_allocator->free(desc.second);
+ }
+}
+
+SlangResult createD3D12BufferDescriptor(
+ BufferResourceImpl* buffer,
+ BufferResourceImpl* counterBuffer,
+ IResourceView::Desc const& desc,
+ DeviceImpl* device,
+ D3D12GeneralExpandingDescriptorHeap* descriptorHeap,
+ D3D12Descriptor* outDescriptor)
+{
+
+ auto resourceImpl = (BufferResourceImpl*)buffer;
+ auto resourceDesc = *resourceImpl->getDesc();
+ const auto counterResourceImpl = static_cast<BufferResourceImpl*>(counterBuffer);
+
+ switch (desc.type)
+ {
+ default:
+ return SLANG_FAIL;
+
+ case IResourceView::Type::UnorderedAccess:
+ {
+ D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
+ uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
+ uavDesc.Format = D3DUtil::getMapFormat(desc.format);
+ uavDesc.Buffer.FirstElement = desc.bufferRange.firstElement;
+ uint64_t viewSize = 0;
+ if (desc.bufferElementSize)
+ {
+ uavDesc.Buffer.StructureByteStride = (UINT)desc.bufferElementSize;
+ uavDesc.Buffer.NumElements =
+ desc.bufferRange.elementCount == 0
+ ? UINT(resourceDesc.sizeInBytes / desc.bufferElementSize)
+ : (UINT)desc.bufferRange.elementCount;
+ viewSize = (uint64_t)desc.bufferElementSize * uavDesc.Buffer.NumElements;
+ }
+ else if (desc.format == Format::Unknown)
+ {
+ uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
+ uavDesc.Buffer.NumElements = desc.bufferRange.elementCount == 0
+ ? UINT(resourceDesc.sizeInBytes / 4)
+ : UINT(desc.bufferRange.elementCount / 4);
+ uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW;
+ viewSize = 4ull * uavDesc.Buffer.NumElements;
+ }
+ else
+ {
+ FormatInfo sizeInfo;
+ gfxGetFormatInfo(desc.format, &sizeInfo);
+ assert(sizeInfo.pixelsPerBlock == 1);
+ uavDesc.Buffer.NumElements =
+ desc.bufferRange.elementCount == 0
+ ? UINT(resourceDesc.sizeInBytes / sizeInfo.blockSizeInBytes)
+ : (UINT)desc.bufferRange.elementCount;
+ viewSize = (uint64_t)uavDesc.Buffer.NumElements * sizeInfo.blockSizeInBytes;
+ }
+
+ if (viewSize >= (1ull << 32) - 8)
+ {
+ // D3D12 does not support view descriptors that has size near 4GB.
+ // We will not create actual SRV/UAVs for such large buffers.
+ // However, a buffer this large can still be bound as root parameter.
+ // So instead of failing, we quietly ignore descriptor creation.
+ outDescriptor->cpuHandle.ptr = 0;
+ }
+ else
+ {
+ SLANG_RETURN_ON_FAIL(descriptorHeap->allocate(outDescriptor));
+ device->m_device->CreateUnorderedAccessView(
+ resourceImpl->m_resource,
+ counterResourceImpl ? counterResourceImpl->m_resource.getResource() : nullptr,
+ &uavDesc,
+ outDescriptor->cpuHandle);
+ }
+ }
+ break;
+
+ case IResourceView::Type::ShaderResource:
+ {
+ D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
+ srvDesc.Format = D3DUtil::getMapFormat(desc.format);
+ srvDesc.Buffer.StructureByteStride = 0;
+ srvDesc.Buffer.FirstElement = desc.bufferRange.firstElement;
+ srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ uint64_t viewSize = 0;
+ if (desc.bufferElementSize)
+ {
+ srvDesc.Buffer.StructureByteStride = (UINT)desc.bufferElementSize;
+ srvDesc.Buffer.NumElements =
+ desc.bufferRange.elementCount == 0
+ ? UINT(resourceDesc.sizeInBytes / desc.bufferElementSize)
+ : (UINT)desc.bufferRange.elementCount;
+ viewSize = (uint64_t)desc.bufferElementSize * srvDesc.Buffer.NumElements;
+ }
+ else if (desc.format == Format::Unknown)
+ {
+ srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
+ srvDesc.Buffer.NumElements = desc.bufferRange.elementCount == 0
+ ? UINT(resourceDesc.sizeInBytes / 4)
+ : UINT(desc.bufferRange.elementCount / 4);
+ srvDesc.Buffer.Flags |= D3D12_BUFFER_SRV_FLAG_RAW;
+ viewSize = 4ull * srvDesc.Buffer.NumElements;
+ }
+ else
+ {
+ FormatInfo sizeInfo;
+ gfxGetFormatInfo(desc.format, &sizeInfo);
+ assert(sizeInfo.pixelsPerBlock == 1);
+ srvDesc.Buffer.NumElements =
+ desc.bufferRange.elementCount == 0
+ ? UINT(resourceDesc.sizeInBytes / sizeInfo.blockSizeInBytes)
+ : (UINT)desc.bufferRange.elementCount;
+ viewSize = (uint64_t)srvDesc.Buffer.NumElements * sizeInfo.blockSizeInBytes;
+ }
+ if (viewSize >= (1ull << 32) - 8)
+ {
+ // D3D12 does not support view descriptors that has size near 4GB.
+ // We will not create actual SRV/UAVs for such large buffers.
+ // However, a buffer this large can still be bound as root parameter.
+ // So instead of failing, we quietly ignore descriptor creation.
+ outDescriptor->cpuHandle.ptr = 0;
+ }
+ else
+ {
+ SLANG_RETURN_ON_FAIL(descriptorHeap->allocate(outDescriptor));
+ device->m_device->CreateShaderResourceView(
+ resourceImpl->m_resource, &srvDesc, outDescriptor->cpuHandle);
+ }
+ }
+ break;
+ }
+ return SLANG_OK;
+}
+
+SlangResult ResourceViewInternalImpl::getBufferDescriptorForBinding(
+ DeviceImpl* device,
+ ResourceViewImpl* view,
+ uint32_t bufferStride,
+ D3D12Descriptor& outDescriptor)
+{
+ // If stride is 0, just use the default descriptor.
+ if (bufferStride == 0)
+ {
+ outDescriptor = m_descriptor;
+ return SLANG_OK;
+ }
+
+ // Otherwise, look for an existing descriptor from the cache if it exists.
+ if (auto descriptor = m_mapBufferStrideToDescriptor.tryGetValue(bufferStride))
+ {
+ outDescriptor = *descriptor;
+ return SLANG_OK;
+ }
+
+ // We need to create and cache a d3d12 descriptor for the resource view that encodes
+ // the given buffer stride.
+ auto bufferResImpl = static_cast<BufferResourceImpl*>(view->m_resource.get());
+ auto desc = view->m_desc;
+ uint64_t bufferSize = 0;
+ if (desc.bufferElementSize == 0)
+ {
+ // If buffer element size is 0, we assume the buffer range from original desc is in bytes.
+ bufferSize = desc.bufferRange.elementCount;
+ if (bufferSize == 0)
+ {
+ bufferSize = bufferResImpl->getDesc()->sizeInBytes - desc.bufferRange.firstElement;
+ }
+ desc.bufferElementSize = bufferStride;
+ desc.bufferRange.firstElement /= bufferStride;
+ desc.bufferRange.elementCount = bufferSize / bufferStride;
+ }
+ else
+ {
+ // If buffer element size is not 0, we assume the buffer range from original desc is in elements
+ // of original stride.
+ if (desc.bufferRange.elementCount == 0)
+ {
+ bufferSize = bufferResImpl->getDesc()->sizeInBytes - desc.bufferRange.firstElement * desc.bufferElementSize;
+ }
+ else
+ {
+ bufferSize = desc.bufferRange.elementCount * desc.bufferElementSize;
+ }
+ desc.bufferElementSize = bufferStride;
+ desc.bufferRange.firstElement = desc.bufferRange.firstElement * desc.bufferElementSize / bufferStride;
+ desc.bufferRange.elementCount = bufferSize / bufferStride;
+ }
+ SLANG_RETURN_ON_FAIL(createD3D12BufferDescriptor(
+ bufferResImpl,
+ static_cast<BufferResourceImpl*>(view->m_counterResource.get()),
+ desc,
+ device,
+ m_allocator,
+ &outDescriptor));
+ m_mapBufferStrideToDescriptor[bufferStride] = outDescriptor;
+
+ return SLANG_OK;
}
Result ResourceViewImpl::getNativeHandle(InteropHandle* outHandle)