Lower final color into final output stage

This commit is contained in:
2026-04-06 16:15:19 +08:00
parent 6645d507d0
commit 33bb84f650
17 changed files with 1149 additions and 42 deletions

View File

@@ -1887,6 +1887,169 @@ TEST(SceneRenderer_Test, ResolvesFinalColorPolicyFromPipelineDefaultsAndCameraOv
EXPECT_FALSE(request.finalOutput.IsRequested());
}
TEST(SceneRenderer_Test, BuildsFinalOutputRequestFromResolvedFinalColorPolicy) {
Scene scene("SceneRendererFinalOutputScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(2.0f);
FinalColorOverrideSettings cameraOverrides = {};
cameraOverrides.overrideExposureMode = true;
cameraOverrides.exposureMode = FinalColorExposureMode::Fixed;
cameraOverrides.overrideExposureValue = true;
cameraOverrides.exposureValue = 1.6f;
cameraOverrides.overrideFinalColorScale = true;
cameraOverrides.finalColorScale = XCEngine::Math::Vector4(0.95f, 0.9f, 0.85f, 1.0f);
camera->SetFinalColorOverrides(cameraOverrides);
auto allocationState = std::make_shared<MockShadowAllocationState>();
MockShadowDevice device(allocationState);
auto* backBufferColorView = new MockShadowView(
allocationState,
XCEngine::RHI::ResourceViewType::RenderTarget,
XCEngine::RHI::Format::R8G8B8A8_UNorm,
XCEngine::RHI::ResourceViewDimension::Texture2D);
auto* depthView = new MockShadowView(
allocationState,
XCEngine::RHI::ResourceViewType::DepthStencil,
XCEngine::RHI::Format::D24_UNorm_S8_UInt,
XCEngine::RHI::ResourceViewDimension::Texture2D);
auto assetState = std::make_shared<MockPipelineAssetState>();
assetState->defaultFinalColorSettings.outputTransferMode =
FinalColorOutputTransferMode::LinearToSRGB;
RenderContext context = CreateValidContext();
context.device = &device;
RenderSurface surface(800, 600);
surface.SetColorAttachment(backBufferColorView);
surface.SetDepthAttachment(depthView);
SceneRenderer renderer(std::make_shared<MockPipelineAsset>(assetState));
const std::vector<CameraRenderRequest> requests =
renderer.BuildRenderRequests(scene, nullptr, context, surface);
ASSERT_EQ(requests.size(), 1u);
const CameraRenderRequest& request = requests[0];
EXPECT_FALSE(request.postProcess.IsRequested());
EXPECT_TRUE(request.finalOutput.IsRequested());
EXPECT_TRUE(request.finalOutput.IsValid());
ASSERT_NE(request.finalOutput.passes, nullptr);
EXPECT_EQ(request.finalOutput.passes->GetPassCount(), 1u);
EXPECT_EQ(request.finalOutput.destinationSurface.GetColorAttachments()[0], backBufferColorView);
EXPECT_EQ(request.finalOutput.destinationSurface.GetDepthAttachment(), depthView);
EXPECT_EQ(request.finalOutput.sourceSurface.GetDepthAttachment(), depthView);
EXPECT_EQ(request.finalOutput.sourceSurface.GetWidth(), 800u);
EXPECT_EQ(request.finalOutput.sourceSurface.GetHeight(), 600u);
EXPECT_NE(request.finalOutput.sourceColorView, nullptr);
EXPECT_NE(request.finalOutput.sourceColorView, backBufferColorView);
ASSERT_FALSE(request.finalOutput.sourceSurface.GetColorAttachments().empty());
EXPECT_NE(request.finalOutput.sourceSurface.GetColorAttachments()[0], backBufferColorView);
EXPECT_EQ(allocationState->createTextureCalls, 1);
EXPECT_EQ(allocationState->createRenderTargetViewCalls, 1);
EXPECT_EQ(allocationState->createShaderViewCalls, 1);
delete depthView;
delete backBufferColorView;
}
TEST(SceneRenderer_Test, RoutesPostProcessIntoIntermediateSurfaceBeforeFinalOutput) {
Scene scene("SceneRendererPostProcessFinalOutputScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(2.0f);
camera->SetViewportRect(XCEngine::Math::Rect(0.25f, 0.125f, 0.5f, 0.625f));
camera->SetPostProcessPasses({
XCEngine::Rendering::CameraPostProcessPassDesc::MakeColorScale(
XCEngine::Math::Vector4(1.0f, 0.75f, 0.75f, 1.0f))
});
FinalColorOverrideSettings cameraOverrides = {};
cameraOverrides.overrideOutputTransferMode = true;
cameraOverrides.outputTransferMode = FinalColorOutputTransferMode::LinearToSRGB;
cameraOverrides.overrideFinalColorScale = true;
cameraOverrides.finalColorScale = XCEngine::Math::Vector4(0.95f, 0.9f, 0.85f, 1.0f);
camera->SetFinalColorOverrides(cameraOverrides);
auto allocationState = std::make_shared<MockShadowAllocationState>();
MockShadowDevice device(allocationState);
auto* backBufferColorView = new MockShadowView(
allocationState,
XCEngine::RHI::ResourceViewType::RenderTarget,
XCEngine::RHI::Format::R8G8B8A8_UNorm,
XCEngine::RHI::ResourceViewDimension::Texture2D);
auto* depthView = new MockShadowView(
allocationState,
XCEngine::RHI::ResourceViewType::DepthStencil,
XCEngine::RHI::Format::D24_UNorm_S8_UInt,
XCEngine::RHI::ResourceViewDimension::Texture2D);
RenderContext context = CreateValidContext();
context.device = &device;
RenderSurface surface(800, 600);
surface.SetColorAttachment(backBufferColorView);
surface.SetDepthAttachment(depthView);
SceneRenderer renderer;
const std::vector<CameraRenderRequest> requests =
renderer.BuildRenderRequests(scene, nullptr, context, surface);
ASSERT_EQ(requests.size(), 1u);
const CameraRenderRequest& request = requests[0];
EXPECT_TRUE(request.postProcess.IsRequested());
EXPECT_TRUE(request.finalOutput.IsRequested());
ASSERT_NE(request.postProcess.passes, nullptr);
ASSERT_NE(request.finalOutput.passes, nullptr);
EXPECT_EQ(request.postProcess.passes->GetPassCount(), 1u);
EXPECT_EQ(request.finalOutput.passes->GetPassCount(), 1u);
ASSERT_FALSE(request.postProcess.sourceSurface.GetColorAttachments().empty());
ASSERT_FALSE(request.postProcess.destinationSurface.GetColorAttachments().empty());
ASSERT_FALSE(request.finalOutput.sourceSurface.GetColorAttachments().empty());
EXPECT_NE(
request.postProcess.sourceSurface.GetColorAttachments()[0],
request.postProcess.destinationSurface.GetColorAttachments()[0]);
EXPECT_EQ(
request.finalOutput.sourceSurface.GetColorAttachments()[0],
request.postProcess.destinationSurface.GetColorAttachments()[0]);
EXPECT_EQ(request.finalOutput.destinationSurface.GetColorAttachments()[0], backBufferColorView);
EXPECT_EQ(request.postProcess.sourceSurface.GetDepthAttachment(), depthView);
EXPECT_EQ(request.postProcess.destinationSurface.GetDepthAttachment(), nullptr);
EXPECT_EQ(request.finalOutput.sourceSurface.GetDepthAttachment(), nullptr);
EXPECT_EQ(request.finalOutput.destinationSurface.GetDepthAttachment(), depthView);
const XCEngine::Math::RectInt postProcessSourceArea = request.postProcess.sourceSurface.GetRenderArea();
EXPECT_EQ(postProcessSourceArea.x, 200);
EXPECT_EQ(postProcessSourceArea.y, 75);
EXPECT_EQ(postProcessSourceArea.width, 400);
EXPECT_EQ(postProcessSourceArea.height, 375);
const XCEngine::Math::RectInt finalOutputSourceArea = request.finalOutput.sourceSurface.GetRenderArea();
EXPECT_EQ(finalOutputSourceArea.x, 200);
EXPECT_EQ(finalOutputSourceArea.y, 75);
EXPECT_EQ(finalOutputSourceArea.width, 400);
EXPECT_EQ(finalOutputSourceArea.height, 375);
EXPECT_NE(request.postProcess.sourceColorView, nullptr);
EXPECT_NE(request.finalOutput.sourceColorView, nullptr);
EXPECT_NE(request.postProcess.sourceColorView, request.finalOutput.sourceColorView);
EXPECT_EQ(allocationState->createTextureCalls, 2);
EXPECT_EQ(allocationState->createRenderTargetViewCalls, 2);
EXPECT_EQ(allocationState->createShaderViewCalls, 2);
delete depthView;
delete backBufferColorView;
}
TEST(CameraRenderer_Test, UsesResolvedRenderAreaForCameraViewportDimensions) {
Scene scene("CameraRendererViewportRectScene");