Refactor new editor host resize pipeline

This commit is contained in:
2026-04-13 23:09:02 +08:00
parent 712f99e723
commit 4362008b39
17 changed files with 1481 additions and 929 deletions

View File

@@ -185,11 +185,11 @@ bool NativeRenderer::AttachWindowRenderer(D3D12WindowRenderer& windowRenderer) {
// fallback-only and should not stay alive while D3D11On12 interop is healthy.
DiscardRenderTarget();
if (!m_backBufferInteropTargets.empty()) {
if (m_windowInterop.HasBackBufferTargets()) {
return true;
}
return RebuildBackBufferInteropTargets();
return m_windowInterop.RebuildBackBufferTargets();
}
void NativeRenderer::DetachWindowRenderer() {
@@ -198,18 +198,7 @@ void NativeRenderer::DetachWindowRenderer() {
}
void NativeRenderer::ReleaseWindowRendererBackBufferTargets() {
ClearActiveInteropSourceTextures();
if (m_d2dDeviceContext != nullptr) {
m_d2dDeviceContext->SetTarget(nullptr);
D2D1_TAG firstTag = 0u;
D2D1_TAG secondTag = 0u;
m_d2dDeviceContext->Flush(&firstTag, &secondTag);
}
if (m_d3d11DeviceContext != nullptr) {
m_d3d11DeviceContext->ClearState();
m_d3d11DeviceContext->Flush();
}
m_backBufferInteropTargets.clear();
m_windowInterop.ReleaseBackBufferTargets();
}
bool NativeRenderer::RebuildWindowRendererBackBufferTargets() {
@@ -219,14 +208,11 @@ bool NativeRenderer::RebuildWindowRendererBackBufferTargets() {
DiscardRenderTarget();
ReleaseWindowRendererBackBufferTargets();
return RebuildBackBufferInteropTargets();
return m_windowInterop.RebuildBackBufferTargets();
}
bool NativeRenderer::HasAttachedWindowRenderer() const {
return m_windowRenderer != nullptr &&
m_d3d11On12Device != nullptr &&
m_d2dDeviceContext != nullptr &&
!m_backBufferInteropTargets.empty();
return m_windowInterop.HasAttachedWindowRenderer();
}
bool NativeRenderer::Render(const ::XCEngine::UI::UIDrawData& drawData) {
@@ -262,19 +248,29 @@ bool NativeRenderer::RenderToWindowRenderer(const ::XCEngine::UI::UIDrawData& dr
return false;
}
if (m_backBufferInteropTargets.empty() &&
!RebuildBackBufferInteropTargets()) {
if (!m_windowInterop.HasBackBufferTargets() &&
!m_windowInterop.RebuildBackBufferTargets()) {
if (m_lastRenderError.empty()) {
m_lastRenderError = "Window renderer back buffer interop targets are unavailable.";
}
return false;
}
const std::uint32_t backBufferIndex =
m_windowRenderer->GetSwapChain() != nullptr
? m_windowRenderer->GetSwapChain()->GetCurrentBackBufferIndex()
: 0u;
if (backBufferIndex >= m_backBufferInteropTargets.size()) {
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;
}
@@ -290,15 +286,15 @@ bool NativeRenderer::RenderToWindowRenderer(const ::XCEngine::UI::UIDrawData& dr
return false;
}
if (!PrepareActiveInteropSourceTextures(drawData)) {
if (!m_windowInterop.PrepareSourceTextures(drawData)) {
ID3D11Resource* backBufferResource =
m_backBufferInteropTargets[backBufferIndex].wrappedResource.Get();
m_windowInterop.GetWrappedBackBufferResource(backBufferIndex);
if (backBufferResource != nullptr) {
m_d3d11On12Device->AcquireWrappedResources(&backBufferResource, 1u);
m_d3d11On12Device->ReleaseWrappedResources(&backBufferResource, 1u);
d3d11On12Device->AcquireWrappedResources(&backBufferResource, 1u);
d3d11On12Device->ReleaseWrappedResources(&backBufferResource, 1u);
}
m_d3d11DeviceContext->Flush();
ClearActiveInteropSourceTextures();
d3d11DeviceContext->Flush();
m_windowInterop.ClearSourceTextures();
const bool signaled = m_windowRenderer->SignalFrameCompletion();
ReleaseWindowRendererInterop();
if (!signaled) {
@@ -309,26 +305,26 @@ bool NativeRenderer::RenderToWindowRenderer(const ::XCEngine::UI::UIDrawData& dr
}
std::vector<ID3D11Resource*> acquiredResources = {};
acquiredResources.reserve(1u + m_activeInteropSourceTextures.size());
acquiredResources.push_back(m_backBufferInteropTargets[backBufferIndex].wrappedResource.Get());
for (const D3D12SourceTextureInteropResource& texture : m_activeInteropSourceTextures) {
acquiredResources.push_back(texture.wrappedResource.Get());
m_windowInterop.BuildAcquiredResources(backBufferIndex, acquiredResources);
if (acquiredResources.empty()) {
m_lastRenderError = "No wrapped interop resources were prepared for UI composition.";
return false;
}
m_d3d11On12Device->AcquireWrappedResources(
d3d11On12Device->AcquireWrappedResources(
acquiredResources.data(),
static_cast<UINT>(acquiredResources.size()));
m_d2dDeviceContext->SetTarget(m_backBufferInteropTargets[backBufferIndex].targetBitmap.Get());
const bool rendered = RenderToTarget(*m_d2dDeviceContext.Get(), *m_interopBrush.Get(), drawData);
const HRESULT hr = m_d2dDeviceContext->EndDraw();
d2dDeviceContext->SetTarget(m_windowInterop.GetBackBufferTargetBitmap(backBufferIndex));
const bool rendered = RenderToTarget(*d2dDeviceContext, *interopBrush, drawData);
const HRESULT hr = d2dDeviceContext->EndDraw();
m_d3d11On12Device->ReleaseWrappedResources(
d3d11On12Device->ReleaseWrappedResources(
acquiredResources.data(),
static_cast<UINT>(acquiredResources.size()));
m_d3d11DeviceContext->Flush();
m_d2dDeviceContext->SetTarget(nullptr);
ClearActiveInteropSourceTextures();
d3d11DeviceContext->Flush();
d2dDeviceContext->SetTarget(nullptr);
m_windowInterop.ClearSourceTextures();
if (!rendered || FAILED(hr)) {
m_lastRenderError = FAILED(hr)
@@ -604,252 +600,18 @@ bool NativeRenderer::EnsureWindowRendererInterop() {
m_lastRenderError = "EnsureWindowRendererInterop requires initialized D2D and DWrite factories.";
return false;
}
if (m_d3d11On12Device != nullptr &&
m_d2dDeviceContext != nullptr &&
m_interopBrush != nullptr) {
return true;
const bool attached = m_windowInterop.Attach(*m_windowRenderer, *m_d2dFactory.Get());
if (!attached) {
m_lastRenderError = m_windowInterop.GetLastError();
} else {
m_lastRenderError.clear();
}
ReleaseWindowRendererInterop();
ID3D12Device* d3d12Device = m_windowRenderer->GetDevice();
ID3D12CommandQueue* d3d12CommandQueue = m_windowRenderer->GetCommandQueue();
if (d3d12Device == nullptr || d3d12CommandQueue == nullptr) {
m_lastRenderError = "The attached D3D12 window renderer does not expose a native device/queue.";
return false;
}
const std::array<D3D_FEATURE_LEVEL, 4> featureLevels = {
D3D_FEATURE_LEVEL_12_1,
D3D_FEATURE_LEVEL_12_0,
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0
};
const std::array<IUnknown*, 1> commandQueues = {
reinterpret_cast<IUnknown*>(d3d12CommandQueue)
};
UINT createFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#ifdef _DEBUG
createFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_FEATURE_LEVEL actualFeatureLevel = D3D_FEATURE_LEVEL_11_0;
HRESULT hr = D3D11On12CreateDevice(
d3d12Device,
createFlags,
featureLevels.data(),
static_cast<UINT>(featureLevels.size()),
commandQueues.data(),
static_cast<UINT>(commandQueues.size()),
0u,
m_d3d11Device.ReleaseAndGetAddressOf(),
m_d3d11DeviceContext.ReleaseAndGetAddressOf(),
&actualFeatureLevel);
#ifdef _DEBUG
if (FAILED(hr)) {
createFlags &= ~D3D11_CREATE_DEVICE_DEBUG;
hr = D3D11On12CreateDevice(
d3d12Device,
createFlags,
featureLevels.data(),
static_cast<UINT>(featureLevels.size()),
commandQueues.data(),
static_cast<UINT>(commandQueues.size()),
0u,
m_d3d11Device.ReleaseAndGetAddressOf(),
m_d3d11DeviceContext.ReleaseAndGetAddressOf(),
&actualFeatureLevel);
}
#endif
if (FAILED(hr) || m_d3d11Device == nullptr || m_d3d11DeviceContext == nullptr) {
m_lastRenderError = HrToString("D3D11On12CreateDevice", hr);
ReleaseWindowRendererInterop();
return false;
}
hr = m_d3d11Device.As(&m_d3d11On12Device);
if (FAILED(hr) || m_d3d11On12Device == nullptr) {
m_lastRenderError = HrToString("ID3D11Device::QueryInterface(ID3D11On12Device)", hr);
ReleaseWindowRendererInterop();
return false;
}
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
hr = m_d3d11Device.As(&dxgiDevice);
if (FAILED(hr) || dxgiDevice == nullptr) {
m_lastRenderError = HrToString("ID3D11Device::QueryInterface(IDXGIDevice)", hr);
ReleaseWindowRendererInterop();
return false;
}
hr = m_d2dFactory->CreateDevice(dxgiDevice.Get(), m_d2dDevice.ReleaseAndGetAddressOf());
if (FAILED(hr) || m_d2dDevice == nullptr) {
m_lastRenderError = HrToString("ID2D1Factory1::CreateDevice", hr);
ReleaseWindowRendererInterop();
return false;
}
hr = m_d2dDevice->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
m_d2dDeviceContext.ReleaseAndGetAddressOf());
if (FAILED(hr) || m_d2dDeviceContext == nullptr) {
m_lastRenderError = HrToString("ID2D1Device::CreateDeviceContext", hr);
ReleaseWindowRendererInterop();
return false;
}
hr = m_d2dDeviceContext->CreateSolidColorBrush(
D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f),
m_interopBrush.ReleaseAndGetAddressOf());
if (FAILED(hr) || m_interopBrush == nullptr) {
m_lastRenderError = HrToString("ID2D1DeviceContext::CreateSolidColorBrush", hr);
ReleaseWindowRendererInterop();
return false;
}
m_d2dDeviceContext->SetDpi(kBaseDpi, kBaseDpi);
m_d2dDeviceContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
return RebuildBackBufferInteropTargets();
return attached;
}
void NativeRenderer::ReleaseWindowRendererInterop() {
ReleaseWindowRendererBackBufferTargets();
m_interopBrush.Reset();
m_d2dDeviceContext.Reset();
m_d2dDevice.Reset();
m_d3d11On12Device.Reset();
m_d3d11DeviceContext.Reset();
m_d3d11Device.Reset();
}
bool NativeRenderer::RebuildBackBufferInteropTargets() {
m_backBufferInteropTargets.clear();
if (m_windowRenderer == nullptr || m_d3d11On12Device == nullptr || m_d2dDeviceContext == nullptr) {
return false;
}
const std::uint32_t backBufferCount = m_windowRenderer->GetBackBufferCount();
m_backBufferInteropTargets.resize(backBufferCount);
for (std::uint32_t index = 0; index < backBufferCount; ++index) {
const ::XCEngine::RHI::D3D12Texture* backBufferTexture =
m_windowRenderer->GetBackBufferTexture(index);
if (backBufferTexture == nullptr || backBufferTexture->GetResource() == nullptr) {
m_lastRenderError = "Failed to resolve a D3D12 swap chain back buffer.";
m_backBufferInteropTargets.clear();
return false;
}
D3D11_RESOURCE_FLAGS resourceFlags = {};
resourceFlags.BindFlags = D3D11_BIND_RENDER_TARGET;
HRESULT hr = m_d3d11On12Device->CreateWrappedResource(
backBufferTexture->GetResource(),
&resourceFlags,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT,
IID_PPV_ARGS(m_backBufferInteropTargets[index].wrappedResource.ReleaseAndGetAddressOf()));
if (FAILED(hr) || m_backBufferInteropTargets[index].wrappedResource == nullptr) {
m_lastRenderError = HrToString("ID3D11On12Device::CreateWrappedResource(backbuffer)", hr);
m_backBufferInteropTargets.clear();
return false;
}
Microsoft::WRL::ComPtr<IDXGISurface> dxgiSurface;
hr = m_backBufferInteropTargets[index].wrappedResource.As(&dxgiSurface);
if (FAILED(hr) || dxgiSurface == nullptr) {
m_lastRenderError = HrToString("ID3D11Resource::QueryInterface(IDXGISurface)", hr);
m_backBufferInteropTargets.clear();
return false;
}
const D2D1_BITMAP_PROPERTIES1 bitmapProperties =
BuildD2DBitmapProperties(
backBufferTexture->GetDesc().Format,
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW);
hr = m_d2dDeviceContext->CreateBitmapFromDxgiSurface(
dxgiSurface.Get(),
&bitmapProperties,
m_backBufferInteropTargets[index].targetBitmap.ReleaseAndGetAddressOf());
if (FAILED(hr) || m_backBufferInteropTargets[index].targetBitmap == nullptr) {
m_lastRenderError = HrToString("ID2D1DeviceContext::CreateBitmapFromDxgiSurface(backbuffer)", hr);
m_backBufferInteropTargets.clear();
return false;
}
}
return true;
}
void NativeRenderer::ClearActiveInteropSourceTextures() {
m_activeInteropBitmaps.clear();
m_activeInteropSourceTextures.clear();
}
bool NativeRenderer::PrepareActiveInteropSourceTextures(
const ::XCEngine::UI::UIDrawData& drawData) {
ClearActiveInteropSourceTextures();
if (m_windowRenderer == nullptr || m_d3d11On12Device == nullptr || m_d2dDeviceContext == nullptr) {
return false;
}
std::vector<::XCEngine::UI::UITextureHandle> textureHandles = {};
CollectInteropTextureHandles(drawData, textureHandles);
m_activeInteropSourceTextures.reserve(textureHandles.size());
for (const ::XCEngine::UI::UITextureHandle& textureHandle : textureHandles) {
auto* texture =
reinterpret_cast<::XCEngine::RHI::RHITexture*>(textureHandle.resourceHandle);
auto* nativeTexture = dynamic_cast<::XCEngine::RHI::D3D12Texture*>(texture);
if (nativeTexture == nullptr || nativeTexture->GetResource() == nullptr) {
m_lastRenderError = "Failed to resolve a D3D12 source texture for UI composition.";
ClearActiveInteropSourceTextures();
return false;
}
D3D11_RESOURCE_FLAGS resourceFlags = {};
resourceFlags.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D12SourceTextureInteropResource resource = {};
resource.key = textureHandle.resourceHandle;
HRESULT hr = m_d3d11On12Device->CreateWrappedResource(
nativeTexture->GetResource(),
&resourceFlags,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
IID_PPV_ARGS(resource.wrappedResource.ReleaseAndGetAddressOf()));
if (FAILED(hr) || resource.wrappedResource == nullptr) {
m_lastRenderError = HrToString("ID3D11On12Device::CreateWrappedResource(source)", hr);
ClearActiveInteropSourceTextures();
return false;
}
Microsoft::WRL::ComPtr<IDXGISurface> dxgiSurface;
hr = resource.wrappedResource.As(&dxgiSurface);
if (FAILED(hr) || dxgiSurface == nullptr) {
m_lastRenderError = HrToString("ID3D11Resource::QueryInterface(IDXGISurface)", hr);
ClearActiveInteropSourceTextures();
return false;
}
const D2D1_BITMAP_PROPERTIES1 bitmapProperties =
BuildD2DBitmapProperties(
nativeTexture->GetDesc().Format,
D2D1_BITMAP_OPTIONS_NONE);
hr = m_d2dDeviceContext->CreateBitmapFromDxgiSurface(
dxgiSurface.Get(),
&bitmapProperties,
resource.bitmap.ReleaseAndGetAddressOf());
if (FAILED(hr) || resource.bitmap == nullptr) {
m_lastRenderError = HrToString("ID2D1DeviceContext::CreateBitmapFromDxgiSurface(source)", hr);
ClearActiveInteropSourceTextures();
return false;
}
m_activeInteropBitmaps.emplace(resource.key, resource.bitmap);
m_activeInteropSourceTextures.push_back(std::move(resource));
}
return true;
m_windowInterop.Detach();
}
bool NativeRenderer::EnsureRenderTarget() {
@@ -1068,18 +830,7 @@ bool NativeRenderer::ResolveTextureBitmap(
bool NativeRenderer::ResolveInteropBitmap(
const ::XCEngine::UI::UITextureHandle& texture,
Microsoft::WRL::ComPtr<ID2D1Bitmap>& outBitmap) const {
outBitmap.Reset();
if (!IsInteropTextureHandle(texture)) {
return false;
}
const auto found = m_activeInteropBitmaps.find(texture.resourceHandle);
if (found == m_activeInteropBitmaps.end() || found->second == nullptr) {
return false;
}
outBitmap = found->second;
return true;
return m_windowInterop.ResolveInteropBitmap(texture, outBitmap);
}
bool NativeRenderer::RenderToTarget(