Add RHI buffer SRV and UAV view support

This commit is contained in:
2026-04-08 18:05:00 +08:00
parent 162f1cc12e
commit 4728b09ae8
28 changed files with 988 additions and 43 deletions

View File

@@ -311,6 +311,89 @@ DXGI_FORMAT ResolveD3D12ShaderResourceViewFormat(Format format) {
}
}
bool IsSupportedBufferViewDimension(ResourceViewDimension dimension) {
return dimension == ResourceViewDimension::Buffer ||
dimension == ResourceViewDimension::StructuredBuffer ||
dimension == ResourceViewDimension::RawBuffer;
}
uint32_t ResolveBufferViewElementStride(RHIBuffer* buffer, const ResourceViewDesc& desc) {
if (desc.dimension == ResourceViewDimension::RawBuffer) {
return 4u;
}
if (desc.structureByteStride > 0) {
return desc.structureByteStride;
}
if (desc.dimension == ResourceViewDimension::Buffer && desc.format != 0) {
return GetFormatBytesPerPixel(static_cast<Format>(desc.format));
}
return buffer != nullptr ? buffer->GetStride() : 0u;
}
bool TryResolveBufferViewFirstElement(
RHIBuffer* buffer,
const ResourceViewDesc& desc,
uint32_t& outFirstElement,
uint32_t& outElementStride) {
outFirstElement = 0;
outElementStride = ResolveBufferViewElementStride(buffer, desc);
if (outElementStride == 0) {
return false;
}
if ((desc.bufferLocation % outElementStride) != 0) {
return false;
}
outFirstElement =
desc.firstElement + static_cast<uint32_t>(desc.bufferLocation / outElementStride);
return true;
}
bool TryResolveBufferViewElementCount(
RHIBuffer* buffer,
const ResourceViewDesc& desc,
uint32_t elementStride,
uint32_t firstElement,
uint32_t& outElementCount) {
outElementCount = 0;
if (desc.elementCount > 0) {
outElementCount = desc.elementCount;
return true;
}
if (buffer == nullptr || elementStride == 0) {
return false;
}
const uint64_t byteOffset = static_cast<uint64_t>(firstElement) * elementStride;
if (byteOffset >= buffer->GetSize()) {
return false;
}
outElementCount = static_cast<uint32_t>((buffer->GetSize() - byteOffset) / elementStride);
return outElementCount > 0;
}
DXGI_FORMAT ResolveD3D12BufferViewFormat(const ResourceViewDesc& desc) {
if (desc.dimension == ResourceViewDimension::RawBuffer) {
return DXGI_FORMAT_R32_TYPELESS;
}
if (desc.dimension == ResourceViewDimension::StructuredBuffer) {
return DXGI_FORMAT_UNKNOWN;
}
if (desc.dimension == ResourceViewDimension::Buffer && desc.format != 0) {
return ToD3D12(static_cast<Format>(desc.format));
}
return DXGI_FORMAT_UNKNOWN;
}
} // namespace
D3D12Device::D3D12Device()
@@ -687,17 +770,27 @@ const RHIDeviceInfo& D3D12Device::GetDeviceInfo() const {
RHIBuffer* D3D12Device::CreateBuffer(const BufferDesc& desc) {
auto* buffer = new D3D12Buffer();
const BufferType bufferType = static_cast<BufferType>(desc.bufferType);
D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_DEFAULT;
if (desc.bufferType == static_cast<uint32_t>(BufferType::ReadBack)) {
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE;
if (bufferType == BufferType::ReadBack) {
heapType = D3D12_HEAP_TYPE_READBACK;
} else if (desc.bufferType == static_cast<uint32_t>(BufferType::Constant) ||
desc.bufferType == static_cast<uint32_t>(BufferType::Vertex) ||
desc.bufferType == static_cast<uint32_t>(BufferType::Index)) {
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
} else if (bufferType == BufferType::Constant ||
bufferType == BufferType::Vertex ||
bufferType == BufferType::Index) {
heapType = D3D12_HEAP_TYPE_UPLOAD;
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
} else if (bufferType == BufferType::Storage) {
resourceFlags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
if (buffer->Initialize(m_device.Get(), desc.size, D3D12_RESOURCE_STATE_COMMON, heapType)) {
if (buffer->Initialize(m_device.Get(), desc.size, initialState, heapType, resourceFlags)) {
buffer->SetStride(desc.stride);
buffer->SetBufferType(static_cast<BufferType>(desc.bufferType));
buffer->SetBufferType(bufferType);
buffer->SetState(ResourceStates::Common);
return buffer;
}
delete buffer;
@@ -1148,6 +1241,60 @@ RHIResourceView* D3D12Device::CreateDepthStencilView(RHITexture* texture, const
return view;
}
RHIResourceView* D3D12Device::CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
if (buffer == nullptr || m_device == nullptr || !IsSupportedBufferViewDimension(desc.dimension)) {
return nullptr;
}
if (desc.dimension == ResourceViewDimension::Buffer && desc.format == 0) {
return nullptr;
}
uint32_t firstElement = 0;
uint32_t elementStride = 0;
if (!TryResolveBufferViewFirstElement(buffer, desc, firstElement, elementStride)) {
return nullptr;
}
uint32_t elementCount = 0;
if (!TryResolveBufferViewElementCount(buffer, desc, elementStride, firstElement, elementCount)) {
return nullptr;
}
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = ResolveD3D12BufferViewFormat(desc);
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Buffer.FirstElement = firstElement;
srvDesc.Buffer.NumElements = elementCount;
srvDesc.Buffer.StructureByteStride =
desc.dimension == ResourceViewDimension::StructuredBuffer ? elementStride : 0u;
srvDesc.Buffer.Flags =
desc.dimension == ResourceViewDimension::RawBuffer
? D3D12_BUFFER_SRV_FLAG_RAW
: D3D12_BUFFER_SRV_FLAG_NONE;
auto heap = std::make_unique<D3D12DescriptorHeap>();
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
return nullptr;
}
auto* view = new D3D12ResourceView();
view->InitializeAsShaderResourceBuffer(
m_device.Get(),
static_cast<D3D12Buffer*>(buffer),
desc,
&srvDesc,
heap.get(),
0);
if (!view->IsValid()) {
delete view;
return nullptr;
}
view->SetOwnedHeap(std::move(heap));
return view;
}
RHIResourceView* D3D12Device::CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) {
auto* view = new D3D12ResourceView();
auto* d3d12Texture = static_cast<D3D12Texture*>(texture);
@@ -1217,6 +1364,59 @@ RHIResourceView* D3D12Device::CreateShaderResourceView(RHITexture* texture, cons
return view;
}
RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
if (buffer == nullptr || m_device == nullptr || !IsSupportedBufferViewDimension(desc.dimension)) {
return nullptr;
}
if (desc.dimension == ResourceViewDimension::Buffer && desc.format == 0) {
return nullptr;
}
uint32_t firstElement = 0;
uint32_t elementStride = 0;
if (!TryResolveBufferViewFirstElement(buffer, desc, firstElement, elementStride)) {
return nullptr;
}
uint32_t elementCount = 0;
if (!TryResolveBufferViewElementCount(buffer, desc, elementStride, firstElement, elementCount)) {
return nullptr;
}
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.Format = ResolveD3D12BufferViewFormat(desc);
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.FirstElement = firstElement;
uavDesc.Buffer.NumElements = elementCount;
uavDesc.Buffer.StructureByteStride =
desc.dimension == ResourceViewDimension::StructuredBuffer ? elementStride : 0u;
uavDesc.Buffer.Flags =
desc.dimension == ResourceViewDimension::RawBuffer
? D3D12_BUFFER_UAV_FLAG_RAW
: D3D12_BUFFER_UAV_FLAG_NONE;
auto heap = std::make_unique<D3D12DescriptorHeap>();
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
return nullptr;
}
auto* view = new D3D12ResourceView();
view->InitializeAsUnorderedAccessBuffer(
m_device.Get(),
static_cast<D3D12Buffer*>(buffer),
desc,
&uavDesc,
heap.get(),
0);
if (!view->IsValid()) {
delete view;
return nullptr;
}
view->SetOwnedHeap(std::move(heap));
return view;
}
RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) {
auto* view = new D3D12ResourceView();
auto* d3d12Texture = static_cast<D3D12Texture*>(texture);