diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h b/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h index 6f1fc86e..16ef4c8a 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12DescriptorHeap.h @@ -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 m_allocatedSets; }; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h index e4d6ceee..21453746 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h @@ -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; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h b/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h index 51fb073b..e7eac6b9 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h @@ -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; diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h index e7dcdb63..64f10933 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h @@ -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 m_bindings; DescriptorSetLayoutBinding* m_layoutBindings; @@ -57,4 +60,4 @@ private: }; } // namespace RHI -} // namespace XCEngine \ No newline at end of file +} // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h index bfa83802..90572e6b 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h @@ -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; diff --git a/engine/include/XCEngine/RHI/RHIDevice.h b/engine/include/XCEngine/RHI/RHIDevice.h index dc0716a4..be8cf725 100644 --- a/engine/include/XCEngine/RHI/RHIDevice.h +++ b/engine/include/XCEngine/RHI/RHIDevice.h @@ -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; diff --git a/engine/src/RHI/D3D12/D3D12CommandList.cpp b/engine/src/RHI/D3D12/D3D12CommandList.cpp index 2ff67e2f..3e81dc71 100644 --- a/engine/src/RHI/D3D12/D3D12CommandList.cpp +++ b/engine/src/RHI/D3D12/D3D12CommandList.cpp @@ -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 + namespace XCEngine { namespace RHI { @@ -151,6 +154,29 @@ void D3D12CommandList::SetGraphicsDescriptorSets( D3D12PipelineLayout* d3d12Layout = static_cast(pipelineLayout); SetPipelineLayout(d3d12Layout); + std::vector descriptorHeaps; + descriptorHeaps.reserve(2); + + for (uint32_t i = 0; i < count; ++i) { + if (descriptorSets[i] == nullptr) { + continue; + } + + D3D12DescriptorSet* d3d12Set = static_cast(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(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(pipelineLayout); SetPipelineLayout(d3d12Layout); + std::vector descriptorHeaps; + descriptorHeaps.reserve(2); + + for (uint32_t i = 0; i < count; ++i) { + if (descriptorSets[i] == nullptr) { + continue; + } + + D3D12DescriptorSet* d3d12Set = static_cast(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(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); } } diff --git a/engine/src/RHI/D3D12/D3D12DescriptorHeap.cpp b/engine/src/RHI/D3D12/D3D12DescriptorHeap.cpp index d5afcfed..6ea358b9 100644 --- a/engine/src/RHI/D3D12/D3D12DescriptorHeap.cpp +++ b/engine/src/RHI/D3D12/D3D12DescriptorHeap.cpp @@ -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(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; } diff --git a/engine/src/RHI/D3D12/D3D12DescriptorSet.cpp b/engine/src/RHI/D3D12/D3D12DescriptorSet.cpp index cb454253..9abcdd4a 100644 --- a/engine/src/RHI/D3D12/D3D12DescriptorSet.cpp +++ b/engine/src/RHI/D3D12/D3D12DescriptorSet.cpp @@ -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(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(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 { @@ -77,4 +127,4 @@ void D3D12DescriptorSet::WriteConstant(uint32_t binding, const void* data, size_ } } // namespace RHI -} // namespace XCEngine \ No newline at end of file +} // namespace XCEngine diff --git a/engine/src/RHI/D3D12/D3D12Device.cpp b/engine/src/RHI/D3D12/D3D12Device.cpp index ebdfbe84..31588f93 100644 --- a/engine/src/RHI/D3D12/D3D12Device.cpp +++ b/engine/src/RHI/D3D12/D3D12Device.cpp @@ -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(TextureType::Texture2D)) { + return nullptr; + } + + const Format format = static_cast(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); diff --git a/engine/src/RHI/D3D12/D3D12Texture.cpp b/engine/src/RHI/D3D12/D3D12Texture.cpp index 7c5a7695..7cc52822 100644 --- a/engine/src/RHI/D3D12/D3D12Texture.cpp +++ b/engine/src/RHI/D3D12/D3D12Texture.cpp @@ -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(&pData)); BYTE* pDstTempBuffer = reinterpret_cast(pData + subresourceFootprint.Offset); const BYTE* pSrcData = reinterpret_cast(pixelData); + const UINT sourceRowPitch = rowPitch > 0 ? rowPitch : static_cast(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; } diff --git a/engine/src/RHI/OpenGL/OpenGLDescriptorSet.cpp b/engine/src/RHI/OpenGL/OpenGLDescriptorSet.cpp index a856f160..1c2c2a77 100644 --- a/engine/src/RHI/OpenGL/OpenGLDescriptorSet.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDescriptorSet.cpp @@ -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(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(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,13 +152,9 @@ 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); - } + glBindTexture(GL_TEXTURE_2D, textureId); } if (samplerId != 0) { @@ -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; } @@ -183,4 +200,4 @@ void OpenGLDescriptorSet::WriteConstant(uint32_t binding, const void* data, size } } // namespace RHI -} // namespace XCEngine \ No newline at end of file +} // namespace XCEngine diff --git a/engine/src/RHI/OpenGL/OpenGLDevice.cpp b/engine/src/RHI/OpenGL/OpenGLDevice.cpp index dcaa8361..609d3d5b 100644 --- a/engine/src/RHI/OpenGL/OpenGLDevice.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDevice.cpp @@ -318,6 +318,53 @@ RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) { RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) { 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; + } + texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, nullptr); + texture->SetFormat(static_cast(desc.format)); + 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) { @@ -351,8 +398,14 @@ RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) { case 9: format = OpenGLFormat::Depth32F; break; default: format = OpenGLFormat::RGBA8; break; } - texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, nullptr); + + if (!texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, initialData)) { + delete texture; + return nullptr; + } + texture->SetFormat(static_cast(desc.format)); + texture->SetState(ResourceStates::PixelShaderResource); return texture; } diff --git a/engine/src/RHI/OpenGL/OpenGLResourceView.cpp b/engine/src/RHI/OpenGL/OpenGLResourceView.cpp index 3a7f572c..f7cf1492 100644 --- a/engine/src/RHI/OpenGL/OpenGLResourceView.cpp +++ b/engine/src/RHI/OpenGL/OpenGLResourceView.cpp @@ -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(desc.format); m_dimension = desc.dimension; m_texture = texture; - m_textureUnit = unit; + m_textureUnit = -1; m_textureUnitAllocator = allocator; - allocator->BindTexture(unit, texture); return true; } diff --git a/tests/RHI/unit/test_descriptor_set.cpp b/tests/RHI/unit/test_descriptor_set.cpp index 12d0b2dd..9b91e13a 100644 --- a/tests/RHI/unit/test_descriptor_set.cpp +++ b/tests/RHI/unit/test_descriptor_set.cpp @@ -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 + using namespace XCEngine::RHI; TEST_P(RHITestFixture, DescriptorSet_Allocate_Basic) { @@ -359,4 +364,132 @@ TEST_P(RHITestFixture, DescriptorSet_ConstantBufferSize) { pool->Shutdown(); delete pool; -} \ No newline at end of file +} + +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(DescriptorType::SRV); + bindings[0].count = 1; + bindings[1].binding = 1; + bindings[1].type = static_cast(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(firstSet); + auto* secondD3D12Set = static_cast(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(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(Format::R8G8B8A8_UNorm); + textureDesc.textureType = static_cast(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(DescriptorType::SRV); + bindings[0].count = 1; + bindings[1].binding = 7; + bindings[1].type = static_cast(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(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(updatedTexture), static_cast(reinterpret_cast(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; +}