fix screen-space reflection when sub-pass colorgrading is used

the problem was that in that case, SSR was using the colorgraded
color buffer as history.
This commit is contained in:
Mathias Agopian
2024-08-22 17:00:04 -07:00
committed by Mathias Agopian
parent a7317e7a99
commit c84f5d2a7f
2 changed files with 32 additions and 15 deletions

View File

@@ -153,6 +153,8 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
}
if (colorGradingConfig.asSubpass) {
assert_invariant(config.msaa <= 1);
assert_invariant(colorBufferDesc.samples <= 1);
data.output = builder.createTexture("Tonemapped Buffer", {
.width = colorBufferDesc.width,
.height = colorBufferDesc.height,
@@ -263,7 +265,9 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
// when color grading is done as a subpass, the output of the color-pass is the ldr buffer
auto output = colorGradingConfig.asSubpass ? colorPass->output : colorPass->color;
blackboard["color"] = output;
// linear color buffer
blackboard["color"] = colorPass->color;
return output;
}
@@ -275,7 +279,7 @@ std::pair<FrameGraphId<FrameGraphTexture>, bool> RendererUtils::refractionPass(
RenderPass const& pass) noexcept {
auto& blackboard = fg.getBlackboard();
auto input = blackboard.get<FrameGraphTexture>("color");
FrameGraphId<FrameGraphTexture> output;
// find the first refractive object in channel 2
@@ -295,13 +299,13 @@ std::pair<FrameGraphId<FrameGraphTexture>, bool> RendererUtils::refractionPass(
PostProcessManager& ppm = engine.getPostProcessManager();
// clear the color/depth buffers, which will orphan (and cull) the color pass
input.clear();
blackboard.remove("color");
blackboard.remove("depth");
config.hasScreenSpaceReflectionsOrRefractions = true;
input = RendererUtils::colorPass(fg, "Color Pass (opaque)", engine, view, {
FrameGraphId<FrameGraphTexture> const input = RendererUtils::colorPass(fg,
"Color Pass (opaque)", engine, view, {
// When rendering the opaques, we need to conserve the sample buffer,
// so create a config that specifies the sample count.
.width = config.physicalViewport.width,
@@ -330,7 +334,8 @@ std::pair<FrameGraphId<FrameGraphTexture>, bool> RendererUtils::refractionPass(
output = RendererUtils::colorPass(fg, "Color Pass (transparent)", engine, view, {
.width = config.physicalViewport.width,
.height = config.physicalViewport.height },
config, colorGradingConfig, pass.getExecutor(refraction, pass.end()));
config, colorGradingConfig,
pass.getExecutor(refraction, pass.end()));
if (config.msaa > 1 && !colorGradingConfig.asSubpass) {
// We need to do a resolve here because later passes (such as color grading or DoF) will
@@ -339,8 +344,8 @@ std::pair<FrameGraphId<FrameGraphTexture>, bool> RendererUtils::refractionPass(
// conserve the multi-sample buffer.
output = ppm.resolve(fg, "Resolved Color Buffer", output, { .levels = 1 });
}
} else {
output = input;
// this becomes the screen-space reflection history
blackboard["color"] = output;
}
return { output, hasScreenSpaceRefraction };
}

View File

@@ -655,16 +655,16 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
// on qualcomm hardware -- we might need a backend dependent toggle at some point
const PostProcessManager::ColorGradingConfig colorGradingConfig{
.asSubpass =
hasColorGrading &&
msaaSampleCount <= 1 &&
!bloomOptions.enabled && !dofOptions.enabled && !taaOptions.enabled &&
driver.isFrameBufferFetchSupported() &&
hasColorGrading &&
!bloomOptions.enabled && !dofOptions.enabled && !taaOptions.enabled &&
!engine.debug.renderer.disable_subpasses,
.customResolve =
msaaOptions.customResolve &&
msaaSampleCount > 1 &&
hasColorGrading &&
driver.isFrameBufferFetchMultiSampleSupported() &&
msaaOptions.customResolve &&
hasColorGrading &&
!engine.debug.renderer.disable_subpasses,
.translucent = needsAlphaChannel,
.fxaa = hasFXAA,
@@ -673,6 +673,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
TextureFormat::RGBA8 : getLdrFormat(needsAlphaChannel)
};
// by construction (msaaSampleCount) both asSubpass and customResolve can't be true
assert_invariant(colorGradingConfig.asSubpass + colorGradingConfig.customResolve < 2);
// whether we're scaled at all
bool scaled = any(notEqual(scale, float2(1.0f)));
@@ -1108,20 +1111,26 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
colorBufferDesc, config, colorGradingConfigForColor, pass.getExecutor());
if (view.isScreenSpaceRefractionEnabled() && !pass.empty()) {
// this cancels the colorPass() call above if refraction is active.
// the color pass + refraction + color-grading as subpass if needed
// This cancels the colorPass() call above if refraction is active.
// The color pass + refraction + color-grading as subpass if needed
const auto [output, enabled] = RendererUtils::refractionPass(fg, mEngine, view,
config, ssrConfig, colorGradingConfigForColor, pass);
colorPassOutput = output;
hasScreenSpaceRefraction = enabled;
if (enabled) {
colorPassOutput = output;
}
}
// Here, colorPassOutput can be either tonemapped or not; it's tonemapped if color gradding
// is done as a subpass.
if (colorGradingConfig.customResolve) {
// TODO: we have to "uncompress" (i.e. detonemap) the color buffer here because it's used
// by many other passes (Bloom, TAA, DoF, etc...). We could make this more
// efficient by using ARM_shader_framebuffer_fetch. We use a load/store (i.e.
// subpass) here because it's more convenient.
colorPassOutput = ppm.customResolveUncompressPass(fg, colorPassOutput);
blackboard["color"] = colorPassOutput;
}
// export the color buffer if screen-space reflections are enabled
@@ -1137,7 +1146,10 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
// The "output" of this pass is going to be used during the next frame as
// an "import".
builder.sideEffect();
data.history = builder.sample(colorPassOutput); // FIXME: an access must be declared for detach(), why?
// we can't use colorPassOutput here because it could be tonemapped
auto color = blackboard.get<FrameGraphTexture>("color");
data.history = builder.sample(color); // FIXME: an access must be declared for detach(), why?
}, [&view, projection](FrameGraphResources const& resources, auto const& data,
backend::DriverApi&) {
auto& history = view.getFrameHistory();