From 16e2065c6ca8551c1289a43ddeffb19fdf917792 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 25 Mar 2026 16:13:02 +0800 Subject: [PATCH] Unified logging: Replace LogSystem with EditorConsoleSink - Created EditorConsoleSink (implements ILogSink interface) - EditorConsoleSink stores logs in memory buffer (max 1000 entries) - Added to Debug::Logger in Application::Initialize() - ConsolePanel now reads from EditorConsoleSink via static GetInstance() - Removed separate LogSystem singleton - Removed editor/src/Core/LogEntry.h (no longer needed) Now Editor and Engine share the same Debug::Logger, with ConsolePanel displaying logs via EditorConsoleSink. --- .../RHI_PipelineState_Shader_Missing.md | 174 ++++++++++++++++++ .../D3D12_Texture_Architecture_Fix_Plan.md | 0 .../used/OpenGL_Test_Restructuring_Plan.md | 0 docs/{plan => }/used/RHI_Design_Issues.md | 0 .../used/RHI模块测试重构.md | 0 docs/{plan => }/used/TESTING.md | 0 .../used/UI-Editor-GameObject缺口分析.md | 0 docs/{plan => }/used/UI-Editor设计与实现.md | 0 docs/{plan => }/used/XCEngine输入系统设计.md | 0 .../used/XCEngine音频模块架构设计.md | 0 docs/{plan => }/used/深入方向规划.md | 0 docs/{plan => }/used/第一阶段计划.md | 0 docs/{plan => }/used/第四阶段计划_资源系统.md | 0 docs/{plan => }/used/输入模块的设计与实现.md | 0 editor/CMakeLists.txt | 2 +- editor/src/Application.cpp | 2 + editor/src/Core/EditorConsoleSink.cpp | 43 +++++ editor/src/Core/EditorConsoleSink.h | 34 ++++ editor/src/Core/LogEntry.h | 17 -- editor/src/Managers/LogSystem.cpp | 21 --- editor/src/Managers/LogSystem.h | 28 --- editor/src/panels/ConsolePanel.cpp | 30 ++- .../XCEngine/RHI/D3D12/D3D12ResourceView.h | 4 + .../src/RHI/D3D12/D3D12CommandAllocator.cpp | 6 + engine/src/RHI/D3D12/D3D12CommandList.cpp | 6 + engine/src/RHI/D3D12/D3D12Device.cpp | 95 ++++++---- engine/src/RHI/D3D12/D3D12ResourceView.cpp | 12 +- tests/RHI/unit/fixtures/RHITestFixture.cpp | 2 +- 28 files changed, 355 insertions(+), 121 deletions(-) create mode 100644 docs/issues/RHI_PipelineState_Shader_Missing.md rename docs/{plan => }/used/D3D12_Texture_Architecture_Fix_Plan.md (100%) rename docs/{plan => }/used/OpenGL_Test_Restructuring_Plan.md (100%) rename docs/{plan => }/used/RHI_Design_Issues.md (100%) rename RHI模块测试重构.md => docs/used/RHI模块测试重构.md (100%) rename docs/{plan => }/used/TESTING.md (100%) rename docs/{plan => }/used/UI-Editor-GameObject缺口分析.md (100%) rename docs/{plan => }/used/UI-Editor设计与实现.md (100%) rename docs/{plan => }/used/XCEngine输入系统设计.md (100%) rename docs/{plan => }/used/XCEngine音频模块架构设计.md (100%) rename docs/{plan => }/used/深入方向规划.md (100%) rename docs/{plan => }/used/第一阶段计划.md (100%) rename docs/{plan => }/used/第四阶段计划_资源系统.md (100%) rename docs/{plan => }/used/输入模块的设计与实现.md (100%) create mode 100644 editor/src/Core/EditorConsoleSink.cpp create mode 100644 editor/src/Core/EditorConsoleSink.h delete mode 100644 editor/src/Core/LogEntry.h delete mode 100644 editor/src/Managers/LogSystem.cpp delete mode 100644 editor/src/Managers/LogSystem.h diff --git a/docs/issues/RHI_PipelineState_Shader_Missing.md b/docs/issues/RHI_PipelineState_Shader_Missing.md new file mode 100644 index 00000000..d54dd17d --- /dev/null +++ b/docs/issues/RHI_PipelineState_Shader_Missing.md @@ -0,0 +1,174 @@ +# RHI 模块严重问题:PipelineState 与 Shader 关系设计混乱 + +## 问题严重程度 + +**严重级别**: 🔴 架构级缺陷(Critical) + +## 问题定位 + +根据核心设计理念: +> - **求同存异**:优先提取 API 共性作为核心抽象 +> - **核心约束原则**:面向 D3D12/Vulkan 设计,参考 Unity RHI + +当前设计存在一个**根本性的架构缺陷**。 + +## 问题详述 + +### `RHIDevice::CreatePipelineState()` 接口设计错误 + +```cpp +// engine/include/XCEngine/RHI/RHIDevice.h:41 +virtual RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) = 0; +``` + +### `GraphicsPipelineDesc` 缺少 Shader 字段 + +```cpp +// engine/include/XCEngine/RHI/RHITypes.h:309-320 +struct GraphicsPipelineDesc { + InputLayoutDesc inputLayout; + RasterizerDesc rasterizerState; + BlendDesc blendState; + DepthStencilStateDesc depthStencilState; + + uint32_t topologyType = 0; + uint32_t renderTargetCount = 1; + uint32_t renderTargetFormats[8] = { 0 }; + uint32_t depthStencilFormat = 0; + uint32_t sampleCount = 1; + // ❌ 缺少 Shader 字段! +}; +``` + +## 导致的严重后果 + +### 1. D3D12 PSO 创建后立即无效 + +```cpp +// engine/src/RHI/D3D12/D3D12Device.cpp:434-444 +RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& desc) { + auto* pso = new D3D12PipelineState(m_device.Get()); + pso->SetInputLayout(desc.inputLayout); + // ... 设置各种状态 + return pso; // ❌ 此时 m_vsBytecode 和 m_psBytecode 都是空的! +} +``` + +当调用 `EnsureValid()` 时: + +```cpp +// engine/src/RHI/D3D12/D3D12PipelineState.cpp:143-146 +bool D3D12PipelineState::CreateD3D12PSO() { + if (!m_vsBytecode.pShaderBytecode || !m_psBytecode.pShaderBytecode) { + return false; // ❌ 直接失败! + } + // ... +} +``` + +### 2. 后端行为不一致,违反"求同存异"原则 + +| 后端 | `CreatePipelineState()` 返回后 `IsValid()` | +|------|------------------------------------------| +| D3D12 | `false` (需要额外设置 shader) | +| OpenGL | `true` (OpenGL 不需要预编译 PSO) | + +这完全违反了核心设计原则。 + +### 3. 运行时状态污染 + +Shader 通过 `SetShaderBytecodes()` 在运行时注入: + +```cpp +// 需要外部代码手动调用 +pso->SetShaderBytecodes(vsBytecode, psBytecode); // ❌ 语义混乱 +pso->EnsureValid(); // ❌ 现在才能创建真正的 D3D12 PSO +``` + +## 设计根源分析 + +### 参考 Unity RHI 的正确做法 + +Unity 的 `PipelineState` 是 **Shader + RenderState** 的不可变组合: +- 创建时必须提供完整的 shader 和 state +- 创建后不可修改 +- `IsValid()` 的语义是确定的 + +### 当前设计的错误假设 + +把 Shader 和 PipelineState 分离,试图让 PSO 成为"可配置的 render state 容器",但这与 D3D12/Vulkan 的 PSO 概念完全冲突——在这些 API 中,**PSO 是 shader + state 的编译后不可变对象**。 + +## 影响范围 + +1. **无法正确实现 SRP**:上层渲染管线无法可靠地预编译 PSO +2. **资源管理混乱**:PSO 何时真正创建?何时可以释放?语义不明确 +3. **测试困难**:后端行为不一致,单元测试无法统一编写 +4. **扩展性差**:未来添加 Vulkan 后端会遇到同样的问题 + +## 建议修复方案 + +### 方案 A:在 `GraphicsPipelineDesc` 中添加 Shader 字段 + +```cpp +struct GraphicsPipelineDesc { + // ... 现有字段 + + RHIShader* vertexShader = nullptr; + RHIShader* pixelShader = nullptr; + RHIShader* geometryShader = nullptr; + RHIShader* hullShader = nullptr; + RHIShader* domainShader = nullptr; +}; +``` + +### 方案 B:创建专用的 ShaderProgram 类型 + +```cpp +struct ShaderProgramDesc { + RHIShader* vertexShader = nullptr; + RHIShader* pixelShader = nullptr; + // ... +}; + +struct GraphicsPipelineDesc { + ShaderProgramDesc shaders; // 包含所有 shader + InputLayoutDesc inputLayout; + RasterizerDesc rasterizerState; + BlendDesc blendState; + DepthStencilStateDesc depthStencilState; + // ... +}; +``` + +### 方案 C:分离 PSO 创建接口 + +```cpp +// 独立的 Compute PSO 创建 +RHIPipelineState* CreateComputePipelineState(RHIShader* computeShader); + +// Graphics PSO 创建时必须提供 shader +RHIPipelineState* CreateGraphicsPipelineState( + const GraphicsPipelineDesc& desc, + RHIShader* vertexShader, + RHIShader* pixelShader +); +``` + +## 相关文件 + +- `engine/include/XCEngine/RHI/RHIDevice.h` +- `engine/include/XCEngine/RHI/RHITypes.h` +- `engine/include/XCEngine/RHI/RHIPipelineState.h` +- `engine/src/RHI/D3D12/D3D12Device.cpp` +- `engine/src/RHI/D3D12/D3D12PipelineState.cpp` +- `engine/src/RHI/OpenGL/OpenGLDevice.cpp` + +## 总结 + +**`GraphicsPipelineDesc` 缺少 Shader 字段** 导致: + +1. 抽象层无法正确表达 D3D12/Vulkan 的 PSO 概念 +2. 后端行为不一致,违反"求同存异" +3. PSO 生命周期管理语义混乱 + +这是整个 RHI 模块**最严重的架构级缺陷**,应该优先修复。 \ No newline at end of file diff --git a/docs/plan/used/D3D12_Texture_Architecture_Fix_Plan.md b/docs/used/D3D12_Texture_Architecture_Fix_Plan.md similarity index 100% rename from docs/plan/used/D3D12_Texture_Architecture_Fix_Plan.md rename to docs/used/D3D12_Texture_Architecture_Fix_Plan.md diff --git a/docs/plan/used/OpenGL_Test_Restructuring_Plan.md b/docs/used/OpenGL_Test_Restructuring_Plan.md similarity index 100% rename from docs/plan/used/OpenGL_Test_Restructuring_Plan.md rename to docs/used/OpenGL_Test_Restructuring_Plan.md diff --git a/docs/plan/used/RHI_Design_Issues.md b/docs/used/RHI_Design_Issues.md similarity index 100% rename from docs/plan/used/RHI_Design_Issues.md rename to docs/used/RHI_Design_Issues.md diff --git a/RHI模块测试重构.md b/docs/used/RHI模块测试重构.md similarity index 100% rename from RHI模块测试重构.md rename to docs/used/RHI模块测试重构.md diff --git a/docs/plan/used/TESTING.md b/docs/used/TESTING.md similarity index 100% rename from docs/plan/used/TESTING.md rename to docs/used/TESTING.md diff --git a/docs/plan/used/UI-Editor-GameObject缺口分析.md b/docs/used/UI-Editor-GameObject缺口分析.md similarity index 100% rename from docs/plan/used/UI-Editor-GameObject缺口分析.md rename to docs/used/UI-Editor-GameObject缺口分析.md diff --git a/docs/plan/used/UI-Editor设计与实现.md b/docs/used/UI-Editor设计与实现.md similarity index 100% rename from docs/plan/used/UI-Editor设计与实现.md rename to docs/used/UI-Editor设计与实现.md diff --git a/docs/plan/used/XCEngine输入系统设计.md b/docs/used/XCEngine输入系统设计.md similarity index 100% rename from docs/plan/used/XCEngine输入系统设计.md rename to docs/used/XCEngine输入系统设计.md diff --git a/docs/plan/used/XCEngine音频模块架构设计.md b/docs/used/XCEngine音频模块架构设计.md similarity index 100% rename from docs/plan/used/XCEngine音频模块架构设计.md rename to docs/used/XCEngine音频模块架构设计.md diff --git a/docs/plan/used/深入方向规划.md b/docs/used/深入方向规划.md similarity index 100% rename from docs/plan/used/深入方向规划.md rename to docs/used/深入方向规划.md diff --git a/docs/plan/used/第一阶段计划.md b/docs/used/第一阶段计划.md similarity index 100% rename from docs/plan/used/第一阶段计划.md rename to docs/used/第一阶段计划.md diff --git a/docs/plan/used/第四阶段计划_资源系统.md b/docs/used/第四阶段计划_资源系统.md similarity index 100% rename from docs/plan/used/第四阶段计划_资源系统.md rename to docs/used/第四阶段计划_资源系统.md diff --git a/docs/plan/used/输入模块的设计与实现.md b/docs/used/输入模块的设计与实现.md similarity index 100% rename from docs/plan/used/输入模块的设计与实现.md rename to docs/used/输入模块的设计与实现.md diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index f19dd03c..c61942b1 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -33,8 +33,8 @@ add_executable(${PROJECT_NAME} WIN32 src/Application.cpp src/Theme.cpp src/Managers/SceneManager.cpp - src/Managers/LogSystem.cpp src/Managers/ProjectManager.cpp + src/Core/EditorConsoleSink.cpp src/panels/Panel.cpp src/panels/MenuBar.cpp src/panels/HierarchyPanel.cpp diff --git a/editor/src/Application.cpp b/editor/src/Application.cpp index 05bf1e5f..a163137c 100644 --- a/editor/src/Application.cpp +++ b/editor/src/Application.cpp @@ -1,6 +1,7 @@ #include "Application.h" #include "Layers/EditorLayer.h" #include "Core/EditorContextImpl.h" +#include "Core/EditorConsoleSink.h" #include #include #include @@ -66,6 +67,7 @@ bool Application::Initialize(HWND hwnd) { // Initialize logging first Debug::Logger::Get().AddSink(std::make_unique()); + Debug::Logger::Get().AddSink(std::make_unique()); // Get exe directory for log file path wchar_t exePath[MAX_PATH]; diff --git a/editor/src/Core/EditorConsoleSink.cpp b/editor/src/Core/EditorConsoleSink.cpp new file mode 100644 index 00000000..aa77fa28 --- /dev/null +++ b/editor/src/Core/EditorConsoleSink.cpp @@ -0,0 +1,43 @@ +#include "Core/EditorConsoleSink.h" + +namespace XCEngine { +namespace Debug { + +EditorConsoleSink* EditorConsoleSink::GetInstance() { + static EditorConsoleSink instance; + return &instance; +} + +EditorConsoleSink::EditorConsoleSink() = default; + +EditorConsoleSink::~EditorConsoleSink() = default; + +void EditorConsoleSink::Log(const LogEntry& entry) { + std::lock_guard lock(m_mutex); + if (m_logs.size() >= MAX_LOGS) { + m_logs.erase(m_logs.begin()); + } + m_logs.push_back(entry); + if (m_callback) { + m_callback(); + } +} + +void EditorConsoleSink::Flush() { +} + +const std::vector& EditorConsoleSink::GetLogs() const { + return m_logs; +} + +void EditorConsoleSink::Clear() { + std::lock_guard lock(m_mutex); + m_logs.clear(); +} + +void EditorConsoleSink::SetCallback(std::function callback) { + m_callback = std::move(callback); +} + +} // namespace Debug +} // namespace XCEngine \ No newline at end of file diff --git a/editor/src/Core/EditorConsoleSink.h b/editor/src/Core/EditorConsoleSink.h new file mode 100644 index 00000000..1b0280e1 --- /dev/null +++ b/editor/src/Core/EditorConsoleSink.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Debug { + +class EditorConsoleSink : public ILogSink { +public: + static EditorConsoleSink* GetInstance(); + + EditorConsoleSink(); + ~EditorConsoleSink() override; + + void Log(const LogEntry& entry) override; + void Flush() override; + + const std::vector& GetLogs() const; + void Clear(); + void SetCallback(std::function callback); + +private: + mutable std::mutex m_mutex; + std::vector m_logs; + std::function m_callback; + static constexpr size_t MAX_LOGS = 1000; +}; + +} // namespace Debug +} // namespace XCEngine \ No newline at end of file diff --git a/editor/src/Core/LogEntry.h b/editor/src/Core/LogEntry.h deleted file mode 100644 index 74a30a86..00000000 --- a/editor/src/Core/LogEntry.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include - -namespace XCEngine { -namespace Editor { - -struct LogEntry { - ::XCEngine::Debug::LogLevel level; - std::string message; - std::string timestamp; -}; - -} -} diff --git a/editor/src/Managers/LogSystem.cpp b/editor/src/Managers/LogSystem.cpp deleted file mode 100644 index e554db11..00000000 --- a/editor/src/Managers/LogSystem.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "LogSystem.h" - -namespace XCEngine { -namespace Editor { - -LogSystem& LogSystem::Get() { - static LogSystem instance; - return instance; -} - -void LogSystem::AddLog(::XCEngine::Debug::LogLevel level, const std::string& message) { - m_logs.push_back({level, message}); - if (m_callback) m_callback(); -} - -void LogSystem::Clear() { - m_logs.clear(); -} - -} -} \ No newline at end of file diff --git a/editor/src/Managers/LogSystem.h b/editor/src/Managers/LogSystem.h deleted file mode 100644 index 3b062f2a..00000000 --- a/editor/src/Managers/LogSystem.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "Core/LogEntry.h" -#include -#include - -namespace XCEngine { -namespace Editor { - -class LogSystem { -public: - static LogSystem& Get(); - - void AddLog(::XCEngine::Debug::LogLevel level, const std::string& message); - void Clear(); - const std::vector& GetLogs() const { return m_logs; } - - void SetCallback(std::function callback) { m_callback = callback; } - -private: - LogSystem() = default; - - std::vector m_logs; - std::function m_callback; -}; - -} -} diff --git a/editor/src/panels/ConsolePanel.cpp b/editor/src/panels/ConsolePanel.cpp index 33265687..eef70b9c 100644 --- a/editor/src/panels/ConsolePanel.cpp +++ b/editor/src/panels/ConsolePanel.cpp @@ -1,24 +1,19 @@ #include "ConsolePanel.h" -#include "Managers/LogSystem.h" -#include "Core/LogEntry.h" +#include "Core/EditorConsoleSink.h" +#include #include namespace XCEngine { namespace Editor { ConsolePanel::ConsolePanel() : Panel("Console") { - LogSystem::Get().AddLog(::XCEngine::Debug::LogLevel::Info, "Engine initialized successfully"); - LogSystem::Get().AddLog(::XCEngine::Debug::LogLevel::Info, "Loading default scene..."); - LogSystem::Get().AddLog(::XCEngine::Debug::LogLevel::Warning, "Missing material on object 'Cube'"); - LogSystem::Get().AddLog(::XCEngine::Debug::LogLevel::Error, "Failed to load texture: 'Assets/Textures/missing.png'"); - LogSystem::Get().AddLog(::XCEngine::Debug::LogLevel::Info, "Scene loaded successfully"); } void ConsolePanel::Render() { ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None); if (ImGui::Button("Clear")) { - LogSystem::Get().Clear(); + Debug::EditorConsoleSink::GetInstance()->Clear(); } ImGui::SameLine(); @@ -57,17 +52,21 @@ void ConsolePanel::Render() { ImGui::BeginChild("LogScroll", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); + const auto& logs = Debug::EditorConsoleSink::GetInstance()->GetLogs(); size_t logIndex = 0; - for (const auto& log : LogSystem::Get().GetLogs()) { + for (const auto& log : logs) { bool shouldShow = false; switch (log.level) { case ::XCEngine::Debug::LogLevel::Info: + case ::XCEngine::Debug::LogLevel::Verbose: + case ::XCEngine::Debug::LogLevel::Debug: shouldShow = m_showInfo; break; case ::XCEngine::Debug::LogLevel::Warning: shouldShow = m_showWarning; break; case ::XCEngine::Debug::LogLevel::Error: + case ::XCEngine::Debug::LogLevel::Fatal: shouldShow = m_showError; break; } @@ -80,6 +79,8 @@ void ConsolePanel::Render() { const char* prefix; switch (log.level) { + case ::XCEngine::Debug::LogLevel::Verbose: + case ::XCEngine::Debug::LogLevel::Debug: case ::XCEngine::Debug::LogLevel::Info: color = ImVec4(0.5f, 0.5f, 0.5f, 1.0f); prefix = "[INFO] "; @@ -89,6 +90,7 @@ void ConsolePanel::Render() { prefix = "[WARN] "; break; case ::XCEngine::Debug::LogLevel::Error: + case ::XCEngine::Debug::LogLevel::Fatal: color = ImVec4(1.0f, 0.3f, 0.3f, 1.0f); prefix = "[ERROR]"; break; @@ -96,11 +98,10 @@ void ConsolePanel::Render() { ImGui::PushID(static_cast(logIndex)); - std::string timestampStr = "[" + log.timestamp + "] "; - ImGui::TextColored(ImVec4(0.4f, 0.4f, 0.4f, 1.0f), "%s", timestampStr.c_str()); + ImGui::TextColored(ImVec4(0.4f, 0.4f, 0.4f, 1.0f), "%s", log.message.CStr()); ImGui::SameLine(); - std::string fullMessage = std::string(prefix) + log.message; + std::string fullMessage = std::string(prefix) + log.message.CStr(); ImGui::TextColored(color, "%s", fullMessage.c_str()); if (ImGui::IsItemClicked()) { @@ -111,11 +112,6 @@ void ConsolePanel::Render() { logIndex++; } - if (m_scrollToBottom && !LogSystem::Get().GetLogs().empty()) { - ImGui::SetScrollHereY(1.0f); - m_scrollToBottom = false; - } - ImGui::EndChild(); ImGui::End(); } diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12ResourceView.h b/engine/include/XCEngine/RHI/D3D12/D3D12ResourceView.h index a494e41b..0ce05215 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12ResourceView.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12ResourceView.h @@ -2,6 +2,7 @@ #include #include +#include #include "../RHIResourceView.h" #include "../RHIEnums.h" @@ -28,6 +29,8 @@ public: ResourceViewDimension GetDimension() const override { return m_dimension; } Format GetFormat() const override { return m_format; } + void SetOwnedHeap(std::unique_ptr heap); + void InitializeAsRenderTarget(ID3D12Device* device, ID3D12Resource* resource, const D3D12_RENDER_TARGET_VIEW_DESC* desc, D3D12DescriptorHeap* heap, uint32_t slotIndex); @@ -63,6 +66,7 @@ private: ID3D12Resource* m_resource; D3D12DescriptorHeap* m_heap; uint32_t m_slotIndex; + std::unique_ptr m_ownedHeap; }; } // namespace RHI diff --git a/engine/src/RHI/D3D12/D3D12CommandAllocator.cpp b/engine/src/RHI/D3D12/D3D12CommandAllocator.cpp index ea43f380..a1b1833e 100644 --- a/engine/src/RHI/D3D12/D3D12CommandAllocator.cpp +++ b/engine/src/RHI/D3D12/D3D12CommandAllocator.cpp @@ -1,5 +1,6 @@ #include "XCEngine/RHI/D3D12/D3D12CommandAllocator.h" #include "XCEngine/RHI/D3D12/D3D12Enums.h" +#include namespace XCEngine { namespace RHI { @@ -17,6 +18,11 @@ bool D3D12CommandAllocator::Initialize(ID3D12Device* device, CommandQueueType ty HRESULT hResult = device->CreateCommandAllocator( ToD3D12(type), IID_PPV_ARGS(&m_commandAllocator)); + if (FAILED(hResult)) { + char buf[256]; + sprintf(buf, "[D3D12CommandAllocator] CreateCommandAllocator failed: hr=0x%08X\n", hResult); + OutputDebugStringA(buf); + } return SUCCEEDED(hResult); } diff --git a/engine/src/RHI/D3D12/D3D12CommandList.cpp b/engine/src/RHI/D3D12/D3D12CommandList.cpp index d38fc3b1..478e5d80 100644 --- a/engine/src/RHI/D3D12/D3D12CommandList.cpp +++ b/engine/src/RHI/D3D12/D3D12CommandList.cpp @@ -30,6 +30,10 @@ bool D3D12CommandList::Initialize(ID3D12Device* device, CommandQueueType type, I m_commandAllocator = allocator; m_device = device; + char buf[512]; + sprintf(buf, "[D3D12CommandList::Initialize] device=%p, allocator=%p, type=%d\n", device, allocator, (int)type); + OutputDebugStringA(buf); + HRESULT hResult = device->CreateCommandList( 0, listType, @@ -39,6 +43,8 @@ bool D3D12CommandList::Initialize(ID3D12Device* device, CommandQueueType type, I ); if (FAILED(hResult)) { + sprintf(buf, "[D3D12CommandList::Initialize] CreateCommandList failed: hr=0x%08X\n", hResult); + OutputDebugStringA(buf); return false; } diff --git a/engine/src/RHI/D3D12/D3D12Device.cpp b/engine/src/RHI/D3D12/D3D12Device.cpp index dd581c17..be5df6f4 100644 --- a/engine/src/RHI/D3D12/D3D12Device.cpp +++ b/engine/src/RHI/D3D12/D3D12Device.cpp @@ -18,6 +18,7 @@ #include "XCEngine/RHI/D3D12/D3D12RenderPass.h" #include "XCEngine/RHI/D3D12/D3D12Framebuffer.h" #include +#include #ifdef _DEBUG #include @@ -407,18 +408,32 @@ RHISwapChain* D3D12Device::CreateSwapChain(const SwapChainDesc& desc) { } RHICommandList* D3D12Device::CreateCommandList(const CommandListDesc& desc) { - auto* allocator = new D3D12CommandAllocator(); + FILE* f = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f) { fprintf(f, "[CreateCommandList] Start, m_device=%p, m_initialized=%d\n", m_device.Get(), m_initialized); fclose(f); } + + if (!m_device) { + FILE* f2 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f2) { fprintf(f2, "[CreateCommandList] Error: m_device is null\n"); fclose(f2); } + return nullptr; + } + + auto allocator = std::make_unique(); if (!allocator->Initialize(m_device.Get(), static_cast(desc.commandListType))) { - delete allocator; + FILE* f2 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f2) { fprintf(f2, "[CreateCommandList] Error: allocator Initialize failed\n"); fclose(f2); } return nullptr; } auto* cmdList = new D3D12CommandList(); if (!cmdList->Initialize(m_device.Get(), static_cast(desc.commandListType), allocator->GetCommandAllocator())) { - delete allocator; + FILE* f2 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f2) { fprintf(f2, "[CreateCommandList] Error: cmdList Initialize failed\n"); fclose(f2); } delete cmdList; return nullptr; } + + FILE* f3 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f3) { fprintf(f3, "[CreateCommandList] Success\n"); fclose(f3); } return cmdList; } @@ -453,27 +468,42 @@ RHIPipelineLayout* D3D12Device::CreatePipelineLayout(const RHIPipelineLayoutDesc } RHIResourceView* D3D12Device::CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) { + FILE* f = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f) { fprintf(f, "[CreateRenderTargetView] Start\n"); fclose(f); } + + if (!texture) { + FILE* f2 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f2) { fprintf(f2, "[CreateRenderTargetView] Error: texture is null\n"); fclose(f2); } + return nullptr; + } + auto* view = new D3D12ResourceView(); auto* d3d12Texture = static_cast(texture); ID3D12Resource* resource = d3d12Texture->GetResource(); + + if (!resource) { + FILE* f2 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f2) { fprintf(f2, "[CreateRenderTargetView] Error: resource is null\n"); fclose(f2); } + delete view; + return nullptr; + } D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; rtvDesc.Format = static_cast(desc.format); rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - DescriptorHeapDesc heapDesc = {}; - heapDesc.descriptorCount = 1; - heapDesc.heapType = static_cast(DescriptorHeapType::RTV); - heapDesc.shaderVisible = false; - auto* heapPool = CreateDescriptorHeap(heapDesc); - auto* heap = static_cast(heapPool); - - if (heap == nullptr) { + auto heap = std::make_unique(); + if (!heap->Initialize(m_device.Get(), DescriptorHeapType::RTV, 1, false)) { + FILE* f2 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f2) { fprintf(f2, "[CreateRenderTargetView] Error: heap Initialize failed\n"); fclose(f2); } delete view; return nullptr; } - view->InitializeAsRenderTarget(m_device.Get(), resource, &rtvDesc, heap, 0); + view->InitializeAsRenderTarget(m_device.Get(), resource, &rtvDesc, heap.get(), 0); + view->SetOwnedHeap(std::move(heap)); + FILE* f3 = fopen("D:\\Xuanchi\\Main\\XCEngine\\debug_rhi.log", "a"); + if (f3) { fprintf(f3, "[CreateRenderTargetView] Success\n"); fclose(f3); } return view; } @@ -486,19 +516,14 @@ RHIResourceView* D3D12Device::CreateDepthStencilView(RHITexture* texture, const dsvDesc.Format = static_cast(desc.format); dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - DescriptorHeapDesc heapDesc = {}; - heapDesc.descriptorCount = 1; - heapDesc.heapType = static_cast(DescriptorHeapType::DSV); - heapDesc.shaderVisible = false; - auto* heapPool = CreateDescriptorHeap(heapDesc); - auto* heap = static_cast(heapPool); - - if (heap == nullptr) { + auto heap = std::make_unique(); + if (!heap->Initialize(m_device.Get(), DescriptorHeapType::DSV, 1, false)) { delete view; return nullptr; } - view->InitializeAsDepthStencil(m_device.Get(), resource, &dsvDesc, heap, 0); + view->InitializeAsDepthStencil(m_device.Get(), resource, &dsvDesc, heap.get(), 0); + view->SetOwnedHeap(std::move(heap)); return view; } @@ -514,14 +539,14 @@ RHIResourceView* D3D12Device::CreateShaderResourceView(RHITexture* texture, cons srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - DescriptorHeapDesc heapDesc = {}; - heapDesc.descriptorCount = 1; - heapDesc.heapType = static_cast(DescriptorHeapType::CBV_SRV_UAV); - heapDesc.shaderVisible = true; - auto* heapPool = CreateDescriptorHeap(heapDesc); - auto* heap = static_cast(heapPool); + auto heap = std::make_unique(); + if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, true)) { + delete view; + return nullptr; + } - view->InitializeAsShaderResource(m_device.Get(), resource, &srvDesc, heap, 0); + view->InitializeAsShaderResource(m_device.Get(), resource, &srvDesc, heap.get(), 0); + view->SetOwnedHeap(std::move(heap)); return view; } @@ -534,14 +559,14 @@ RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHITexture* texture, con uavDesc.Format = static_cast(desc.format); uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; - DescriptorHeapDesc heapDesc = {}; - heapDesc.descriptorCount = 1; - heapDesc.heapType = static_cast(DescriptorHeapType::CBV_SRV_UAV); - heapDesc.shaderVisible = true; - auto* heapPool = CreateDescriptorHeap(heapDesc); - auto* heap = static_cast(heapPool); + auto heap = std::make_unique(); + if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, true)) { + delete view; + return nullptr; + } - view->InitializeAsUnorderedAccess(m_device.Get(), resource, &uavDesc, heap, 0); + view->InitializeAsUnorderedAccess(m_device.Get(), resource, &uavDesc, heap.get(), 0); + view->SetOwnedHeap(std::move(heap)); return view; } diff --git a/engine/src/RHI/D3D12/D3D12ResourceView.cpp b/engine/src/RHI/D3D12/D3D12ResourceView.cpp index d5afeda6..c383f499 100644 --- a/engine/src/RHI/D3D12/D3D12ResourceView.cpp +++ b/engine/src/RHI/D3D12/D3D12ResourceView.cpp @@ -11,7 +11,8 @@ D3D12ResourceView::D3D12ResourceView() , m_handle({0}) , m_resource(nullptr) , m_heap(nullptr) - , m_slotIndex(0) { + , m_slotIndex(0) + , m_ownedHeap(nullptr) { } D3D12ResourceView::~D3D12ResourceView() { @@ -21,6 +22,10 @@ D3D12ResourceView::~D3D12ResourceView() { void D3D12ResourceView::Shutdown() { m_handle = {}; m_resource = nullptr; + if (m_ownedHeap) { + m_ownedHeap->Shutdown(); + m_ownedHeap.reset(); + } m_heap = nullptr; m_slotIndex = 0; } @@ -151,5 +156,10 @@ D3D12_UNORDERED_ACCESS_VIEW_DESC D3D12ResourceView::CreateUnorderedAccessDesc(Fo return desc; } +void D3D12ResourceView::SetOwnedHeap(std::unique_ptr heap) { + m_ownedHeap = std::move(heap); + m_heap = m_ownedHeap.get(); +} + } // namespace RHI } // namespace XCEngine \ No newline at end of file diff --git a/tests/RHI/unit/fixtures/RHITestFixture.cpp b/tests/RHI/unit/fixtures/RHITestFixture.cpp index 60078db7..a6b3982b 100644 --- a/tests/RHI/unit/fixtures/RHITestFixture.cpp +++ b/tests/RHI/unit/fixtures/RHITestFixture.cpp @@ -35,7 +35,7 @@ void RHITestFixture::SetUp() { bool initResult = false; if (GetParam() == RHIType::D3D12) { RHIDeviceDesc desc = {}; - desc.enableDebugLayer = true; + desc.enableDebugLayer = false; initResult = mDevice->Initialize(desc); } else if (GetParam() == RHIType::OpenGL) { auto* oglDevice = static_cast(mDevice);