refactor: back editor host rendering with engine rhi

This commit is contained in:
2026-03-28 16:50:04 +08:00
parent 519bc1dbf2
commit 6fcb6ac8fb
4 changed files with 247 additions and 165 deletions

View File

@@ -38,7 +38,7 @@ bool Application::InitializeWindowRenderer(HWND hwnd) {
return true;
}
MessageBoxW(hwnd, L"Failed to create D3D12 device", L"Error", MB_OK | MB_ICONERROR);
MessageBoxW(hwnd, L"Failed to initialize editor window renderer", L"Error", MB_OK | MB_ICONERROR);
return false;
}

View File

@@ -4,6 +4,7 @@
#include "UI/ImGuiBackendBridge.h"
#include "UI/ImGuiSession.h"
#include <XCEngine/Rendering/RenderContext.h>
#include <memory>
#include <string>
#include <windows.h>
@@ -11,6 +12,11 @@
#include <XCEngine/Core/LayerStack.h>
namespace XCEngine {
namespace RHI {
class RHIDevice;
class RHISwapChain;
} // namespace RHI
namespace Editor {
class EditorLayer;
@@ -26,6 +32,9 @@ public:
void OnResize(int width, int height);
bool SwitchProject(const std::string& projectPath);
void SaveProjectState();
Rendering::RenderContext GetMainRenderContext() const { return m_windowRenderer.GetRenderContext(); }
RHI::RHIDevice* GetMainRHIDevice() const { return m_windowRenderer.GetRHIDevice(); }
RHI::RHISwapChain* GetMainSwapChain() const { return m_windowRenderer.GetSwapChain(); }
bool IsRenderReady() const { return m_renderReady; }
HWND GetWindowHandle() const { return m_hwnd; }

View File

@@ -2,9 +2,21 @@
#include "UI/ImGuiBackendBridge.h"
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/RHI/RHICommandList.h>
#include <XCEngine/RHI/RHICommandQueue.h>
#include <XCEngine/RHI/RHIDevice.h>
#include <XCEngine/RHI/RHIFactory.h>
#include <XCEngine/RHI/RHIResourceView.h>
#include <XCEngine/RHI/RHISwapChain.h>
#include <XCEngine/RHI/D3D12/D3D12CommandList.h>
#include <XCEngine/RHI/D3D12/D3D12CommandQueue.h>
#include <XCEngine/RHI/D3D12/D3D12DescriptorHeap.h>
#include <XCEngine/RHI/D3D12/D3D12Device.h>
#include <XCEngine/RHI/D3D12/D3D12SwapChain.h>
#include <d3d12.h>
#include <dxgi1_6.h>
#include <array>
#include <vector>
#include <windows.h>
namespace XCEngine {
@@ -14,106 +26,187 @@ namespace Platform {
class D3D12WindowRenderer {
public:
static constexpr UINT kSrvDescriptorCount = 64;
static constexpr uint32_t kSwapChainBufferCount = 3;
bool Initialize(HWND hwnd, int width, int height) {
Shutdown();
if (hwnd == nullptr || width <= 0 || height <= 0) {
return false;
}
m_hwnd = hwnd;
m_width = width;
m_height = height;
return CreateDevice() && CreateRenderTarget();
m_device = RHI::RHIFactory::CreateRHIDevice(RHI::RHIType::D3D12);
if (m_device == nullptr) {
Shutdown();
return false;
}
RHI::RHIDeviceDesc deviceDesc = {};
if (!m_device->Initialize(deviceDesc)) {
Shutdown();
return false;
}
RHI::CommandQueueDesc queueDesc = {};
queueDesc.queueType = static_cast<uint32_t>(RHI::CommandQueueType::Direct);
m_commandQueue = m_device->CreateCommandQueue(queueDesc);
if (m_commandQueue == nullptr || GetD3D12CommandQueue() == nullptr) {
Shutdown();
return false;
}
RHI::CommandListDesc commandListDesc = {};
commandListDesc.commandListType = static_cast<uint32_t>(RHI::CommandQueueType::Direct);
m_commandList = m_device->CreateCommandList(commandListDesc);
if (m_commandList == nullptr || GetD3D12CommandList() == nullptr) {
Shutdown();
return false;
}
m_commandList->Close();
RHI::SwapChainDesc swapChainDesc = {};
swapChainDesc.windowHandle = hwnd;
swapChainDesc.width = static_cast<uint32_t>(width);
swapChainDesc.height = static_cast<uint32_t>(height);
swapChainDesc.bufferCount = kSwapChainBufferCount;
m_swapChain = m_device->CreateSwapChain(swapChainDesc, m_commandQueue);
if (m_swapChain == nullptr || GetD3D12SwapChain() == nullptr) {
Shutdown();
return false;
}
RHI::DescriptorPoolDesc srvPoolDesc = {};
srvPoolDesc.type = RHI::DescriptorHeapType::CBV_SRV_UAV;
srvPoolDesc.descriptorCount = kSrvDescriptorCount;
srvPoolDesc.shaderVisible = true;
m_srvPool = m_device->CreateDescriptorPool(srvPoolDesc);
m_srvHeap = dynamic_cast<RHI::D3D12DescriptorHeap*>(m_srvPool);
if (m_srvPool == nullptr || m_srvHeap == nullptr) {
Shutdown();
return false;
}
m_srvDescriptorSize = m_srvHeap->GetDescriptorSize();
if (!RecreateBackBufferViews()) {
Shutdown();
return false;
}
return true;
}
void Shutdown() {
CleanupRenderTarget();
WaitForGpuIdle();
ReleaseBackBufferViews();
if (m_fence) m_fence->Release();
if (m_commandList) m_commandList->Release();
if (m_commandAllocator) m_commandAllocator->Release();
if (m_commandQueue) m_commandQueue->Release();
if (m_rtvHeap) m_rtvHeap->Release();
if (m_srvHeap) m_srvHeap->Release();
if (m_swapChain) m_swapChain->Release();
if (m_device) m_device->Release();
if (m_srvPool) {
m_srvPool->Shutdown();
delete m_srvPool;
m_srvPool = nullptr;
}
m_srvHeap = nullptr;
if (m_swapChain) {
m_swapChain->Shutdown();
delete m_swapChain;
m_swapChain = nullptr;
}
if (m_commandList) {
m_commandList->Shutdown();
delete m_commandList;
m_commandList = nullptr;
}
if (m_commandQueue) {
m_commandQueue->Shutdown();
delete m_commandQueue;
m_commandQueue = nullptr;
}
if (m_device) {
m_device->Shutdown();
delete m_device;
m_device = nullptr;
}
m_hwnd = nullptr;
m_width = 1280;
m_height = 720;
m_fenceValue = 0;
m_rtvDescriptorSize = 0;
m_width = 0;
m_height = 0;
m_srvDescriptorSize = 0;
m_frameIndex = 0;
m_srvDescriptorUsage.fill(false);
}
void Resize(int width, int height) {
if (width <= 0 || height <= 0) {
if (width <= 0 || height <= 0 || m_swapChain == nullptr) {
return;
}
WaitForGpuIdle();
ReleaseBackBufferViews();
m_swapChain->Resize(static_cast<uint32_t>(width), static_cast<uint32_t>(height));
m_width = width;
m_height = height;
CleanupRenderTarget();
if (m_swapChain) {
DXGI_SWAP_CHAIN_DESC desc;
m_swapChain->GetDesc(&desc);
m_swapChain->ResizeBuffers(3, width, height, desc.BufferDesc.Format, desc.Flags);
}
CreateRenderTarget();
RecreateBackBufferViews();
}
void Render(UI::ImGuiBackendBridge& imguiBackend, const float clearColor[4]) {
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
m_commandAllocator->Reset();
m_commandList->Reset(m_commandAllocator, nullptr);
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = m_renderTargets[m_frameIndex];
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
m_commandList->ResourceBarrier(1, &barrier);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_rtvHeap->GetCPUDescriptorHandleForHeapStart();
rtvHandle.ptr += m_frameIndex * m_rtvDescriptorSize;
m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
ID3D12DescriptorHeap* heaps[] = { m_srvHeap };
m_commandList->SetDescriptorHeaps(1, heaps);
imguiBackend.RenderDrawData(m_commandList);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
m_commandList->ResourceBarrier(1, &barrier);
m_commandList->Close();
ID3D12CommandList* commandLists[] = { m_commandList };
m_commandQueue->ExecuteCommandLists(1, commandLists);
m_swapChain->Present(1, 0);
++m_fenceValue;
m_commandQueue->Signal(m_fence, m_fenceValue);
if (m_fence->GetCompletedValue() < m_fenceValue) {
m_fence->SetEventOnCompletion(m_fenceValue, nullptr);
auto* d3d12Queue = GetD3D12CommandQueue();
auto* d3d12CommandList = GetD3D12CommandList();
if (m_swapChain == nullptr ||
d3d12Queue == nullptr ||
d3d12CommandList == nullptr ||
m_srvHeap == nullptr) {
return;
}
d3d12Queue->WaitForPreviousFrame();
m_commandList->Reset();
const uint32_t backBufferIndex = m_swapChain->GetCurrentBackBufferIndex();
if (backBufferIndex >= m_backBufferViews.size() || m_backBufferViews[backBufferIndex] == nullptr) {
return;
}
RHI::RHIResourceView* renderTargetView = m_backBufferViews[backBufferIndex];
d3d12CommandList->TransitionBarrier(
renderTargetView,
RHI::ResourceStates::Present,
RHI::ResourceStates::RenderTarget);
d3d12CommandList->SetRenderTargets(1, &renderTargetView, nullptr);
d3d12CommandList->ClearRenderTarget(renderTargetView, clearColor);
ID3D12DescriptorHeap* descriptorHeaps[] = { m_srvHeap->GetDescriptorHeap() };
d3d12CommandList->SetDescriptorHeaps(1, descriptorHeaps);
imguiBackend.RenderDrawData(d3d12CommandList->GetCommandList());
d3d12CommandList->TransitionBarrier(
renderTargetView,
RHI::ResourceStates::RenderTarget,
RHI::ResourceStates::Present);
m_commandList->Close();
void* commandLists[] = { m_commandList };
m_commandQueue->ExecuteCommandLists(1, commandLists);
m_swapChain->Present(1, 0);
}
ID3D12Device* GetDevice() const {
return m_device;
const auto* device = GetD3D12Device();
return device ? device->GetDevice() : nullptr;
}
ID3D12DescriptorHeap* GetSrvHeap() const {
return m_srvHeap;
return m_srvHeap ? m_srvHeap->GetDescriptorHeap() : nullptr;
}
ID3D12CommandQueue* GetCommandQueue() const {
return m_commandQueue;
const auto* queue = GetD3D12CommandQueue();
return queue ? queue->GetCommandQueue() : nullptr;
}
UINT GetSrvDescriptorSize() const {
@@ -124,114 +217,93 @@ public:
return kSrvDescriptorCount;
}
RHI::RHIDevice* GetRHIDevice() const {
return m_device;
}
RHI::RHISwapChain* GetSwapChain() const {
return m_swapChain;
}
Rendering::RenderContext GetRenderContext() const {
Rendering::RenderContext context = {};
context.device = m_device;
context.commandList = m_commandList;
context.commandQueue = m_commandQueue;
context.backendType = RHI::RHIType::D3D12;
return context;
}
private:
bool CreateDevice() {
HRESULT hr = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
if (FAILED(hr)) {
RHI::D3D12Device* GetD3D12Device() const {
return m_device ? static_cast<RHI::D3D12Device*>(m_device) : nullptr;
}
RHI::D3D12CommandQueue* GetD3D12CommandQueue() const {
return m_commandQueue ? static_cast<RHI::D3D12CommandQueue*>(m_commandQueue) : nullptr;
}
RHI::D3D12CommandList* GetD3D12CommandList() const {
return m_commandList ? static_cast<RHI::D3D12CommandList*>(m_commandList) : nullptr;
}
RHI::D3D12SwapChain* GetD3D12SwapChain() const {
return m_swapChain ? static_cast<RHI::D3D12SwapChain*>(m_swapChain) : nullptr;
}
void WaitForGpuIdle() {
if (m_commandQueue != nullptr) {
m_commandQueue->WaitForIdle();
}
}
void ReleaseBackBufferViews() {
for (RHI::RHIResourceView* view : m_backBufferViews) {
if (view != nullptr) {
view->Shutdown();
delete view;
}
}
m_backBufferViews.clear();
}
bool RecreateBackBufferViews() {
auto* d3d12SwapChain = GetD3D12SwapChain();
if (m_device == nullptr || d3d12SwapChain == nullptr) {
return false;
}
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Priority = 0;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 0;
hr = m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue));
if (FAILED(hr)) return false;
m_backBufferViews.resize(kSwapChainBufferCount, nullptr);
hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator));
if (FAILED(hr)) return false;
RHI::ResourceViewDesc viewDesc = {};
viewDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
viewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, nullptr, IID_PPV_ARGS(&m_commandList));
if (FAILED(hr)) return false;
m_commandList->Close();
hr = m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));
if (FAILED(hr)) return false;
IDXGIFactory4* factory = nullptr;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
if (FAILED(hr)) return false;
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = 3;
swapChainDesc.Width = m_width;
swapChainDesc.Height = m_height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1;
IDXGISwapChain1* swapChain1 = nullptr;
hr = factory->CreateSwapChainForHwnd(m_commandQueue, m_hwnd, &swapChainDesc, nullptr, nullptr, &swapChain1);
factory->Release();
if (FAILED(hr)) return false;
hr = swapChain1->QueryInterface(IID_PPV_ARGS(&m_swapChain));
swapChain1->Release();
if (FAILED(hr)) return false;
D3D12_DESCRIPTOR_HEAP_DESC rtvDesc = {};
rtvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvDesc.NumDescriptors = 3;
rtvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = m_device->CreateDescriptorHeap(&rtvDesc, IID_PPV_ARGS(&m_rtvHeap));
if (FAILED(hr)) return false;
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_DESCRIPTOR_HEAP_DESC srvDesc = {};
srvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvDesc.NumDescriptors = kSrvDescriptorCount;
srvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
hr = m_device->CreateDescriptorHeap(&srvDesc, IID_PPV_ARGS(&m_srvHeap));
if (FAILED(hr)) return false;
m_srvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
m_srvDescriptorUsage.fill(false);
return true;
}
bool CreateRenderTarget() {
if (!m_swapChain || !m_device || !m_rtvHeap) return false;
for (UINT i = 0; i < 3; ++i) {
HRESULT hr = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_renderTargets[i]));
if (FAILED(hr)) return false;
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_rtvHeap->GetCPUDescriptorHandleForHeapStart();
rtvHandle.ptr += i * m_rtvDescriptorSize;
m_device->CreateRenderTargetView(m_renderTargets[i], nullptr, rtvHandle);
}
return true;
}
void CleanupRenderTarget() {
for (UINT i = 0; i < 3; ++i) {
if (m_renderTargets[i]) {
m_renderTargets[i]->Release();
m_renderTargets[i] = nullptr;
for (uint32_t backBufferIndex = 0; backBufferIndex < kSwapChainBufferCount; ++backBufferIndex) {
m_backBufferViews[backBufferIndex] = m_device->CreateRenderTargetView(
&d3d12SwapChain->GetBackBuffer(backBufferIndex),
viewDesc);
if (m_backBufferViews[backBufferIndex] == nullptr) {
ReleaseBackBufferViews();
return false;
}
}
return true;
}
HWND m_hwnd = nullptr;
int m_width = 1280;
int m_height = 720;
int m_width = 0;
int m_height = 0;
ID3D12Device* m_device = nullptr;
ID3D12CommandQueue* m_commandQueue = nullptr;
ID3D12CommandAllocator* m_commandAllocator = nullptr;
ID3D12GraphicsCommandList* m_commandList = nullptr;
IDXGISwapChain3* m_swapChain = nullptr;
ID3D12DescriptorHeap* m_rtvHeap = nullptr;
ID3D12DescriptorHeap* m_srvHeap = nullptr;
ID3D12Resource* m_renderTargets[3] = {};
ID3D12Fence* m_fence = nullptr;
UINT64 m_fenceValue = 0;
UINT m_rtvDescriptorSize = 0;
RHI::RHIDevice* m_device = nullptr;
RHI::RHICommandQueue* m_commandQueue = nullptr;
RHI::RHICommandList* m_commandList = nullptr;
RHI::RHISwapChain* m_swapChain = nullptr;
RHI::RHIDescriptorPool* m_srvPool = nullptr;
RHI::D3D12DescriptorHeap* m_srvHeap = nullptr;
std::vector<RHI::RHIResourceView*> m_backBufferViews;
UINT m_srvDescriptorSize = 0;
UINT m_frameIndex = 0;
std::array<bool, kSrvDescriptorCount> m_srvDescriptorUsage = {};
};
} // namespace Platform