refactor: extract viewport render targets
This commit is contained in:
@@ -6,8 +6,8 @@
|
||||
#include "IViewportHostService.h"
|
||||
#include "SceneViewportPicker.h"
|
||||
#include "SceneViewportCameraController.h"
|
||||
#include "ViewportHostRenderTargets.h"
|
||||
#include "ViewportObjectIdPicker.h"
|
||||
#include "ViewportHostSurfaceUtils.h"
|
||||
#include "UI/ImGuiBackendBridge.h"
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
|
||||
void Shutdown() {
|
||||
for (ViewportEntry& entry : m_entries) {
|
||||
DestroyViewportResources(entry);
|
||||
DestroyViewportRenderTargets(m_backend, entry.renderTargets);
|
||||
entry = {};
|
||||
}
|
||||
|
||||
@@ -158,10 +158,12 @@ public:
|
||||
}
|
||||
|
||||
EditorViewportFrame frame = {};
|
||||
frame.textureId = entry.textureId;
|
||||
frame.textureId = entry.renderTargets.textureId;
|
||||
frame.requestedSize = requestedSize;
|
||||
frame.renderSize = ImVec2(static_cast<float>(entry.width), static_cast<float>(entry.height));
|
||||
frame.hasTexture = entry.textureId != ImTextureID{};
|
||||
frame.renderSize = ImVec2(
|
||||
static_cast<float>(entry.renderTargets.width),
|
||||
static_cast<float>(entry.renderTargets.height));
|
||||
frame.hasTexture = entry.renderTargets.textureId != ImTextureID{};
|
||||
frame.wasRequested = entry.requestedThisFrame;
|
||||
frame.statusText = entry.statusText;
|
||||
return frame;
|
||||
@@ -302,24 +304,10 @@ public:
|
||||
private:
|
||||
struct ViewportEntry {
|
||||
EditorViewportKind kind = EditorViewportKind::Scene;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t requestedWidth = 0;
|
||||
uint32_t requestedHeight = 0;
|
||||
bool requestedThisFrame = false;
|
||||
RHI::RHITexture* colorTexture = nullptr;
|
||||
RHI::RHIResourceView* colorView = nullptr;
|
||||
RHI::RHITexture* depthTexture = nullptr;
|
||||
RHI::RHIResourceView* depthView = nullptr;
|
||||
RHI::RHITexture* objectIdTexture = nullptr;
|
||||
RHI::RHIResourceView* objectIdView = nullptr;
|
||||
RHI::RHIResourceView* objectIdShaderView = nullptr;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE imguiCpuHandle = {};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE imguiGpuHandle = {};
|
||||
ImTextureID textureId = {};
|
||||
RHI::ResourceStates colorState = RHI::ResourceStates::Common;
|
||||
RHI::ResourceStates objectIdState = RHI::ResourceStates::Common;
|
||||
bool hasValidObjectIdFrame = false;
|
||||
ViewportRenderTargets renderTargets = {};
|
||||
std::string statusText;
|
||||
};
|
||||
|
||||
@@ -413,81 +401,13 @@ private:
|
||||
m_sceneViewCamera.controller.Focus(center);
|
||||
}
|
||||
|
||||
bool CreateViewportColorResources(ViewportEntry& entry) {
|
||||
const RHI::TextureDesc colorDesc =
|
||||
BuildViewportTextureDesc(entry.width, entry.height, RHI::Format::R8G8B8A8_UNorm);
|
||||
entry.colorTexture = m_device->CreateTexture(colorDesc);
|
||||
if (entry.colorTexture == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RHI::ResourceViewDesc colorViewDesc =
|
||||
BuildViewportTextureViewDesc(RHI::Format::R8G8B8A8_UNorm);
|
||||
entry.colorView = m_device->CreateRenderTargetView(entry.colorTexture, colorViewDesc);
|
||||
return entry.colorView != nullptr;
|
||||
}
|
||||
|
||||
bool CreateViewportDepthResources(ViewportEntry& entry) {
|
||||
const RHI::TextureDesc depthDesc =
|
||||
BuildViewportTextureDesc(entry.width, entry.height, RHI::Format::D24_UNorm_S8_UInt);
|
||||
entry.depthTexture = m_device->CreateTexture(depthDesc);
|
||||
if (entry.depthTexture == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RHI::ResourceViewDesc depthViewDesc =
|
||||
BuildViewportTextureViewDesc(RHI::Format::D24_UNorm_S8_UInt);
|
||||
entry.depthView = m_device->CreateDepthStencilView(entry.depthTexture, depthViewDesc);
|
||||
return entry.depthView != nullptr;
|
||||
}
|
||||
|
||||
bool CreateSceneViewportObjectIdResources(ViewportEntry& entry) {
|
||||
const RHI::TextureDesc objectIdDesc =
|
||||
BuildViewportTextureDesc(entry.width, entry.height, RHI::Format::R8G8B8A8_UNorm);
|
||||
entry.objectIdTexture = m_device->CreateTexture(objectIdDesc);
|
||||
if (entry.objectIdTexture == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RHI::ResourceViewDesc objectIdViewDesc =
|
||||
BuildViewportTextureViewDesc(RHI::Format::R8G8B8A8_UNorm);
|
||||
entry.objectIdView = m_device->CreateRenderTargetView(
|
||||
entry.objectIdTexture,
|
||||
objectIdViewDesc);
|
||||
if (entry.objectIdView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.objectIdShaderView = m_device->CreateShaderResourceView(
|
||||
entry.objectIdTexture,
|
||||
objectIdViewDesc);
|
||||
return entry.objectIdShaderView != nullptr;
|
||||
}
|
||||
|
||||
bool CreateViewportTextureDescriptor(ViewportEntry& entry) {
|
||||
return m_backend->CreateTextureDescriptor(
|
||||
m_device,
|
||||
entry.colorTexture,
|
||||
&entry.imguiCpuHandle,
|
||||
&entry.imguiGpuHandle,
|
||||
&entry.textureId);
|
||||
}
|
||||
|
||||
bool EnsureViewportResources(ViewportEntry& entry) {
|
||||
ViewportHostResourceReuseQuery reuseQuery = {};
|
||||
reuseQuery.kind = entry.kind;
|
||||
reuseQuery.width = entry.width;
|
||||
reuseQuery.height = entry.height;
|
||||
reuseQuery.requestedWidth = entry.requestedWidth;
|
||||
reuseQuery.requestedHeight = entry.requestedHeight;
|
||||
reuseQuery.resources.hasColorTexture = entry.colorTexture != nullptr;
|
||||
reuseQuery.resources.hasColorView = entry.colorView != nullptr;
|
||||
reuseQuery.resources.hasDepthTexture = entry.depthTexture != nullptr;
|
||||
reuseQuery.resources.hasDepthView = entry.depthView != nullptr;
|
||||
reuseQuery.resources.hasObjectIdTexture = entry.objectIdTexture != nullptr;
|
||||
reuseQuery.resources.hasObjectIdView = entry.objectIdView != nullptr;
|
||||
reuseQuery.resources.hasObjectIdShaderView = entry.objectIdShaderView != nullptr;
|
||||
reuseQuery.resources.hasTextureDescriptor = entry.textureId != ImTextureID{};
|
||||
const ViewportHostResourceReuseQuery reuseQuery =
|
||||
BuildViewportRenderTargetsReuseQuery(
|
||||
entry.kind,
|
||||
entry.renderTargets,
|
||||
entry.requestedWidth,
|
||||
entry.requestedHeight);
|
||||
if (CanReuseViewportResources(reuseQuery)) {
|
||||
return true;
|
||||
}
|
||||
@@ -496,53 +416,21 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
DestroyViewportResources(entry);
|
||||
|
||||
entry.width = entry.requestedWidth;
|
||||
entry.height = entry.requestedHeight;
|
||||
|
||||
if (!CreateViewportColorResources(entry)) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateViewportDepthResources(entry)) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ViewportRequiresObjectIdResources(entry.kind) &&
|
||||
!CreateSceneViewportObjectIdResources(entry)) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateViewportTextureDescriptor(entry)) {
|
||||
DestroyViewportResources(entry);
|
||||
return false;
|
||||
}
|
||||
entry.colorState = RHI::ResourceStates::Common;
|
||||
entry.objectIdState = RHI::ResourceStates::Common;
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
return true;
|
||||
return CreateViewportRenderTargets(
|
||||
entry.kind,
|
||||
entry.requestedWidth,
|
||||
entry.requestedHeight,
|
||||
m_device,
|
||||
m_backend,
|
||||
entry.renderTargets);
|
||||
}
|
||||
|
||||
Rendering::RenderSurface BuildSurface(const ViewportEntry& entry) const {
|
||||
return BuildViewportRenderSurface(
|
||||
entry.width,
|
||||
entry.height,
|
||||
entry.colorView,
|
||||
entry.depthView,
|
||||
entry.colorState);
|
||||
return BuildViewportColorSurface(entry.renderTargets);
|
||||
}
|
||||
|
||||
Rendering::RenderSurface BuildObjectIdSurface(const ViewportEntry& entry) const {
|
||||
return BuildViewportRenderSurface(
|
||||
entry.width,
|
||||
entry.height,
|
||||
entry.objectIdView,
|
||||
entry.depthView,
|
||||
entry.objectIdState);
|
||||
return BuildViewportObjectIdSurface(entry.renderTargets);
|
||||
}
|
||||
|
||||
void AddSceneColorToRenderTargetPass(
|
||||
@@ -552,10 +440,10 @@ private:
|
||||
"SceneColorToRenderTarget",
|
||||
[&entry](const Rendering::RenderPassContext& context) {
|
||||
context.renderContext.commandList->TransitionBarrier(
|
||||
entry.colorView,
|
||||
entry.renderTargets.colorView,
|
||||
context.surface.GetColorStateAfter(),
|
||||
RHI::ResourceStates::RenderTarget);
|
||||
entry.colorState = RHI::ResourceStates::RenderTarget;
|
||||
entry.renderTargets.colorState = RHI::ResourceStates::RenderTarget;
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
@@ -588,7 +476,7 @@ private:
|
||||
const bool rendered = m_sceneSelectionOutlinePass.Render(
|
||||
context.renderContext,
|
||||
context.surface,
|
||||
entry.objectIdShaderView,
|
||||
entry.renderTargets.objectIdShaderView,
|
||||
selectedObjectIds,
|
||||
Rendering::Passes::ObjectIdOutlineStyle{
|
||||
Math::Color(1.0f, 0.4f, 0.0f, 1.0f),
|
||||
@@ -609,10 +497,10 @@ private:
|
||||
"SceneColorToShaderResource",
|
||||
[&entry](const Rendering::RenderPassContext& context) {
|
||||
context.renderContext.commandList->TransitionBarrier(
|
||||
entry.colorView,
|
||||
entry.renderTargets.colorView,
|
||||
RHI::ResourceStates::RenderTarget,
|
||||
context.surface.GetColorStateAfter());
|
||||
entry.colorState = context.surface.GetColorStateAfter();
|
||||
entry.renderTargets.colorState = context.surface.GetColorStateAfter();
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
@@ -626,14 +514,17 @@ private:
|
||||
[this, &entry, selectedObjectIds](
|
||||
const Rendering::RenderPassContext& context) {
|
||||
const float debugClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
RHI::RHIResourceView* colorView = entry.colorView;
|
||||
context.renderContext.commandList->SetRenderTargets(1, &colorView, entry.depthView);
|
||||
RHI::RHIResourceView* colorView = entry.renderTargets.colorView;
|
||||
context.renderContext.commandList->SetRenderTargets(
|
||||
1,
|
||||
&colorView,
|
||||
entry.renderTargets.depthView);
|
||||
context.renderContext.commandList->ClearRenderTarget(colorView, debugClearColor);
|
||||
|
||||
const bool rendered = m_sceneSelectionOutlinePass.Render(
|
||||
context.renderContext,
|
||||
context.surface,
|
||||
entry.objectIdShaderView,
|
||||
entry.renderTargets.objectIdShaderView,
|
||||
selectedObjectIds,
|
||||
Rendering::Passes::ObjectIdOutlineStyle{
|
||||
Math::Color(1.0f, 0.4f, 0.0f, 1.0f),
|
||||
@@ -683,7 +574,7 @@ private:
|
||||
const std::vector<uint64_t>& selectedObjectIds,
|
||||
Rendering::RenderPassSequence& outPostPasses) {
|
||||
const bool hasSelection = !selectedObjectIds.empty();
|
||||
const bool hasObjectIdShaderView = entry.objectIdShaderView != nullptr;
|
||||
const bool hasObjectIdShaderView = entry.renderTargets.objectIdShaderView != nullptr;
|
||||
|
||||
if (hasSelection &&
|
||||
!kDebugSceneSelectionMask &&
|
||||
@@ -744,7 +635,7 @@ private:
|
||||
if (!EnsureSceneViewCamera()) {
|
||||
entry.statusText = "Scene view camera is unavailable";
|
||||
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
entry.renderTargets.hasValidObjectIdFrame = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -753,7 +644,7 @@ private:
|
||||
if (scene == nullptr) {
|
||||
entry.statusText = "No active scene";
|
||||
ClearViewport(entry, renderContext, 0.07f, 0.08f, 0.10f, 1.0f);
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
entry.renderTargets.hasValidObjectIdFrame = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -765,7 +656,7 @@ private:
|
||||
if (requests.empty()) {
|
||||
SetViewportStatusIfEmpty(entry.statusText, "Scene renderer failed");
|
||||
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
entry.renderTargets.hasValidObjectIdFrame = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -773,7 +664,7 @@ private:
|
||||
requests[0].postScenePasses = &sceneState.postPasses;
|
||||
}
|
||||
|
||||
if (entry.objectIdView != nullptr) {
|
||||
if (entry.renderTargets.objectIdView != nullptr) {
|
||||
requests[0].objectId.surface = BuildObjectIdSurface(entry);
|
||||
requests[0].objectId.surface.SetRenderArea(requests[0].surface.GetRenderArea());
|
||||
}
|
||||
@@ -781,13 +672,13 @@ private:
|
||||
if (!m_sceneRenderer->Render(requests)) {
|
||||
SetViewportStatusIfEmpty(entry.statusText, "Scene renderer failed");
|
||||
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
entry.renderTargets.hasValidObjectIdFrame = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.objectIdState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.hasValidObjectIdFrame = requests[0].objectId.IsRequested();
|
||||
entry.renderTargets.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.renderTargets.objectIdState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.renderTargets.hasValidObjectIdFrame = requests[0].objectId.IsRequested();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -812,11 +703,11 @@ private:
|
||||
if (!m_sceneRenderer->Render(*scene, nullptr, renderContext, surface)) {
|
||||
entry.statusText = "Scene renderer failed";
|
||||
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
entry.renderTargets.hasValidObjectIdFrame = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.renderTargets.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.statusText.clear();
|
||||
return true;
|
||||
}
|
||||
@@ -826,7 +717,7 @@ private:
|
||||
IEditorContext& context,
|
||||
const Components::Scene* scene,
|
||||
const Rendering::RenderContext& renderContext) {
|
||||
if (entry.colorView == nullptr || entry.depthView == nullptr) {
|
||||
if (entry.renderTargets.colorView == nullptr || entry.renderTargets.depthView == nullptr) {
|
||||
entry.statusText = "Viewport render target is unavailable";
|
||||
return;
|
||||
}
|
||||
@@ -854,21 +745,22 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
ViewportRenderTargets& targets = entry.renderTargets;
|
||||
const float clearColor[4] = { r, g, b, a };
|
||||
RHI::RHIResourceView* colorView = entry.colorView;
|
||||
RHI::RHIResourceView* colorView = targets.colorView;
|
||||
commandList->TransitionBarrier(
|
||||
colorView,
|
||||
entry.colorState,
|
||||
targets.colorState,
|
||||
RHI::ResourceStates::RenderTarget);
|
||||
commandList->SetRenderTargets(1, &colorView, entry.depthView);
|
||||
commandList->SetRenderTargets(1, &colorView, targets.depthView);
|
||||
commandList->ClearRenderTarget(colorView, clearColor);
|
||||
commandList->ClearDepthStencil(entry.depthView, 1.0f, 0);
|
||||
commandList->ClearDepthStencil(targets.depthView, 1.0f, 0);
|
||||
commandList->TransitionBarrier(
|
||||
colorView,
|
||||
RHI::ResourceStates::RenderTarget,
|
||||
RHI::ResourceStates::PixelShaderResource);
|
||||
entry.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
targets.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||
targets.hasValidObjectIdFrame = false;
|
||||
}
|
||||
|
||||
bool TryPickSceneViewEntityWithObjectId(
|
||||
@@ -883,11 +775,11 @@ private:
|
||||
|
||||
ViewportObjectIdPickContext pickContext = {};
|
||||
pickContext.commandQueue = m_sceneViewLastRenderContext.commandQueue;
|
||||
pickContext.texture = entry.objectIdTexture;
|
||||
pickContext.textureState = entry.objectIdState;
|
||||
pickContext.textureWidth = entry.width;
|
||||
pickContext.textureHeight = entry.height;
|
||||
pickContext.hasValidFrame = entry.hasValidObjectIdFrame;
|
||||
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;
|
||||
|
||||
@@ -906,63 +798,6 @@ private:
|
||||
outEntityId);
|
||||
}
|
||||
|
||||
void DestroyViewportResources(ViewportEntry& entry) {
|
||||
if (m_backend != nullptr && entry.imguiCpuHandle.ptr != 0) {
|
||||
m_backend->FreeTextureDescriptor(entry.imguiCpuHandle, entry.imguiGpuHandle);
|
||||
}
|
||||
|
||||
if (entry.objectIdView != nullptr) {
|
||||
entry.objectIdView->Shutdown();
|
||||
delete entry.objectIdView;
|
||||
entry.objectIdView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.objectIdShaderView != nullptr) {
|
||||
entry.objectIdShaderView->Shutdown();
|
||||
delete entry.objectIdShaderView;
|
||||
entry.objectIdShaderView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.objectIdTexture != nullptr) {
|
||||
entry.objectIdTexture->Shutdown();
|
||||
delete entry.objectIdTexture;
|
||||
entry.objectIdTexture = nullptr;
|
||||
}
|
||||
|
||||
if (entry.depthView != nullptr) {
|
||||
entry.depthView->Shutdown();
|
||||
delete entry.depthView;
|
||||
entry.depthView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.depthTexture != nullptr) {
|
||||
entry.depthTexture->Shutdown();
|
||||
delete entry.depthTexture;
|
||||
entry.depthTexture = nullptr;
|
||||
}
|
||||
|
||||
if (entry.colorView != nullptr) {
|
||||
entry.colorView->Shutdown();
|
||||
delete entry.colorView;
|
||||
entry.colorView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.colorTexture != nullptr) {
|
||||
entry.colorTexture->Shutdown();
|
||||
delete entry.colorTexture;
|
||||
entry.colorTexture = nullptr;
|
||||
}
|
||||
|
||||
entry.width = 0;
|
||||
entry.height = 0;
|
||||
entry.imguiCpuHandle = {};
|
||||
entry.imguiGpuHandle = {};
|
||||
entry.textureId = {};
|
||||
entry.colorState = RHI::ResourceStates::Common;
|
||||
entry.objectIdState = RHI::ResourceStates::Common;
|
||||
entry.hasValidObjectIdFrame = false;
|
||||
}
|
||||
|
||||
UI::ImGuiBackendBridge* m_backend = nullptr;
|
||||
RHI::RHIDevice* m_device = nullptr;
|
||||
std::unique_ptr<Rendering::SceneRenderer> m_sceneRenderer;
|
||||
|
||||
Reference in New Issue
Block a user