refactor: split viewport host rendering paths
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user