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

@@ -17,7 +17,12 @@ public:
D3D12Buffer();
~D3D12Buffer() override;
bool Initialize(ID3D12Device* device, uint64_t size, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON, D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_DEFAULT);
bool Initialize(
ID3D12Device* device,
uint64_t size,
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON,
D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_DEFAULT,
D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE);
bool InitializeFromExisting(ID3D12Resource* resource);
bool InitializeWithData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList,
const void* data, uint64_t size, D3D12_RESOURCE_STATES finalState);

View File

@@ -93,7 +93,9 @@ public:
RHIResourceView* CreateIndexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) override;
bool ReadTexturePixelRGBA8(
RHICommandQueue* commandQueue,

View File

@@ -42,9 +42,23 @@ public:
void InitializeAsShaderResource(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_SHADER_RESOURCE_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);
void InitializeAsShaderResourceBuffer(
ID3D12Device* device,
D3D12Buffer* buffer,
const ResourceViewDesc& resourceViewDesc,
const D3D12_SHADER_RESOURCE_VIEW_DESC* desc,
D3D12DescriptorHeap* heap,
uint32_t slotIndex);
void InitializeAsUnorderedAccess(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);
void InitializeAsUnorderedAccessBuffer(
ID3D12Device* device,
D3D12Buffer* buffer,
const ResourceViewDesc& resourceViewDesc,
const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc,
D3D12DescriptorHeap* heap,
uint32_t slotIndex);
void InitializeAsConstantBuffer(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_CONSTANT_BUFFER_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);

View File

@@ -16,7 +16,8 @@ enum class OpenGLBufferType {
AtomicCounter,
DispatchIndirect,
DrawIndirect,
ShaderBindingTable
ShaderBindingTable,
ShaderStorage
};
class OpenGLBuffer : public RHIBuffer {

View File

@@ -16,9 +16,13 @@ struct DescriptorBinding {
uint32_t binding;
DescriptorType type;
uint32_t count;
ResourceViewDimension resourceDimension = ResourceViewDimension::Unknown;
std::vector<uint32_t> textureUnits;
std::vector<uint32_t> textureIds;
std::vector<uint32_t> textureTargets;
std::vector<uint32_t> bufferIds;
std::vector<uint64_t> bufferOffsets;
std::vector<uint32_t> bufferSizes;
std::vector<uint32_t> samplerIds;
};

View File

@@ -64,7 +64,9 @@ public:
RHIResourceView* CreateIndexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) override;
const RHICapabilities& GetCapabilities() const override;

View File

@@ -164,6 +164,7 @@ inline GLenum ToOpenGL(OpenGLBufferType type) {
case OpenGLBufferType::DispatchIndirect: return GL_DISPATCH_INDIRECT_BUFFER;
case OpenGLBufferType::DrawIndirect: return GL_DRAW_INDIRECT_BUFFER;
case OpenGLBufferType::ShaderBindingTable: return GL_SHADER_STORAGE_BUFFER;
case OpenGLBufferType::ShaderStorage: return GL_SHADER_STORAGE_BUFFER;
default: return GL_ARRAY_BUFFER;
}
}

View File

@@ -36,11 +36,17 @@ public:
OpenGLTexture* texture,
const ResourceViewDesc& desc,
OpenGLTextureUnitAllocator* allocator);
bool InitializeAsShaderResource(
OpenGLBuffer* buffer,
const ResourceViewDesc& desc);
bool InitializeAsUnorderedAccess(
OpenGLTexture* texture,
const ResourceViewDesc& desc,
OpenGLTextureUnitAllocator* allocator);
bool InitializeAsUnorderedAccess(
OpenGLBuffer* buffer,
const ResourceViewDesc& desc);
bool InitializeAsConstantBuffer(
OpenGLBuffer* buffer,

View File

@@ -64,7 +64,9 @@ public:
virtual RHIResourceView* CreateIndexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) = 0;
virtual bool ReadTexturePixelRGBA8(

View File

@@ -108,9 +108,25 @@ enum class BufferType : uint8_t {
ReadBack,
Indirect,
RaytracingAccelerationStructure,
ShaderBindingTable
ShaderBindingTable,
Storage
};
enum class BufferFlags : uint64_t {
None = 0,
AllowUnorderedAccess = 1ull << 0
};
inline BufferFlags operator|(BufferFlags left, BufferFlags right) {
return static_cast<BufferFlags>(
static_cast<uint64_t>(left) | static_cast<uint64_t>(right));
}
inline BufferFlags operator&(BufferFlags left, BufferFlags right) {
return static_cast<BufferFlags>(
static_cast<uint64_t>(left) & static_cast<uint64_t>(right));
}
enum class DescriptorType : uint8_t {
CBV,
SRV,
@@ -277,6 +293,12 @@ enum class ResourceViewDimension : uint8_t {
RawBuffer
};
inline bool IsBufferResourceViewDimension(ResourceViewDimension dimension) {
return dimension == ResourceViewDimension::Buffer ||
dimension == ResourceViewDimension::StructuredBuffer ||
dimension == ResourceViewDimension::RawBuffer;
}
enum class ResourceViewType : uint8_t {
VertexBuffer,
IndexBuffer,

View File

@@ -370,6 +370,7 @@ struct DescriptorSetLayoutBinding {
uint32_t type = 0;
uint32_t count = 0;
uint32_t visibility = 0;
ResourceViewDimension resourceDimension = ResourceViewDimension::Unknown;
};
struct DescriptorSetLayoutDesc {
@@ -394,6 +395,8 @@ struct ResourceViewDesc {
uint32_t firstArraySlice = 0;
uint32_t planeSlice = 0;
uint64_t bufferLocation = 0;
uint32_t firstElement = 0;
uint32_t elementCount = 0;
uint32_t structureByteStride = 0;
};

View File

@@ -324,14 +324,20 @@ inline VkSampleCountFlagBits ToVulkanSampleCount(uint32_t sampleCount) {
}
}
inline VkDescriptorType ToVulkanDescriptorType(DescriptorType type) {
inline VkDescriptorType ToVulkanDescriptorType(
DescriptorType type,
ResourceViewDimension resourceDimension = ResourceViewDimension::Unknown) {
switch (type) {
case DescriptorType::CBV:
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
case DescriptorType::SRV:
return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
return IsBufferResourceViewDimension(resourceDimension)
? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
: VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
case DescriptorType::UAV:
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
return IsBufferResourceViewDimension(resourceDimension)
? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case DescriptorType::Sampler:
return VK_DESCRIPTOR_TYPE_SAMPLER;
default:

View File

@@ -39,7 +39,9 @@ public:
RHIResourceView* CreateIndexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) override;
RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) override;
const RHICapabilities& GetCapabilities() const override { return m_capabilities; }

View File

@@ -17,7 +17,9 @@ public:
bool InitializeAsRenderTarget(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc);
bool InitializeAsDepthStencil(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc);
bool InitializeAsShaderResource(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc);
bool InitializeAsShaderResource(VulkanBuffer* buffer, const ResourceViewDesc& desc);
bool InitializeAsUnorderedAccess(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc);
bool InitializeAsUnorderedAccess(VulkanBuffer* buffer, const ResourceViewDesc& desc);
bool InitializeAsVertexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc);
bool InitializeAsIndexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc);

View File

@@ -10,7 +10,12 @@ D3D12Buffer::~D3D12Buffer() {
Shutdown();
}
bool D3D12Buffer::Initialize(ID3D12Device* device, uint64_t size, D3D12_RESOURCE_STATES initialState, D3D12_HEAP_TYPE heapType) {
bool D3D12Buffer::Initialize(
ID3D12Device* device,
uint64_t size,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_TYPE heapType,
D3D12_RESOURCE_FLAGS resourceFlags) {
D3D12_HEAP_PROPERTIES heapProperties = {};
heapProperties.Type = heapType;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
@@ -29,7 +34,7 @@ bool D3D12Buffer::Initialize(ID3D12Device* device, uint64_t size, D3D12_RESOURCE
bufferDesc.SampleDesc.Count = 1;
bufferDesc.SampleDesc.Quality = 0;
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
bufferDesc.Flags = resourceFlags;
HRESULT hResult = device->CreateCommittedResource(
&heapProperties,

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);

View File

@@ -60,6 +60,49 @@ ResourceViewDimension ToResourceViewDimension(D3D12_UAV_DIMENSION dimension) {
}
}
uint32_t ResolveBufferElementStride(D3D12Buffer* buffer, const ResourceViewDesc& desc) {
if (desc.dimension == ResourceViewDimension::RawBuffer) {
return 4u;
}
if (desc.structureByteStride > 0) {
return desc.structureByteStride;
}
return buffer != nullptr ? buffer->GetStride() : 0u;
}
uint64_t ResolveBufferByteOffset(D3D12Buffer* buffer, const ResourceViewDesc& desc) {
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return desc.bufferLocation;
}
return desc.bufferLocation + static_cast<uint64_t>(desc.firstElement) * elementStride;
}
uint32_t ResolveBufferElementCount(D3D12Buffer* buffer, const ResourceViewDesc& desc) {
if (desc.elementCount > 0) {
return desc.elementCount;
}
if (buffer == nullptr) {
return 0;
}
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return 0;
}
const uint64_t byteOffset = ResolveBufferByteOffset(buffer, desc);
if (byteOffset >= buffer->GetSize()) {
return 0;
}
return static_cast<uint32_t>((buffer->GetSize() - byteOffset) / elementStride);
}
} // namespace
D3D12ResourceView::D3D12ResourceView()
@@ -161,6 +204,29 @@ void D3D12ResourceView::InitializeAsShaderResource(ID3D12Device* device, ID3D12R
device->CreateShaderResourceView(resource, desc, m_handle);
}
void D3D12ResourceView::InitializeAsShaderResourceBuffer(
ID3D12Device* device,
D3D12Buffer* buffer,
const ResourceViewDesc& resourceViewDesc,
const D3D12_SHADER_RESOURCE_VIEW_DESC* desc,
D3D12DescriptorHeap* heap,
uint32_t slotIndex) {
if (buffer == nullptr) {
return;
}
InitializeAsShaderResource(device, buffer->GetResource(), desc, heap, slotIndex);
m_dimension =
resourceViewDesc.dimension != ResourceViewDimension::Unknown
? resourceViewDesc.dimension
: ResourceViewDimension::Buffer;
m_bufferOffset = ResolveBufferByteOffset(buffer, resourceViewDesc);
m_bufferLocation = buffer->GetGPUVirtualAddress() + m_bufferOffset;
m_bufferStride = ResolveBufferElementStride(buffer, resourceViewDesc);
const uint32_t elementCount = ResolveBufferElementCount(buffer, resourceViewDesc);
m_bufferSize = elementCount * m_bufferStride;
}
void D3D12ResourceView::InitializeAsUnorderedAccess(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex) {
@@ -176,6 +242,29 @@ void D3D12ResourceView::InitializeAsUnorderedAccess(ID3D12Device* device, ID3D12
device->CreateUnorderedAccessView(resource, nullptr, desc, m_handle);
}
void D3D12ResourceView::InitializeAsUnorderedAccessBuffer(
ID3D12Device* device,
D3D12Buffer* buffer,
const ResourceViewDesc& resourceViewDesc,
const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc,
D3D12DescriptorHeap* heap,
uint32_t slotIndex) {
if (buffer == nullptr) {
return;
}
InitializeAsUnorderedAccess(device, buffer->GetResource(), desc, heap, slotIndex);
m_dimension =
resourceViewDesc.dimension != ResourceViewDimension::Unknown
? resourceViewDesc.dimension
: ResourceViewDimension::Buffer;
m_bufferOffset = ResolveBufferByteOffset(buffer, resourceViewDesc);
m_bufferLocation = buffer->GetGPUVirtualAddress() + m_bufferOffset;
m_bufferStride = ResolveBufferElementStride(buffer, resourceViewDesc);
const uint32_t elementCount = ResolveBufferElementCount(buffer, resourceViewDesc);
m_bufferSize = elementCount * m_bufferStride;
}
void D3D12ResourceView::InitializeAsConstantBuffer(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_CONSTANT_BUFFER_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex) {

View File

@@ -34,6 +34,10 @@ uint32_t ResolveBindingPoint(
}
}
bool UsesBufferBinding(ResourceViewDimension dimension) {
return IsBufferResourceViewDimension(dimension);
}
} // namespace
OpenGLDescriptorSet::OpenGLDescriptorSet()
@@ -81,11 +85,20 @@ bool OpenGLDescriptorSet::Initialize(OpenGLTextureUnitAllocator* allocator, uint
m_bindings[i].binding = layout.bindings[i].binding;
m_bindings[i].type = static_cast<DescriptorType>(layout.bindings[i].type);
m_bindings[i].count = layout.bindings[i].count;
m_bindings[i].resourceDimension = layout.bindings[i].resourceDimension;
m_bindings[i].textureUnits.resize(layout.bindings[i].count);
m_bindings[i].textureIds.resize(layout.bindings[i].count, 0);
m_bindings[i].textureTargets.resize(layout.bindings[i].count, GL_TEXTURE_2D);
m_bindings[i].bufferIds.resize(layout.bindings[i].count, 0);
m_bindings[i].bufferOffsets.resize(layout.bindings[i].count, 0);
m_bindings[i].bufferSizes.resize(layout.bindings[i].count, 0);
m_bindings[i].samplerIds.resize(layout.bindings[i].count, 0);
if (UsesBufferBinding(m_bindings[i].resourceDimension)) {
m_bindings[i].textureUnits.clear();
continue;
}
if (m_bindings[i].type != DescriptorType::SRV &&
m_bindings[i].type != DescriptorType::Sampler &&
m_bindings[i].type != DescriptorType::UAV) {
@@ -156,11 +169,32 @@ void OpenGLDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
}
DescriptorBinding* binding = FindBinding(offset);
if (binding == nullptr || binding->textureIds.empty()) {
if (binding == nullptr) {
return;
}
OpenGLResourceView* glView = static_cast<OpenGLResourceView*>(view);
const bool expectsBuffer = UsesBufferBinding(binding->resourceDimension);
const bool viewIsBuffer = IsBufferResourceViewDimension(glView->GetDimension());
if (expectsBuffer != viewIsBuffer) {
return;
}
if (expectsBuffer) {
if (binding->bufferIds.empty()) {
return;
}
binding->bufferIds[0] = glView->GetBuffer();
binding->bufferOffsets[0] = glView->GetBufferOffset();
binding->bufferSizes[0] = glView->GetBufferSize();
return;
}
if (binding->textureIds.empty()) {
return;
}
binding->textureIds[0] = glView->GetTexture();
if (const OpenGLTexture* texture = glView->GetTextureResource()) {
binding->textureTargets[0] = static_cast<uint32_t>(ToOpenGL(texture->GetOpenGLType()));
@@ -199,6 +233,31 @@ void OpenGLDescriptorSet::Bind() {
for (size_t i = 0; i < m_bindings.size(); ++i) {
const auto& binding = m_bindings[i];
if (UsesBufferBinding(binding.resourceDimension)) {
for (size_t j = 0; j < binding.bufferIds.size(); ++j) {
const GLuint bufferId = binding.bufferIds[j];
if (bufferId == 0) {
continue;
}
const GLuint rangeSize = j < binding.bufferSizes.size() ? binding.bufferSizes[j] : 0u;
if (rangeSize > 0) {
glBindBufferRange(
GL_SHADER_STORAGE_BUFFER,
binding.binding + static_cast<uint32_t>(j),
bufferId,
static_cast<GLintptr>(binding.bufferOffsets[j]),
static_cast<GLsizeiptr>(rangeSize));
} else {
glBindBufferBase(
GL_SHADER_STORAGE_BUFFER,
binding.binding + static_cast<uint32_t>(j),
bufferId);
}
}
continue;
}
for (size_t j = 0; j < binding.textureUnits.size(); ++j) {
uint32_t unit = binding.textureUnits[j];
uint32_t textureId = binding.textureIds[j];
@@ -246,6 +305,29 @@ void OpenGLDescriptorSet::BindWithPipelineLayout(const OpenGLPipelineLayout* pip
continue;
}
if (UsesBufferBinding(binding.resourceDimension)) {
for (size_t i = 0; i < binding.bufferIds.size(); ++i) {
const GLuint bufferId = binding.bufferIds[i];
if (bufferId == 0) {
continue;
}
const uint32_t bindingPoint = baseBindingPoint + static_cast<uint32_t>(i);
const GLuint rangeSize = i < binding.bufferSizes.size() ? binding.bufferSizes[i] : 0u;
if (rangeSize > 0) {
glBindBufferRange(
GL_SHADER_STORAGE_BUFFER,
bindingPoint,
bufferId,
static_cast<GLintptr>(binding.bufferOffsets[i]),
static_cast<GLsizeiptr>(rangeSize));
} else {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, bindingPoint, bufferId);
}
}
continue;
}
for (size_t i = 0; i < binding.textureIds.size(); ++i) {
const uint32_t bindingPoint = baseBindingPoint + static_cast<uint32_t>(i);
const uint32_t textureId = binding.textureIds[i];
@@ -282,6 +364,13 @@ void OpenGLDescriptorSet::Unbind() {
}
}
if (UsesBufferBinding(binding.resourceDimension)) {
for (size_t j = 0; j < binding.bufferIds.size(); ++j) {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding.binding + static_cast<uint32_t>(j), 0);
}
continue;
}
for (size_t j = 0; j < binding.textureUnits.size(); ++j) {
uint32_t unit = binding.textureUnits[j];

View File

@@ -1181,20 +1181,35 @@ void OpenGLDevice::SwapBuffers() {
RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) {
auto* buffer = new OpenGLBuffer();
OpenGLBufferType bufferType = OpenGLBufferType::Vertex;
switch (desc.bufferType) {
case 1:
switch (static_cast<BufferType>(desc.bufferType)) {
case BufferType::Index:
bufferType = OpenGLBufferType::Index;
break;
case 2:
case BufferType::Constant:
bufferType = OpenGLBufferType::Uniform;
break;
case BufferType::ReadBack:
bufferType = OpenGLBufferType::CopyRead;
break;
case BufferType::Indirect:
bufferType = OpenGLBufferType::DrawIndirect;
break;
case BufferType::Storage:
bufferType = OpenGLBufferType::ShaderStorage;
break;
case BufferType::Vertex:
default:
bufferType = OpenGLBufferType::Vertex;
break;
}
buffer->Initialize(bufferType, desc.size, nullptr, false);
if (!buffer->Initialize(bufferType, desc.size, nullptr, false)) {
delete buffer;
return nullptr;
}
buffer->SetBufferType(static_cast<BufferType>(desc.bufferType));
buffer->SetStride(desc.stride);
return buffer;
}
@@ -1575,6 +1590,21 @@ RHIResourceView* OpenGLDevice::CreateDepthStencilView(RHITexture* texture, const
return view;
}
RHIResourceView* OpenGLDevice::CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
if (!buffer || !IsBufferResourceViewDimension(desc.dimension)) {
return nullptr;
}
auto* glBuffer = static_cast<OpenGLBuffer*>(buffer);
auto* view = new OpenGLResourceView();
if (!view->InitializeAsShaderResource(glBuffer, desc)) {
delete view;
return nullptr;
}
return view;
}
RHIResourceView* OpenGLDevice::CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) {
if (!texture) {
return nullptr;
@@ -1591,6 +1621,21 @@ RHIResourceView* OpenGLDevice::CreateShaderResourceView(RHITexture* texture, con
return view;
}
RHIResourceView* OpenGLDevice::CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
if (!buffer || !IsBufferResourceViewDimension(desc.dimension)) {
return nullptr;
}
auto* glBuffer = static_cast<OpenGLBuffer*>(buffer);
auto* view = new OpenGLResourceView();
if (!view->InitializeAsUnorderedAccess(glBuffer, desc)) {
delete view;
return nullptr;
}
return view;
}
RHIResourceView* OpenGLDevice::CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) {
if (!texture) {
return nullptr;

View File

@@ -55,6 +55,49 @@ FramebufferAttachmentType ResolveDepthAttachmentType(Format format) {
: FramebufferAttachmentType::Depth;
}
uint32_t ResolveBufferElementStride(OpenGLBuffer* buffer, const ResourceViewDesc& desc) {
if (desc.dimension == ResourceViewDimension::RawBuffer) {
return 4u;
}
if (desc.structureByteStride > 0) {
return desc.structureByteStride;
}
return buffer != nullptr ? buffer->GetStride() : 0u;
}
uint64_t ResolveBufferByteOffset(OpenGLBuffer* buffer, const ResourceViewDesc& desc) {
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return desc.bufferLocation;
}
return desc.bufferLocation + static_cast<uint64_t>(desc.firstElement) * elementStride;
}
uint32_t ResolveBufferElementCount(OpenGLBuffer* buffer, const ResourceViewDesc& desc) {
if (desc.elementCount > 0) {
return desc.elementCount;
}
if (buffer == nullptr) {
return 0;
}
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return 0;
}
const uint64_t byteOffset = ResolveBufferByteOffset(buffer, desc);
if (byteOffset >= buffer->GetSize()) {
return 0;
}
return static_cast<uint32_t>((buffer->GetSize() - byteOffset) / elementStride);
}
} // namespace
OpenGLResourceView::OpenGLResourceView()
@@ -113,7 +156,8 @@ void* OpenGLResourceView::GetNativeHandle() {
return reinterpret_cast<void*>(static_cast<uintptr_t>(m_framebufferID));
case ResourceViewType::ShaderResource:
case ResourceViewType::UnorderedAccess:
return reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture ? m_texture->GetID() : 0));
return reinterpret_cast<void*>(static_cast<uintptr_t>(
m_texture != nullptr ? m_texture->GetID() : (m_buffer != nullptr ? m_buffer->GetID() : 0)));
case ResourceViewType::ConstantBuffer:
return reinterpret_cast<void*>(static_cast<uintptr_t>(m_buffer ? m_buffer->GetID() : 0));
default:
@@ -130,9 +174,11 @@ bool OpenGLResourceView::IsValid() const {
case ResourceViewType::DepthStencil:
return m_framebufferID != 0;
case ResourceViewType::ShaderResource:
return m_texture != nullptr && m_texture->GetID() != 0;
return (m_texture != nullptr && m_texture->GetID() != 0) ||
(m_buffer != nullptr && m_buffer->GetID() != 0 && m_bufferSize > 0);
case ResourceViewType::UnorderedAccess:
return m_texture != nullptr && m_textureUnit >= 0;
return (m_texture != nullptr && m_textureUnit >= 0) ||
(m_buffer != nullptr && m_buffer->GetID() != 0 && m_bufferSize > 0);
case ResourceViewType::ConstantBuffer:
return m_buffer != nullptr && m_bindingPoint >= 0;
default:
@@ -230,6 +276,62 @@ bool OpenGLResourceView::InitializeAsUnorderedAccess(
return true;
}
bool OpenGLResourceView::InitializeAsShaderResource(
OpenGLBuffer* buffer,
const ResourceViewDesc& desc) {
if (!buffer || !IsBufferResourceViewDimension(desc.dimension)) {
return false;
}
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return false;
}
const uint32_t elementCount = ResolveBufferElementCount(buffer, desc);
if (elementCount == 0) {
return false;
}
m_viewType = ResourceViewType::ShaderResource;
m_format = desc.format != 0 ? static_cast<Format>(desc.format) : Format::Unknown;
m_dimension =
desc.dimension != ResourceViewDimension::Unknown ? desc.dimension : ResourceViewDimension::Buffer;
m_buffer = buffer;
m_bufferOffset = ResolveBufferByteOffset(buffer, desc);
m_bufferStride = elementStride;
m_bufferSize = elementCount * elementStride;
return true;
}
bool OpenGLResourceView::InitializeAsUnorderedAccess(
OpenGLBuffer* buffer,
const ResourceViewDesc& desc) {
if (!buffer || !IsBufferResourceViewDimension(desc.dimension)) {
return false;
}
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return false;
}
const uint32_t elementCount = ResolveBufferElementCount(buffer, desc);
if (elementCount == 0) {
return false;
}
m_viewType = ResourceViewType::UnorderedAccess;
m_format = desc.format != 0 ? static_cast<Format>(desc.format) : Format::Unknown;
m_dimension =
desc.dimension != ResourceViewDimension::Unknown ? desc.dimension : ResourceViewDimension::Buffer;
m_buffer = buffer;
m_bufferOffset = ResolveBufferByteOffset(buffer, desc);
m_bufferStride = elementStride;
m_bufferSize = elementCount * elementStride;
return true;
}
bool OpenGLResourceView::InitializeAsConstantBuffer(
OpenGLBuffer* buffer,
const ResourceViewDesc& desc,

View File

@@ -17,7 +17,9 @@ std::vector<VkDescriptorSetLayoutBinding> BuildVulkanLayoutBindings(const Descri
const DescriptorSetLayoutBinding& binding = layout.bindings[i];
VkDescriptorSetLayoutBinding vkBinding = {};
vkBinding.binding = binding.binding;
vkBinding.descriptorType = ToVulkanDescriptorType(static_cast<DescriptorType>(binding.type));
vkBinding.descriptorType = ToVulkanDescriptorType(
static_cast<DescriptorType>(binding.type),
binding.resourceDimension);
vkBinding.descriptorCount = binding.count > 0 ? binding.count : 1u;
vkBinding.stageFlags = ToVulkanShaderStageFlags(binding.visibility);
bindings.push_back(vkBinding);
@@ -47,6 +49,7 @@ bool VulkanDescriptorPool::Initialize(VkDevice device, const DescriptorPoolDesc&
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, desc.descriptorCount });
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, desc.descriptorCount });
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, desc.descriptorCount });
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, desc.descriptorCount });
break;
case DescriptorHeapType::Sampler:
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_SAMPLER, desc.descriptorCount });

View File

@@ -80,32 +80,63 @@ void VulkanDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
}
auto* vulkanView = static_cast<VulkanResourceView*>(view);
if (vulkanView == nullptr || vulkanView->GetImageView() == VK_NULL_HANDLE) {
if (vulkanView == nullptr) {
return;
}
VkDescriptorImageInfo imageInfo = {};
imageInfo.imageView = vulkanView->GetImageView();
VkWriteDescriptorSet write = {};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = m_descriptorSet;
write.dstBinding = offset;
write.descriptorCount = 1;
switch (static_cast<DescriptorType>(binding->type)) {
case DescriptorType::SRV:
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
write.pImageInfo = &imageInfo;
break;
case DescriptorType::UAV:
imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
write.pImageInfo = &imageInfo;
break;
default:
const DescriptorType descriptorType = static_cast<DescriptorType>(binding->type);
const bool expectsBuffer = IsBufferResourceViewDimension(binding->resourceDimension);
const bool viewIsBuffer = IsBufferResourceViewDimension(vulkanView->GetDimension());
if (viewIsBuffer) {
if (!expectsBuffer) {
return;
}
if (vulkanView->GetBuffer() == VK_NULL_HANDLE || vulkanView->GetBufferSize() == 0) {
return;
}
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = vulkanView->GetBuffer();
bufferInfo.offset = static_cast<VkDeviceSize>(vulkanView->GetBufferOffset());
bufferInfo.range = static_cast<VkDeviceSize>(vulkanView->GetBufferSize());
write.descriptorType = ToVulkanDescriptorType(descriptorType, binding->resourceDimension);
write.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr);
return;
}
if (expectsBuffer) {
return;
}
if (vulkanView->GetImageView() == VK_NULL_HANDLE) {
return;
}
VkDescriptorImageInfo imageInfo = {};
imageInfo.imageView = vulkanView->GetImageView();
switch (descriptorType) {
case DescriptorType::SRV:
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
write.pImageInfo = &imageInfo;
break;
case DescriptorType::UAV:
imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
write.pImageInfo = &imageInfo;
break;
default:
return;
}
vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr);

View File

@@ -510,6 +510,9 @@ RHIBuffer* VulkanDevice::CreateBuffer(const BufferDesc& desc) {
case BufferType::Constant:
usageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
break;
case BufferType::Storage:
usageFlags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
break;
case BufferType::Vertex:
default:
usageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
@@ -772,6 +775,20 @@ RHIResourceView* VulkanDevice::CreateDepthStencilView(RHITexture* texture, const
return nullptr;
}
RHIResourceView* VulkanDevice::CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
if (buffer == nullptr || !IsBufferResourceViewDimension(desc.dimension)) {
return nullptr;
}
auto* view = new VulkanResourceView();
if (view->InitializeAsShaderResource(static_cast<VulkanBuffer*>(buffer), desc)) {
return view;
}
delete view;
return nullptr;
}
RHIResourceView* VulkanDevice::CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) {
auto* view = new VulkanResourceView();
if (view->InitializeAsShaderResource(m_device, static_cast<VulkanTexture*>(texture), desc)) {
@@ -782,6 +799,20 @@ RHIResourceView* VulkanDevice::CreateShaderResourceView(RHITexture* texture, con
return nullptr;
}
RHIResourceView* VulkanDevice::CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
if (buffer == nullptr || !IsBufferResourceViewDimension(desc.dimension)) {
return nullptr;
}
auto* view = new VulkanResourceView();
if (view->InitializeAsUnorderedAccess(static_cast<VulkanBuffer*>(buffer), desc)) {
return view;
}
delete view;
return nullptr;
}
RHIResourceView* VulkanDevice::CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) {
auto* view = new VulkanResourceView();
if (view->InitializeAsUnorderedAccess(m_device, static_cast<VulkanTexture*>(texture), desc)) {

View File

@@ -145,7 +145,9 @@ bool VulkanPipelineLayout::CreateNativeSetLayouts() {
const DescriptorSetLayoutBinding& binding = setLayout.bindings[i];
VkDescriptorSetLayoutBinding vkBinding = {};
vkBinding.binding = binding.binding;
vkBinding.descriptorType = ToVulkanDescriptorType(static_cast<DescriptorType>(binding.type));
vkBinding.descriptorType = ToVulkanDescriptorType(
static_cast<DescriptorType>(binding.type),
binding.resourceDimension);
vkBinding.descriptorCount = binding.count > 0 ? binding.count : 1u;
vkBinding.stageFlags = ToVulkanShaderStageFlags(binding.visibility);
vkBindings.push_back(vkBinding);

View File

@@ -6,6 +6,53 @@
namespace XCEngine {
namespace RHI {
namespace {
uint32_t ResolveBufferElementStride(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
if (desc.dimension == ResourceViewDimension::RawBuffer) {
return 4u;
}
if (desc.structureByteStride > 0) {
return desc.structureByteStride;
}
return buffer != nullptr ? buffer->GetStride() : 0u;
}
uint64_t ResolveBufferByteOffset(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return desc.bufferLocation;
}
return desc.bufferLocation + static_cast<uint64_t>(desc.firstElement) * elementStride;
}
uint32_t ResolveBufferElementCount(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
if (desc.elementCount > 0) {
return desc.elementCount;
}
if (buffer == nullptr) {
return 0;
}
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return 0;
}
const uint64_t byteOffset = ResolveBufferByteOffset(buffer, desc);
if (byteOffset >= buffer->GetSize()) {
return 0;
}
return static_cast<uint32_t>((buffer->GetSize() - byteOffset) / elementStride);
}
} // namespace
VulkanResourceView::~VulkanResourceView() {
Shutdown();
}
@@ -85,6 +132,32 @@ bool VulkanResourceView::InitializeAsShaderResource(VkDevice device, VulkanTextu
return vkCreateImageView(device, &viewInfo, nullptr, &m_imageView) == VK_SUCCESS;
}
bool VulkanResourceView::InitializeAsShaderResource(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
if (buffer == nullptr || buffer->GetBuffer() == VK_NULL_HANDLE || !IsBufferResourceViewDimension(desc.dimension)) {
return false;
}
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return false;
}
const uint32_t elementCount = ResolveBufferElementCount(buffer, desc);
if (elementCount == 0) {
return false;
}
m_viewType = ResourceViewType::ShaderResource;
m_dimension =
desc.dimension != ResourceViewDimension::Unknown ? desc.dimension : ResourceViewDimension::Buffer;
m_format = desc.format != 0 ? static_cast<Format>(desc.format) : Format::Unknown;
m_buffer = buffer;
m_bufferOffset = ResolveBufferByteOffset(buffer, desc);
m_bufferStride = elementStride;
m_bufferSize = elementCount * elementStride;
return true;
}
bool VulkanResourceView::InitializeAsUnorderedAccess(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc) {
if (device == VK_NULL_HANDLE || texture == nullptr || texture->GetImage() == VK_NULL_HANDLE) {
return false;
@@ -110,6 +183,32 @@ bool VulkanResourceView::InitializeAsUnorderedAccess(VkDevice device, VulkanText
return vkCreateImageView(device, &viewInfo, nullptr, &m_imageView) == VK_SUCCESS;
}
bool VulkanResourceView::InitializeAsUnorderedAccess(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
if (buffer == nullptr || buffer->GetBuffer() == VK_NULL_HANDLE || !IsBufferResourceViewDimension(desc.dimension)) {
return false;
}
const uint32_t elementStride = ResolveBufferElementStride(buffer, desc);
if (elementStride == 0) {
return false;
}
const uint32_t elementCount = ResolveBufferElementCount(buffer, desc);
if (elementCount == 0) {
return false;
}
m_viewType = ResourceViewType::UnorderedAccess;
m_dimension =
desc.dimension != ResourceViewDimension::Unknown ? desc.dimension : ResourceViewDimension::Buffer;
m_format = desc.format != 0 ? static_cast<Format>(desc.format) : Format::Unknown;
m_buffer = buffer;
m_bufferOffset = ResolveBufferByteOffset(buffer, desc);
m_bufferStride = elementStride;
m_bufferSize = elementCount * elementStride;
return true;
}
bool VulkanResourceView::InitializeAsVertexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
if (buffer == nullptr || buffer->GetBuffer() == VK_NULL_HANDLE) {
return false;
@@ -155,9 +254,11 @@ bool VulkanResourceView::IsValid() const {
return m_buffer != nullptr && m_buffer->GetBuffer() != VK_NULL_HANDLE;
case ResourceViewType::RenderTarget:
case ResourceViewType::DepthStencil:
return m_imageView != VK_NULL_HANDLE;
case ResourceViewType::ShaderResource:
case ResourceViewType::UnorderedAccess:
return m_imageView != VK_NULL_HANDLE;
return m_imageView != VK_NULL_HANDLE ||
(m_buffer != nullptr && m_buffer->GetBuffer() != VK_NULL_HANDLE && m_bufferSize > 0);
default:
return false;
}