Add RHI texture upload and descriptor set fixes
This commit is contained in:
@@ -51,6 +51,7 @@ private:
|
||||
DescriptorHeapType m_type;
|
||||
uint32_t m_numDescriptors;
|
||||
uint32_t m_descriptorSize;
|
||||
uint32_t m_nextFreeOffset;
|
||||
bool m_shaderVisible;
|
||||
std::vector<D3D12DescriptorSet*> m_allocatedSets;
|
||||
};
|
||||
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
|
||||
RHIBuffer* CreateBuffer(const BufferDesc& desc) override;
|
||||
RHITexture* CreateTexture(const TextureDesc& desc) override;
|
||||
RHITexture* CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch = 0) override;
|
||||
RHISwapChain* CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) override;
|
||||
RHICommandList* CreateCommandList(const CommandListDesc& desc) override;
|
||||
RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override;
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
bool Initialize(ID3D12Device* device, const D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON);
|
||||
bool InitializeFromExisting(ID3D12Resource* resource, bool ownsResource = false);
|
||||
bool InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList,
|
||||
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format);
|
||||
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format, uint32_t rowPitch = 0);
|
||||
bool InitializeDepthStencil(ID3D12Device* device, uint32_t width, uint32_t height, DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT);
|
||||
void Shutdown() override;
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@ public:
|
||||
uint32_t GetBindingPoint(uint32_t binding) const;
|
||||
|
||||
private:
|
||||
DescriptorBinding* FindBinding(uint32_t binding);
|
||||
const DescriptorBinding* FindBinding(uint32_t binding) const;
|
||||
|
||||
OpenGLTextureUnitAllocator* m_allocator;
|
||||
std::vector<DescriptorBinding> m_bindings;
|
||||
DescriptorSetLayoutBinding* m_layoutBindings;
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
|
||||
RHIBuffer* CreateBuffer(const BufferDesc& desc) override;
|
||||
RHITexture* CreateTexture(const TextureDesc& desc) override;
|
||||
RHITexture* CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch = 0) override;
|
||||
RHISwapChain* CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) override;
|
||||
RHICommandList* CreateCommandList(const CommandListDesc& desc) override;
|
||||
RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override;
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
|
||||
virtual RHIBuffer* CreateBuffer(const BufferDesc& desc) = 0;
|
||||
virtual RHITexture* CreateTexture(const TextureDesc& desc) = 0;
|
||||
virtual RHITexture* CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch = 0) = 0;
|
||||
virtual RHISwapChain* CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) = 0;
|
||||
virtual RHICommandList* CreateCommandList(const CommandListDesc& desc) = 0;
|
||||
virtual RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) = 0;
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12RenderPass.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12Framebuffer.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
@@ -151,6 +154,29 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
D3D12PipelineLayout* d3d12Layout = static_cast<D3D12PipelineLayout*>(pipelineLayout);
|
||||
SetPipelineLayout(d3d12Layout);
|
||||
|
||||
std::vector<ID3D12DescriptorHeap*> descriptorHeaps;
|
||||
descriptorHeaps.reserve(2);
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
D3D12DescriptorSet* d3d12Set = static_cast<D3D12DescriptorSet*>(descriptorSets[i]);
|
||||
D3D12DescriptorHeap* heap = d3d12Set->GetHeap();
|
||||
if (heap != nullptr) {
|
||||
ID3D12DescriptorHeap* nativeHeap = heap->GetDescriptorHeap();
|
||||
if (nativeHeap != nullptr &&
|
||||
std::find(descriptorHeaps.begin(), descriptorHeaps.end(), nativeHeap) == descriptorHeaps.end()) {
|
||||
descriptorHeaps.push_back(nativeHeap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!descriptorHeaps.empty()) {
|
||||
SetDescriptorHeaps(static_cast<uint32_t>(descriptorHeaps.size()), descriptorHeaps.data());
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
continue;
|
||||
@@ -160,6 +186,13 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandle();
|
||||
|
||||
uint32_t rootIndex = firstSet + i;
|
||||
if (d3d12Set->GetHeap() != nullptr) {
|
||||
if (d3d12Set->GetHeap()->GetType() == DescriptorHeapType::CBV_SRV_UAV && d3d12Layout->HasRootParameter(100)) {
|
||||
rootIndex = d3d12Layout->GetRootParameterIndex(100);
|
||||
} else if (d3d12Set->GetHeap()->GetType() == DescriptorHeapType::Sampler && d3d12Layout->HasRootParameter(200)) {
|
||||
rootIndex = d3d12Layout->GetRootParameterIndex(200);
|
||||
}
|
||||
}
|
||||
SetGraphicsRootDescriptorTable(rootIndex, gpuHandle);
|
||||
}
|
||||
}
|
||||
@@ -176,6 +209,29 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
D3D12PipelineLayout* d3d12Layout = static_cast<D3D12PipelineLayout*>(pipelineLayout);
|
||||
SetPipelineLayout(d3d12Layout);
|
||||
|
||||
std::vector<ID3D12DescriptorHeap*> descriptorHeaps;
|
||||
descriptorHeaps.reserve(2);
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
D3D12DescriptorSet* d3d12Set = static_cast<D3D12DescriptorSet*>(descriptorSets[i]);
|
||||
D3D12DescriptorHeap* heap = d3d12Set->GetHeap();
|
||||
if (heap != nullptr) {
|
||||
ID3D12DescriptorHeap* nativeHeap = heap->GetDescriptorHeap();
|
||||
if (nativeHeap != nullptr &&
|
||||
std::find(descriptorHeaps.begin(), descriptorHeaps.end(), nativeHeap) == descriptorHeaps.end()) {
|
||||
descriptorHeaps.push_back(nativeHeap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!descriptorHeaps.empty()) {
|
||||
SetDescriptorHeaps(static_cast<uint32_t>(descriptorHeaps.size()), descriptorHeaps.data());
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] == nullptr) {
|
||||
continue;
|
||||
@@ -185,6 +241,13 @@ void D3D12CommandList::SetComputeDescriptorSets(
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandle();
|
||||
|
||||
uint32_t rootIndex = firstSet + i;
|
||||
if (d3d12Set->GetHeap() != nullptr) {
|
||||
if (d3d12Set->GetHeap()->GetType() == DescriptorHeapType::CBV_SRV_UAV && d3d12Layout->HasRootParameter(100)) {
|
||||
rootIndex = d3d12Layout->GetRootParameterIndex(100);
|
||||
} else if (d3d12Set->GetHeap()->GetType() == DescriptorHeapType::Sampler && d3d12Layout->HasRootParameter(200)) {
|
||||
rootIndex = d3d12Layout->GetRootParameterIndex(200);
|
||||
}
|
||||
}
|
||||
m_commandList->SetComputeRootDescriptorTable(rootIndex, gpuHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ D3D12DescriptorHeap::D3D12DescriptorHeap()
|
||||
: m_type(DescriptorHeapType::CBV_SRV_UAV)
|
||||
, m_numDescriptors(0)
|
||||
, m_descriptorSize(0)
|
||||
, m_nextFreeOffset(0)
|
||||
, m_shaderVisible(false) {
|
||||
}
|
||||
|
||||
@@ -40,12 +41,17 @@ bool D3D12DescriptorHeap::Initialize(ID3D12Device* device, DescriptorHeapType ty
|
||||
m_numDescriptors = numDescriptors;
|
||||
m_shaderVisible = shaderVisible;
|
||||
m_descriptorSize = device->GetDescriptorHandleIncrementSize(ToD3D12(type));
|
||||
m_nextFreeOffset = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12DescriptorHeap::Shutdown() {
|
||||
m_descriptorHeap.Reset();
|
||||
m_allocatedSets.clear();
|
||||
m_numDescriptors = 0;
|
||||
m_descriptorSize = 0;
|
||||
m_nextFreeOffset = 0;
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart() const {
|
||||
@@ -95,12 +101,12 @@ RHIDescriptorSet* D3D12DescriptorHeap::AllocateSet(const DescriptorSetLayoutDesc
|
||||
requiredDescriptors += layout.bindings[i].count;
|
||||
}
|
||||
|
||||
if (m_allocatedSets.size() >= m_numDescriptors) {
|
||||
if (m_nextFreeOffset + requiredDescriptors > m_numDescriptors) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D12DescriptorSet* newSet = new D3D12DescriptorSet();
|
||||
uint32_t offset = static_cast<uint32_t>(m_allocatedSets.size());
|
||||
uint32_t offset = m_nextFreeOffset;
|
||||
|
||||
if (!newSet->Initialize(this, offset, requiredDescriptors, layout)) {
|
||||
delete newSet;
|
||||
@@ -108,6 +114,7 @@ RHIDescriptorSet* D3D12DescriptorHeap::AllocateSet(const DescriptorSetLayoutDesc
|
||||
}
|
||||
|
||||
m_allocatedSets.push_back(newSet);
|
||||
m_nextFreeOffset += requiredDescriptors;
|
||||
return newSet;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12ResourceView.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12Sampler.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
@@ -50,13 +52,61 @@ void D3D12DescriptorSet::Unbind() {
|
||||
}
|
||||
|
||||
void D3D12DescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
|
||||
(void)offset;
|
||||
(void)view;
|
||||
if (m_heap == nullptr || view == nullptr || m_heap->GetType() != DescriptorHeapType::CBV_SRV_UAV) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t descriptorOffset = 0;
|
||||
bool foundBinding = false;
|
||||
for (uint32_t i = 0; i < m_bindingCount; ++i) {
|
||||
if (m_bindings[i].binding == offset) {
|
||||
foundBinding = true;
|
||||
break;
|
||||
}
|
||||
descriptorOffset += m_bindings[i].count;
|
||||
}
|
||||
|
||||
if (!foundBinding) {
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12ResourceView* d3d12View = static_cast<D3D12ResourceView*>(view);
|
||||
if (!d3d12View->IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CPUDescriptorHandle dstHandle = m_heap->GetCPUDescriptorHandle(m_offset + descriptorOffset);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE dst = { dstHandle.ptr };
|
||||
m_heap->GetDevice()->CopyDescriptorsSimple(
|
||||
1,
|
||||
dst,
|
||||
d3d12View->GetCPUHandle(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
}
|
||||
|
||||
void D3D12DescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
|
||||
(void)offset;
|
||||
(void)sampler;
|
||||
if (m_heap == nullptr || sampler == nullptr || m_heap->GetType() != DescriptorHeapType::Sampler) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t descriptorOffset = 0;
|
||||
bool foundBinding = false;
|
||||
for (uint32_t i = 0; i < m_bindingCount; ++i) {
|
||||
if (m_bindings[i].binding == offset) {
|
||||
foundBinding = true;
|
||||
break;
|
||||
}
|
||||
descriptorOffset += m_bindings[i].count;
|
||||
}
|
||||
|
||||
if (!foundBinding) {
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12Sampler* d3d12Sampler = static_cast<D3D12Sampler*>(sampler);
|
||||
CPUDescriptorHandle dstHandle = m_heap->GetCPUDescriptorHandle(m_offset + descriptorOffset);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE dst = { dstHandle.ptr };
|
||||
m_heap->GetDevice()->CreateSampler(&d3d12Sampler->GetDesc(), dst);
|
||||
}
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE D3D12DescriptorSet::GetGPUHandle(uint32_t index) const {
|
||||
|
||||
@@ -60,6 +60,27 @@ bool CompileD3D12Shader(const ShaderCompileDesc& desc, D3D12Shader& shader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t GetFormatBytesPerPixel(Format format) {
|
||||
switch (format) {
|
||||
case Format::R8_UNorm:
|
||||
return 1;
|
||||
case Format::R8G8_UNorm:
|
||||
return 2;
|
||||
case Format::R8G8B8A8_UNorm:
|
||||
return 4;
|
||||
case Format::R16_Float:
|
||||
return 2;
|
||||
case Format::R16G16B16A16_Float:
|
||||
return 8;
|
||||
case Format::R32_Float:
|
||||
return 4;
|
||||
case Format::R32G32B32A32_Float:
|
||||
return 16;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
D3D12Device::D3D12Device()
|
||||
@@ -326,6 +347,77 @@ RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch) {
|
||||
(void)initialDataSize;
|
||||
|
||||
if (initialData == nullptr) {
|
||||
return CreateTexture(desc);
|
||||
}
|
||||
|
||||
if (desc.textureType != static_cast<uint32_t>(TextureType::Texture2D)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Format format = static_cast<Format>(desc.format);
|
||||
uint32_t resolvedRowPitch = rowPitch;
|
||||
if (resolvedRowPitch == 0) {
|
||||
const uint32_t bytesPerPixel = GetFormatBytesPerPixel(format);
|
||||
if (bytesPerPixel == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
resolvedRowPitch = desc.width * bytesPerPixel;
|
||||
}
|
||||
|
||||
D3D12CommandQueue uploadQueue;
|
||||
if (!uploadQueue.Initialize(m_device.Get(), CommandQueueType::Direct)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D12CommandAllocator uploadAllocator;
|
||||
if (!uploadAllocator.Initialize(m_device.Get(), CommandQueueType::Direct)) {
|
||||
uploadQueue.Shutdown();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D12CommandList uploadCommandList;
|
||||
if (!uploadCommandList.Initialize(m_device.Get(), CommandQueueType::Direct, uploadAllocator.GetCommandAllocator())) {
|
||||
uploadAllocator.Shutdown();
|
||||
uploadQueue.Shutdown();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uploadAllocator.Reset();
|
||||
uploadCommandList.Reset();
|
||||
|
||||
auto* texture = new D3D12Texture();
|
||||
if (!texture->InitializeFromData(
|
||||
m_device.Get(),
|
||||
uploadCommandList.GetCommandList(),
|
||||
initialData,
|
||||
desc.width,
|
||||
desc.height,
|
||||
ToD3D12(format),
|
||||
resolvedRowPitch)) {
|
||||
delete texture;
|
||||
uploadCommandList.Shutdown();
|
||||
uploadAllocator.Shutdown();
|
||||
uploadQueue.Shutdown();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
texture->SetState(ResourceStates::PixelShaderResource);
|
||||
|
||||
uploadCommandList.Close();
|
||||
ID3D12CommandList* commandLists[] = { uploadCommandList.GetCommandList() };
|
||||
uploadQueue.ExecuteCommandListsInternal(1, commandLists);
|
||||
uploadQueue.WaitForIdle();
|
||||
|
||||
uploadCommandList.Shutdown();
|
||||
uploadAllocator.Shutdown();
|
||||
uploadQueue.Shutdown();
|
||||
return texture;
|
||||
}
|
||||
|
||||
RHIShader* D3D12Device::CreateShader(const ShaderCompileDesc& desc) {
|
||||
auto* shader = new D3D12Shader();
|
||||
const std::string entryPoint = NarrowAscii(desc.entryPoint);
|
||||
|
||||
@@ -44,7 +44,7 @@ bool D3D12Texture::InitializeFromExisting(ID3D12Resource* resource, bool ownsRes
|
||||
}
|
||||
|
||||
bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList,
|
||||
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format) {
|
||||
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format, uint32_t rowPitch) {
|
||||
|
||||
D3D12_RESOURCE_DESC textureDesc = {};
|
||||
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
@@ -74,6 +74,7 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
||||
if (FAILED(hResult)) {
|
||||
return false;
|
||||
}
|
||||
m_ownsResource = true;
|
||||
|
||||
textureDesc = m_resource->GetDesc();
|
||||
UINT64 memorySizeUsed = 0;
|
||||
@@ -117,8 +118,9 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
||||
tempBufferObject->Map(0, nullptr, reinterpret_cast<void**>(&pData));
|
||||
BYTE* pDstTempBuffer = reinterpret_cast<BYTE*>(pData + subresourceFootprint.Offset);
|
||||
const BYTE* pSrcData = reinterpret_cast<const BYTE*>(pixelData);
|
||||
const UINT sourceRowPitch = rowPitch > 0 ? rowPitch : static_cast<UINT>(rowSizeInBytes);
|
||||
for (UINT i = 0; i < rowUsed; i++) {
|
||||
memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + rowSizeInBytes * i, rowSizeInBytes);
|
||||
memcpy(pDstTempBuffer + subresourceFootprint.Footprint.RowPitch * i, pSrcData + sourceRowPitch * i, rowSizeInBytes);
|
||||
}
|
||||
tempBufferObject->Unmap(0, nullptr);
|
||||
|
||||
@@ -141,6 +143,9 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
commandList->ResourceBarrier(1, &barrier);
|
||||
m_state = ResourceStates::PixelShaderResource;
|
||||
|
||||
tempBufferObject->Release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,24 @@ OpenGLDescriptorSet::~OpenGLDescriptorSet() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
DescriptorBinding* OpenGLDescriptorSet::FindBinding(uint32_t binding) {
|
||||
for (auto& descriptorBinding : m_bindings) {
|
||||
if (descriptorBinding.binding == binding) {
|
||||
return &descriptorBinding;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const DescriptorBinding* OpenGLDescriptorSet::FindBinding(uint32_t binding) const {
|
||||
for (const auto& descriptorBinding : m_bindings) {
|
||||
if (descriptorBinding.binding == binding) {
|
||||
return &descriptorBinding;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool OpenGLDescriptorSet::Initialize(OpenGLTextureUnitAllocator* allocator, uint32_t count, const DescriptorSetLayoutDesc& layout) {
|
||||
m_allocator = allocator;
|
||||
m_bindingCount = layout.bindingCount;
|
||||
@@ -38,6 +56,18 @@ bool OpenGLDescriptorSet::Initialize(OpenGLTextureUnitAllocator* allocator, uint
|
||||
m_bindings[i].textureIds.resize(layout.bindings[i].count, 0);
|
||||
m_bindings[i].samplerIds.resize(layout.bindings[i].count, 0);
|
||||
|
||||
if (m_bindings[i].type != DescriptorType::SRV &&
|
||||
m_bindings[i].type != DescriptorType::Sampler &&
|
||||
m_bindings[i].type != DescriptorType::UAV) {
|
||||
m_bindings[i].textureUnits.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_allocator == nullptr) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < layout.bindings[i].count; ++j) {
|
||||
int32_t unit = m_allocator->Allocate();
|
||||
if (unit < 0) {
|
||||
@@ -80,17 +110,13 @@ void OpenGLDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bindingIndex = offset;
|
||||
if (bindingIndex >= m_bindings.size()) {
|
||||
DescriptorBinding* binding = FindBinding(offset);
|
||||
if (binding == nullptr || binding->textureIds.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OpenGLResourceView* glView = static_cast<OpenGLResourceView*>(view);
|
||||
uint32_t textureId = glView->GetTexture();
|
||||
|
||||
if (offset < m_bindings[bindingIndex].textureIds.size()) {
|
||||
m_bindings[bindingIndex].textureIds[offset] = textureId;
|
||||
}
|
||||
binding->textureIds[0] = glView->GetTexture();
|
||||
}
|
||||
|
||||
void OpenGLDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
|
||||
@@ -98,17 +124,13 @@ void OpenGLDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bindingIndex = offset;
|
||||
if (bindingIndex >= m_bindings.size()) {
|
||||
DescriptorBinding* binding = FindBinding(offset);
|
||||
if (binding == nullptr || binding->samplerIds.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OpenGLSampler* glSampler = static_cast<OpenGLSampler*>(sampler);
|
||||
uint32_t samplerId = glSampler->GetID();
|
||||
|
||||
if (offset < m_bindings[bindingIndex].samplerIds.size()) {
|
||||
m_bindings[bindingIndex].samplerIds[offset] = samplerId;
|
||||
}
|
||||
binding->samplerIds[0] = glSampler->GetID();
|
||||
}
|
||||
|
||||
void OpenGLDescriptorSet::Bind() {
|
||||
@@ -130,14 +152,10 @@ void OpenGLDescriptorSet::Bind() {
|
||||
uint32_t textureId = binding.textureIds[j];
|
||||
uint32_t samplerId = binding.samplerIds[j];
|
||||
|
||||
if (textureId != 0) {
|
||||
if (textureId != 0 && binding.type != DescriptorType::Sampler) {
|
||||
glActiveTexture(GL_TEXTURE0 + unit);
|
||||
if (binding.type == DescriptorType::Sampler) {
|
||||
glBindTexture(GL_SAMPLER, textureId);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
}
|
||||
}
|
||||
|
||||
if (samplerId != 0) {
|
||||
glBindSampler(unit, samplerId);
|
||||
@@ -165,10 +183,9 @@ void OpenGLDescriptorSet::Unbind() {
|
||||
}
|
||||
|
||||
uint32_t OpenGLDescriptorSet::GetBindingPoint(uint32_t binding) const {
|
||||
for (size_t i = 0; i < m_bindings.size(); ++i) {
|
||||
if (m_bindings[i].binding == binding && !m_bindings[i].textureUnits.empty()) {
|
||||
return m_bindings[i].textureUnits[0];
|
||||
}
|
||||
const DescriptorBinding* descriptorBinding = FindBinding(binding);
|
||||
if (descriptorBinding != nullptr && !descriptorBinding->textureUnits.empty()) {
|
||||
return descriptorBinding->textureUnits[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -356,6 +356,59 @@ RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch) {
|
||||
(void)initialDataSize;
|
||||
(void)rowPitch;
|
||||
|
||||
if (!MakeContextCurrent()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* texture = new OpenGLTexture();
|
||||
|
||||
OpenGLTextureType type = OpenGLTextureType::Texture2D;
|
||||
switch (desc.textureType) {
|
||||
case 0:
|
||||
type = OpenGLTextureType::Texture1D;
|
||||
break;
|
||||
case 2:
|
||||
type = OpenGLTextureType::Texture2DArray;
|
||||
break;
|
||||
case 3:
|
||||
type = OpenGLTextureType::Texture3D;
|
||||
break;
|
||||
case 4:
|
||||
type = OpenGLTextureType::TextureCube;
|
||||
break;
|
||||
default:
|
||||
type = OpenGLTextureType::Texture2D;
|
||||
break;
|
||||
}
|
||||
|
||||
OpenGLFormat format = OpenGLFormat::RGBA8;
|
||||
switch (desc.format) {
|
||||
case 1: format = OpenGLFormat::R8; break;
|
||||
case 2: format = OpenGLFormat::RG8; break;
|
||||
case 3: format = OpenGLFormat::RGBA8; break;
|
||||
case 4: format = OpenGLFormat::RGBA16F; break;
|
||||
case 5: format = OpenGLFormat::RGBA32F; break;
|
||||
case 6: format = OpenGLFormat::RGBA16F; break;
|
||||
case 7: format = OpenGLFormat::RGBA32F; break;
|
||||
case 8: format = OpenGLFormat::Depth24Stencil8; break;
|
||||
case 9: format = OpenGLFormat::Depth32F; break;
|
||||
default: format = OpenGLFormat::RGBA8; break;
|
||||
}
|
||||
|
||||
if (!texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, initialData)) {
|
||||
delete texture;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
texture->SetFormat(static_cast<Format>(desc.format));
|
||||
texture->SetState(ResourceStates::PixelShaderResource);
|
||||
return texture;
|
||||
}
|
||||
|
||||
RHISwapChain* OpenGLDevice::CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) {
|
||||
if (presentQueue == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@@ -82,6 +82,7 @@ bool OpenGLResourceView::IsValid() const {
|
||||
case ResourceViewType::DepthStencil:
|
||||
return m_framebufferID != 0;
|
||||
case ResourceViewType::ShaderResource:
|
||||
return m_texture != nullptr && m_texture->GetID() != 0;
|
||||
case ResourceViewType::UnorderedAccess:
|
||||
return m_texture != nullptr && m_textureUnit >= 0;
|
||||
case ResourceViewType::ConstantBuffer:
|
||||
@@ -129,12 +130,7 @@ bool OpenGLResourceView::InitializeAsShaderResource(
|
||||
OpenGLTexture* texture,
|
||||
const ResourceViewDesc& desc,
|
||||
OpenGLTextureUnitAllocator* allocator) {
|
||||
if (!texture || !allocator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t unit = allocator->Allocate();
|
||||
if (unit < 0) {
|
||||
if (!texture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -142,9 +138,8 @@ bool OpenGLResourceView::InitializeAsShaderResource(
|
||||
m_format = static_cast<Format>(desc.format);
|
||||
m_dimension = desc.dimension;
|
||||
m_texture = texture;
|
||||
m_textureUnit = unit;
|
||||
m_textureUnit = -1;
|
||||
m_textureUnitAllocator = allocator;
|
||||
allocator->BindTexture(unit, texture);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
#include "fixtures/RHITestFixture.h"
|
||||
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
|
||||
#include "XCEngine/RHI/RHIDescriptorPool.h"
|
||||
#include "XCEngine/RHI/RHIDescriptorSet.h"
|
||||
#include "XCEngine/RHI/RHISampler.h"
|
||||
#include "XCEngine/RHI/RHIResourceView.h"
|
||||
#include "XCEngine/RHI/RHITexture.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
using namespace XCEngine::RHI;
|
||||
|
||||
TEST_P(RHITestFixture, DescriptorSet_Allocate_Basic) {
|
||||
@@ -360,3 +365,131 @@ TEST_P(RHITestFixture, DescriptorSet_ConstantBufferSize) {
|
||||
pool->Shutdown();
|
||||
delete pool;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, DescriptorSet_MultipleAllocations_AdvanceDescriptorOffsets) {
|
||||
DescriptorPoolDesc poolDesc = {};
|
||||
poolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
|
||||
poolDesc.descriptorCount = 8;
|
||||
poolDesc.shaderVisible = true;
|
||||
|
||||
RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc);
|
||||
ASSERT_NE(pool, nullptr);
|
||||
|
||||
DescriptorSetLayoutBinding bindings[2] = {};
|
||||
bindings[0].binding = 0;
|
||||
bindings[0].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||
bindings[0].count = 1;
|
||||
bindings[1].binding = 1;
|
||||
bindings[1].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||
bindings[1].count = 1;
|
||||
|
||||
DescriptorSetLayoutDesc layoutDesc = {};
|
||||
layoutDesc.bindings = bindings;
|
||||
layoutDesc.bindingCount = 2;
|
||||
|
||||
RHIDescriptorSet* firstSet = pool->AllocateSet(layoutDesc);
|
||||
RHIDescriptorSet* secondSet = pool->AllocateSet(layoutDesc);
|
||||
ASSERT_NE(firstSet, nullptr);
|
||||
ASSERT_NE(secondSet, nullptr);
|
||||
|
||||
if (GetBackendType() == RHIType::D3D12) {
|
||||
auto* firstD3D12Set = static_cast<D3D12DescriptorSet*>(firstSet);
|
||||
auto* secondD3D12Set = static_cast<D3D12DescriptorSet*>(secondSet);
|
||||
EXPECT_EQ(firstD3D12Set->GetOffset(), 0u);
|
||||
EXPECT_EQ(secondD3D12Set->GetOffset(), 2u);
|
||||
}
|
||||
|
||||
firstSet->Shutdown();
|
||||
delete firstSet;
|
||||
secondSet->Shutdown();
|
||||
delete secondSet;
|
||||
pool->Shutdown();
|
||||
delete pool;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, DescriptorSet_Update_UsesBindingNumberOnOpenGL) {
|
||||
if (GetBackendType() != RHIType::OpenGL) {
|
||||
GTEST_SKIP() << "OpenGL-specific descriptor binding verification";
|
||||
}
|
||||
|
||||
auto* openGLDevice = static_cast<OpenGLDevice*>(GetDevice());
|
||||
ASSERT_NE(openGLDevice, nullptr);
|
||||
ASSERT_TRUE(openGLDevice->MakeContextCurrent());
|
||||
|
||||
DescriptorPoolDesc poolDesc = {};
|
||||
poolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
|
||||
poolDesc.descriptorCount = 8;
|
||||
poolDesc.shaderVisible = true;
|
||||
|
||||
RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc);
|
||||
ASSERT_NE(pool, nullptr);
|
||||
|
||||
TextureDesc textureDesc = {};
|
||||
textureDesc.width = 1;
|
||||
textureDesc.height = 1;
|
||||
textureDesc.depth = 1;
|
||||
textureDesc.mipLevels = 1;
|
||||
textureDesc.arraySize = 1;
|
||||
textureDesc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
||||
textureDesc.textureType = static_cast<uint32_t>(TextureType::Texture2D);
|
||||
textureDesc.sampleCount = 1;
|
||||
|
||||
const uint8_t pixel[4] = { 255, 255, 255, 255 };
|
||||
RHITexture* texture = GetDevice()->CreateTexture(textureDesc, pixel, sizeof(pixel), 4);
|
||||
ASSERT_NE(texture, nullptr);
|
||||
|
||||
ResourceViewDesc srvDesc = {};
|
||||
srvDesc.format = textureDesc.format;
|
||||
srvDesc.dimension = ResourceViewDimension::Texture2D;
|
||||
RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, srvDesc);
|
||||
ASSERT_NE(srv, nullptr);
|
||||
|
||||
DescriptorSetLayoutBinding bindings[2] = {};
|
||||
bindings[0].binding = 3;
|
||||
bindings[0].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||
bindings[0].count = 1;
|
||||
bindings[1].binding = 7;
|
||||
bindings[1].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||
bindings[1].count = 1;
|
||||
|
||||
DescriptorSetLayoutDesc layoutDesc = {};
|
||||
layoutDesc.bindings = bindings;
|
||||
layoutDesc.bindingCount = 2;
|
||||
|
||||
RHIDescriptorSet* set = pool->AllocateSet(layoutDesc);
|
||||
ASSERT_NE(set, nullptr);
|
||||
|
||||
auto* openGLSet = static_cast<OpenGLDescriptorSet*>(set);
|
||||
const uint32_t untouchedUnit = openGLSet->GetBindingPoint(3);
|
||||
const uint32_t updatedUnit = openGLSet->GetBindingPoint(7);
|
||||
ASSERT_NE(untouchedUnit, updatedUnit);
|
||||
|
||||
set->Update(7, srv);
|
||||
set->Bind();
|
||||
|
||||
GLint updatedTexture = 0;
|
||||
glActiveTexture(GL_TEXTURE0 + updatedUnit);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &updatedTexture);
|
||||
EXPECT_EQ(static_cast<unsigned int>(updatedTexture), static_cast<unsigned int>(reinterpret_cast<uintptr_t>(srv->GetNativeHandle())));
|
||||
|
||||
GLint untouchedTexture = 0;
|
||||
glActiveTexture(GL_TEXTURE0 + untouchedUnit);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &untouchedTexture);
|
||||
EXPECT_EQ(untouchedTexture, 0);
|
||||
|
||||
set->Unbind();
|
||||
|
||||
GLint unboundTexture = 0;
|
||||
glActiveTexture(GL_TEXTURE0 + updatedUnit);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &unboundTexture);
|
||||
EXPECT_EQ(unboundTexture, 0);
|
||||
|
||||
set->Shutdown();
|
||||
delete set;
|
||||
srv->Shutdown();
|
||||
delete srv;
|
||||
texture->Shutdown();
|
||||
delete texture;
|
||||
pool->Shutdown();
|
||||
delete pool;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user