Refactor new editor boundaries and test ownership
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
#include "ViewportHostService.h"
|
||||
|
||||
#include "Host/ViewportRenderHost.h"
|
||||
#include <Rendering/D3D12/D3D12ShaderResourceDescriptorAllocator.h>
|
||||
#include "Ports/ViewportRenderPort.h"
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
#include <XCEngine/RHI/RHICommandList.h>
|
||||
#include <XCEngine/Rendering/Execution/SceneRenderer.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -15,111 +12,94 @@ namespace {
|
||||
|
||||
using ::XCEngine::RHI::ResourceStates;
|
||||
|
||||
void SetViewportStatusIfEmpty(
|
||||
std::string& statusText,
|
||||
std::string_view message) {
|
||||
if (statusText.empty()) {
|
||||
statusText = std::string(message);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ViewportHostService::ViewportHostService()
|
||||
: m_textureDescriptorAllocator(
|
||||
std::make_unique<Host::D3D12ShaderResourceDescriptorAllocator>()) {
|
||||
}
|
||||
ViewportHostService::ViewportHostService() = default;
|
||||
|
||||
ViewportHostService::~ViewportHostService() = default;
|
||||
|
||||
void ViewportHostService::AttachWindowRenderer(
|
||||
Host::ViewportRenderHost& windowRenderer) {
|
||||
Ports::ViewportRenderPort& windowRenderer) {
|
||||
if (m_windowRenderer == &windowRenderer) {
|
||||
m_device = windowRenderer.GetRHIDevice();
|
||||
if (m_device != nullptr &&
|
||||
!m_textureDescriptorAllocator->IsInitialized()) {
|
||||
m_textureDescriptorAllocator->Initialize(*m_device);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
ReleaseWindowResources();
|
||||
m_windowRenderer = &windowRenderer;
|
||||
m_device = windowRenderer.GetRHIDevice();
|
||||
if (m_device != nullptr) {
|
||||
m_textureDescriptorAllocator->Initialize(*m_device);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportHostService::DetachWindowRenderer() {
|
||||
Shutdown();
|
||||
ReleaseWindowResources();
|
||||
}
|
||||
|
||||
void ViewportHostService::SetSurfacePresentationEnabled(bool enabled) {
|
||||
m_surfacePresentationEnabled = enabled;
|
||||
}
|
||||
|
||||
void ViewportHostService::SetSceneViewportRenderRequest(
|
||||
SceneViewportRenderRequest request) {
|
||||
m_sceneViewportRenderRequest = request;
|
||||
void ViewportHostService::SetContentRenderer(
|
||||
std::string_view viewportId,
|
||||
IViewportContentRenderer* renderer,
|
||||
const ViewportResourceRequirements& requirements) {
|
||||
ViewportEntry& entry = GetOrCreateEntry(viewportId);
|
||||
entry.renderer = renderer;
|
||||
entry.requirements = requirements;
|
||||
}
|
||||
|
||||
void ViewportHostService::Shutdown() {
|
||||
for (ViewportEntry& entry : m_entries) {
|
||||
for (auto& [viewportId, entry] : m_entries) {
|
||||
DestroyViewportEntry(entry);
|
||||
}
|
||||
|
||||
m_sceneViewportRenderPassBundle.Shutdown();
|
||||
m_textureDescriptorAllocator->Shutdown();
|
||||
m_windowRenderer = nullptr;
|
||||
m_device = nullptr;
|
||||
m_surfacePresentationEnabled = false;
|
||||
m_sceneViewportRenderRequest = {};
|
||||
m_sceneRenderer.reset();
|
||||
m_sceneViewportLastRenderContext = {};
|
||||
m_entries.clear();
|
||||
}
|
||||
|
||||
void ViewportHostService::BeginFrame() {
|
||||
for (ViewportEntry& entry : m_entries) {
|
||||
for (auto& [viewportId, entry] : m_entries) {
|
||||
entry.requestedWidth = 0;
|
||||
entry.requestedHeight = 0;
|
||||
entry.requestedThisFrame = false;
|
||||
entry.renderedThisFrame = false;
|
||||
entry.kind = (&entry == &m_entries[0]) ? ViewportKind::Scene : ViewportKind::Game;
|
||||
}
|
||||
}
|
||||
|
||||
ViewportHostService::ViewportEntry& ViewportHostService::GetEntry(
|
||||
ViewportKind kind) {
|
||||
const std::size_t index = kind == ViewportKind::Scene ? 0u : 1u;
|
||||
ViewportEntry& entry = m_entries[index];
|
||||
entry.kind = kind;
|
||||
return entry;
|
||||
void ViewportHostService::ReleaseWindowResources() {
|
||||
for (auto& [viewportId, entry] : m_entries) {
|
||||
DestroyViewportEntry(entry);
|
||||
}
|
||||
|
||||
m_windowRenderer = nullptr;
|
||||
m_device = nullptr;
|
||||
m_surfacePresentationEnabled = false;
|
||||
}
|
||||
|
||||
const ViewportHostService::ViewportEntry& ViewportHostService::GetEntry(
|
||||
ViewportKind kind) const {
|
||||
const std::size_t index = kind == ViewportKind::Scene ? 0u : 1u;
|
||||
return m_entries[index];
|
||||
ViewportHostService::ViewportEntry& ViewportHostService::GetOrCreateEntry(
|
||||
std::string_view viewportId) {
|
||||
const auto [it, inserted] =
|
||||
m_entries.try_emplace(std::string(viewportId));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void ViewportHostService::DestroyViewportEntry(ViewportEntry& entry) {
|
||||
m_renderTargetManager.DestroyTargets(
|
||||
m_textureDescriptorAllocator.get(),
|
||||
m_windowRenderer,
|
||||
entry.renderTargets);
|
||||
entry = {};
|
||||
}
|
||||
|
||||
void ViewportHostService::EnsureSceneRenderer() {
|
||||
if (!m_sceneRenderer) {
|
||||
m_sceneRenderer = std::make_unique<::XCEngine::Rendering::SceneRenderer>();
|
||||
}
|
||||
entry.requestedWidth = 0;
|
||||
entry.requestedHeight = 0;
|
||||
entry.requestedThisFrame = false;
|
||||
entry.renderedThisFrame = false;
|
||||
entry.renderTargets = {};
|
||||
entry.statusText.clear();
|
||||
}
|
||||
|
||||
ViewportFrame ViewportHostService::RequestViewport(
|
||||
ViewportKind kind,
|
||||
std::string_view viewportId,
|
||||
const ::XCEngine::UI::UISize& requestedSize) {
|
||||
ViewportEntry& entry = GetEntry(kind);
|
||||
ViewportEntry& entry = GetOrCreateEntry(viewportId);
|
||||
entry.requestedThisFrame = requestedSize.width > 1.0f && requestedSize.height > 1.0f;
|
||||
entry.requestedWidth = entry.requestedThisFrame
|
||||
? static_cast<std::uint32_t>(requestedSize.width)
|
||||
@@ -143,42 +123,31 @@ ViewportFrame ViewportHostService::RequestViewport(
|
||||
return BuildFrame(entry, requestedSize);
|
||||
}
|
||||
|
||||
ViewportObjectIdPickResult ViewportHostService::PickSceneViewportObject(
|
||||
const ::XCEngine::UI::UISize& viewportSize,
|
||||
const ::XCEngine::UI::UIPoint& viewportMousePosition) {
|
||||
if (!m_sceneViewportRenderRequest.IsValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
ViewportEntry& entry = GetEntry(ViewportKind::Scene);
|
||||
const ViewportObjectIdPickResult objectIdPick =
|
||||
PickSceneViewportObjectWithObjectId(
|
||||
entry,
|
||||
viewportSize,
|
||||
viewportMousePosition);
|
||||
if (objectIdPick.status == ViewportObjectIdPickStatus::ReadbackFailed) {
|
||||
SetViewportStatusIfEmpty(
|
||||
entry.statusText,
|
||||
"Scene object id readback failed");
|
||||
}
|
||||
return objectIdPick;
|
||||
}
|
||||
|
||||
void ViewportHostService::RenderRequestedViewports(
|
||||
const ::XCEngine::Rendering::RenderContext& renderContext) {
|
||||
if (m_windowRenderer == nullptr || m_device == nullptr || !renderContext.IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_sceneViewportLastRenderContext = renderContext;
|
||||
|
||||
for (ViewportEntry& entry : m_entries) {
|
||||
for (auto& [viewportId, entry] : m_entries) {
|
||||
if (!entry.requestedThisFrame || !EnsureViewportResources(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.kind == ViewportKind::Scene) {
|
||||
RenderSceneViewport(entry, renderContext);
|
||||
IViewportContentRenderer* renderer = entry.renderer;
|
||||
if (renderer != nullptr) {
|
||||
const ViewportRenderResult renderResult =
|
||||
renderer->Render(
|
||||
entry.renderTargets,
|
||||
*m_device,
|
||||
renderContext);
|
||||
entry.statusText = renderResult.statusText;
|
||||
if (!renderResult.rendered && renderResult.requiresFallbackClear) {
|
||||
ApplyViewportFallback(
|
||||
entry,
|
||||
renderContext,
|
||||
renderResult);
|
||||
}
|
||||
} else {
|
||||
entry.statusText.clear();
|
||||
ClearViewport(entry, renderContext, 0.09f, 0.09f, 0.09f, 1.0f);
|
||||
@@ -191,7 +160,7 @@ void ViewportHostService::RenderRequestedViewports(
|
||||
bool ViewportHostService::EnsureViewportResources(ViewportEntry& entry) {
|
||||
const ViewportResourceReuseQuery reuseQuery =
|
||||
BuildViewportRenderTargetsReuseQuery(
|
||||
entry.kind,
|
||||
entry.requirements,
|
||||
entry.renderTargets,
|
||||
entry.requestedWidth,
|
||||
entry.requestedHeight);
|
||||
@@ -207,140 +176,27 @@ bool ViewportHostService::EnsureViewportResources(ViewportEntry& entry) {
|
||||
}
|
||||
|
||||
return m_renderTargetManager.EnsureTargets(
|
||||
entry.kind,
|
||||
entry.requirements,
|
||||
entry.requestedWidth,
|
||||
entry.requestedHeight,
|
||||
*m_device,
|
||||
*m_textureDescriptorAllocator,
|
||||
*m_windowRenderer,
|
||||
entry.renderTargets);
|
||||
}
|
||||
|
||||
bool ViewportHostService::RenderSceneViewport(
|
||||
ViewportEntry& entry,
|
||||
const ::XCEngine::Rendering::RenderContext& renderContext) {
|
||||
if (m_sceneViewportRenderRequest.camera == nullptr) {
|
||||
ApplySceneViewportFallback(
|
||||
entry,
|
||||
renderContext,
|
||||
"Scene view camera is unavailable",
|
||||
0.18f,
|
||||
0.07f,
|
||||
0.07f,
|
||||
1.0f);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_sceneViewportRenderRequest.scene == nullptr) {
|
||||
ApplySceneViewportFallback(
|
||||
entry,
|
||||
renderContext,
|
||||
"No active scene",
|
||||
0.07f,
|
||||
0.08f,
|
||||
0.10f,
|
||||
1.0f);
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureSceneRenderer();
|
||||
entry.statusText.clear();
|
||||
|
||||
::XCEngine::Rendering::RenderSurface surface =
|
||||
BuildViewportColorSurface(entry.renderTargets);
|
||||
std::vector<::XCEngine::Rendering::CameraFramePlan> plans =
|
||||
m_sceneRenderer->BuildFramePlans(
|
||||
*m_sceneViewportRenderRequest.scene,
|
||||
m_sceneViewportRenderRequest.camera,
|
||||
renderContext,
|
||||
surface);
|
||||
if (plans.empty()) {
|
||||
ApplySceneViewportFallback(
|
||||
entry,
|
||||
renderContext,
|
||||
"Scene renderer failed",
|
||||
0.18f,
|
||||
0.07f,
|
||||
0.07f,
|
||||
1.0f);
|
||||
return false;
|
||||
}
|
||||
|
||||
SceneViewportRenderPlanBuildResult renderPlan =
|
||||
m_sceneViewportRenderPassBundle.BuildRenderPlan(
|
||||
entry.renderTargets,
|
||||
m_sceneViewportRenderRequest);
|
||||
ApplySceneViewportRenderPlan(
|
||||
entry.renderTargets,
|
||||
renderPlan.plan,
|
||||
plans.front());
|
||||
if (renderPlan.warningStatusText != nullptr) {
|
||||
SetViewportStatusIfEmpty(entry.statusText, renderPlan.warningStatusText);
|
||||
}
|
||||
|
||||
if (!m_sceneRenderer->Render(plans)) {
|
||||
ApplySceneViewportFallback(
|
||||
entry,
|
||||
renderContext,
|
||||
"Scene renderer failed",
|
||||
0.18f,
|
||||
0.07f,
|
||||
0.07f,
|
||||
1.0f);
|
||||
return false;
|
||||
}
|
||||
|
||||
MarkSceneViewportRenderSuccess(
|
||||
entry.renderTargets,
|
||||
renderPlan.plan,
|
||||
plans.front());
|
||||
return true;
|
||||
}
|
||||
|
||||
ViewportObjectIdPickResult ViewportHostService::PickSceneViewportObjectWithObjectId(
|
||||
ViewportEntry& entry,
|
||||
const ::XCEngine::UI::UISize& viewportSize,
|
||||
const ::XCEngine::UI::UIPoint& viewportMousePosition) {
|
||||
if (m_device == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
ViewportObjectIdPickContext pickContext = {};
|
||||
pickContext.commandQueue = m_sceneViewportLastRenderContext.commandQueue;
|
||||
pickContext.texture = entry.renderTargets.objectIdTexture;
|
||||
pickContext.textureState = entry.renderTargets.objectIdState;
|
||||
pickContext.textureWidth = entry.renderTargets.width;
|
||||
pickContext.textureHeight = entry.renderTargets.height;
|
||||
pickContext.hasValidFrame = entry.renderTargets.hasValidObjectIdFrame;
|
||||
pickContext.viewportSize = viewportSize;
|
||||
pickContext.viewportMousePosition = viewportMousePosition;
|
||||
|
||||
return PickViewportObjectIdEntity(
|
||||
pickContext,
|
||||
[this](
|
||||
const ViewportObjectIdReadbackRequest& request,
|
||||
std::array<std::uint8_t, 4>& outRgba) {
|
||||
return m_device != nullptr &&
|
||||
m_device->ReadTexturePixelRGBA8(
|
||||
request.commandQueue,
|
||||
request.texture,
|
||||
request.textureState,
|
||||
request.pixelX,
|
||||
request.pixelY,
|
||||
outRgba);
|
||||
});
|
||||
}
|
||||
|
||||
void ViewportHostService::ApplySceneViewportFallback(
|
||||
void ViewportHostService::ApplyViewportFallback(
|
||||
ViewportEntry& entry,
|
||||
const ::XCEngine::Rendering::RenderContext& renderContext,
|
||||
std::string statusText,
|
||||
float r,
|
||||
float g,
|
||||
float b,
|
||||
float a) {
|
||||
entry.statusText = std::move(statusText);
|
||||
const ViewportRenderResult& renderResult) {
|
||||
entry.statusText = renderResult.statusText;
|
||||
entry.renderTargets.hasValidObjectIdFrame = false;
|
||||
ClearViewport(entry, renderContext, r, g, b, a);
|
||||
ClearViewport(
|
||||
entry,
|
||||
renderContext,
|
||||
renderResult.fallbackClearR,
|
||||
renderResult.fallbackClearG,
|
||||
renderResult.fallbackClearB,
|
||||
renderResult.fallbackClearA);
|
||||
}
|
||||
|
||||
void ViewportHostService::ClearViewport(
|
||||
|
||||
Reference in New Issue
Block a user