2026-04-15 08:24:06 +08:00
|
|
|
#include "ViewportHostService.h"
|
2026-04-12 23:13:00 +08:00
|
|
|
|
|
|
|
|
#include <XCEngine/RHI/RHICommandList.h>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
using ::XCEngine::RHI::ResourceStates;
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
ViewportFrame ViewportHostService::RequestViewport(
|
|
|
|
|
ViewportKind kind,
|
2026-04-12 23:13:00 +08:00
|
|
|
const ::XCEngine::UI::UISize& requestedSize) {
|
|
|
|
|
ViewportEntry& entry = GetEntry(kind);
|
|
|
|
|
entry.requestedThisFrame = requestedSize.width > 1.0f && requestedSize.height > 1.0f;
|
|
|
|
|
entry.requestedWidth = entry.requestedThisFrame
|
|
|
|
|
? static_cast<std::uint32_t>(requestedSize.width)
|
|
|
|
|
: 0u;
|
|
|
|
|
entry.requestedHeight = entry.requestedThisFrame
|
|
|
|
|
? static_cast<std::uint32_t>(requestedSize.height)
|
|
|
|
|
: 0u;
|
|
|
|
|
|
|
|
|
|
if (!entry.requestedThisFrame) {
|
|
|
|
|
return BuildFrame(entry, requestedSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_windowRenderer == nullptr || m_device == nullptr) {
|
|
|
|
|
return BuildFrame(entry, requestedSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!EnsureViewportResources(entry)) {
|
|
|
|
|
return BuildFrame(entry, requestedSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BuildFrame(entry, requestedSize);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
void ViewportHostService::RenderRequestedViewports(
|
2026-04-12 23:13:00 +08:00
|
|
|
const ::XCEngine::Rendering::RenderContext& renderContext) {
|
|
|
|
|
if (m_windowRenderer == nullptr || m_device == nullptr || !renderContext.IsValid()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (ViewportEntry& entry : m_entries) {
|
|
|
|
|
if (!entry.requestedThisFrame || !EnsureViewportResources(entry)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
if (entry.kind == ViewportKind::Scene) {
|
|
|
|
|
ClearViewport(entry, renderContext, 0.09f, 0.09f, 0.09f, 1.0f);
|
2026-04-12 23:13:00 +08:00
|
|
|
} else {
|
2026-04-15 08:24:06 +08:00
|
|
|
ClearViewport(entry, renderContext, 0.09f, 0.09f, 0.09f, 1.0f);
|
2026-04-12 23:13:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry.renderedThisFrame = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
bool ViewportHostService::EnsureViewportResources(ViewportEntry& entry) {
|
|
|
|
|
const ViewportResourceReuseQuery reuseQuery =
|
|
|
|
|
BuildViewportRenderTargetsReuseQuery(
|
2026-04-12 23:13:00 +08:00
|
|
|
entry.kind,
|
|
|
|
|
entry.renderTargets,
|
|
|
|
|
entry.requestedWidth,
|
|
|
|
|
entry.requestedHeight);
|
2026-04-15 08:24:06 +08:00
|
|
|
if (CanReuseViewportResources(reuseQuery)) {
|
2026-04-12 23:13:00 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_windowRenderer == nullptr ||
|
|
|
|
|
m_device == nullptr ||
|
|
|
|
|
entry.requestedWidth == 0u ||
|
|
|
|
|
entry.requestedHeight == 0u) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-13 19:57:25 +08:00
|
|
|
return m_renderTargetManager.EnsureTargets(
|
2026-04-12 23:13:00 +08:00
|
|
|
entry.kind,
|
|
|
|
|
entry.requestedWidth,
|
|
|
|
|
entry.requestedHeight,
|
2026-04-13 19:57:25 +08:00
|
|
|
*m_device,
|
|
|
|
|
m_textureDescriptorAllocator,
|
2026-04-12 23:13:00 +08:00
|
|
|
entry.renderTargets);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
void ViewportHostService::ClearViewport(
|
2026-04-12 23:13:00 +08:00
|
|
|
ViewportEntry& entry,
|
|
|
|
|
const ::XCEngine::Rendering::RenderContext& renderContext,
|
|
|
|
|
float r,
|
|
|
|
|
float g,
|
|
|
|
|
float b,
|
|
|
|
|
float a) {
|
|
|
|
|
if (renderContext.commandList == nullptr ||
|
|
|
|
|
entry.renderTargets.colorView == nullptr ||
|
|
|
|
|
entry.renderTargets.depthView == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto* commandList = renderContext.commandList;
|
|
|
|
|
auto* colorView = entry.renderTargets.colorView;
|
|
|
|
|
const float clearColor[4] = { r, g, b, a };
|
|
|
|
|
commandList->TransitionBarrier(
|
|
|
|
|
colorView,
|
|
|
|
|
entry.renderTargets.colorState,
|
|
|
|
|
ResourceStates::RenderTarget);
|
|
|
|
|
commandList->SetRenderTargets(1, &colorView, entry.renderTargets.depthView);
|
|
|
|
|
commandList->ClearRenderTarget(colorView, clearColor);
|
|
|
|
|
commandList->ClearDepthStencil(entry.renderTargets.depthView, 1.0f, 0);
|
|
|
|
|
commandList->TransitionBarrier(
|
|
|
|
|
colorView,
|
|
|
|
|
ResourceStates::RenderTarget,
|
|
|
|
|
ResourceStates::PixelShaderResource);
|
|
|
|
|
entry.renderTargets.colorState = ResourceStates::PixelShaderResource;
|
|
|
|
|
entry.renderTargets.hasValidObjectIdFrame = false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
ViewportFrame ViewportHostService::BuildFrame(
|
2026-04-12 23:13:00 +08:00
|
|
|
const ViewportEntry& entry,
|
|
|
|
|
const ::XCEngine::UI::UISize& requestedSize) const {
|
2026-04-15 08:24:06 +08:00
|
|
|
ViewportFrame frame = {};
|
2026-04-12 23:13:00 +08:00
|
|
|
frame.requestedSize = requestedSize;
|
|
|
|
|
frame.renderSize = ::XCEngine::UI::UISize(
|
|
|
|
|
static_cast<float>(entry.renderTargets.width),
|
|
|
|
|
static_cast<float>(entry.renderTargets.height));
|
|
|
|
|
frame.wasRequested = entry.requestedThisFrame;
|
|
|
|
|
frame.statusText = entry.statusText;
|
|
|
|
|
|
|
|
|
|
if (m_surfacePresentationEnabled &&
|
|
|
|
|
entry.renderTargets.textureHandle.IsValid()) {
|
|
|
|
|
frame.texture = entry.renderTargets.textureHandle;
|
|
|
|
|
frame.hasTexture = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|