Add RHI buffer SRV and UAV view support
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -16,7 +16,8 @@ enum class OpenGLBufferType {
|
||||
AtomicCounter,
|
||||
DispatchIndirect,
|
||||
DrawIndirect,
|
||||
ShaderBindingTable
|
||||
ShaderBindingTable,
|
||||
ShaderStorage
|
||||
};
|
||||
|
||||
class OpenGLBuffer : public RHIBuffer {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user