关键节点
This commit is contained in:
291
editor/app/Rendering/D3D12/D3D12WindowRenderer.cpp
Normal file
291
editor/app/Rendering/D3D12/D3D12WindowRenderer.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
#include "D3D12WindowRenderer.h"
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
|
||||
namespace XCEngine::UI::Editor::Host {
|
||||
|
||||
using ::XCEngine::RHI::RHIDevice;
|
||||
using ::XCEngine::RHI::RHISwapChain;
|
||||
using ::XCEngine::RHI::D3D12Texture;
|
||||
|
||||
namespace {
|
||||
|
||||
void TraceRenderer(std::string_view message, const void* renderer) {
|
||||
std::ostringstream stream = {};
|
||||
stream << message
|
||||
<< " renderer=0x" << std::hex << std::uppercase
|
||||
<< reinterpret_cast<std::uintptr_t>(renderer);
|
||||
AppendUIEditorRuntimeTrace("window-close", stream.str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool D3D12WindowRenderer::Initialize(HWND hwnd, int width, int height) {
|
||||
Shutdown();
|
||||
|
||||
if (hwnd == nullptr || width <= 0 || height <= 0) {
|
||||
m_lastError = "Initialize rejected an invalid hwnd or size.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_hostDevice.Initialize()) {
|
||||
m_lastError = m_hostDevice.GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_presenter.Initialize(m_hostDevice, hwnd, width, height)) {
|
||||
m_lastError = m_presenter.GetLastError();
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* device = m_hostDevice.GetRHIDevice();
|
||||
if (device == nullptr ||
|
||||
!m_textureAllocator.Initialize(*device, 512u)) {
|
||||
m_lastError = "Failed to initialize the UI texture descriptor allocator.";
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lastError.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12WindowRenderer::Shutdown() {
|
||||
TraceRenderer("D3D12WindowRenderer::Shutdown begin", this);
|
||||
m_textureCpuHandles.clear();
|
||||
m_textureAllocator.Shutdown();
|
||||
m_capture.Shutdown();
|
||||
m_presenter.Shutdown();
|
||||
m_hostDevice.Shutdown();
|
||||
m_activeFrameSlot = 0u;
|
||||
m_nextFrameSlot = 0u;
|
||||
m_activeBackBufferIndex = 0u;
|
||||
m_lastError.clear();
|
||||
TraceRenderer("D3D12WindowRenderer::Shutdown end", this);
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::Resize(int width, int height) {
|
||||
if (!m_presenter.Resize(width, height)) {
|
||||
m_lastError = m_presenter.GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_activeFrameSlot = 0u;
|
||||
m_nextFrameSlot = 0u;
|
||||
m_activeBackBufferIndex = m_presenter.GetCurrentBackBufferIndex();
|
||||
m_lastError = m_presenter.GetLastError();
|
||||
if (!m_lastError.empty()) {
|
||||
return true;
|
||||
}
|
||||
m_lastError.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::BeginFrame() {
|
||||
if (m_presenter.GetSwapChain() == nullptr) {
|
||||
m_lastError = "BeginFrame requires an initialized swap chain.";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_activeBackBufferIndex = m_presenter.GetCurrentBackBufferIndex();
|
||||
const std::uint32_t frameSlot = m_nextFrameSlot;
|
||||
if (!m_hostDevice.BeginFrame(frameSlot)) {
|
||||
m_lastError = m_hostDevice.GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_activeFrameSlot = frameSlot;
|
||||
m_nextFrameSlot = (frameSlot + 1u) % kFrameContextCount;
|
||||
m_lastError.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::PrepareCurrentBackBufferForUiRender() {
|
||||
::XCEngine::Rendering::RenderContext renderContext = GetRenderContext();
|
||||
if (!renderContext.IsValid() || renderContext.commandList == nullptr) {
|
||||
m_lastError = "PrepareCurrentBackBufferForUiRender requires a valid render context.";
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool prepared = m_presenter.PrepareCurrentBackBufferForRender(renderContext);
|
||||
m_lastError = prepared ? std::string() : m_presenter.GetLastError();
|
||||
return prepared;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::FinalizeCurrentBackBufferForPresent() {
|
||||
::XCEngine::Rendering::RenderContext renderContext = GetRenderContext();
|
||||
if (!renderContext.IsValid() || renderContext.commandList == nullptr) {
|
||||
m_lastError = "FinalizeCurrentBackBufferForPresent requires a valid render context.";
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool finalized = m_presenter.FinalizeCurrentBackBufferForPresent(renderContext);
|
||||
m_lastError = finalized ? std::string() : m_presenter.GetLastError();
|
||||
return finalized;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::SubmitFrame() {
|
||||
if (!m_hostDevice.SubmitFrame(m_activeFrameSlot)) {
|
||||
m_lastError = m_hostDevice.GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lastError.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::SignalFrameCompletion() {
|
||||
if (!m_hostDevice.SignalFrameCompletion(m_activeFrameSlot)) {
|
||||
m_lastError = m_hostDevice.GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lastError.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::PresentFrame() {
|
||||
const bool presented = m_presenter.PresentFrame();
|
||||
m_lastError = presented ? std::string() : m_presenter.GetLastError();
|
||||
return presented;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::CaptureCurrentBackBufferToPng(
|
||||
const std::filesystem::path& outputPath,
|
||||
std::string& outError) {
|
||||
const bool captured = m_capture.CaptureCurrentBackBufferToPng(*this, outputPath, outError);
|
||||
if (!captured && outError.empty()) {
|
||||
outError = "CaptureCurrentBackBufferToPng failed.";
|
||||
}
|
||||
return captured;
|
||||
}
|
||||
|
||||
void D3D12WindowRenderer::WaitForGpuIdle() {
|
||||
TraceRenderer("D3D12WindowRenderer::WaitForGpuIdle begin", this);
|
||||
m_hostDevice.WaitForGpuIdle();
|
||||
TraceRenderer("D3D12WindowRenderer::WaitForGpuIdle end", this);
|
||||
}
|
||||
|
||||
ID3D12Device* D3D12WindowRenderer::GetDevice() const {
|
||||
return m_hostDevice.GetDevice();
|
||||
}
|
||||
|
||||
ID3D12CommandQueue* D3D12WindowRenderer::GetCommandQueue() const {
|
||||
return m_hostDevice.GetCommandQueue();
|
||||
}
|
||||
|
||||
const std::string& D3D12WindowRenderer::GetLastError() const {
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
RHIDevice* D3D12WindowRenderer::GetRHIDevice() const {
|
||||
return m_hostDevice.GetRHIDevice();
|
||||
}
|
||||
|
||||
std::uint32_t D3D12WindowRenderer::GetViewportResourceRetirementSlotCount() const {
|
||||
return kFrameContextCount;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::TryGetActiveViewportResourceRetirementSlot(std::uint32_t& outSlot) const {
|
||||
outSlot = 0u;
|
||||
if (GetRHIDevice() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outSlot = m_activeFrameSlot;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12WindowRenderer::CreateViewportTextureHandle(
|
||||
::XCEngine::RHI::RHITexture& texture,
|
||||
std::uint32_t width,
|
||||
std::uint32_t height,
|
||||
::XCEngine::UI::UITextureHandle& outTexture) {
|
||||
outTexture = {};
|
||||
if (width == 0u ||
|
||||
height == 0u ||
|
||||
!m_textureAllocator.IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
|
||||
if (!m_textureAllocator.CreateTextureDescriptor(
|
||||
&texture,
|
||||
&cpuHandle,
|
||||
&gpuHandle) ||
|
||||
cpuHandle.ptr == 0u ||
|
||||
gpuHandle.ptr == 0u) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outTexture.nativeHandle = static_cast<std::uintptr_t>(gpuHandle.ptr);
|
||||
outTexture.width = width;
|
||||
outTexture.height = height;
|
||||
outTexture.kind = ::XCEngine::UI::UITextureHandleKind::ShaderResourceView;
|
||||
outTexture.resourceHandle = reinterpret_cast<std::uintptr_t>(&texture);
|
||||
m_textureCpuHandles[outTexture.nativeHandle] = cpuHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12WindowRenderer::ReleaseViewportTextureHandle(
|
||||
::XCEngine::UI::UITextureHandle& texture) {
|
||||
if (!texture.IsValid()) {
|
||||
texture = {};
|
||||
return;
|
||||
}
|
||||
|
||||
const auto found = m_textureCpuHandles.find(texture.nativeHandle);
|
||||
if (found != m_textureCpuHandles.end()) {
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
|
||||
gpuHandle.ptr = static_cast<UINT64>(texture.nativeHandle);
|
||||
m_textureAllocator.Free(found->second, gpuHandle);
|
||||
m_textureCpuHandles.erase(found);
|
||||
}
|
||||
|
||||
texture = {};
|
||||
}
|
||||
|
||||
RHISwapChain* D3D12WindowRenderer::GetSwapChain() const {
|
||||
return m_presenter.GetSwapChain();
|
||||
}
|
||||
|
||||
const ::XCEngine::Rendering::RenderSurface* D3D12WindowRenderer::GetCurrentRenderSurface() const {
|
||||
return m_presenter.GetCurrentRenderSurface();
|
||||
}
|
||||
|
||||
const D3D12Texture* D3D12WindowRenderer::GetCurrentBackBufferTexture() const {
|
||||
return m_presenter.GetCurrentBackBufferTexture();
|
||||
}
|
||||
|
||||
const D3D12Texture* D3D12WindowRenderer::GetBackBufferTexture(std::uint32_t index) const {
|
||||
return m_presenter.GetBackBufferTexture(index);
|
||||
}
|
||||
|
||||
std::uint32_t D3D12WindowRenderer::GetBackBufferCount() const {
|
||||
return m_presenter.GetBackBufferCount();
|
||||
}
|
||||
|
||||
std::uint32_t D3D12WindowRenderer::GetActiveFrameSlot() const {
|
||||
return m_activeFrameSlot;
|
||||
}
|
||||
|
||||
::XCEngine::Rendering::RenderContext D3D12WindowRenderer::GetRenderContext() const {
|
||||
return m_hostDevice.GetRenderContext(m_activeFrameSlot);
|
||||
}
|
||||
|
||||
D3D12ShaderResourceDescriptorAllocator&
|
||||
D3D12WindowRenderer::GetTextureDescriptorAllocator() {
|
||||
return m_textureAllocator;
|
||||
}
|
||||
|
||||
const D3D12ShaderResourceDescriptorAllocator&
|
||||
D3D12WindowRenderer::GetTextureDescriptorAllocator() const {
|
||||
return m_textureAllocator;
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Host
|
||||
Reference in New Issue
Block a user