2026-04-15 22:47:42 +08:00
|
|
|
#include "NativeRendererInternal.h"
|
2026-04-15 08:24:06 +08:00
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::Host {
|
|
|
|
|
|
2026-04-15 22:47:42 +08:00
|
|
|
using namespace NativeRendererInternal;
|
2026-04-15 08:24:06 +08:00
|
|
|
|
|
|
|
|
bool NativeRenderer::Render(const ::XCEngine::UI::UIDrawData& drawData) {
|
|
|
|
|
if (!EnsureRenderTarget()) {
|
|
|
|
|
if (m_lastRenderError.empty()) {
|
|
|
|
|
m_lastRenderError = "EnsureRenderTarget failed.";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool rendered = RenderToTarget(*m_renderTarget.Get(), *m_solidBrush.Get(), drawData);
|
|
|
|
|
const HRESULT hr = m_renderTarget->EndDraw();
|
|
|
|
|
if (hr == D2DERR_RECREATE_TARGET) {
|
|
|
|
|
m_lastRenderError = HrToString("ID2D1HwndRenderTarget::EndDraw", hr);
|
|
|
|
|
DiscardRenderTarget();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!rendered || FAILED(hr)) {
|
|
|
|
|
m_lastRenderError = HrToString("ID2D1HwndRenderTarget::EndDraw", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_lastRenderError.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NativeRenderer::RenderToWindowRenderer(const ::XCEngine::UI::UIDrawData& drawData) {
|
|
|
|
|
if (!EnsureWindowRendererInterop()) {
|
|
|
|
|
if (m_lastRenderError.empty()) {
|
|
|
|
|
m_lastRenderError = "Window renderer interop is not available.";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_windowInterop.HasBackBufferTargets() &&
|
|
|
|
|
!m_windowInterop.RebuildBackBufferTargets()) {
|
|
|
|
|
if (m_lastRenderError.empty()) {
|
|
|
|
|
m_lastRenderError = "Window renderer back buffer interop targets are unavailable.";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ID3D11On12Device* d3d11On12Device = m_windowInterop.GetD3D11On12Device();
|
|
|
|
|
ID3D11DeviceContext* d3d11DeviceContext = m_windowInterop.GetD3D11DeviceContext();
|
|
|
|
|
ID2D1DeviceContext* d2dDeviceContext = m_windowInterop.GetD2DDeviceContext();
|
|
|
|
|
ID2D1SolidColorBrush* interopBrush = m_windowInterop.GetInteropBrush();
|
|
|
|
|
if (d3d11On12Device == nullptr ||
|
|
|
|
|
d3d11DeviceContext == nullptr ||
|
|
|
|
|
d2dDeviceContext == nullptr ||
|
|
|
|
|
interopBrush == nullptr) {
|
|
|
|
|
m_lastRenderError = "Window renderer interop resources are incomplete.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::uint32_t backBufferIndex = m_windowInterop.GetCurrentBackBufferIndex();
|
|
|
|
|
if (m_windowInterop.GetWrappedBackBufferResource(backBufferIndex) == nullptr ||
|
|
|
|
|
m_windowInterop.GetBackBufferTargetBitmap(backBufferIndex) == nullptr) {
|
|
|
|
|
m_lastRenderError = "Back buffer interop target index is out of range.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_windowRenderer->PreparePresentSurface()) {
|
|
|
|
|
m_lastRenderError = "Failed to prepare the D3D12 present surface: " +
|
|
|
|
|
m_windowRenderer->GetLastError();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_windowRenderer->SubmitFrame(false)) {
|
|
|
|
|
m_lastRenderError = "Failed to submit the D3D12 frame before UI composition.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_windowInterop.PrepareSourceTextures(drawData)) {
|
|
|
|
|
ID3D11Resource* backBufferResource =
|
|
|
|
|
m_windowInterop.GetWrappedBackBufferResource(backBufferIndex);
|
|
|
|
|
if (backBufferResource != nullptr) {
|
|
|
|
|
d3d11On12Device->AcquireWrappedResources(&backBufferResource, 1u);
|
|
|
|
|
d3d11On12Device->ReleaseWrappedResources(&backBufferResource, 1u);
|
|
|
|
|
}
|
|
|
|
|
d3d11DeviceContext->Flush();
|
|
|
|
|
m_windowInterop.ClearSourceTextures();
|
|
|
|
|
const bool signaled = m_windowRenderer->SignalFrameCompletion();
|
|
|
|
|
ReleaseWindowRendererInterop();
|
|
|
|
|
if (!signaled) {
|
|
|
|
|
m_lastRenderError =
|
|
|
|
|
"Failed to signal D3D12 frame completion after interop preparation failed.";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<ID3D11Resource*> acquiredResources = {};
|
|
|
|
|
m_windowInterop.BuildAcquiredResources(backBufferIndex, acquiredResources);
|
|
|
|
|
if (acquiredResources.empty()) {
|
|
|
|
|
m_lastRenderError = "No wrapped interop resources were prepared for UI composition.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d3d11On12Device->AcquireWrappedResources(
|
|
|
|
|
acquiredResources.data(),
|
|
|
|
|
static_cast<UINT>(acquiredResources.size()));
|
|
|
|
|
|
|
|
|
|
d2dDeviceContext->SetTarget(m_windowInterop.GetBackBufferTargetBitmap(backBufferIndex));
|
|
|
|
|
const bool rendered = RenderToTarget(*d2dDeviceContext, *interopBrush, drawData);
|
|
|
|
|
const HRESULT hr = d2dDeviceContext->EndDraw();
|
|
|
|
|
|
|
|
|
|
d3d11On12Device->ReleaseWrappedResources(
|
|
|
|
|
acquiredResources.data(),
|
|
|
|
|
static_cast<UINT>(acquiredResources.size()));
|
|
|
|
|
d3d11DeviceContext->Flush();
|
|
|
|
|
d2dDeviceContext->SetTarget(nullptr);
|
|
|
|
|
m_windowInterop.ClearSourceTextures();
|
|
|
|
|
|
|
|
|
|
if (!rendered || FAILED(hr)) {
|
|
|
|
|
m_lastRenderError = FAILED(hr)
|
|
|
|
|
? HrToString("ID2D1DeviceContext::EndDraw", hr)
|
|
|
|
|
: "RenderToTarget failed during D3D11On12 composition.";
|
|
|
|
|
const bool signaled = m_windowRenderer->SignalFrameCompletion();
|
|
|
|
|
if (hr == D2DERR_RECREATE_TARGET) {
|
|
|
|
|
ReleaseWindowRendererBackBufferTargets();
|
|
|
|
|
} else {
|
|
|
|
|
ReleaseWindowRendererInterop();
|
|
|
|
|
}
|
|
|
|
|
if (!signaled) {
|
|
|
|
|
m_lastRenderError =
|
|
|
|
|
"Failed to signal D3D12 frame completion after UI composition failed.";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_windowRenderer->SignalFrameCompletion()) {
|
|
|
|
|
m_lastRenderError = "Failed to signal D3D12 frame completion after UI composition.";
|
|
|
|
|
ReleaseWindowRendererInterop();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!m_windowRenderer->PresentFrame()) {
|
|
|
|
|
m_lastRenderError = "Failed to present the D3D12 swap chain.";
|
|
|
|
|
ReleaseWindowRendererInterop();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_lastRenderError.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::Host
|