Refactor new editor host resize pipeline
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user