diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index ac578ff9..c9480d51 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -156,6 +156,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/OpenGL/OpenGLResourceView.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/OpenGL/OpenGLDescriptorPool.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLBuffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLTexture.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLSampler.cpp @@ -177,6 +178,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLResourceView.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLDescriptorPool.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLDescriptorSet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLPipelineLayout.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../tests/opengl/package/src/glad.c # RHI Factory @@ -327,4 +329,4 @@ else() target_compile_options(XCEngine PRIVATE -Wall) endif() -target_compile_definitions(XCEngine PRIVATE XCENGINE_SUPPORT_OPENGL) \ No newline at end of file +target_compile_definitions(XCEngine PRIVATE XCENGINE_SUPPORT_OPENGL) diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h new file mode 100644 index 00000000..e9e24f9a --- /dev/null +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h @@ -0,0 +1,25 @@ +#pragma once + +#include "../RHIPipelineLayout.h" + +namespace XCEngine { +namespace RHI { + +class OpenGLPipelineLayout : public RHIPipelineLayout { +public: + OpenGLPipelineLayout() = default; + ~OpenGLPipelineLayout() override = default; + + bool Initialize(const RHIPipelineLayoutDesc& desc) override; + void Shutdown() override; + + void* GetNativeHandle() override { return m_initialized ? this : nullptr; } + const RHIPipelineLayoutDesc& GetDesc() const { return m_desc; } + +private: + RHIPipelineLayoutDesc m_desc = {}; + bool m_initialized = false; +}; + +} // namespace RHI +} // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/RHITypes.h b/engine/include/XCEngine/RHI/RHITypes.h index d5e6adc7..f0a73686 100644 --- a/engine/include/XCEngine/RHI/RHITypes.h +++ b/engine/include/XCEngine/RHI/RHITypes.h @@ -9,6 +9,8 @@ namespace XCEngine { namespace RHI { +class RHIPipelineLayout; + struct Viewport { float topLeftX; float topLeftY; @@ -310,6 +312,7 @@ struct GraphicsPipelineDesc { ShaderCompileDesc vertexShader; ShaderCompileDesc fragmentShader; ShaderCompileDesc geometryShader; + RHIPipelineLayout* pipelineLayout = nullptr; InputLayoutDesc inputLayout; RasterizerDesc rasterizerState; BlendDesc blendState; diff --git a/engine/src/RHI/D3D12/D3D12Device.cpp b/engine/src/RHI/D3D12/D3D12Device.cpp index d9c53740..ebdfbe84 100644 --- a/engine/src/RHI/D3D12/D3D12Device.cpp +++ b/engine/src/RHI/D3D12/D3D12Device.cpp @@ -523,14 +523,19 @@ RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& d return nullptr; } - auto* rootSignature = CreateRootSignature({}); - if (rootSignature == nullptr) { - delete pso; - return nullptr; + D3D12RootSignature* rootSignature = nullptr; + if (desc.pipelineLayout != nullptr) { + auto* pipelineLayout = static_cast(desc.pipelineLayout); + pso->SetRootSignature(pipelineLayout->GetRootSignature()); + } else { + rootSignature = CreateRootSignature({}); + if (rootSignature == nullptr) { + delete pso; + return nullptr; + } + pso->SetRootSignature(rootSignature->GetRootSignature()); } - pso->SetRootSignature(rootSignature->GetRootSignature()); - D3D12Shader vertexShader; D3D12Shader fragmentShader; D3D12Shader geometryShader; @@ -539,8 +544,10 @@ RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& d const bool geometryCompiled = !hasGeometryShader || CompileD3D12Shader(desc.geometryShader, geometryShader); if (!vertexCompiled || !fragmentCompiled || !geometryCompiled) { - rootSignature->Shutdown(); - delete rootSignature; + if (rootSignature != nullptr) { + rootSignature->Shutdown(); + delete rootSignature; + } delete pso; return nullptr; } @@ -551,8 +558,10 @@ RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& d hasGeometryShader ? geometryShader.GetD3D12Bytecode() : D3D12_SHADER_BYTECODE{}); pso->EnsureValid(); - rootSignature->Shutdown(); - delete rootSignature; + if (rootSignature != nullptr) { + rootSignature->Shutdown(); + delete rootSignature; + } if (!pso->IsValid()) { delete pso; diff --git a/engine/src/RHI/OpenGL/OpenGLDescriptorPool.cpp b/engine/src/RHI/OpenGL/OpenGLDescriptorPool.cpp index dad1ce62..19676663 100644 --- a/engine/src/RHI/OpenGL/OpenGLDescriptorPool.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDescriptorPool.cpp @@ -22,9 +22,6 @@ bool OpenGLDescriptorPool::Initialize(const DescriptorPoolDesc& desc) { } void OpenGLDescriptorPool::Shutdown() { - for (auto* set : m_allocatedSets) { - delete set; - } m_allocatedSets.clear(); m_textureUnitAllocator = nullptr; } @@ -59,4 +56,4 @@ void OpenGLDescriptorPool::FreeSet(RHIDescriptorSet* set) { } } // 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 f6a8a7ba..dcaa8361 100644 --- a/engine/src/RHI/OpenGL/OpenGLDevice.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDevice.cpp @@ -21,6 +21,7 @@ #include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" #include "XCEngine/RHI/OpenGL/OpenGLDescriptorPool.h" #include "XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h" +#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h" #include "XCEngine/Debug/Logger.h" typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc); @@ -476,7 +477,12 @@ RHIPipelineState* OpenGLDevice::CreatePipelineState(const GraphicsPipelineDesc& } RHIPipelineLayout* OpenGLDevice::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) { - return nullptr; + auto* layout = new OpenGLPipelineLayout(); + if (!layout->Initialize(desc)) { + delete layout; + return nullptr; + } + return layout; } RHIFence* OpenGLDevice::CreateFence(const FenceDesc& desc) { diff --git a/engine/src/RHI/OpenGL/OpenGLPipelineLayout.cpp b/engine/src/RHI/OpenGL/OpenGLPipelineLayout.cpp new file mode 100644 index 00000000..4d899b13 --- /dev/null +++ b/engine/src/RHI/OpenGL/OpenGLPipelineLayout.cpp @@ -0,0 +1,18 @@ +#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h" + +namespace XCEngine { +namespace RHI { + +bool OpenGLPipelineLayout::Initialize(const RHIPipelineLayoutDesc& desc) { + m_desc = desc; + m_initialized = true; + return true; +} + +void OpenGLPipelineLayout::Shutdown() { + m_desc = {}; + m_initialized = false; +} + +} // namespace RHI +} // namespace XCEngine diff --git a/tests/RHI/unit/test_pipeline_state.cpp b/tests/RHI/unit/test_pipeline_state.cpp index 7e90fb54..e842f177 100644 --- a/tests/RHI/unit/test_pipeline_state.cpp +++ b/tests/RHI/unit/test_pipeline_state.cpp @@ -1,4 +1,5 @@ #include "fixtures/RHITestFixture.h" +#include "XCEngine/RHI/RHIPipelineLayout.h" #include "XCEngine/RHI/RHIPipelineState.h" #include @@ -248,3 +249,92 @@ void main() { pso->Shutdown(); delete pso; } + +TEST_P(RHITestFixture, PipelineState_Create_WithPipelineLayout) { + RHIPipelineLayoutDesc layoutDesc = {}; + layoutDesc.textureCount = 1; + layoutDesc.samplerCount = 1; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(layoutDesc); + ASSERT_NE(layout, nullptr); + ASSERT_NE(layout->GetNativeHandle(), nullptr); + + GraphicsPipelineDesc desc = {}; + desc.pipelineLayout = layout; + desc.topologyType = static_cast(PrimitiveTopologyType::Triangle); + desc.renderTargetFormats[0] = static_cast(Format::R8G8B8A8_UNorm); + desc.depthStencilFormat = static_cast(Format::Unknown); + + InputElementDesc position = {}; + position.semanticName = "POSITION"; + position.semanticIndex = 0; + position.format = static_cast(Format::R32G32B32A32_Float); + position.inputSlot = 0; + position.alignedByteOffset = 0; + desc.inputLayout.elements.push_back(position); + + if (GetBackendType() == RHIType::D3D12) { + const char* hlslSource = R"( +struct VSInput { + float4 position : POSITION; +}; + +struct PSInput { + float4 position : SV_POSITION; +}; + +PSInput MainVS(VSInput input) { + PSInput output; + output.position = input.position; + return output; +} + +float4 MainPS(PSInput input) : SV_TARGET { + return float4(1.0f, 0.0f, 0.0f, 1.0f); +} +)"; + + desc.vertexShader.source.assign(hlslSource, hlslSource + std::strlen(hlslSource)); + desc.vertexShader.entryPoint = L"MainVS"; + desc.vertexShader.profile = L"vs_5_0"; + desc.vertexShader.sourceLanguage = ShaderLanguage::HLSL; + + desc.fragmentShader.source.assign(hlslSource, hlslSource + std::strlen(hlslSource)); + desc.fragmentShader.entryPoint = L"MainPS"; + desc.fragmentShader.profile = L"ps_5_0"; + desc.fragmentShader.sourceLanguage = ShaderLanguage::HLSL; + } else { + const char* vertexSource = R"(#version 430 +layout(location = 0) in vec4 aPosition; + +void main() { + gl_Position = aPosition; +} +)"; + const char* fragmentSource = R"(#version 430 +layout(location = 0) out vec4 fragColor; + +void main() { + fragColor = vec4(1.0, 0.0, 0.0, 1.0); +} +)"; + + desc.vertexShader.source.assign(vertexSource, vertexSource + std::strlen(vertexSource)); + desc.vertexShader.sourceLanguage = ShaderLanguage::GLSL; + desc.vertexShader.profile = L"vs_4_30"; + + desc.fragmentShader.source.assign(fragmentSource, fragmentSource + std::strlen(fragmentSource)); + desc.fragmentShader.sourceLanguage = ShaderLanguage::GLSL; + desc.fragmentShader.profile = L"fs_4_30"; + } + + RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc); + ASSERT_NE(pso, nullptr); + EXPECT_TRUE(pso->IsValid()); + EXPECT_NE(pso->GetNativeHandle(), nullptr); + + pso->Shutdown(); + delete pso; + layout->Shutdown(); + delete layout; +}