179 lines
5.0 KiB
C++
179 lines
5.0 KiB
C++
|
|
#include "Rendering/Viewport/SceneViewportRenderService.h"
|
||
|
|
|
||
|
|
#include <XCEngine/Rendering/Execution/SceneRenderer.h>
|
||
|
|
|
||
|
|
#include <utility>
|
||
|
|
|
||
|
|
namespace XCEngine::UI::Editor::App {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
ViewportRenderResult BuildFallbackResult(
|
||
|
|
std::string statusText,
|
||
|
|
float r,
|
||
|
|
float g,
|
||
|
|
float b,
|
||
|
|
float a) {
|
||
|
|
ViewportRenderResult result = {};
|
||
|
|
result.rendered = false;
|
||
|
|
result.requiresFallbackClear = true;
|
||
|
|
result.statusText = std::move(statusText);
|
||
|
|
result.fallbackClearR = r;
|
||
|
|
result.fallbackClearG = g;
|
||
|
|
result.fallbackClearB = b;
|
||
|
|
result.fallbackClearA = a;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
void SetStatusIfEmpty(
|
||
|
|
std::string& statusText,
|
||
|
|
std::string_view message) {
|
||
|
|
if (statusText.empty()) {
|
||
|
|
statusText = std::string(message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
SceneViewportRenderService::SceneViewportRenderService() = default;
|
||
|
|
|
||
|
|
SceneViewportRenderService::~SceneViewportRenderService() = default;
|
||
|
|
|
||
|
|
ViewportResourceRequirements
|
||
|
|
SceneViewportRenderService::GetViewportResourceRequirements() {
|
||
|
|
ViewportResourceRequirements requirements = {};
|
||
|
|
requirements.requiresDepthSampling = true;
|
||
|
|
requirements.requiresObjectIdSurface = true;
|
||
|
|
requirements.requiresSelectionMaskSurface = true;
|
||
|
|
return requirements;
|
||
|
|
}
|
||
|
|
|
||
|
|
void SceneViewportRenderService::Shutdown() {
|
||
|
|
m_renderRequest = {};
|
||
|
|
m_renderPassBundle.Shutdown();
|
||
|
|
m_sceneRenderer.reset();
|
||
|
|
m_device = nullptr;
|
||
|
|
m_lastTargets = nullptr;
|
||
|
|
m_lastRenderContext = {};
|
||
|
|
}
|
||
|
|
|
||
|
|
void SceneViewportRenderService::SetRenderRequest(
|
||
|
|
SceneViewportRenderRequest request) {
|
||
|
|
m_renderRequest = std::move(request);
|
||
|
|
}
|
||
|
|
|
||
|
|
ViewportRenderResult SceneViewportRenderService::Render(
|
||
|
|
ViewportRenderTargets& targets,
|
||
|
|
::XCEngine::RHI::RHIDevice& device,
|
||
|
|
const ::XCEngine::Rendering::RenderContext& renderContext) {
|
||
|
|
m_device = &device;
|
||
|
|
m_lastTargets = &targets;
|
||
|
|
m_lastRenderContext = renderContext;
|
||
|
|
|
||
|
|
if (m_renderRequest.camera == nullptr) {
|
||
|
|
return BuildFallbackResult(
|
||
|
|
"Scene view camera is unavailable",
|
||
|
|
0.18f,
|
||
|
|
0.07f,
|
||
|
|
0.07f,
|
||
|
|
1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_renderRequest.scene == nullptr) {
|
||
|
|
return BuildFallbackResult(
|
||
|
|
"No active scene",
|
||
|
|
0.07f,
|
||
|
|
0.08f,
|
||
|
|
0.10f,
|
||
|
|
1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
EnsureSceneRenderer();
|
||
|
|
|
||
|
|
::XCEngine::Rendering::RenderSurface surface =
|
||
|
|
BuildViewportColorSurface(targets);
|
||
|
|
std::vector<::XCEngine::Rendering::CameraFramePlan> plans =
|
||
|
|
m_sceneRenderer->BuildFramePlans(
|
||
|
|
*m_renderRequest.scene,
|
||
|
|
m_renderRequest.camera,
|
||
|
|
renderContext,
|
||
|
|
surface);
|
||
|
|
if (plans.empty()) {
|
||
|
|
return BuildFallbackResult(
|
||
|
|
"Scene renderer failed",
|
||
|
|
0.18f,
|
||
|
|
0.07f,
|
||
|
|
0.07f,
|
||
|
|
1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
ViewportRenderResult result = {};
|
||
|
|
SceneViewportRenderPlanBuildResult renderPlan =
|
||
|
|
m_renderPassBundle.BuildRenderPlan(targets, m_renderRequest);
|
||
|
|
ApplySceneViewportRenderPlan(
|
||
|
|
targets,
|
||
|
|
renderPlan.plan,
|
||
|
|
plans.front());
|
||
|
|
if (renderPlan.warningStatusText != nullptr) {
|
||
|
|
SetStatusIfEmpty(result.statusText, renderPlan.warningStatusText);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!m_sceneRenderer->Render(plans)) {
|
||
|
|
return BuildFallbackResult(
|
||
|
|
"Scene renderer failed",
|
||
|
|
0.18f,
|
||
|
|
0.07f,
|
||
|
|
0.07f,
|
||
|
|
1.0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
MarkSceneViewportRenderSuccess(
|
||
|
|
targets,
|
||
|
|
renderPlan.plan,
|
||
|
|
plans.front());
|
||
|
|
result.rendered = true;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
ViewportObjectIdPickResult SceneViewportRenderService::PickObject(
|
||
|
|
const ::XCEngine::UI::UISize& viewportSize,
|
||
|
|
const ::XCEngine::UI::UIPoint& viewportMousePosition) const {
|
||
|
|
if (!m_renderRequest.IsValid() ||
|
||
|
|
m_device == nullptr ||
|
||
|
|
m_lastTargets == nullptr) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
ViewportObjectIdPickContext pickContext = {};
|
||
|
|
pickContext.commandQueue = m_lastRenderContext.commandQueue;
|
||
|
|
pickContext.texture = m_lastTargets->objectIdTexture;
|
||
|
|
pickContext.textureState = m_lastTargets->objectIdState;
|
||
|
|
pickContext.textureWidth = m_lastTargets->width;
|
||
|
|
pickContext.textureHeight = m_lastTargets->height;
|
||
|
|
pickContext.hasValidFrame = m_lastTargets->hasValidObjectIdFrame;
|
||
|
|
pickContext.viewportSize = viewportSize;
|
||
|
|
pickContext.viewportMousePosition = viewportMousePosition;
|
||
|
|
|
||
|
|
return PickViewportObjectIdEntity(
|
||
|
|
pickContext,
|
||
|
|
[this](
|
||
|
|
const ViewportObjectIdReadbackRequest& request,
|
||
|
|
std::array<std::uint8_t, 4>& outRgba) {
|
||
|
|
return m_device->ReadTexturePixelRGBA8(
|
||
|
|
request.commandQueue,
|
||
|
|
request.texture,
|
||
|
|
request.textureState,
|
||
|
|
request.pixelX,
|
||
|
|
request.pixelY,
|
||
|
|
outRgba);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void SceneViewportRenderService::EnsureSceneRenderer() {
|
||
|
|
if (!m_sceneRenderer) {
|
||
|
|
m_sceneRenderer = std::make_unique<::XCEngine::Rendering::SceneRenderer>();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace XCEngine::UI::Editor::App
|