512 lines
16 KiB
C++
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
|