Add RHI texture upload and descriptor set fixes

This commit is contained in:
2026-03-26 00:04:51 +08:00
parent 605ef56e16
commit 76c4c2ace2
15 changed files with 468 additions and 46 deletions

View File

@@ -51,6 +51,7 @@ private:
DescriptorHeapType m_type; DescriptorHeapType m_type;
uint32_t m_numDescriptors; uint32_t m_numDescriptors;
uint32_t m_descriptorSize; uint32_t m_descriptorSize;
uint32_t m_nextFreeOffset;
bool m_shaderVisible; bool m_shaderVisible;
std::vector<D3D12DescriptorSet*> m_allocatedSets; std::vector<D3D12DescriptorSet*> m_allocatedSets;
}; };

View File

@@ -65,6 +65,7 @@ public:
RHIBuffer* CreateBuffer(const BufferDesc& desc) override; RHIBuffer* CreateBuffer(const BufferDesc& desc) override;
RHITexture* CreateTexture(const TextureDesc& 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; RHISwapChain* CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) override;
RHICommandList* CreateCommandList(const CommandListDesc& desc) override; RHICommandList* CreateCommandList(const CommandListDesc& desc) override;
RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override; RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override;

View File

@@ -20,7 +20,7 @@ public:
bool Initialize(ID3D12Device* device, const D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON); 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 InitializeFromExisting(ID3D12Resource* resource, bool ownsResource = false);
bool InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList, 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); bool InitializeDepthStencil(ID3D12Device* device, uint32_t width, uint32_t height, DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT);
void Shutdown() override; void Shutdown() override;

View File

@@ -46,6 +46,9 @@ public:
uint32_t GetBindingPoint(uint32_t binding) const; uint32_t GetBindingPoint(uint32_t binding) const;
private: private:
DescriptorBinding* FindBinding(uint32_t binding);
const DescriptorBinding* FindBinding(uint32_t binding) const;
OpenGLTextureUnitAllocator* m_allocator; OpenGLTextureUnitAllocator* m_allocator;
std::vector<DescriptorBinding> m_bindings; std::vector<DescriptorBinding> m_bindings;
DescriptorSetLayoutBinding* m_layoutBindings; DescriptorSetLayoutBinding* m_layoutBindings;
@@ -57,4 +60,4 @@ private:
}; };
} // namespace RHI } // namespace RHI
} // namespace XCEngine } // namespace XCEngine

View File

@@ -36,6 +36,7 @@ public:
RHIBuffer* CreateBuffer(const BufferDesc& desc) override; RHIBuffer* CreateBuffer(const BufferDesc& desc) override;
RHITexture* CreateTexture(const TextureDesc& 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; RHISwapChain* CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) override;
RHICommandList* CreateCommandList(const CommandListDesc& desc) override; RHICommandList* CreateCommandList(const CommandListDesc& desc) override;
RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override; RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override;

View File

@@ -34,6 +34,7 @@ public:
virtual RHIBuffer* CreateBuffer(const BufferDesc& desc) = 0; virtual RHIBuffer* CreateBuffer(const BufferDesc& desc) = 0;
virtual RHITexture* CreateTexture(const TextureDesc& 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 RHISwapChain* CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) = 0;
virtual RHICommandList* CreateCommandList(const CommandListDesc& desc) = 0; virtual RHICommandList* CreateCommandList(const CommandListDesc& desc) = 0;
virtual RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) = 0; virtual RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) = 0;

View File

@@ -5,8 +5,11 @@
#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h" #include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h"
#include "XCEngine/RHI/D3D12/D3D12RenderPass.h" #include "XCEngine/RHI/D3D12/D3D12RenderPass.h"
#include "XCEngine/RHI/D3D12/D3D12Framebuffer.h" #include "XCEngine/RHI/D3D12/D3D12Framebuffer.h"
#include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h"
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h" #include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
#include <algorithm>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
@@ -151,6 +154,29 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
D3D12PipelineLayout* d3d12Layout = static_cast<D3D12PipelineLayout*>(pipelineLayout); D3D12PipelineLayout* d3d12Layout = static_cast<D3D12PipelineLayout*>(pipelineLayout);
SetPipelineLayout(d3d12Layout); 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) { for (uint32_t i = 0; i < count; ++i) {
if (descriptorSets[i] == nullptr) { if (descriptorSets[i] == nullptr) {
continue; continue;
@@ -160,6 +186,13 @@ void D3D12CommandList::SetGraphicsDescriptorSets(
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandle(); D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandle();
uint32_t rootIndex = firstSet + i; 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); SetGraphicsRootDescriptorTable(rootIndex, gpuHandle);
} }
} }
@@ -176,6 +209,29 @@ void D3D12CommandList::SetComputeDescriptorSets(
D3D12PipelineLayout* d3d12Layout = static_cast<D3D12PipelineLayout*>(pipelineLayout); D3D12PipelineLayout* d3d12Layout = static_cast<D3D12PipelineLayout*>(pipelineLayout);
SetPipelineLayout(d3d12Layout); 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) { for (uint32_t i = 0; i < count; ++i) {
if (descriptorSets[i] == nullptr) { if (descriptorSets[i] == nullptr) {
continue; continue;
@@ -185,6 +241,13 @@ void D3D12CommandList::SetComputeDescriptorSets(
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandle(); D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = d3d12Set->GetGPUHandle();
uint32_t rootIndex = firstSet + i; 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); m_commandList->SetComputeRootDescriptorTable(rootIndex, gpuHandle);
} }
} }

View File

@@ -8,6 +8,7 @@ D3D12DescriptorHeap::D3D12DescriptorHeap()
: m_type(DescriptorHeapType::CBV_SRV_UAV) : m_type(DescriptorHeapType::CBV_SRV_UAV)
, m_numDescriptors(0) , m_numDescriptors(0)
, m_descriptorSize(0) , m_descriptorSize(0)
, m_nextFreeOffset(0)
, m_shaderVisible(false) { , m_shaderVisible(false) {
} }
@@ -40,12 +41,17 @@ bool D3D12DescriptorHeap::Initialize(ID3D12Device* device, DescriptorHeapType ty
m_numDescriptors = numDescriptors; m_numDescriptors = numDescriptors;
m_shaderVisible = shaderVisible; m_shaderVisible = shaderVisible;
m_descriptorSize = device->GetDescriptorHandleIncrementSize(ToD3D12(type)); m_descriptorSize = device->GetDescriptorHandleIncrementSize(ToD3D12(type));
m_nextFreeOffset = 0;
return true; return true;
} }
void D3D12DescriptorHeap::Shutdown() { void D3D12DescriptorHeap::Shutdown() {
m_descriptorHeap.Reset(); m_descriptorHeap.Reset();
m_allocatedSets.clear();
m_numDescriptors = 0;
m_descriptorSize = 0;
m_nextFreeOffset = 0;
} }
D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart() const { D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart() const {
@@ -95,12 +101,12 @@ RHIDescriptorSet* D3D12DescriptorHeap::AllocateSet(const DescriptorSetLayoutDesc
requiredDescriptors += layout.bindings[i].count; requiredDescriptors += layout.bindings[i].count;
} }
if (m_allocatedSets.size() >= m_numDescriptors) { if (m_nextFreeOffset + requiredDescriptors > m_numDescriptors) {
return nullptr; return nullptr;
} }
D3D12DescriptorSet* newSet = new D3D12DescriptorSet(); 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)) { if (!newSet->Initialize(this, offset, requiredDescriptors, layout)) {
delete newSet; delete newSet;
@@ -108,6 +114,7 @@ RHIDescriptorSet* D3D12DescriptorHeap::AllocateSet(const DescriptorSetLayoutDesc
} }
m_allocatedSets.push_back(newSet); m_allocatedSets.push_back(newSet);
m_nextFreeOffset += requiredDescriptors;
return newSet; return newSet;
} }

View File

@@ -1,5 +1,7 @@
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h" #include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
#include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h" #include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h"
#include "XCEngine/RHI/D3D12/D3D12ResourceView.h"
#include "XCEngine/RHI/D3D12/D3D12Sampler.h"
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
@@ -50,13 +52,61 @@ void D3D12DescriptorSet::Unbind() {
} }
void D3D12DescriptorSet::Update(uint32_t offset, RHIResourceView* view) { void D3D12DescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
(void)offset; if (m_heap == nullptr || view == nullptr || m_heap->GetType() != DescriptorHeapType::CBV_SRV_UAV) {
(void)view; 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 D3D12DescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
(void)offset; if (m_heap == nullptr || sampler == nullptr || m_heap->GetType() != DescriptorHeapType::Sampler) {
(void)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 { 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 RHI
} // namespace XCEngine } // namespace XCEngine

View File

@@ -60,6 +60,27 @@ bool CompileD3D12Shader(const ShaderCompileDesc& desc, D3D12Shader& shader) {
return false; 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 } // namespace
D3D12Device::D3D12Device() D3D12Device::D3D12Device()
@@ -326,6 +347,77 @@ RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc) {
return nullptr; 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) { RHIShader* D3D12Device::CreateShader(const ShaderCompileDesc& desc) {
auto* shader = new D3D12Shader(); auto* shader = new D3D12Shader();
const std::string entryPoint = NarrowAscii(desc.entryPoint); const std::string entryPoint = NarrowAscii(desc.entryPoint);

View File

@@ -44,7 +44,7 @@ bool D3D12Texture::InitializeFromExisting(ID3D12Resource* resource, bool ownsRes
} }
bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList, 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 = {}; D3D12_RESOURCE_DESC textureDesc = {};
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
@@ -74,6 +74,7 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
if (FAILED(hResult)) { if (FAILED(hResult)) {
return false; return false;
} }
m_ownsResource = true;
textureDesc = m_resource->GetDesc(); textureDesc = m_resource->GetDesc();
UINT64 memorySizeUsed = 0; UINT64 memorySizeUsed = 0;
@@ -117,8 +118,9 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
tempBufferObject->Map(0, nullptr, reinterpret_cast<void**>(&pData)); tempBufferObject->Map(0, nullptr, reinterpret_cast<void**>(&pData));
BYTE* pDstTempBuffer = reinterpret_cast<BYTE*>(pData + subresourceFootprint.Offset); BYTE* pDstTempBuffer = reinterpret_cast<BYTE*>(pData + subresourceFootprint.Offset);
const BYTE* pSrcData = reinterpret_cast<const BYTE*>(pixelData); 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++) { 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); 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.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
commandList->ResourceBarrier(1, &barrier); commandList->ResourceBarrier(1, &barrier);
m_state = ResourceStates::PixelShaderResource;
tempBufferObject->Release();
return true; return true;
} }

View File

@@ -18,6 +18,24 @@ OpenGLDescriptorSet::~OpenGLDescriptorSet() {
Shutdown(); 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) { bool OpenGLDescriptorSet::Initialize(OpenGLTextureUnitAllocator* allocator, uint32_t count, const DescriptorSetLayoutDesc& layout) {
m_allocator = allocator; m_allocator = allocator;
m_bindingCount = layout.bindingCount; 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].textureIds.resize(layout.bindings[i].count, 0);
m_bindings[i].samplerIds.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) { for (uint32_t j = 0; j < layout.bindings[i].count; ++j) {
int32_t unit = m_allocator->Allocate(); int32_t unit = m_allocator->Allocate();
if (unit < 0) { if (unit < 0) {
@@ -80,17 +110,13 @@ void OpenGLDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
return; return;
} }
uint32_t bindingIndex = offset; DescriptorBinding* binding = FindBinding(offset);
if (bindingIndex >= m_bindings.size()) { if (binding == nullptr || binding->textureIds.empty()) {
return; return;
} }
OpenGLResourceView* glView = static_cast<OpenGLResourceView*>(view); OpenGLResourceView* glView = static_cast<OpenGLResourceView*>(view);
uint32_t textureId = glView->GetTexture(); binding->textureIds[0] = glView->GetTexture();
if (offset < m_bindings[bindingIndex].textureIds.size()) {
m_bindings[bindingIndex].textureIds[offset] = textureId;
}
} }
void OpenGLDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) { void OpenGLDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
@@ -98,17 +124,13 @@ void OpenGLDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
return; return;
} }
uint32_t bindingIndex = offset; DescriptorBinding* binding = FindBinding(offset);
if (bindingIndex >= m_bindings.size()) { if (binding == nullptr || binding->samplerIds.empty()) {
return; return;
} }
OpenGLSampler* glSampler = static_cast<OpenGLSampler*>(sampler); OpenGLSampler* glSampler = static_cast<OpenGLSampler*>(sampler);
uint32_t samplerId = glSampler->GetID(); binding->samplerIds[0] = glSampler->GetID();
if (offset < m_bindings[bindingIndex].samplerIds.size()) {
m_bindings[bindingIndex].samplerIds[offset] = samplerId;
}
} }
void OpenGLDescriptorSet::Bind() { void OpenGLDescriptorSet::Bind() {
@@ -130,13 +152,9 @@ void OpenGLDescriptorSet::Bind() {
uint32_t textureId = binding.textureIds[j]; uint32_t textureId = binding.textureIds[j];
uint32_t samplerId = binding.samplerIds[j]; uint32_t samplerId = binding.samplerIds[j];
if (textureId != 0) { if (textureId != 0 && binding.type != DescriptorType::Sampler) {
glActiveTexture(GL_TEXTURE0 + unit); glActiveTexture(GL_TEXTURE0 + unit);
if (binding.type == DescriptorType::Sampler) { glBindTexture(GL_TEXTURE_2D, textureId);
glBindTexture(GL_SAMPLER, textureId);
} else {
glBindTexture(GL_TEXTURE_2D, textureId);
}
} }
if (samplerId != 0) { if (samplerId != 0) {
@@ -165,10 +183,9 @@ void OpenGLDescriptorSet::Unbind() {
} }
uint32_t OpenGLDescriptorSet::GetBindingPoint(uint32_t binding) const { uint32_t OpenGLDescriptorSet::GetBindingPoint(uint32_t binding) const {
for (size_t i = 0; i < m_bindings.size(); ++i) { const DescriptorBinding* descriptorBinding = FindBinding(binding);
if (m_bindings[i].binding == binding && !m_bindings[i].textureUnits.empty()) { if (descriptorBinding != nullptr && !descriptorBinding->textureUnits.empty()) {
return m_bindings[i].textureUnits[0]; return descriptorBinding->textureUnits[0];
}
} }
return 0; return 0;
} }
@@ -183,4 +200,4 @@ void OpenGLDescriptorSet::WriteConstant(uint32_t binding, const void* data, size
} }
} // namespace RHI } // namespace RHI
} // namespace XCEngine } // namespace XCEngine

View File

@@ -318,6 +318,53 @@ RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) {
RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) { RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) {
auto* texture = new OpenGLTexture(); 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<Format>(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; OpenGLTextureType type = OpenGLTextureType::Texture2D;
switch (desc.textureType) { switch (desc.textureType) {
@@ -351,8 +398,14 @@ RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) {
case 9: format = OpenGLFormat::Depth32F; break; case 9: format = OpenGLFormat::Depth32F; break;
default: format = OpenGLFormat::RGBA8; 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<Format>(desc.format)); texture->SetFormat(static_cast<Format>(desc.format));
texture->SetState(ResourceStates::PixelShaderResource);
return texture; return texture;
} }

View File

@@ -82,6 +82,7 @@ bool OpenGLResourceView::IsValid() const {
case ResourceViewType::DepthStencil: case ResourceViewType::DepthStencil:
return m_framebufferID != 0; return m_framebufferID != 0;
case ResourceViewType::ShaderResource: case ResourceViewType::ShaderResource:
return m_texture != nullptr && m_texture->GetID() != 0;
case ResourceViewType::UnorderedAccess: case ResourceViewType::UnorderedAccess:
return m_texture != nullptr && m_textureUnit >= 0; return m_texture != nullptr && m_textureUnit >= 0;
case ResourceViewType::ConstantBuffer: case ResourceViewType::ConstantBuffer:
@@ -129,12 +130,7 @@ bool OpenGLResourceView::InitializeAsShaderResource(
OpenGLTexture* texture, OpenGLTexture* texture,
const ResourceViewDesc& desc, const ResourceViewDesc& desc,
OpenGLTextureUnitAllocator* allocator) { OpenGLTextureUnitAllocator* allocator) {
if (!texture || !allocator) { if (!texture) {
return false;
}
int32_t unit = allocator->Allocate();
if (unit < 0) {
return false; return false;
} }
@@ -142,9 +138,8 @@ bool OpenGLResourceView::InitializeAsShaderResource(
m_format = static_cast<Format>(desc.format); m_format = static_cast<Format>(desc.format);
m_dimension = desc.dimension; m_dimension = desc.dimension;
m_texture = texture; m_texture = texture;
m_textureUnit = unit; m_textureUnit = -1;
m_textureUnitAllocator = allocator; m_textureUnitAllocator = allocator;
allocator->BindTexture(unit, texture);
return true; return true;
} }

View File

@@ -1,10 +1,15 @@
#include "fixtures/RHITestFixture.h" #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/RHIDescriptorPool.h"
#include "XCEngine/RHI/RHIDescriptorSet.h" #include "XCEngine/RHI/RHIDescriptorSet.h"
#include "XCEngine/RHI/RHISampler.h" #include "XCEngine/RHI/RHISampler.h"
#include "XCEngine/RHI/RHIResourceView.h" #include "XCEngine/RHI/RHIResourceView.h"
#include "XCEngine/RHI/RHITexture.h" #include "XCEngine/RHI/RHITexture.h"
#include <glad/glad.h>
using namespace XCEngine::RHI; using namespace XCEngine::RHI;
TEST_P(RHITestFixture, DescriptorSet_Allocate_Basic) { TEST_P(RHITestFixture, DescriptorSet_Allocate_Basic) {
@@ -359,4 +364,132 @@ TEST_P(RHITestFixture, DescriptorSet_ConstantBufferSize) {
pool->Shutdown(); pool->Shutdown();
delete pool; 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;
}