Separate request and frame-stage execution contracts

This commit is contained in:
2026-04-14 00:30:15 +08:00
parent c3d443eb85
commit 21b0530f7b
7 changed files with 248 additions and 346 deletions

View File

@@ -479,10 +479,12 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraFramePlan.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraFrameStage.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraRenderer.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/DirectionalShadowExecutionState.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/DrawSettings.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/FrameExecutionContext.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/FrameStageRenderRequest.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/ScenePhase.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/SceneRenderer.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/CullingResults.h

View File

@@ -1,5 +1,6 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraFrameStage.h>
#include <XCEngine/Rendering/Planning/CameraRenderRequest.h>
namespace XCEngine {
@@ -76,6 +77,21 @@ struct CameraFramePlan {
}
}
const ScenePassRenderRequest* GetScenePassRequest(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::ShadowCaster:
return &shadowCaster;
case CameraFrameStage::DepthOnly:
return &request.depthOnly;
default:
return nullptr;
}
}
const ObjectIdRenderRequest* GetObjectIdRequest(CameraFrameStage stage) const {
return stage == CameraFrameStage::ObjectId ? &request.objectId : nullptr;
}
const RenderSurface& GetMainSceneSurface() const {
if (postProcess.IsRequested()) {
return postProcess.sourceSurface;

View File

@@ -0,0 +1,65 @@
#pragma once
#include <array>
#include <cstdint>
namespace XCEngine {
namespace Rendering {
enum class CameraFrameStage : uint8_t {
PreScenePasses,
ShadowCaster,
DepthOnly,
MainScene,
PostProcess,
FinalOutput,
ObjectId,
PostScenePasses,
OverlayPasses
};
struct CameraFrameStageInfo {
CameraFrameStage stage = CameraFrameStage::MainScene;
const char* name = "";
bool runtimeStage = true;
};
inline constexpr std::array<CameraFrameStageInfo, 9> kOrderedCameraFrameStages = { {
{ CameraFrameStage::PreScenePasses, "PreScenePasses", false },
{ CameraFrameStage::ShadowCaster, "ShadowCaster", true },
{ CameraFrameStage::DepthOnly, "DepthOnly", true },
{ CameraFrameStage::MainScene, "MainScene", true },
{ CameraFrameStage::PostProcess, "PostProcess", true },
{ CameraFrameStage::FinalOutput, "FinalOutput", true },
{ CameraFrameStage::ObjectId, "ObjectId", false },
{ CameraFrameStage::PostScenePasses, "PostScenePasses", false },
{ CameraFrameStage::OverlayPasses, "OverlayPasses", false }
} };
inline constexpr const char* GetCameraFrameStageName(CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::PreScenePasses:
return "PreScenePasses";
case CameraFrameStage::ShadowCaster:
return "ShadowCaster";
case CameraFrameStage::DepthOnly:
return "DepthOnly";
case CameraFrameStage::MainScene:
return "MainScene";
case CameraFrameStage::PostProcess:
return "PostProcess";
case CameraFrameStage::FinalOutput:
return "FinalOutput";
case CameraFrameStage::ObjectId:
return "ObjectId";
case CameraFrameStage::PostScenePasses:
return "PostScenePasses";
case CameraFrameStage::OverlayPasses:
return "OverlayPasses";
default:
return "Unknown";
}
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -1,6 +1,6 @@
#pragma once
#include <XCEngine/Rendering/Planning/CameraRenderRequest.h>
#include <XCEngine/Rendering/Execution/FrameStageRenderRequest.h>
#include <XCEngine/Rendering/Shadow/DirectionalShadowData.h>
namespace XCEngine {

View File

@@ -0,0 +1,116 @@
#pragma once
#include <XCEngine/Rendering/FrameData/RenderCameraData.h>
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <cstdint>
namespace XCEngine {
namespace RHI {
class RHIResourceView;
} // namespace RHI
namespace Rendering {
struct ScenePassRenderRequest {
RenderSurface surface;
RenderClearFlags clearFlags = RenderClearFlags::Depth;
bool hasClearColorOverride = false;
Math::Color clearColorOverride = Math::Color::Black();
bool hasCameraDataOverride = false;
RenderCameraData cameraDataOverride = {};
bool IsRequested() const {
return surface.GetDepthAttachment() != nullptr ||
!surface.GetColorAttachments().empty();
}
bool IsValid() const {
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
return surface.GetDepthAttachment() != nullptr &&
(colorAttachments.empty() || colorAttachments[0] != nullptr) &&
surface.GetRenderAreaWidth() > 0 &&
surface.GetRenderAreaHeight() > 0;
}
};
using DepthOnlyRenderRequest = ScenePassRenderRequest;
using ShadowCasterRenderRequest = ScenePassRenderRequest;
inline bool HasValidColorTarget(const RenderSurface& surface) {
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
return !colorAttachments.empty() &&
colorAttachments[0] != nullptr &&
surface.GetRenderAreaWidth() > 0 &&
surface.GetRenderAreaHeight() > 0;
}
inline bool HasValidSurfaceSampleDescription(const RenderSurface& surface) {
const uint32_t sampleCount = surface.GetSampleCount();
const uint32_t sampleQuality = surface.GetSampleQuality();
return sampleCount > 0u &&
(sampleCount > 1u || sampleQuality == 0u);
}
inline bool HasValidSingleSampleColorSource(const RenderSurface& surface) {
return HasValidColorTarget(surface) &&
HasValidSurfaceSampleDescription(surface) &&
surface.GetSampleCount() == 1u &&
surface.GetSampleQuality() == 0u;
}
struct ObjectIdRenderRequest {
RenderSurface surface;
bool IsRequested() const {
return !surface.GetColorAttachments().empty();
}
bool IsValid() const {
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
return !colorAttachments.empty() &&
colorAttachments[0] != nullptr &&
surface.GetDepthAttachment() != nullptr &&
surface.GetRenderAreaWidth() > 0 &&
surface.GetRenderAreaHeight() > 0;
}
};
struct FullscreenPassRenderRequest {
RenderSurface sourceSurface;
RHI::RHIResourceView* sourceColorView = nullptr;
RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common;
RenderSurface destinationSurface;
RenderPassSequence* passes = nullptr;
size_t GetPassCount() const {
return passes != nullptr ? passes->GetPassCount() : 0u;
}
bool IsRequested() const {
return passes != nullptr;
}
bool RequiresIntermediateSurface() const {
return GetPassCount() > 1u;
}
bool IsValid() const {
const bool sourceStateIsUsable =
sourceSurface.IsAutoTransitionEnabled() ||
sourceColorState == RHI::ResourceStates::PixelShaderResource;
return passes != nullptr &&
HasValidSingleSampleColorSource(sourceSurface) &&
sourceColorView != nullptr &&
sourceStateIsUsable &&
HasValidColorTarget(destinationSurface) &&
HasValidSurfaceSampleDescription(destinationSurface);
}
};
using PostProcessRenderRequest = FullscreenPassRenderRequest;
using FinalOutputRenderRequest = FullscreenPassRenderRequest;
} // namespace Rendering
} // namespace XCEngine

View File

@@ -1,13 +1,10 @@
#pragma once
#include <XCEngine/Rendering/FrameData/RenderCameraData.h>
#include <XCEngine/Rendering/Execution/FrameStageRenderRequest.h>
#include <XCEngine/Rendering/Planning/FinalColorSettings.h>
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/Rendering/Shadow/DirectionalShadowData.h>
#include <array>
#include <cstdint>
namespace XCEngine {
@@ -16,166 +13,8 @@ class CameraComponent;
class Scene;
} // namespace Components
namespace RHI {
class RHIResourceView;
} // namespace RHI
namespace Rendering {
enum class CameraFrameStage : uint8_t {
PreScenePasses,
ShadowCaster,
DepthOnly,
MainScene,
PostProcess,
FinalOutput,
ObjectId,
PostScenePasses,
OverlayPasses
};
struct CameraFrameStageInfo {
CameraFrameStage stage = CameraFrameStage::MainScene;
const char* name = "";
bool runtimeStage = true;
};
inline constexpr std::array<CameraFrameStageInfo, 9> kOrderedCameraFrameStages = {{
{ CameraFrameStage::PreScenePasses, "PreScenePasses", false },
{ CameraFrameStage::ShadowCaster, "ShadowCaster", true },
{ CameraFrameStage::DepthOnly, "DepthOnly", true },
{ CameraFrameStage::MainScene, "MainScene", true },
{ CameraFrameStage::PostProcess, "PostProcess", true },
{ CameraFrameStage::FinalOutput, "FinalOutput", true },
{ CameraFrameStage::ObjectId, "ObjectId", false },
{ CameraFrameStage::PostScenePasses, "PostScenePasses", false },
{ CameraFrameStage::OverlayPasses, "OverlayPasses", false }
}};
inline constexpr const char* GetCameraFrameStageName(CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::PreScenePasses:
return "PreScenePasses";
case CameraFrameStage::ShadowCaster:
return "ShadowCaster";
case CameraFrameStage::DepthOnly:
return "DepthOnly";
case CameraFrameStage::MainScene:
return "MainScene";
case CameraFrameStage::PostProcess:
return "PostProcess";
case CameraFrameStage::FinalOutput:
return "FinalOutput";
case CameraFrameStage::ObjectId:
return "ObjectId";
case CameraFrameStage::PostScenePasses:
return "PostScenePasses";
case CameraFrameStage::OverlayPasses:
return "OverlayPasses";
default:
return "Unknown";
}
}
struct ScenePassRenderRequest {
RenderSurface surface;
RenderClearFlags clearFlags = RenderClearFlags::Depth;
bool hasClearColorOverride = false;
Math::Color clearColorOverride = Math::Color::Black();
bool hasCameraDataOverride = false;
RenderCameraData cameraDataOverride = {};
bool IsRequested() const {
return surface.GetDepthAttachment() != nullptr ||
!surface.GetColorAttachments().empty();
}
bool IsValid() const {
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
return surface.GetDepthAttachment() != nullptr &&
(colorAttachments.empty() || colorAttachments[0] != nullptr) &&
surface.GetRenderAreaWidth() > 0 &&
surface.GetRenderAreaHeight() > 0;
}
};
using DepthOnlyRenderRequest = ScenePassRenderRequest;
using ShadowCasterRenderRequest = ScenePassRenderRequest;
inline bool HasValidColorTarget(const RenderSurface& surface) {
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
return !colorAttachments.empty() &&
colorAttachments[0] != nullptr &&
surface.GetRenderAreaWidth() > 0 &&
surface.GetRenderAreaHeight() > 0;
}
inline bool HasValidSurfaceSampleDescription(const RenderSurface& surface) {
const uint32_t sampleCount = surface.GetSampleCount();
const uint32_t sampleQuality = surface.GetSampleQuality();
return sampleCount > 0u &&
(sampleCount > 1u || sampleQuality == 0u);
}
inline bool HasValidSingleSampleColorSource(const RenderSurface& surface) {
return HasValidColorTarget(surface) &&
HasValidSurfaceSampleDescription(surface) &&
surface.GetSampleCount() == 1u &&
surface.GetSampleQuality() == 0u;
}
struct ObjectIdRenderRequest {
RenderSurface surface;
bool IsRequested() const {
return !surface.GetColorAttachments().empty();
}
bool IsValid() const {
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
return !colorAttachments.empty() &&
colorAttachments[0] != nullptr &&
surface.GetDepthAttachment() != nullptr &&
surface.GetRenderAreaWidth() > 0 &&
surface.GetRenderAreaHeight() > 0;
}
};
struct FullscreenPassRenderRequest {
RenderSurface sourceSurface;
RHI::RHIResourceView* sourceColorView = nullptr;
RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common;
RenderSurface destinationSurface;
RenderPassSequence* passes = nullptr;
size_t GetPassCount() const {
return passes != nullptr ? passes->GetPassCount() : 0u;
}
bool IsRequested() const {
return passes != nullptr;
}
bool RequiresIntermediateSurface() const {
return GetPassCount() > 1u;
}
bool IsValid() const {
const bool sourceStateIsUsable =
sourceSurface.IsAutoTransitionEnabled() ||
sourceColorState == RHI::ResourceStates::PixelShaderResource;
return passes != nullptr &&
HasValidSingleSampleColorSource(sourceSurface) &&
sourceColorView != nullptr &&
sourceStateIsUsable &&
HasValidColorTarget(destinationSurface) &&
HasValidSurfaceSampleDescription(destinationSurface);
}
};
using PostProcessRenderRequest = FullscreenPassRenderRequest;
using FinalOutputRenderRequest = FullscreenPassRenderRequest;
struct CameraRenderRequest {
const Components::Scene* scene = nullptr;
Components::CameraComponent* camera = nullptr;
@@ -197,147 +36,6 @@ struct CameraRenderRequest {
RenderPassSequence* postScenePasses = nullptr;
RenderPassSequence* overlayPasses = nullptr;
bool HasFrameStage(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PreScenePasses:
return preScenePasses != nullptr;
case CameraFrameStage::ShadowCaster:
return shadowCaster.IsRequested() || directionalShadow.IsValid();
case CameraFrameStage::DepthOnly:
return depthOnly.IsRequested();
case CameraFrameStage::MainScene:
return true;
case CameraFrameStage::PostProcess:
return postProcess.IsRequested();
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested();
case CameraFrameStage::ObjectId:
return objectId.IsRequested();
case CameraFrameStage::PostScenePasses:
return postScenePasses != nullptr;
case CameraFrameStage::OverlayPasses:
return overlayPasses != nullptr;
default:
return false;
}
}
RenderPassSequence* GetPassSequence(CameraFrameStage stage) const {
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 ScenePassRenderRequest* GetScenePassRequest(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::ShadowCaster:
return &shadowCaster;
case CameraFrameStage::DepthOnly:
return &depthOnly;
default:
return nullptr;
}
}
const ObjectIdRenderRequest* GetObjectIdRequest(CameraFrameStage stage) const {
return stage == CameraFrameStage::ObjectId ? &objectId : nullptr;
}
const RenderSurface& GetMainSceneSurface() const {
if (postProcess.IsRequested()) {
return postProcess.sourceSurface;
}
if (finalOutput.IsRequested()) {
return finalOutput.sourceSurface;
}
return surface;
}
const RenderSurface& GetFinalCompositedSurface() const {
if (finalOutput.IsRequested()) {
return finalOutput.destinationSurface;
}
if (postProcess.IsRequested()) {
return postProcess.destinationSurface;
}
return surface;
}
const RenderSurface* GetOutputSurface(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PreScenePasses:
case CameraFrameStage::MainScene:
return &GetMainSceneSurface();
case CameraFrameStage::ShadowCaster:
return shadowCaster.IsRequested() ? &shadowCaster.surface : nullptr;
case CameraFrameStage::DepthOnly:
return depthOnly.IsRequested() ? &depthOnly.surface : nullptr;
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? &postProcess.destinationSurface : nullptr;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? &finalOutput.destinationSurface : nullptr;
case CameraFrameStage::ObjectId:
return objectId.IsRequested() ? &objectId.surface : nullptr;
case CameraFrameStage::PostScenePasses:
case CameraFrameStage::OverlayPasses:
return &GetFinalCompositedSurface();
default:
return nullptr;
}
}
const RenderSurface* GetSourceSurface(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? &postProcess.sourceSurface : nullptr;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? &finalOutput.sourceSurface : nullptr;
default:
return nullptr;
}
}
RHI::RHIResourceView* GetSourceColorView(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? postProcess.sourceColorView : nullptr;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? finalOutput.sourceColorView : nullptr;
default:
return nullptr;
}
}
RHI::ResourceStates GetSourceColorState(CameraFrameStage stage) const {
switch (stage) {
case CameraFrameStage::PostProcess:
return postProcess.IsRequested() ? postProcess.sourceColorState : RHI::ResourceStates::Common;
case CameraFrameStage::FinalOutput:
return finalOutput.IsRequested() ? finalOutput.sourceColorState : RHI::ResourceStates::Common;
default:
return RHI::ResourceStates::Common;
}
}
bool RequiresIntermediateSceneColor() const {
return postProcess.IsRequested() || finalOutput.IsRequested();
}
bool IsValid() const {
return scene != nullptr &&
camera != nullptr &&

View File

@@ -581,48 +581,49 @@ TEST(CameraRenderRequest_Test, ReportsFormalFrameStageContract) {
EXPECT_STREQ(GetCameraFrameStageName(CameraFrameStage::FinalOutput), "FinalOutput");
EXPECT_STREQ(GetCameraFrameStageName(CameraFrameStage::OverlayPasses), "OverlayPasses");
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::PreScenePasses));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::ShadowCaster));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::DepthOnly));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::MainScene));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::PostProcess));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::FinalOutput));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::ObjectId));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::PostScenePasses));
EXPECT_TRUE(request.HasFrameStage(CameraFrameStage::OverlayPasses));
const CameraFramePlan plan = CameraFramePlan::FromRequest(request);
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::PreScenePasses));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::ShadowCaster));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::DepthOnly));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::MainScene));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::PostProcess));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::FinalOutput));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::ObjectId));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::PostScenePasses));
EXPECT_TRUE(plan.HasFrameStage(CameraFrameStage::OverlayPasses));
EXPECT_EQ(request.GetPassSequence(CameraFrameStage::PreScenePasses), &prePasses);
EXPECT_EQ(request.GetPassSequence(CameraFrameStage::PostProcess), &postProcessPasses);
EXPECT_EQ(request.GetPassSequence(CameraFrameStage::FinalOutput), &finalOutputPasses);
EXPECT_EQ(request.GetPassSequence(CameraFrameStage::PostScenePasses), &postPasses);
EXPECT_EQ(request.GetPassSequence(CameraFrameStage::OverlayPasses), &overlayPasses);
EXPECT_EQ(request.GetScenePassRequest(CameraFrameStage::ShadowCaster), &request.shadowCaster);
EXPECT_EQ(request.GetScenePassRequest(CameraFrameStage::DepthOnly), &request.depthOnly);
EXPECT_EQ(request.GetScenePassRequest(CameraFrameStage::MainScene), nullptr);
EXPECT_EQ(request.GetObjectIdRequest(CameraFrameStage::ObjectId), &request.objectId);
EXPECT_EQ(request.GetObjectIdRequest(CameraFrameStage::MainScene), nullptr);
EXPECT_TRUE(request.RequiresIntermediateSceneColor());
EXPECT_EQ(request.GetMainSceneSurface().GetRenderAreaWidth(), 256u);
EXPECT_EQ(request.GetMainSceneSurface().GetRenderAreaHeight(), 128u);
EXPECT_EQ(request.GetFinalCompositedSurface().GetRenderAreaWidth(), 640u);
EXPECT_EQ(request.GetFinalCompositedSurface().GetRenderAreaHeight(), 360u);
ASSERT_NE(request.GetOutputSurface(CameraFrameStage::PostProcess), nullptr);
EXPECT_EQ(request.GetOutputSurface(CameraFrameStage::PostProcess)->GetRenderAreaWidth(), 512u);
ASSERT_NE(request.GetSourceSurface(CameraFrameStage::PostProcess), nullptr);
EXPECT_EQ(request.GetSourceSurface(CameraFrameStage::PostProcess)->GetRenderAreaWidth(), 256u);
EXPECT_EQ(plan.GetPassSequence(CameraFrameStage::PreScenePasses), &prePasses);
EXPECT_EQ(plan.GetPassSequence(CameraFrameStage::PostProcess), &postProcessPasses);
EXPECT_EQ(plan.GetPassSequence(CameraFrameStage::FinalOutput), &finalOutputPasses);
EXPECT_EQ(plan.GetPassSequence(CameraFrameStage::PostScenePasses), &postPasses);
EXPECT_EQ(plan.GetPassSequence(CameraFrameStage::OverlayPasses), &overlayPasses);
EXPECT_EQ(plan.GetScenePassRequest(CameraFrameStage::ShadowCaster), &plan.shadowCaster);
EXPECT_EQ(plan.GetScenePassRequest(CameraFrameStage::DepthOnly), &plan.request.depthOnly);
EXPECT_EQ(plan.GetScenePassRequest(CameraFrameStage::MainScene), nullptr);
EXPECT_EQ(plan.GetObjectIdRequest(CameraFrameStage::ObjectId), &plan.request.objectId);
EXPECT_EQ(plan.GetObjectIdRequest(CameraFrameStage::MainScene), nullptr);
EXPECT_TRUE(plan.RequiresIntermediateSceneColor());
EXPECT_EQ(plan.GetMainSceneSurface().GetRenderAreaWidth(), 256u);
EXPECT_EQ(plan.GetMainSceneSurface().GetRenderAreaHeight(), 128u);
EXPECT_EQ(plan.GetFinalCompositedSurface().GetRenderAreaWidth(), 640u);
EXPECT_EQ(plan.GetFinalCompositedSurface().GetRenderAreaHeight(), 360u);
ASSERT_NE(plan.GetOutputSurface(CameraFrameStage::PostProcess), nullptr);
EXPECT_EQ(plan.GetOutputSurface(CameraFrameStage::PostProcess)->GetRenderAreaWidth(), 512u);
ASSERT_NE(plan.GetSourceSurface(CameraFrameStage::PostProcess), nullptr);
EXPECT_EQ(plan.GetSourceSurface(CameraFrameStage::PostProcess)->GetRenderAreaWidth(), 256u);
EXPECT_EQ(
request.GetSourceColorView(CameraFrameStage::PostProcess),
plan.GetSourceColorView(CameraFrameStage::PostProcess),
reinterpret_cast<XCEngine::RHI::RHIResourceView*>(20));
EXPECT_EQ(
request.GetSourceColorState(CameraFrameStage::PostProcess),
plan.GetSourceColorState(CameraFrameStage::PostProcess),
XCEngine::RHI::ResourceStates::PixelShaderResource);
ASSERT_NE(request.GetSourceSurface(CameraFrameStage::FinalOutput), nullptr);
EXPECT_EQ(request.GetSourceSurface(CameraFrameStage::FinalOutput)->GetRenderAreaWidth(), 512u);
ASSERT_NE(plan.GetSourceSurface(CameraFrameStage::FinalOutput), nullptr);
EXPECT_EQ(plan.GetSourceSurface(CameraFrameStage::FinalOutput)->GetRenderAreaWidth(), 512u);
EXPECT_EQ(
request.GetSourceColorView(CameraFrameStage::FinalOutput),
plan.GetSourceColorView(CameraFrameStage::FinalOutput),
reinterpret_cast<XCEngine::RHI::RHIResourceView*>(40));
EXPECT_EQ(
request.GetSourceColorState(CameraFrameStage::FinalOutput),
plan.GetSourceColorState(CameraFrameStage::FinalOutput),
XCEngine::RHI::ResourceStates::PixelShaderResource);
}
@@ -2334,8 +2335,9 @@ TEST(SceneRenderer_Test, ReusesTrackedSceneColorStateAcrossFramesWhenPostProcess
std::vector<CameraRenderRequest> firstFrameRequests =
renderer.BuildRenderRequests(scene, nullptr, context, surface);
ASSERT_EQ(firstFrameRequests.size(), 1u);
CameraFramePlan firstFramePlan = CameraFramePlan::FromRequest(firstFrameRequests[0]);
EXPECT_EQ(
firstFrameRequests[0].GetMainSceneSurface().GetColorStateBefore(),
firstFramePlan.GetMainSceneSurface().GetColorStateBefore(),
XCEngine::RHI::ResourceStates::Common);
RenderPassSequence postProcessPasses;
@@ -2347,11 +2349,12 @@ TEST(SceneRenderer_Test, ReusesTrackedSceneColorStateAcrossFramesWhenPostProcess
const std::vector<CameraRenderRequest> secondFrameRequests =
renderer.BuildRenderRequests(scene, nullptr, context, surface);
ASSERT_EQ(secondFrameRequests.size(), 1u);
const CameraFramePlan secondFramePlan = CameraFramePlan::FromRequest(secondFrameRequests[0]);
EXPECT_EQ(
secondFrameRequests[0].GetMainSceneSurface().GetColorStateBefore(),
secondFramePlan.GetMainSceneSurface().GetColorStateBefore(),
XCEngine::RHI::ResourceStates::PixelShaderResource);
EXPECT_EQ(
secondFrameRequests[0].GetMainSceneSurface().GetColorStateAfter(),
secondFramePlan.GetMainSceneSurface().GetColorStateAfter(),
XCEngine::RHI::ResourceStates::PixelShaderResource);
delete depthView;
@@ -2402,13 +2405,14 @@ TEST(SceneRenderer_Test, ReusesTrackedPostProcessOutputStateAcrossFramesWhenFina
std::vector<CameraRenderRequest> firstFrameRequests =
renderer.BuildRenderRequests(scene, nullptr, context, surface);
ASSERT_EQ(firstFrameRequests.size(), 1u);
CameraFramePlan firstFramePlan = CameraFramePlan::FromRequest(firstFrameRequests[0]);
EXPECT_TRUE(firstFrameRequests[0].postProcess.IsRequested());
EXPECT_TRUE(firstFrameRequests[0].finalOutput.IsRequested());
EXPECT_EQ(
firstFrameRequests[0].GetMainSceneSurface().GetColorStateBefore(),
firstFramePlan.GetMainSceneSurface().GetColorStateBefore(),
XCEngine::RHI::ResourceStates::Common);
EXPECT_EQ(
firstFrameRequests[0].postProcess.destinationSurface.GetColorStateBefore(),
firstFramePlan.postProcess.destinationSurface.GetColorStateBefore(),
XCEngine::RHI::ResourceStates::Common);
RenderPassSequence postProcessPasses;
@@ -2423,14 +2427,15 @@ TEST(SceneRenderer_Test, ReusesTrackedPostProcessOutputStateAcrossFramesWhenFina
const std::vector<CameraRenderRequest> secondFrameRequests =
renderer.BuildRenderRequests(scene, nullptr, context, surface);
ASSERT_EQ(secondFrameRequests.size(), 1u);
const CameraFramePlan secondFramePlan = CameraFramePlan::FromRequest(secondFrameRequests[0]);
EXPECT_EQ(
secondFrameRequests[0].GetMainSceneSurface().GetColorStateBefore(),
secondFramePlan.GetMainSceneSurface().GetColorStateBefore(),
XCEngine::RHI::ResourceStates::PixelShaderResource);
EXPECT_EQ(
secondFrameRequests[0].postProcess.destinationSurface.GetColorStateBefore(),
secondFramePlan.postProcess.destinationSurface.GetColorStateBefore(),
XCEngine::RHI::ResourceStates::PixelShaderResource);
EXPECT_EQ(
secondFrameRequests[0].finalOutput.sourceSurface.GetColorStateBefore(),
secondFramePlan.finalOutput.sourceSurface.GetColorStateBefore(),
XCEngine::RHI::ResourceStates::PixelShaderResource);
delete depthView;