refactor: split viewport host rendering paths

This commit is contained in:
2026-03-31 22:10:27 +08:00
parent e6076ecc5a
commit c17fcd450f

View File

@@ -300,6 +300,13 @@ private:
SceneViewportCameraController controller;
};
struct SceneViewportRenderState {
SceneViewportOverlayData overlay = {};
Rendering::RenderPassSequence postPasses;
Rendering::RenderCameraData cameraData = {};
std::vector<Rendering::VisibleRenderItem> selectionRenderables;
};
ViewportEntry& GetEntry(EditorViewportKind kind) {
const size_t index = kind == EditorViewportKind::Scene ? 0u : 1u;
m_entries[index].kind = kind;
@@ -378,6 +385,100 @@ private:
m_sceneViewCamera.controller.Focus(center);
}
RHI::TextureDesc BuildViewportTextureDesc(uint32_t width, uint32_t height, RHI::Format format) const {
RHI::TextureDesc desc = {};
desc.width = width;
desc.height = height;
desc.depth = 1;
desc.mipLevels = 1;
desc.arraySize = 1;
desc.format = static_cast<uint32_t>(format);
desc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
desc.sampleCount = 1;
desc.sampleQuality = 0;
desc.flags = 0;
return desc;
}
RHI::ResourceViewDesc BuildViewportTextureViewDesc(RHI::Format format) const {
RHI::ResourceViewDesc desc = {};
desc.format = static_cast<uint32_t>(format);
desc.dimension = RHI::ResourceViewDimension::Texture2D;
return desc;
}
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 CreateSceneViewportSelectionMaskResources(ViewportEntry& entry) {
const RHI::TextureDesc selectionMaskDesc =
BuildViewportTextureDesc(entry.width, entry.height, RHI::Format::R8G8B8A8_UNorm);
entry.selectionMaskTexture = m_device->CreateTexture(selectionMaskDesc);
if (entry.selectionMaskTexture == nullptr) {
return false;
}
const RHI::ResourceViewDesc selectionMaskViewDesc =
BuildViewportTextureViewDesc(RHI::Format::R8G8B8A8_UNorm);
entry.selectionMaskView = m_device->CreateRenderTargetView(
entry.selectionMaskTexture,
selectionMaskViewDesc);
if (entry.selectionMaskView == nullptr) {
return false;
}
entry.selectionMaskShaderView = m_device->CreateShaderResourceView(
entry.selectionMaskTexture,
selectionMaskViewDesc);
return entry.selectionMaskShaderView != nullptr;
}
bool CreateViewportTextureDescriptor(ViewportEntry& entry) {
m_backend->AllocateTextureDescriptor(&entry.imguiCpuHandle, &entry.imguiGpuHandle);
if (entry.imguiCpuHandle.ptr == 0 || entry.imguiGpuHandle.ptr == 0) {
return false;
}
auto* nativeTexture = static_cast<RHI::D3D12Texture*>(entry.colorTexture);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
m_device->GetDevice()->CreateShaderResourceView(
nativeTexture->GetResource(),
&srvDesc,
entry.imguiCpuHandle);
entry.textureId = static_cast<ImTextureID>(entry.imguiGpuHandle.ptr);
return true;
}
bool EnsureViewportResources(ViewportEntry& entry) {
if (entry.requestedWidth == 0 || entry.requestedHeight == 0) {
return false;
@@ -402,110 +503,26 @@ private:
entry.width = entry.requestedWidth;
entry.height = entry.requestedHeight;
RHI::TextureDesc colorDesc = {};
colorDesc.width = entry.width;
colorDesc.height = entry.height;
colorDesc.depth = 1;
colorDesc.mipLevels = 1;
colorDesc.arraySize = 1;
colorDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
colorDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
colorDesc.sampleCount = 1;
colorDesc.sampleQuality = 0;
colorDesc.flags = 0;
entry.colorTexture = m_device->CreateTexture(colorDesc);
if (entry.colorTexture == nullptr) {
if (!CreateViewportColorResources(entry)) {
DestroyViewportResources(entry);
return false;
}
RHI::ResourceViewDesc colorViewDesc = {};
colorViewDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
colorViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
entry.colorView = m_device->CreateRenderTargetView(entry.colorTexture, colorViewDesc);
if (entry.colorView == nullptr) {
if (!CreateViewportDepthResources(entry)) {
DestroyViewportResources(entry);
return false;
}
RHI::TextureDesc depthDesc = {};
depthDesc.width = entry.width;
depthDesc.height = entry.height;
depthDesc.depth = 1;
depthDesc.mipLevels = 1;
depthDesc.arraySize = 1;
depthDesc.format = static_cast<uint32_t>(RHI::Format::D24_UNorm_S8_UInt);
depthDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
depthDesc.sampleCount = 1;
depthDesc.sampleQuality = 0;
depthDesc.flags = 0;
entry.depthTexture = m_device->CreateTexture(depthDesc);
if (entry.depthTexture == nullptr) {
DestroyViewportResources(entry);
return false;
}
RHI::ResourceViewDesc depthViewDesc = {};
depthViewDesc.format = static_cast<uint32_t>(RHI::Format::D24_UNorm_S8_UInt);
depthViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
entry.depthView = m_device->CreateDepthStencilView(entry.depthTexture, depthViewDesc);
if (entry.depthView == nullptr) {
DestroyViewportResources(entry);
return false;
}
if (entry.kind == EditorViewportKind::Scene) {
RHI::TextureDesc selectionMaskDesc = {};
selectionMaskDesc.width = entry.width;
selectionMaskDesc.height = entry.height;
selectionMaskDesc.depth = 1;
selectionMaskDesc.mipLevels = 1;
selectionMaskDesc.arraySize = 1;
selectionMaskDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
selectionMaskDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
selectionMaskDesc.sampleCount = 1;
selectionMaskDesc.sampleQuality = 0;
selectionMaskDesc.flags = 0;
entry.selectionMaskTexture = m_device->CreateTexture(selectionMaskDesc);
if (entry.selectionMaskTexture == nullptr) {
if (entry.kind == EditorViewportKind::Scene &&
!CreateSceneViewportSelectionMaskResources(entry)) {
DestroyViewportResources(entry);
return false;
}
RHI::ResourceViewDesc selectionMaskViewDesc = {};
selectionMaskViewDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
selectionMaskViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
entry.selectionMaskView = m_device->CreateRenderTargetView(entry.selectionMaskTexture, selectionMaskViewDesc);
if (entry.selectionMaskView == nullptr) {
DestroyViewportResources(entry);
return false;
}
entry.selectionMaskShaderView = m_device->CreateShaderResourceView(entry.selectionMaskTexture, selectionMaskViewDesc);
if (entry.selectionMaskShaderView == nullptr) {
DestroyViewportResources(entry);
return false;
}
}
m_backend->AllocateTextureDescriptor(&entry.imguiCpuHandle, &entry.imguiGpuHandle);
if (entry.imguiCpuHandle.ptr == 0 || entry.imguiGpuHandle.ptr == 0) {
if (!CreateViewportTextureDescriptor(entry)) {
DestroyViewportResources(entry);
return false;
}
auto* nativeTexture = static_cast<RHI::D3D12Texture*>(entry.colorTexture);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
m_device->GetDevice()->CreateShaderResourceView(
nativeTexture->GetResource(),
&srvDesc,
entry.imguiCpuHandle);
entry.textureId = static_cast<ImTextureID>(entry.imguiGpuHandle.ptr);
entry.colorState = RHI::ResourceStates::Common;
entry.selectionMaskState = RHI::ResourceStates::Common;
return true;
@@ -746,6 +763,110 @@ private:
return true;
}
void BuildSceneViewportRenderState(
ViewportEntry& entry,
IEditorContext& context,
const Components::Scene& scene,
SceneViewportRenderState& outState) {
outState.overlay = GetSceneViewOverlayData();
if (!outState.overlay.valid) {
return;
}
outState.selectionRenderables = CollectSceneViewportSelectionRenderables(
scene,
context.GetSelectionManager().GetSelectedEntities(),
outState.overlay.cameraPosition);
if (!outState.selectionRenderables.empty()) {
outState.cameraData = BuildSceneViewportCameraData(
*m_sceneViewCamera.camera,
entry.width,
entry.height);
}
BuildSceneViewPostPassSequence(
entry,
outState.overlay,
outState.cameraData,
outState.selectionRenderables,
outState.postPasses);
}
bool RenderSceneViewportEntry(
ViewportEntry& entry,
IEditorContext& context,
const Components::Scene* scene,
const Rendering::RenderContext& renderContext,
Rendering::RenderSurface& surface) {
surface.SetClearColorOverride(Math::Color(0.27f, 0.27f, 0.27f, 1.0f));
if (!EnsureSceneViewCamera()) {
entry.statusText = "Scene view camera is unavailable";
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return false;
}
ApplySceneViewCameraController();
entry.statusText.clear();
if (scene == nullptr) {
entry.statusText = "No active scene";
ClearViewport(entry, renderContext, 0.07f, 0.08f, 0.10f, 1.0f);
return false;
}
SceneViewportRenderState sceneState = {};
BuildSceneViewportRenderState(entry, context, *scene, sceneState);
std::vector<Rendering::CameraRenderRequest> requests =
m_sceneRenderer->BuildRenderRequests(*scene, m_sceneViewCamera.camera, renderContext, surface);
if (requests.empty()) {
SetViewportStatusIfEmpty(entry.statusText, "Scene renderer failed");
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return false;
}
if (sceneState.postPasses.GetPassCount() > 0) {
requests[0].postScenePasses = &sceneState.postPasses;
}
if (!m_sceneRenderer->Render(requests)) {
SetViewportStatusIfEmpty(entry.statusText, "Scene renderer failed");
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return false;
}
entry.colorState = RHI::ResourceStates::PixelShaderResource;
return true;
}
bool RenderGameViewportEntry(
ViewportEntry& entry,
const Components::Scene* scene,
const Rendering::RenderContext& renderContext,
const Rendering::RenderSurface& surface) {
if (scene == nullptr) {
entry.statusText = "No active scene";
ClearViewport(entry, renderContext, 0.07f, 0.08f, 0.10f, 1.0f);
return false;
}
const auto cameras = scene->FindObjectsOfType<Components::CameraComponent>();
if (cameras.empty()) {
entry.statusText = "No camera in scene";
ClearViewport(entry, renderContext, 0.10f, 0.09f, 0.08f, 1.0f);
return false;
}
if (!m_sceneRenderer->Render(*scene, nullptr, renderContext, surface)) {
entry.statusText = "Scene renderer failed";
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return false;
}
entry.colorState = RHI::ResourceStates::PixelShaderResource;
entry.statusText.clear();
return true;
}
void RenderViewportEntry(
ViewportEntry& entry,
IEditorContext& context,
@@ -759,86 +880,11 @@ private:
Rendering::RenderSurface surface = BuildSurface(entry);
if (entry.kind == EditorViewportKind::Scene) {
surface.SetClearColorOverride(Math::Color(0.27f, 0.27f, 0.27f, 1.0f));
if (!EnsureSceneViewCamera()) {
entry.statusText = "Scene view camera is unavailable";
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return;
}
ApplySceneViewCameraController();
entry.statusText.clear();
if (scene == nullptr) {
entry.statusText = "No active scene";
ClearViewport(entry, renderContext, 0.07f, 0.08f, 0.10f, 1.0f);
return;
}
const SceneViewportOverlayData overlay = GetSceneViewOverlayData();
Rendering::RenderPassSequence sceneViewPostPasses;
Rendering::RenderCameraData cameraData = {};
std::vector<Rendering::VisibleRenderItem> selectionRenderables;
if (overlay.valid) {
selectionRenderables = CollectSceneViewportSelectionRenderables(
*scene,
context.GetSelectionManager().GetSelectedEntities(),
overlay.cameraPosition);
if (!selectionRenderables.empty()) {
cameraData = BuildSceneViewportCameraData(
*m_sceneViewCamera.camera,
entry.width,
entry.height);
}
BuildSceneViewPostPassSequence(
entry,
overlay,
cameraData,
selectionRenderables,
sceneViewPostPasses);
}
std::vector<Rendering::CameraRenderRequest> requests =
m_sceneRenderer->BuildRenderRequests(*scene, m_sceneViewCamera.camera, renderContext, surface);
if (requests.empty()) {
SetViewportStatusIfEmpty(entry.statusText, "Scene renderer failed");
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return;
}
if (sceneViewPostPasses.GetPassCount() > 0) {
requests[0].postScenePasses = &sceneViewPostPasses;
}
if (!m_sceneRenderer->Render(requests)) {
SetViewportStatusIfEmpty(entry.statusText, "Scene renderer failed");
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return;
}
entry.colorState = RHI::ResourceStates::PixelShaderResource;
RenderSceneViewportEntry(entry, context, scene, renderContext, surface);
return;
}
if (scene == nullptr) {
entry.statusText = "No active scene";
ClearViewport(entry, renderContext, 0.07f, 0.08f, 0.10f, 1.0f);
return;
}
const auto cameras = scene->FindObjectsOfType<Components::CameraComponent>();
if (cameras.empty()) {
entry.statusText = "No camera in scene";
ClearViewport(entry, renderContext, 0.10f, 0.09f, 0.08f, 1.0f);
return;
}
if (!m_sceneRenderer->Render(*scene, nullptr, renderContext, surface)) {
entry.statusText = "Scene renderer failed";
ClearViewport(entry, renderContext, 0.18f, 0.07f, 0.07f, 1.0f);
return;
}
entry.colorState = RHI::ResourceStates::PixelShaderResource;
entry.statusText.clear();
RenderGameViewportEntry(entry, scene, renderContext, surface);
}
void ClearViewport(