diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 9db293a8..592d3b65 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -103,6 +103,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/D3D12/D3D12Shader.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/D3D12/D3D12Texture.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/D3D12/D3D12RootSignature.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/D3D12/D3D12PipelineLayout.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/D3D12/D3D12SwapChain.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/D3D12/D3D12Fence.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/D3D12/D3D12Screenshot.h @@ -119,6 +120,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/D3D12/D3D12Shader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/D3D12/D3D12Texture.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/D3D12/D3D12RootSignature.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/D3D12/D3D12PipelineLayout.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/D3D12/D3D12SwapChain.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/D3D12/D3D12Fence.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/D3D12/D3D12Screenshot.cpp diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h b/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h index 163187f2..e99bfdbb 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h @@ -17,6 +17,8 @@ namespace RHI { class RHIPipelineState; class D3D12ResourceView; +class D3D12Shader; +class D3D12PipelineLayout; class D3D12CommandList : public RHICommandList { public: @@ -31,6 +33,21 @@ public: ID3D12GraphicsCommandList* GetCommandList() const { return m_commandList.Get(); } + void SetShader(RHIShader* shader) override; + + void SetUniformInt(const char* name, int value) override; + void SetUniformFloat(const char* name, float value) override; + void SetUniformVec3(const char* name, float x, float y, float z) override; + void SetUniformVec4(const char* name, float x, float y, float z, float w) override; + void SetUniformMat4(const char* name, const float* value) override; + + void SetGlobalInt(const char* name, int value) override; + void SetGlobalFloat(const char* name, float value) override; + void SetGlobalVec3(const char* name, float x, float y, float z) override; + void SetGlobalVec4(const char* name, float x, float y, float z, float w) override; + void SetGlobalMat4(const char* name, const float* value) override; + void SetGlobalTexture(const char* name, RHIResourceView* texture) override; + void TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) override; void TransitionBarrier(ID3D12Resource* resource, ResourceStates stateBefore, ResourceStates stateAfter); void TransitionBarrierInternal(ID3D12Resource* resource, ResourceStates stateBefore, ResourceStates stateAfter, uint32_t subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); @@ -42,6 +59,7 @@ public: void SetPipelineState(RHIPipelineState* pso) override; void SetPipelineState(ID3D12PipelineState* pso); void SetPipelineStateInternal(ID3D12PipelineState* pso); + void SetPipelineLayout(D3D12PipelineLayout* layout); void SetRootSignature(ID3D12RootSignature* signature); void SetViewport(const Viewport& viewport) override; void SetViewports(uint32_t count, const Viewport* viewports) override; @@ -131,7 +149,16 @@ private: std::vector m_boundRenderTargets; D3D12_CPU_DESCRIPTOR_HANDLE m_boundDepthStencil; bool m_depthStencilBound = false; + + D3D12Shader* m_currentShader; + class D3D12PipelineLayout* m_currentPipelineLayout; + std::unordered_map m_globalIntCache; + std::unordered_map m_globalFloatCache; + std::unordered_map> m_globalVec3Cache; + std::unordered_map> m_globalVec4Cache; + std::unordered_map> m_globalMat4Cache; + std::unordered_map m_globalTextureCache; }; } // namespace RHI -} // namespace XCEngine +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h index d681e4da..c6a13df8 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h @@ -10,6 +10,7 @@ #include "../RHIEnums.h" #include "../RHITypes.h" #include "D3D12Enums.h" +#include "D3D12PipelineLayout.h" using Microsoft::WRL::ComPtr; @@ -69,6 +70,7 @@ public: RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override; RHIShader* CompileShader(const ShaderCompileDesc& desc) override; RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) override; + RHIPipelineLayout* CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) override; RHIFence* CreateFence(const FenceDesc& desc) override; RHISampler* CreateSampler(const SamplerDesc& desc) override; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12PipelineLayout.h b/engine/include/XCEngine/RHI/D3D12/D3D12PipelineLayout.h new file mode 100644 index 00000000..361f9eb1 --- /dev/null +++ b/engine/include/XCEngine/RHI/D3D12/D3D12PipelineLayout.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +#include "../RHIPipelineLayout.h" +#include "D3D12RootSignature.h" + +using Microsoft::WRL::ComPtr; + +namespace XCEngine { +namespace RHI { + +class D3D12Device; + +class D3D12PipelineLayout : public RHIPipelineLayout { +public: + D3D12PipelineLayout(); + ~D3D12PipelineLayout() override; + + bool InitializeWithDevice(D3D12Device* device, const RHIPipelineLayoutDesc& desc); + void Shutdown() override; + bool Initialize(const RHIPipelineLayoutDesc& desc) override { return false; } + + void* GetNativeHandle() override { return m_rootSignature.Get(); } + ID3D12RootSignature* GetRootSignature() const { return m_rootSignature.Get(); } + + uint32_t GetRootParameterIndex(uint32_t shaderRegister) const; + bool HasRootParameter(uint32_t shaderRegister) const; + +private: + bool InitializeInternal(D3D12Device* device, const RHIPipelineLayoutDesc& desc); + + ComPtr m_rootSignature; + D3D12Device* m_device; + std::unordered_map m_registerToRootIndex; + std::vector m_rootParameters; +}; + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h b/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h index 6b3d329b..75befb19 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "../RHIShader.h" #include "D3D12Enums.h" @@ -32,21 +33,19 @@ public: void* GetNativeHandle() override { return m_bytecode.Get(); } bool IsValid() const override { return m_bytecode != nullptr; } - void Bind() override { } - void Unbind() override { } - - void SetInt(const char* name, int value) override { } - void SetFloat(const char* name, float value) override { } - void SetVec3(const char* name, float x, float y, float z) override { } - void SetVec4(const char* name, float x, float y, float z, float w) override { } - void SetMat4(const char* name, const float* value) override { } + const std::vector& GetUniformInfos() const override; + const UniformInfo* GetUniformInfo(const char* name) const override; private: + void CacheUniformInfos() const; + ComPtr m_bytecode; ComPtr m_error; ShaderType m_type; InputLayoutDesc m_inputLayout; + mutable std::vector m_uniformInfos; + mutable bool m_uniformsCached = false; }; } // namespace RHI -} // namespace XCEngine +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h index e44c84f5..1476309b 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h @@ -2,6 +2,7 @@ #include #include +#include #include "../RHICommandList.h" @@ -51,6 +52,21 @@ public: void ClearStencil(int stencil); void ClearDepthStencil(float depth, int stencil); + void SetShader(RHIShader* shader) override; + + void SetUniformInt(const char* name, int value) override; + void SetUniformFloat(const char* name, float value) override; + void SetUniformVec3(const char* name, float x, float y, float z) override; + void SetUniformVec4(const char* name, float x, float y, float z, float w) override; + void SetUniformMat4(const char* name, const float* value) override; + + void SetGlobalInt(const char* name, int value) override; + void SetGlobalFloat(const char* name, float value) override; + void SetGlobalVec3(const char* name, float x, float y, float z) override; + void SetGlobalVec4(const char* name, float x, float y, float z, float w) override; + void SetGlobalMat4(const char* name, const float* value) override; + void SetGlobalTexture(const char* name, RHIResourceView* texture) override; + void SetPipelineState(RHIPipelineState* pipelineState) override; void SetVertexBuffer(uint32_t slot, RHIResourceView* buffer, uint64_t offset) override; void SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) override; @@ -176,7 +192,14 @@ private: unsigned int m_primitiveType; unsigned int m_currentVAO; unsigned int m_currentProgram; + OpenGLShader* m_currentShader; + std::unordered_map m_globalIntCache; + std::unordered_map m_globalFloatCache; + std::unordered_map> m_globalVec3Cache; + std::unordered_map> m_globalVec4Cache; + std::unordered_map> m_globalMat4Cache; + std::unordered_map m_globalTextureCache; }; } // namespace RHI -} // namespace XCEngine +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h index 644c0bd4..a9d4ba39 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h @@ -50,6 +50,7 @@ public: RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override; RHIShader* CompileShader(const ShaderCompileDesc& desc) override; RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) override; + RHIPipelineLayout* CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) override; RHIFence* CreateFence(const FenceDesc& desc) override; RHISampler* CreateSampler(const SamplerDesc& desc) override; diff --git a/engine/include/XCEngine/RHI/RHICommandList.h b/engine/include/XCEngine/RHI/RHICommandList.h index 83689f21..37be0408 100644 --- a/engine/include/XCEngine/RHI/RHICommandList.h +++ b/engine/include/XCEngine/RHI/RHICommandList.h @@ -8,6 +8,7 @@ namespace RHI { class RHIResourceView; class RHIPipelineState; +class RHIShader; struct DepthStencilState { bool depthEnable = true; @@ -54,6 +55,21 @@ public: virtual void TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) = 0; + virtual void SetShader(RHIShader* shader) = 0; + + virtual void SetUniformInt(const char* name, int value) = 0; + virtual void SetUniformFloat(const char* name, float value) = 0; + virtual void SetUniformVec3(const char* name, float x, float y, float z) = 0; + virtual void SetUniformVec4(const char* name, float x, float y, float z, float w) = 0; + virtual void SetUniformMat4(const char* name, const float* value) = 0; + + virtual void SetGlobalInt(const char* name, int value) = 0; + virtual void SetGlobalFloat(const char* name, float value) = 0; + virtual void SetGlobalVec3(const char* name, float x, float y, float z) = 0; + virtual void SetGlobalVec4(const char* name, float x, float y, float z, float w) = 0; + virtual void SetGlobalMat4(const char* name, const float* value) = 0; + virtual void SetGlobalTexture(const char* name, RHIResourceView* texture) = 0; + virtual void SetPipelineState(RHIPipelineState* pso) = 0; virtual void SetPrimitiveTopology(PrimitiveTopology topology) = 0; virtual void SetViewport(const Viewport& viewport) = 0; @@ -86,4 +102,4 @@ public: }; } // namespace RHI -} // namespace XCEngine +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/RHIDevice.h b/engine/include/XCEngine/RHI/RHIDevice.h index 9bc0db1a..765f95e2 100644 --- a/engine/include/XCEngine/RHI/RHIDevice.h +++ b/engine/include/XCEngine/RHI/RHIDevice.h @@ -14,6 +14,7 @@ class RHICommandList; class RHICommandQueue; class RHIShader; class RHIPipelineState; +class RHIPipelineLayout; class RHIFence; class RHISampler; class RHIResourceView; @@ -32,6 +33,7 @@ public: virtual RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) = 0; virtual RHIShader* CompileShader(const ShaderCompileDesc& desc) = 0; virtual RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) = 0; + virtual RHIPipelineLayout* CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) = 0; virtual RHIFence* CreateFence(const FenceDesc& desc) = 0; virtual RHISampler* CreateSampler(const SamplerDesc& desc) = 0; @@ -47,4 +49,4 @@ public: }; } // namespace RHI -} // namespace XCEngine +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/RHIShader.h b/engine/include/XCEngine/RHI/RHIShader.h index a5363baf..9b1f2695 100644 --- a/engine/include/XCEngine/RHI/RHIShader.h +++ b/engine/include/XCEngine/RHI/RHIShader.h @@ -28,6 +28,7 @@ public: uint32_t size; uint32_t type; uint32_t arraySize; + uint32_t offset; }; virtual const std::vector& GetUniformInfos() const = 0; diff --git a/engine/src/RHI/D3D12/D3D12CommandList.cpp b/engine/src/RHI/D3D12/D3D12CommandList.cpp index 26b64004..3cdad7e5 100644 --- a/engine/src/RHI/D3D12/D3D12CommandList.cpp +++ b/engine/src/RHI/D3D12/D3D12CommandList.cpp @@ -1,6 +1,8 @@ #include "XCEngine/RHI/D3D12/D3D12CommandList.h" #include "XCEngine/RHI/D3D12/D3D12ResourceView.h" #include "XCEngine/RHI/D3D12/D3D12PipelineState.h" +#include "XCEngine/RHI/D3D12/D3D12Shader.h" +#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h" namespace XCEngine { namespace RHI { @@ -10,7 +12,9 @@ D3D12CommandList::D3D12CommandList() , m_currentTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST) , m_currentPipelineState(nullptr) , m_currentRootSignature(nullptr) - , m_currentDescriptorHeap(nullptr) { + , m_currentDescriptorHeap(nullptr) + , m_currentShader(nullptr) + , m_currentPipelineLayout(nullptr) { } D3D12CommandList::~D3D12CommandList() { @@ -55,6 +59,13 @@ void D3D12CommandList::Shutdown() { m_rtvHeap.Reset(); m_resourceStateMap.clear(); m_trackedResources.clear(); + m_currentShader = nullptr; + m_globalIntCache.clear(); + m_globalFloatCache.clear(); + m_globalVec3Cache.clear(); + m_globalVec4Cache.clear(); + m_globalMat4Cache.clear(); + m_globalTextureCache.clear(); } void D3D12CommandList::Reset() { @@ -64,6 +75,7 @@ void D3D12CommandList::Reset() { m_currentTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; m_currentPipelineState = nullptr; m_currentRootSignature = nullptr; + m_currentPipelineLayout = nullptr; m_currentDescriptorHeap = nullptr; m_resourceStateMap.clear(); m_trackedResources.clear(); @@ -75,6 +87,103 @@ void D3D12CommandList::Close() { m_commandList->Close(); } +void D3D12CommandList::SetShader(RHIShader* shader) { + m_currentShader = static_cast(shader); +} + +void D3D12CommandList::SetPipelineLayout(D3D12PipelineLayout* layout) { + m_currentPipelineLayout = layout; + if (layout) { + SetRootSignature(layout->GetRootSignature()); + } +} + +void D3D12CommandList::SetUniformInt(const char* name, int value) { + if (m_currentShader && m_currentPipelineLayout) { + const RHIShader::UniformInfo* info = m_currentShader->GetUniformInfo(name); + if (info) { + uint32_t rootIndex = m_currentPipelineLayout->GetRootParameterIndex(info->bindPoint); + if (rootIndex != UINT32_MAX) { + m_commandList->SetGraphicsRoot32BitConstants(rootIndex, 1, &value, 0); + } + } + } +} + +void D3D12CommandList::SetUniformFloat(const char* name, float value) { + if (m_currentShader && m_currentPipelineLayout) { + const RHIShader::UniformInfo* info = m_currentShader->GetUniformInfo(name); + if (info) { + uint32_t rootIndex = m_currentPipelineLayout->GetRootParameterIndex(info->bindPoint); + if (rootIndex != UINT32_MAX) { + m_commandList->SetGraphicsRoot32BitConstants(rootIndex, 1, &value, 0); + } + } + } +} + +void D3D12CommandList::SetUniformVec3(const char* name, float x, float y, float z) { + if (m_currentShader && m_currentPipelineLayout) { + const RHIShader::UniformInfo* info = m_currentShader->GetUniformInfo(name); + if (info) { + uint32_t rootIndex = m_currentPipelineLayout->GetRootParameterIndex(info->bindPoint); + if (rootIndex != UINT32_MAX) { + float values[3] = { x, y, z }; + m_commandList->SetGraphicsRoot32BitConstants(rootIndex, 3, values, 0); + } + } + } +} + +void D3D12CommandList::SetUniformVec4(const char* name, float x, float y, float z, float w) { + if (m_currentShader && m_currentPipelineLayout) { + const RHIShader::UniformInfo* info = m_currentShader->GetUniformInfo(name); + if (info) { + uint32_t rootIndex = m_currentPipelineLayout->GetRootParameterIndex(info->bindPoint); + if (rootIndex != UINT32_MAX) { + float values[4] = { x, y, z, w }; + m_commandList->SetGraphicsRoot32BitConstants(rootIndex, 4, values, 0); + } + } + } +} + +void D3D12CommandList::SetUniformMat4(const char* name, const float* value) { + if (m_currentShader && m_currentPipelineLayout) { + const RHIShader::UniformInfo* info = m_currentShader->GetUniformInfo(name); + if (info) { + uint32_t rootIndex = m_currentPipelineLayout->GetRootParameterIndex(info->bindPoint); + if (rootIndex != UINT32_MAX) { + m_commandList->SetGraphicsRoot32BitConstants(rootIndex, 16, value, 0); + } + } + } +} + +void D3D12CommandList::SetGlobalInt(const char* name, int value) { + m_globalIntCache[name] = value; +} + +void D3D12CommandList::SetGlobalFloat(const char* name, float value) { + m_globalFloatCache[name] = value; +} + +void D3D12CommandList::SetGlobalVec3(const char* name, float x, float y, float z) { + m_globalVec3Cache[name] = { x, y, z }; +} + +void D3D12CommandList::SetGlobalVec4(const char* name, float x, float y, float z, float w) { + m_globalVec4Cache[name] = { x, y, z, w }; +} + +void D3D12CommandList::SetGlobalMat4(const char* name, const float* value) { + m_globalMat4Cache[name] = std::vector(value, value + 16); +} + +void D3D12CommandList::SetGlobalTexture(const char* name, RHIResourceView* texture) { + m_globalTextureCache[name] = texture; +} + void D3D12CommandList::TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) { if (!resource || !resource->IsValid()) return; D3D12ResourceView* d3d12View = static_cast(resource); @@ -139,6 +248,9 @@ void D3D12CommandList::AliasBarrierInternal(ID3D12Resource* beforeResource, ID3D void D3D12CommandList::SetPipelineStateInternal(ID3D12PipelineState* pso) { m_commandList->SetPipelineState(pso); m_currentPipelineState = pso; + if (m_currentRootSignature) { + m_commandList->SetGraphicsRootSignature(m_currentRootSignature); + } } void D3D12CommandList::SetRootSignature(ID3D12RootSignature* signature) { diff --git a/engine/src/RHI/D3D12/D3D12Device.cpp b/engine/src/RHI/D3D12/D3D12Device.cpp index 3c058d04..73b37736 100644 --- a/engine/src/RHI/D3D12/D3D12Device.cpp +++ b/engine/src/RHI/D3D12/D3D12Device.cpp @@ -6,6 +6,7 @@ #include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h" #include "XCEngine/RHI/D3D12/D3D12QueryHeap.h" #include "XCEngine/RHI/D3D12/D3D12RootSignature.h" +#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h" #include "XCEngine/RHI/D3D12/D3D12PipelineState.h" #include "XCEngine/RHI/D3D12/D3D12Sampler.h" #include "XCEngine/RHI/D3D12/D3D12Texture.h" @@ -380,6 +381,15 @@ RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& d return pso; } +RHIPipelineLayout* D3D12Device::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) { + auto* pipelineLayout = new D3D12PipelineLayout(); + if (!pipelineLayout->InitializeWithDevice(this, desc)) { + delete pipelineLayout; + return nullptr; + } + return pipelineLayout; +} + RHIResourceView* D3D12Device::CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) { auto* view = new D3D12ResourceView(); auto* d3d12Texture = static_cast(texture); diff --git a/engine/src/RHI/D3D12/D3D12PipelineLayout.cpp b/engine/src/RHI/D3D12/D3D12PipelineLayout.cpp new file mode 100644 index 00000000..abcc4948 --- /dev/null +++ b/engine/src/RHI/D3D12/D3D12PipelineLayout.cpp @@ -0,0 +1,119 @@ +#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h" +#include "XCEngine/RHI/D3D12/D3D12Device.h" + +namespace XCEngine { +namespace RHI { + +D3D12PipelineLayout::D3D12PipelineLayout() + : m_device(nullptr) { +} + +D3D12PipelineLayout::~D3D12PipelineLayout() { + Shutdown(); +} + +bool D3D12PipelineLayout::InitializeWithDevice(D3D12Device* device, const RHIPipelineLayoutDesc& desc) { + return InitializeInternal(device, desc); +} + +bool D3D12PipelineLayout::InitializeInternal(D3D12Device* device, const RHIPipelineLayoutDesc& desc) { + if (!device) { + return false; + } + + m_device = device; + + m_rootParameters.clear(); + m_registerToRootIndex.clear(); + + uint32_t rootIndex = 0; + + if (desc.constantBufferCount > 0) { + D3D12_ROOT_PARAMETER param = D3D12RootSignature::Create32BitConstants( + 0, desc.constantBufferCount * 16, ShaderVisibility::All, 0); + m_rootParameters.push_back(param); + for (uint32_t i = 0; i < desc.constantBufferCount; ++i) { + m_registerToRootIndex[i] = rootIndex; + } + rootIndex++; + } + + if (desc.textureCount > 0) { + D3D12_DESCRIPTOR_RANGE range = D3D12RootSignature::CreateDescriptorRange( + D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, desc.textureCount, 0); + D3D12_ROOT_PARAMETER param = D3D12RootSignature::CreateDescriptorTable(1, &range, ShaderVisibility::All); + m_rootParameters.push_back(param); + for (uint32_t i = 0; i < desc.textureCount; ++i) { + m_registerToRootIndex[100 + i] = rootIndex; + } + rootIndex++; + } + + if (desc.samplerCount > 0) { + D3D12_DESCRIPTOR_RANGE range = D3D12RootSignature::CreateDescriptorRange( + D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, desc.samplerCount, 0); + D3D12_ROOT_PARAMETER param = D3D12RootSignature::CreateDescriptorTable(1, &range, ShaderVisibility::All); + m_rootParameters.push_back(param); + for (uint32_t i = 0; i < desc.samplerCount; ++i) { + m_registerToRootIndex[200 + i] = rootIndex; + } + rootIndex++; + } + + if (m_rootParameters.empty()) { + return false; + } + + D3D12_ROOT_SIGNATURE_DESC rootSigDesc = D3D12RootSignature::CreateDesc( + m_rootParameters.data(), + static_cast(m_rootParameters.size()), + nullptr, 0, + D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); + + ID3D12Device* d3d12Device = device->GetDevice(); + if (!d3d12Device) { + return false; + } + + ID3DBlob* signature = nullptr; + ID3DBlob* error = nullptr; + + HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error); + if (FAILED(hr)) { + if (error) { + error->Release(); + } + return false; + } + + hr = d3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)); + signature->Release(); + + if (FAILED(hr)) { + return false; + } + + return true; +} + +void D3D12PipelineLayout::Shutdown() { + m_rootSignature.Reset(); + m_rootParameters.clear(); + m_registerToRootIndex.clear(); + m_device = nullptr; +} + +uint32_t D3D12PipelineLayout::GetRootParameterIndex(uint32_t shaderRegister) const { + auto it = m_registerToRootIndex.find(shaderRegister); + if (it != m_registerToRootIndex.end()) { + return it->second; + } + return UINT32_MAX; +} + +bool D3D12PipelineLayout::HasRootParameter(uint32_t shaderRegister) const { + return m_registerToRootIndex.find(shaderRegister) != m_registerToRootIndex.end(); +} + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file diff --git a/engine/src/RHI/D3D12/D3D12Shader.cpp b/engine/src/RHI/D3D12/D3D12Shader.cpp index 57f2e850..2a3a9217 100644 --- a/engine/src/RHI/D3D12/D3D12Shader.cpp +++ b/engine/src/RHI/D3D12/D3D12Shader.cpp @@ -1,11 +1,15 @@ #include "XCEngine/RHI/D3D12/D3D12Shader.h" #include +static const IID IID_ID3D12ShaderReflection = { + 0x8e5c5a69, 0x5c6a, 0x427d, {0xb0, 0xdc, 0x27, 0x63, 0xae, 0xac, 0xe3, 0x75} +}; + namespace XCEngine { namespace RHI { D3D12Shader::D3D12Shader() - : m_type(ShaderType::Vertex) { + : m_type(ShaderType::Vertex), m_uniformsCached(false) { } D3D12Shader::~D3D12Shader() { @@ -35,6 +39,7 @@ bool D3D12Shader::CompileFromFile(const wchar_t* filePath, const char* entryPoin m_type = ShaderType::Compute; } + m_uniformsCached = false; return true; } @@ -50,12 +55,87 @@ bool D3D12Shader::Compile(const void* sourceData, size_t sourceSize, const char* return false; } + m_uniformsCached = false; return true; } void D3D12Shader::Shutdown() { m_bytecode.Reset(); m_error.Reset(); + m_uniformInfos.clear(); + m_uniformsCached = false; +} + +void D3D12Shader::CacheUniformInfos() const { + if (m_uniformsCached || !m_bytecode) { + return; + } + + m_uniformInfos.clear(); + + ComPtr pReflection; + HRESULT hr = D3DReflect(m_bytecode->GetBufferPointer(), m_bytecode->GetBufferSize(), + IID_ID3D12ShaderReflection, (void**)&pReflection); + + if (FAILED(hr)) { + return; + } + + D3D12_SHADER_DESC shaderDesc; + pReflection->GetDesc(&shaderDesc); + + for (UINT i = 0; i < shaderDesc.BoundResources; ++i) { + D3D12_SHADER_INPUT_BIND_DESC bindDesc; + pReflection->GetResourceBindingDesc(i, &bindDesc); + + UniformInfo info; + info.name = bindDesc.Name; + info.bindPoint = bindDesc.BindPoint; + info.arraySize = bindDesc.NumSamples; + + switch (bindDesc.Type) { + case D3D_SIT_CBUFFER: + info.type = static_cast(D3D_SIT_CBUFFER); + break; + case D3D_SIT_TEXTURE: + info.type = static_cast(D3D_SIT_TEXTURE); + break; + case D3D_SIT_SAMPLER: + info.type = static_cast(D3D_SIT_SAMPLER); + break; + default: + info.type = static_cast(bindDesc.Type); + break; + } + + D3D12_SHADER_BUFFER_DESC bufferDesc; + if (bindDesc.Type == D3D_SIT_CBUFFER) { + ID3D12ShaderReflectionConstantBuffer* pCB = pReflection->GetConstantBufferByIndex(bindDesc.BindPoint); + pCB->GetDesc(&bufferDesc); + info.size = bufferDesc.Size; + } else { + info.size = 0; + } + + m_uniformInfos.push_back(info); + } + + m_uniformsCached = true; +} + +const std::vector& D3D12Shader::GetUniformInfos() const { + CacheUniformInfos(); + return m_uniformInfos; +} + +const RHIShader::UniformInfo* D3D12Shader::GetUniformInfo(const char* name) const { + CacheUniformInfos(); + for (const auto& info : m_uniformInfos) { + if (info.name == name) { + return &info; + } + } + return nullptr; } const D3D12_SHADER_BYTECODE D3D12Shader::GetD3D12Bytecode() const { @@ -90,4 +170,4 @@ ShaderType D3D12Shader::GetType() const { } } // namespace RHI -} // namespace XCEngine +} // namespace XCEngine \ No newline at end of file diff --git a/engine/src/RHI/OpenGL/OpenGLCommandList.cpp b/engine/src/RHI/OpenGL/OpenGLCommandList.cpp index 0bf8c15f..2fd5a602 100644 --- a/engine/src/RHI/OpenGL/OpenGLCommandList.cpp +++ b/engine/src/RHI/OpenGL/OpenGLCommandList.cpp @@ -1,6 +1,7 @@ #include "XCEngine/RHI/OpenGL/OpenGLCommandList.h" #include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" #include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h" +#include "XCEngine/RHI/OpenGL/OpenGLShader.h" #include namespace XCEngine { @@ -24,7 +25,8 @@ static unsigned int ToGLPrimitiveType(PrimitiveType type) { OpenGLCommandList::OpenGLCommandList() : m_primitiveType(GL_TRIANGLES) , m_currentVAO(0) - , m_currentProgram(0) { + , m_currentProgram(0) + , m_currentShader(nullptr) { } OpenGLCommandList::~OpenGLCommandList() { @@ -423,6 +425,13 @@ void OpenGLCommandList::PopDebugGroup() { } void OpenGLCommandList::Shutdown() { + m_currentShader = nullptr; + m_globalIntCache.clear(); + m_globalFloatCache.clear(); + m_globalVec3Cache.clear(); + m_globalVec4Cache.clear(); + m_globalMat4Cache.clear(); + m_globalTextureCache.clear(); } void OpenGLCommandList::Reset() { @@ -431,6 +440,67 @@ void OpenGLCommandList::Reset() { void OpenGLCommandList::Close() { } +void OpenGLCommandList::SetShader(RHIShader* shader) { + m_currentShader = static_cast(shader); + if (m_currentShader) { + UseShader(m_currentShader->GetID()); + } +} + +void OpenGLCommandList::SetUniformInt(const char* name, int value) { + if (m_currentShader) { + glUniform1i(glGetUniformLocation(m_currentShader->GetID(), name), value); + } +} + +void OpenGLCommandList::SetUniformFloat(const char* name, float value) { + if (m_currentShader) { + glUniform1f(glGetUniformLocation(m_currentShader->GetID(), name), value); + } +} + +void OpenGLCommandList::SetUniformVec3(const char* name, float x, float y, float z) { + if (m_currentShader) { + glUniform3f(glGetUniformLocation(m_currentShader->GetID(), name), x, y, z); + } +} + +void OpenGLCommandList::SetUniformVec4(const char* name, float x, float y, float z, float w) { + if (m_currentShader) { + glUniform4f(glGetUniformLocation(m_currentShader->GetID(), name), x, y, z, w); + } +} + +void OpenGLCommandList::SetUniformMat4(const char* name, const float* value) { + if (m_currentShader) { + glUniformMatrix4fv(glGetUniformLocation(m_currentShader->GetID(), name), 1, GL_FALSE, value); + } +} + +void OpenGLCommandList::SetGlobalInt(const char* name, int value) { + m_globalIntCache[name] = value; +} + +void OpenGLCommandList::SetGlobalFloat(const char* name, float value) { + m_globalFloatCache[name] = value; +} + +void OpenGLCommandList::SetGlobalVec3(const char* name, float x, float y, float z) { + m_globalVec3Cache[name] = {x, y, z}; +} + +void OpenGLCommandList::SetGlobalVec4(const char* name, float x, float y, float z, float w) { + m_globalVec4Cache[name] = {x, y, z, w}; +} + +void OpenGLCommandList::SetGlobalMat4(const char* name, const float* value) { + m_globalMat4Cache[name] = std::vector(value, value + 16); +} + +void OpenGLCommandList::SetGlobalTexture(const char* name, RHIResourceView* texture) { + m_globalTextureCache[name] = texture; +} + void OpenGLCommandList::TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) { (void)resource; (void)stateBefore; diff --git a/engine/src/RHI/OpenGL/OpenGLDevice.cpp b/engine/src/RHI/OpenGL/OpenGLDevice.cpp index ea5d2ca6..0973c653 100644 --- a/engine/src/RHI/OpenGL/OpenGLDevice.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDevice.cpp @@ -456,6 +456,10 @@ RHIPipelineState* OpenGLDevice::CreatePipelineState(const GraphicsPipelineDesc& return pso; } +RHIPipelineLayout* OpenGLDevice::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) { + return nullptr; +} + RHIFence* OpenGLDevice::CreateFence(const FenceDesc& desc) { auto* fence = new OpenGLFence(); fence->Initialize(desc.initialValue > 0); diff --git a/engine/src/RHI/OpenGL/OpenGLShader.cpp b/engine/src/RHI/OpenGL/OpenGLShader.cpp index 9403ae5a..a366fa7b 100644 --- a/engine/src/RHI/OpenGL/OpenGLShader.cpp +++ b/engine/src/RHI/OpenGL/OpenGLShader.cpp @@ -260,8 +260,7 @@ void OpenGLShader::CacheUniformInfos() const { info.offset = static_cast(values[2]); info.arraySize = static_cast(values[3]); - GLint size = 0; - glGetActiveUniformsiv(m_program, 1, &i, GL_SIZE, &size); + GLint size = values[3]; switch (values[1]) { case GL_FLOAT: info.size = sizeof(GLfloat) * size; break; case GL_FLOAT_VEC2: info.size = sizeof(GLfloat) * 2 * size; break; diff --git a/tests/OpenGL/main.cpp b/tests/OpenGL/main.cpp index d3787128..0059fa75 100644 --- a/tests/OpenGL/main.cpp +++ b/tests/OpenGL/main.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -20,6 +19,7 @@ #include "XCEngine/RHI/OpenGL/OpenGLShader.h" #include "XCEngine/RHI/OpenGL/OpenGLDevice.h" #include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h" +#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h" using namespace XCEngine::Debug; using namespace XCEngine::RHI; @@ -264,13 +264,9 @@ Model* model = nullptr; OpenGLShader* shader = nullptr; OpenGLDevice* device = nullptr; OpenGLPipelineState* pipeline = nullptr; +OpenGLCommandList* cmdList = nullptr; int frameCount = 0; -void framebuffer_size_callback(GLFWwindow* window, int width, int height) -{ - glViewport(0, 0, width, height); -} - void Initialize() { char exePath[MAX_PATH]; @@ -293,6 +289,8 @@ void Initialize() shader = new OpenGLShader(); shader->CompileFromFile("Shaders/vertexshader.glsl", "Shaders/fragmentshader.glsl"); + cmdList = new OpenGLCommandList(); + Log("Initialization complete"); } @@ -336,15 +334,16 @@ void Render() glm::mat4 modelMat = glm::mat4(1.0f); glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); - shader->SetMat4("view", &view[0][0]); - shader->SetMat4("model", &modelMat[0][0]); - shader->SetMat4("projection", &projection[0][0]); - shader->SetVec3("viewPos", 0.0f, 0.0f, 3.0f); - shader->SetFloat("material.shininess", 32.0f); - shader->SetVec3("dirLight.direction", 0.0f, -1.0f, 0.0f); - shader->SetVec3("dirLight.ambient", 0.3f, 0.3f, 0.3f); - shader->SetVec3("dirLight.diffuse", 0.8f, 0.8f, 0.8f); - shader->SetVec3("dirLight.specular", 0.5f, 0.5f, 0.5f); + cmdList->SetShader(shader); + cmdList->SetUniformMat4("view", &view[0][0]); + cmdList->SetUniformMat4("model", &modelMat[0][0]); + cmdList->SetUniformMat4("projection", &projection[0][0]); + cmdList->SetUniformVec3("viewPos", 0.0f, 0.0f, 3.0f); + cmdList->SetUniformFloat("material.shininess", 32.0f); + cmdList->SetUniformVec3("dirLight.direction", 0.0f, -1.0f, 0.0f); + cmdList->SetUniformVec3("dirLight.ambient", 0.3f, 0.3f, 0.3f); + cmdList->SetUniformVec3("dirLight.diffuse", 0.8f, 0.8f, 0.8f); + cmdList->SetUniformVec3("dirLight.specular", 0.5f, 0.5f, 0.5f); model->Draw(shader); } @@ -361,24 +360,34 @@ int main() if (!device->CreateRenderWindow(SCR_WIDTH, SCR_HEIGHT, "XCRender", false)) { Log("Failed to create window"); - glfwTerminate(); return -1; } - glfwSetFramebufferSizeCallback(device->GetWindow(), framebuffer_size_callback); - - const OpenGLDeviceInfo& info = device->GetDeviceInfo(); - Log("OpenGL Version: %s", info.version.c_str()); - Log("Renderer: %s", info.renderer.c_str()); + const RHIDeviceInfo& info = device->GetDeviceInfo(); + Log("OpenGL Version: %ls", info.version.c_str()); + Log("Renderer: %ls", info.renderer.c_str()); Initialize(); device->PollEvents(); - while (!glfwWindowShouldClose(device->GetWindow())) + MSG msg = {}; + bool shouldClose = false; + while (!shouldClose) { - if (glfwGetKey(device->GetWindow(), GLFW_KEY_ESCAPE) == GLFW_PRESS) - glfwSetWindowShouldClose(device->GetWindow(), GLFW_TRUE); + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + shouldClose = true; + break; + } + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + if (shouldClose) + break; Render(); device->SwapBuffers(); @@ -389,12 +398,13 @@ int main() if (frameCount == 30) { Log("Saving screenshot at frame %d", frameCount); SaveScreenshot("screenshot.ppm"); - glfwSetWindowShouldClose(device->GetWindow(), GLFW_TRUE); + PostMessageW(device->GetWindow(), WM_CLOSE, 0, 0); } } Log("Application closed"); + delete cmdList; delete pipeline; delete device; delete shader; diff --git a/tests/RHI/OpenGL/integration/quad/main.cpp b/tests/RHI/OpenGL/integration/quad/main.cpp index 47e7d2c7..3db40bcd 100644 --- a/tests/RHI/OpenGL/integration/quad/main.cpp +++ b/tests/RHI/OpenGL/integration/quad/main.cpp @@ -161,7 +161,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } Log("[INFO] Shaders compiled successfully"); - shader.SetInt("uTexture", 0); + commandList.SetShader(&shader); + commandList.SetUniformInt("uTexture", 0); OpenGLPipelineState pipelineState; OpenGLRasterizerState rasterizerState; diff --git a/tests/RHI/OpenGL/integration/sphere/main.cpp b/tests/RHI/OpenGL/integration/sphere/main.cpp index 1f3b4bcb..0390e8cf 100644 --- a/tests/RHI/OpenGL/integration/sphere/main.cpp +++ b/tests/RHI/OpenGL/integration/sphere/main.cpp @@ -283,10 +283,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine int viewLoc = shader.GetUniformLocation("gViewMatrix"); int projLoc = shader.GetUniformLocation("gProjectionMatrix"); Log("[DEBUG] Uniform locations - gModelMatrix: %d, gViewMatrix: %d, gProjectionMatrix: %d", modelLoc, viewLoc, projLoc); - shader.SetMat4("gModelMatrix", modelMatrix); - shader.SetMat4("gViewMatrix", viewMatrix); - shader.SetMat4("gProjectionMatrix", projectionMatrix); - shader.SetInt("uTexture", 0); + commandList.SetShader(&shader); + commandList.SetUniformMat4("gModelMatrix", modelMatrix); + commandList.SetUniformMat4("gViewMatrix", viewMatrix); + commandList.SetUniformMat4("gProjectionMatrix", projectionMatrix); + commandList.SetUniformInt("uTexture", 0); OpenGLTexture texture; if (!texture.LoadFromFile("Res/Image/earth.png", true)) { diff --git a/tests/RHI/OpenGL/unit/test_shader.cpp b/tests/RHI/OpenGL/unit/test_shader.cpp index d76ffb10..908a98a4 100644 --- a/tests/RHI/OpenGL/unit/test_shader.cpp +++ b/tests/RHI/OpenGL/unit/test_shader.cpp @@ -1,5 +1,6 @@ #include "fixtures/OpenGLTestFixture.h" #include "XCEngine/RHI/OpenGL/OpenGLShader.h" +#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h" using namespace XCEngine::RHI; @@ -102,15 +103,17 @@ TEST_F(OpenGLTestFixture, Shader_SetUniforms) { shader.Compile(vs, fs); ASSERT_TRUE(shader.IsValid()); - shader.Use(); + auto cmdList = static_cast(GetDevice()->CreateCommandList(CommandListDesc{})); + ASSERT_NE(cmdList, nullptr); - shader.SetInt("uIntValue", 42); - shader.SetFloat("uFloatValue", 3.14f); - shader.SetVec3("uVec3Value", 1.0f, 2.0f, 3.0f); + cmdList->SetShader(&shader); + cmdList->SetUniformInt("uIntValue", 42); + cmdList->SetUniformFloat("uFloatValue", 3.14f); + cmdList->SetUniformVec3("uVec3Value", 1.0f, 2.0f, 3.0f); float mat[16] = {}; mat[0] = 1.0f; mat[5] = 1.0f; mat[10] = 1.0f; mat[15] = 1.0f; - shader.SetMat4("uMat4Value", mat); + cmdList->SetUniformMat4("uMat4Value", mat); GLenum error = glGetError(); EXPECT_EQ(error, GL_NO_ERROR);