Files
XCEngine/engine/src/Rendering/Execution/CameraFramePlan.cpp

512 lines
16 KiB
C++

#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <atomic>
namespace XCEngine {
namespace Rendering {
namespace {
uint64_t AllocateCameraFramePlanId() {
static std::atomic<uint64_t> s_nextFramePlanId{ 1u };
uint64_t framePlanId =
s_nextFramePlanId.fetch_add(
1u,
std::memory_order_relaxed);
if (framePlanId == 0u) {
framePlanId =
s_nextFramePlanId.fetch_add(
1u,
std::memory_order_relaxed);
}
return framePlanId;
}
CameraFrameFullscreenStagePlan* GetMutableFullscreenStagePlan(
CameraFramePlan& plan,
CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::PostProcess:
return &plan.colorChain.postProcess;
case CameraFrameStage::FinalOutput:
return &plan.colorChain.finalOutput;
default:
return nullptr;
}
}
FullscreenPassRenderRequest* GetMutableFullscreenPassRequest(
CameraFramePlan& plan,
CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::PostProcess:
return &plan.postProcess;
case CameraFrameStage::FinalOutput:
return &plan.finalOutput;
default:
return nullptr;
}
}
bool DoesStageNeedGraphManagedSceneColor(
const CameraFrameFullscreenStagePlan& stagePlan) {
return stagePlan.requested &&
stagePlan.source == CameraFrameColorSource::MainSceneColor;
}
} // namespace
RenderSurface CameraFramePlan::BuildGraphManagedIntermediateSurfaceTemplate(
const RenderSurface& surface) {
RenderSurface graphManagedSurface = surface;
graphManagedSurface.SetColorAttachments({});
graphManagedSurface.SetAutoTransitionEnabled(false);
graphManagedSurface.SetColorStateBefore(RHI::ResourceStates::Common);
graphManagedSurface.SetColorStateAfter(RHI::ResourceStates::Common);
return graphManagedSurface;
}
RenderSurface CameraFramePlan::BuildCameraDepthOnlySurfaceTemplate(
const RenderSurface& surface) {
RenderSurface depthOnlySurface = surface;
depthOnlySurface.SetColorAttachments({});
depthOnlySurface.ClearClearColorOverride();
return depthOnlySurface;
}
CameraFramePlan CameraFramePlan::FromRequest(const CameraRenderRequest& request) {
CameraFramePlan plan = {};
plan.framePlanId = AllocateCameraFramePlanId();
plan.request = request;
plan.shadowCaster = request.shadowCaster;
plan.directionalShadow = request.directionalShadow;
plan.postProcess = request.postProcess;
plan.finalOutput = request.finalOutput;
plan.finalColorPolicy = request.finalColorPolicy;
plan.preScenePasses = request.preScenePasses;
plan.postScenePasses = request.postScenePasses;
plan.overlayPasses = request.overlayPasses;
plan.shadowCasterStage.requested =
request.shadowCaster.IsRequested() ||
request.directionalShadow.IsValid();
plan.depthOnlyStage.requested =
request.depthOnly.IsRequested();
plan.colorChain.postProcess.requested = request.postProcess.IsRequested();
plan.colorChain.finalOutput.requested = request.finalOutput.IsRequested();
return plan;
}
bool CameraFramePlan::IsValid() const {
return request.IsValid();
}
void CameraFramePlan::ConfigureGraphManagedSceneSurface() {
graphManagedSceneSurface =
BuildGraphManagedIntermediateSurfaceTemplate(request.surface);
}
void CameraFramePlan::ClearOwnedPostProcessSequence() {
if (postProcess.passes == m_ownedPostProcessSequence.get()) {
postProcess.passes = nullptr;
}
m_ownedPostProcessSequence.reset();
}
void CameraFramePlan::SetOwnedPostProcessSequence(
std::shared_ptr<RenderPassSequence> sequence) {
ClearOwnedPostProcessSequence();
m_ownedPostProcessSequence = std::move(sequence);
if (m_ownedPostProcessSequence != nullptr) {
postProcess.passes = m_ownedPostProcessSequence.get();
}
}
void CameraFramePlan::ClearOwnedFinalOutputSequence() {
if (finalOutput.passes == m_ownedFinalOutputSequence.get()) {
finalOutput.passes = nullptr;
}
m_ownedFinalOutputSequence.reset();
}
void CameraFramePlan::SetOwnedFinalOutputSequence(
std::shared_ptr<RenderPassSequence> sequence) {
ClearOwnedFinalOutputSequence();
m_ownedFinalOutputSequence = std::move(sequence);
if (m_ownedFinalOutputSequence != nullptr) {
finalOutput.passes = m_ownedFinalOutputSequence.get();
}
}
bool CameraFramePlan::UsesGraphManagedSceneColor() const {
return colorChain.usesGraphManagedSceneColor;
}
bool CameraFramePlan::UsesGraphManagedOutputColor(CameraFrameStage stage) const {
if (SupportsCameraFramePipelineGraphRecording(stage)) {
return UsesGraphManagedSceneColor();
}
if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan =
GetFullscreenStagePlan(stage);
fullscreenStagePlan != nullptr) {
return fullscreenStagePlan->usesGraphManagedOutputColor;
}
return false;
}
CameraFrameColorSource CameraFramePlan::ResolveStageColorSource(CameraFrameStage stage) const {
if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan =
GetFullscreenStagePlan(stage);
fullscreenStagePlan != nullptr) {
return fullscreenStagePlan->source;
}
return CameraFrameColorSource::ExplicitSurface;
}
bool CameraFramePlan::IsFullscreenStageRequested(CameraFrameStage stage) const {
if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan =
GetFullscreenStagePlan(stage);
fullscreenStagePlan != nullptr) {
return fullscreenStagePlan->requested;
}
return false;
}
bool CameraFramePlan::RequestFullscreenStage(
CameraFrameStage stage,
CameraFrameColorSource source,
bool usesGraphManagedOutputColor,
bool explicitlyConfigured) {
CameraFrameFullscreenStagePlan* const fullscreenStagePlan =
GetMutableFullscreenStagePlan(*this, stage);
FullscreenPassRenderRequest* const fullscreenRequest =
GetMutableFullscreenPassRequest(*this, stage);
if (fullscreenStagePlan == nullptr || fullscreenRequest == nullptr) {
return false;
}
fullscreenStagePlan->requested = true;
fullscreenStagePlan->source = source;
fullscreenStagePlan->usesGraphManagedOutputColor =
stage == CameraFrameStage::PostProcess
? usesGraphManagedOutputColor
: false;
fullscreenStagePlan->explicitlyConfigured =
fullscreenStagePlan->explicitlyConfigured ||
explicitlyConfigured;
if (source != CameraFrameColorSource::ExplicitSurface) {
fullscreenRequest->sourceSurface = {};
fullscreenRequest->sourceColorView = nullptr;
fullscreenRequest->sourceColorState = RHI::ResourceStates::Common;
}
if (stage == CameraFrameStage::PostProcess) {
fullscreenRequest->destinationSurface =
fullscreenStagePlan->usesGraphManagedOutputColor
? RenderSurface{}
: request.surface;
} else {
fullscreenRequest->destinationSurface = request.surface;
}
RefreshGraphManagedSceneSurfaceState();
return true;
}
void CameraFramePlan::ClearFullscreenStage(
CameraFrameStage stage,
bool explicitlyConfigured) {
if (stage == CameraFrameStage::PostProcess) {
ClearOwnedPostProcessSequence();
postProcess = {};
colorChain.postProcess = {};
colorChain.postProcess.explicitlyConfigured =
explicitlyConfigured;
} else if (stage == CameraFrameStage::FinalOutput) {
ClearOwnedFinalOutputSequence();
finalOutput = {};
colorChain.finalOutput = {};
colorChain.finalOutput.explicitlyConfigured =
explicitlyConfigured;
} else {
return;
}
RefreshGraphManagedSceneSurfaceState();
}
bool CameraFramePlan::RequestShadowCasterStage(
bool explicitlyConfigured) {
shadowCasterStage.requested =
shadowCaster.IsRequested() ||
directionalShadow.IsValid();
shadowCasterStage.explicitlyConfigured =
shadowCasterStage.explicitlyConfigured ||
explicitlyConfigured;
return shadowCasterStage.requested;
}
void CameraFramePlan::ClearShadowCasterStage(
bool explicitlyConfigured) {
shadowCasterStage.requested = false;
shadowCasterStage.explicitlyConfigured =
shadowCasterStage.explicitlyConfigured ||
explicitlyConfigured;
}
bool CameraFramePlan::RequestDepthOnlyStage(
bool explicitlyConfigured) {
depthOnlyStage.requested =
request.depthOnly.IsRequested();
depthOnlyStage.explicitlyConfigured =
depthOnlyStage.explicitlyConfigured ||
explicitlyConfigured;
return depthOnlyStage.requested;
}
void CameraFramePlan::ClearDepthOnlyStage(
bool explicitlyConfigured) {
depthOnlyStage.requested = false;
depthOnlyStage.explicitlyConfigured =
depthOnlyStage.explicitlyConfigured ||
explicitlyConfigured;
}
bool CameraFramePlan::HasExplicitFullscreenStageConfiguration(
CameraFrameStage stage) const {
if (const CameraFrameFullscreenStagePlan* fullscreenStagePlan =
GetFullscreenStagePlan(stage);
fullscreenStagePlan != nullptr) {
return fullscreenStagePlan->explicitlyConfigured;
}
return false;
}
bool CameraFramePlan::HasExplicitShadowCasterStageConfiguration() const {
return shadowCasterStage.explicitlyConfigured;
}
bool CameraFramePlan::HasExplicitDepthOnlyStageConfiguration() const {
return depthOnlyStage.explicitlyConfigured;
}
bool CameraFramePlan::IsShadowCasterStageRequested() const {
return shadowCasterStage.requested;
}
bool CameraFramePlan::IsDepthOnlyStageRequested() const {
return depthOnlyStage.requested;
}
bool CameraFramePlan::IsPostProcessStageValid() const {
if (!IsFullscreenStageRequested(CameraFrameStage::PostProcess)) {
return true;
}
const CameraFrameColorSource postProcessSource =
ResolveStageColorSource(CameraFrameStage::PostProcess);
if (postProcessSource == CameraFrameColorSource::ExplicitSurface) {
return postProcess.IsValid();
}
if (postProcessSource != CameraFrameColorSource::MainSceneColor) {
return false;
}
const bool hasUsableDestination =
UsesGraphManagedOutputColor(CameraFrameStage::PostProcess) ||
(HasValidColorTarget(postProcess.destinationSurface) &&
HasValidSurfaceSampleDescription(postProcess.destinationSurface));
return UsesGraphManagedOutputColor(CameraFrameStage::MainScene) &&
HasValidSingleSampleColorSource(request.surface) &&
hasUsableDestination;
}
bool CameraFramePlan::IsFinalOutputStageValid() const {
if (!IsFullscreenStageRequested(CameraFrameStage::FinalOutput)) {
return true;
}
const CameraFrameColorSource finalOutputSource =
ResolveStageColorSource(CameraFrameStage::FinalOutput);
if (finalOutputSource == CameraFrameColorSource::ExplicitSurface) {
return finalOutput.IsValid();
}
const bool hasUsableSource =
finalOutputSource == CameraFrameColorSource::MainSceneColor
? UsesGraphManagedOutputColor(CameraFrameStage::MainScene)
: UsesGraphManagedOutputColor(CameraFrameStage::PostProcess);
return hasUsableSource &&
HasValidColorTarget(finalOutput.destinationSurface) &&
HasValidSurfaceSampleDescription(finalOutput.destinationSurface);
}
bool CameraFramePlan::HasFrameStage(CameraFrameStage stage) const {
if (SupportsCameraFramePipelineGraphRecording(stage)) {
return true;
}
if (IsCameraFrameSequenceStage(stage)) {
if (IsCameraFrameFullscreenSequenceStage(stage)) {
return IsFullscreenStageRequested(stage);
}
if (const FullscreenPassRenderRequest* fullscreenRequest =
GetFullscreenPassRequest(stage);
fullscreenRequest != nullptr) {
return fullscreenRequest->IsRequested();
}
return GetPassSequence(stage) != nullptr;
}
switch (GetCameraFrameStageRequestKind(stage)) {
case CameraFrameStageRequestKind::ShadowCaster:
return IsShadowCasterStageRequested();
case CameraFrameStageRequestKind::DepthOnly:
return IsDepthOnlyStageRequested();
case CameraFrameStageRequestKind::ObjectId:
return request.objectId.IsRequested();
default:
return false;
}
}
RenderPassSequence* CameraFramePlan::GetPassSequence(CameraFrameStage stage) const {
if (!IsCameraFrameSequenceStage(stage)) {
return nullptr;
}
switch (stage) {
case CameraFrameStage::PreScenePasses:
return preScenePasses;
case CameraFrameStage::PostProcess:
return postProcess.passes;
case CameraFrameStage::FinalOutput:
return finalOutput.passes;
case CameraFrameStage::PostScenePasses:
return postScenePasses;
case CameraFrameStage::OverlayPasses:
return overlayPasses;
default:
return nullptr;
}
}
const FullscreenPassRenderRequest* CameraFramePlan::GetFullscreenPassRequest(
CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return &postProcess;
case CameraFrameStage::FinalOutput:
return &finalOutput;
default:
return nullptr;
}
}
const CameraFrameFullscreenStagePlan* CameraFramePlan::GetFullscreenStagePlan(
CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return &colorChain.postProcess;
case CameraFrameStage::FinalOutput:
return &colorChain.finalOutput;
default:
return nullptr;
}
}
const ScenePassRenderRequest* CameraFramePlan::GetScenePassRequest(CameraFrameStage stage) const {
switch (GetCameraFrameStageRequestKind(stage)) {
case CameraFrameStageRequestKind::ShadowCaster:
return &shadowCaster;
case CameraFrameStageRequestKind::DepthOnly:
return &request.depthOnly;
default:
return nullptr;
}
}
const ObjectIdRenderRequest* CameraFramePlan::GetObjectIdRequest(CameraFrameStage stage) const {
return GetCameraFrameStageRequestKind(stage) ==
CameraFrameStageRequestKind::ObjectId
? &request.objectId
: nullptr;
}
const RenderSurface* CameraFramePlan::GetSharedStageOutputSurface(
CameraFrameStage stage) const {
switch (GetCameraFrameStageSharedOutputSurfaceRole(stage)) {
case CameraFrameStageSharedSurfaceRole::MainScene:
return &GetMainSceneSurface();
case CameraFrameStageSharedSurfaceRole::FinalComposited:
return &GetFinalCompositedSurface();
default:
return nullptr;
}
}
const RenderSurface& CameraFramePlan::GetMainSceneSurface() const {
if (UsesGraphManagedOutputColor(CameraFrameStage::MainScene) &&
graphManagedSceneSurface.GetWidth() > 0u &&
graphManagedSceneSurface.GetHeight() > 0u) {
return graphManagedSceneSurface;
}
if (IsFullscreenStageRequested(CameraFrameStage::PostProcess) &&
HasValidColorTarget(postProcess.sourceSurface)) {
return postProcess.sourceSurface;
}
if (IsFullscreenStageRequested(CameraFrameStage::FinalOutput) &&
HasValidColorTarget(finalOutput.sourceSurface)) {
return finalOutput.sourceSurface;
}
return request.surface;
}
const RenderSurface& CameraFramePlan::GetFinalCompositedSurface() const {
if (IsFullscreenStageRequested(CameraFrameStage::FinalOutput) &&
HasValidColorTarget(finalOutput.destinationSurface)) {
return finalOutput.destinationSurface;
}
if (IsFullscreenStageRequested(CameraFrameStage::PostProcess) &&
HasValidColorTarget(postProcess.destinationSurface)) {
return postProcess.destinationSurface;
}
return request.surface;
}
bool CameraFramePlan::RequiresIntermediateSceneColor() const {
return IsFullscreenStageRequested(CameraFrameStage::PostProcess) ||
IsFullscreenStageRequested(CameraFrameStage::FinalOutput);
}
void CameraFramePlan::RefreshGraphManagedSceneSurfaceState() {
colorChain.usesGraphManagedSceneColor =
DoesStageNeedGraphManagedSceneColor(colorChain.postProcess) ||
DoesStageNeedGraphManagedSceneColor(colorChain.finalOutput);
if (colorChain.usesGraphManagedSceneColor) {
ConfigureGraphManagedSceneSurface();
} else {
graphManagedSceneSurface = {};
}
}
} // namespace Rendering
} // namespace XCEngine