Add RHI buffer SRV and UAV view support
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user