Files
XCEngine/new_editor/app/Rendering/D3D12/D3D12WindowRenderer.cpp

227 lines
6.6 KiB
C++

#include "D3D12WindowRenderer.h"
namespace XCEngine::UI::Editor::Host {
using ::XCEngine::RHI::RHIDevice;
using ::XCEngine::RHI::RHISwapChain;
using ::XCEngine::RHI::D3D12Texture;
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_viewportTextureAllocator.Initialize(*device)) {
m_lastError = "Failed to initialize the viewport texture allocator.";
Shutdown();
return false;
}
m_lastError.clear();
return true;
}
void D3D12WindowRenderer::Shutdown() {
m_viewportTextureCpuHandles.clear();
m_viewportTextureAllocator.Shutdown();
m_presenter.Shutdown();
m_hostDevice.Shutdown();
m_activeFrameSlot = 0u;
m_nextFrameSlot = 0u;
m_activeBackBufferIndex = 0u;
m_lastError.clear();
}
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::PreparePresentSurface() {
::XCEngine::Rendering::RenderContext renderContext = GetRenderContext();
if (!renderContext.IsValid() || renderContext.commandList == nullptr) {
m_lastError = "PreparePresentSurface requires a valid render context.";
return false;
}
const bool prepared = m_presenter.PreparePresentSurface(renderContext);
m_lastError = prepared ? std::string() : m_presenter.GetLastError();
return prepared;
}
bool D3D12WindowRenderer::SubmitFrame(bool presentSwapChain) {
if (presentSwapChain && m_presenter.GetSwapChain() == nullptr) {
m_lastError = "SubmitFrame requested present without a swap chain.";
return false;
}
if (!m_hostDevice.SubmitFrame(m_activeFrameSlot)) {
m_lastError = m_hostDevice.GetLastError();
return false;
}
if (presentSwapChain) {
if (!m_presenter.PresentFrame()) {
m_lastError = m_presenter.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;
}
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();
}
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_viewportTextureAllocator.IsInitialized()) {
return false;
}
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
if (!m_viewportTextureAllocator.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_viewportTextureCpuHandles[outTexture.nativeHandle] = cpuHandle;
return true;
}
void D3D12WindowRenderer::ReleaseViewportTextureHandle(
::XCEngine::UI::UITextureHandle& texture) {
if (!texture.IsValid()) {
texture = {};
return;
}
const auto found = m_viewportTextureCpuHandles.find(texture.nativeHandle);
if (found != m_viewportTextureCpuHandles.end()) {
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
gpuHandle.ptr = static_cast<UINT64>(texture.nativeHandle);
m_viewportTextureAllocator.Free(found->second, gpuHandle);
m_viewportTextureCpuHandles.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();
}
::XCEngine::Rendering::RenderContext D3D12WindowRenderer::GetRenderContext() const {
return m_hostDevice.GetRenderContext(m_activeFrameSlot);
}
} // namespace XCEngine::UI::Editor::Host