Skip to content

Commit 85ebd67

Browse files
authored
feat(taa): Overhaul TAA implementation for improved quality and upscaling (#9573)
This commit introduces a significant rework of the Temporal Anti-Aliasing (TAA) system, focusing on improving reconstruction quality, robustness, and introducing flexible upscaling. Core TAA Algorithm improvements: - Replaced the Catmull-Rom filter with a more efficient 5-tap Lanczos filter for history sampling, which includes deringing to reduce artifacts. - The input color buffer is now properly "unjittered" using a Lanczos reconstruction filter. - Improved the history rejection algorithm by skipping the expensive accurate clipping when the history sample is already within the neighborhood's color gamut. - Added a new `hdr` option to properly handle HDR content by tonemapping colors before blending and untonemapping the result. - Removed the ineffective `VARIANCE` only history rejection method. - Added protection against negative numbers in `sqrt()` for increased stability. TAA Upscaling: - Replaced the boolean `upscaling` flag with a float factor, allowing for variable upscaling ratios (e.g., 1.5x, 2x). - Upscaling now correctly adjusts viewport and projection settings. - The TAA shader now receives viewport and resolution information to correctly handle upscaled rendering. API and Configuration Changes: - Deprecated the `filterWidth` TAA option as it no longer has an effect. - Introduced the `upscaling` float property to `TemporalAntiAliasingOptions`. - Added the `hdr` boolean property to `TemporalAntiAliasingOptions`. Other Changes: - Updated UI elements in the viewer and material sandbox to reflect the new TAA options. - Updated Javascript bindings and TypeScript definitions for the new TAA settings. - Refactored shader code for clarity and performance.
1 parent f33a779 commit 85ebd67

File tree

14 files changed

+326
-206
lines changed

14 files changed

+326
-206
lines changed

android/filament-android/src/main/java/com/google/android/filament/View.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,10 +2041,6 @@ public enum BoxType {
20412041
* use an AABB neighborhood
20422042
*/
20432043
AABB,
2044-
/**
2045-
* use the variance of the neighborhood (not recommended)
2046-
*/
2047-
VARIANCE,
20482044
/**
20492045
* use both AABB and variance
20502046
*/
@@ -2075,7 +2071,7 @@ public enum JitterPattern {
20752071
}
20762072

20772073
/**
2078-
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
2074+
* @deprecated has no effect.
20792075
*/
20802076
public float filterWidth = 1.0f;
20812077
/**
@@ -2095,9 +2091,9 @@ public enum JitterPattern {
20952091
*/
20962092
public boolean enabled = false;
20972093
/**
2098-
* 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
2094+
* Upscaling factor. Disables Dynamic Resolution. [BETA]
20992095
*/
2100-
public boolean upscaling = false;
2096+
public float upscaling = 1.0f;
21012097
/**
21022098
* whether to filter the history buffer
21032099
*/
@@ -2110,6 +2106,10 @@ public enum JitterPattern {
21102106
* whether to use the YcoCg color-space for history rejection
21112107
*/
21122108
public boolean useYCoCg = false;
2109+
/**
2110+
* set to true for HDR content
2111+
*/
2112+
public boolean hdr = true;
21132113
/**
21142114
* type of color gamut box
21152115
*/

filament/include/filament/Options.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,16 +489,15 @@ struct MultiSampleAntiAliasingOptions {
489489
* @see setTemporalAntiAliasingOptions()
490490
*/
491491
struct TemporalAntiAliasingOptions {
492-
float filterWidth = 1.0f; //!< reconstruction filter width typically between 1 (sharper) and 2 (smoother)
492+
float filterWidth = 1.0f; //!< @deprecated has no effect.
493493
float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
494494
float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2)
495495
float sharpness = 0.0f; //!< post-TAA sharpen, especially useful when upscaling is true.
496496
bool enabled = false; //!< enables or disables temporal anti-aliasing
497-
bool upscaling = false; //!< 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
497+
float upscaling = 1.0f; //!< Upscaling factor. Disables Dynamic Resolution. [BETA]
498498

499499
enum class BoxType : uint8_t {
500500
AABB, //!< use an AABB neighborhood
501-
VARIANCE, //!< use the variance of the neighborhood (not recommended)
502501
AABB_VARIANCE //!< use both AABB and variance
503502
};
504503

@@ -519,6 +518,7 @@ struct TemporalAntiAliasingOptions {
519518
bool filterHistory = true; //!< whether to filter the history buffer
520519
bool filterInput = true; //!< whether to apply the reconstruction filter to the input
521520
bool useYCoCg = false; //!< whether to use the YcoCg color-space for history rejection
521+
bool hdr = true; //!< set to true for HDR content
522522
BoxType boxType = BoxType::AABB; //!< type of color gamut box
523523
BoxClipping boxClipping = BoxClipping::ACCURATE; //!< clipping algorithm
524524
JitterPattern jitterPattern = JitterPattern::HALTON_23_X16; //! Jitter Pattern

filament/src/PostProcessManager.cpp

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,11 +2911,12 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(
29112911
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine);
29122912
bool dirty = false;
29132913

2914-
setConstantParameter(ma, "upscaling", taaOptions.upscaling, dirty);
2914+
setConstantParameter(ma, "upscaling", taaOptions.upscaling > 1.0f, dirty);
29152915
setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection, dirty);
29162916
setConstantParameter(ma, "filterHistory", taaOptions.filterHistory, dirty);
29172917
setConstantParameter(ma, "filterInput", taaOptions.filterInput, dirty);
29182918
setConstantParameter(ma, "useYCoCg", taaOptions.useYCoCg, dirty);
2919+
setConstantParameter(ma, "hdr", taaOptions.hdr, dirty);
29192920
setConstantParameter(ma, "preventFlickering", taaOptions.preventFlickering, dirty);
29202921
setConstantParameter(ma, "boxType", int32_t(taaOptions.boxType), dirty);
29212922
setConstantParameter(ma, "boxClipping", int32_t(taaOptions.boxClipping), dirty);
@@ -2984,6 +2985,8 @@ FMaterialInstance* PostProcessManager::configureColorGradingMaterial(
29842985
FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
29852986
FrameGraphId<FrameGraphTexture> input,
29862987
FrameGraphId<FrameGraphTexture> const depth,
2988+
filament::Viewport const& xvp,
2989+
filament::Viewport const& vp,
29872990
FrameHistory& frameHistory,
29882991
FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa,
29892992
TemporalAntiAliasingOptions const& taaOptions,
@@ -3013,9 +3016,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
30133016
auto const& taaPass = fg.addPass<TAAData>("TAA",
30143017
[&](FrameGraph::Builder& builder, auto& data) {
30153018
auto desc = fg.getDescriptor(input);
3016-
if (taaOptions.upscaling) {
3017-
desc.width *= 2;
3018-
desc.height *= 2;
3019+
if (taaOptions.upscaling > 1.0f) {
3020+
desc.width *= taaOptions.upscaling;
3021+
desc.height *= taaOptions.upscaling;
30193022
}
30203023
data.color = builder.sample(input);
30213024
data.depth = builder.sample(depth);
@@ -3047,55 +3050,15 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
30473050
0, 0, 0, 1
30483051
}};
30493052

3050-
constexpr float2 sampleOffsets[9] = {
3051-
{ -1.0f, -1.0f }, { 0.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 0.0f },
3052-
{ 0.0f, 0.0f },
3053-
{ 1.0f, 0.0f }, { -1.0f, 1.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f },
3054-
};
3053+
auto out = resources.getRenderPassInfo();
30553054

3056-
constexpr float2 subSampleOffsets[4] = {
3057-
{ -0.25f, 0.25f },
3058-
{ 0.25f, 0.25f },
3059-
{ 0.25f, -0.25f },
3060-
{ -0.25f, -0.25f }
3061-
};
3055+
auto const color = resources.getTexture(data.color);
3056+
auto const depth = resources.getTexture(data.depth);
3057+
auto const history = resources.getTexture(data.history);
30623058

3063-
UTILS_UNUSED
3064-
auto const lanczos = [](float const x, float const a) -> float {
3065-
if (x <= std::numeric_limits<float>::epsilon()) {
3066-
return 1.0f;
3067-
}
3068-
if (std::abs(x) <= a) {
3069-
return (a * std::sin(f::PI * x) * std::sin(f::PI * x / a))
3070-
/ ((f::PI * f::PI) * (x * x));
3071-
}
3072-
return 0.0f;
3073-
};
3059+
auto const& colorDesc = resources.getDescriptor(data.color);
3060+
auto const& historyDesc = resources.getDescriptor(data.history);
30743061

3075-
float const filterWidth = std::clamp(taaOptions.filterWidth, 1.0f, 2.0f);
3076-
float4 sum = 0.0;
3077-
float4 weights[9];
3078-
3079-
// this doesn't get vectorized (probably because of exp()), so don't bother
3080-
// unrolling it.
3081-
UTILS_NOUNROLL
3082-
for (size_t i = 0; i < 9; i++) {
3083-
float2 const o = sampleOffsets[i];
3084-
for (size_t j = 0; j < 4; j++) {
3085-
float2 const subPixelOffset = taaOptions.upscaling ? subSampleOffsets[j] : float2{ 0 };
3086-
float2 const d = (o - (current.jitter - subPixelOffset)) / filterWidth;
3087-
weights[i][j] = lanczos(length(d), filterWidth);
3088-
}
3089-
sum += weights[i];
3090-
}
3091-
for (auto& w : weights) {
3092-
w /= sum;
3093-
}
3094-
3095-
auto out = resources.getRenderPassInfo();
3096-
auto color = resources.getTexture(data.color);
3097-
auto depth = resources.getTexture(data.depth);
3098-
auto history = resources.getTexture(data.history);
30993062
auto const& material = getPostProcessMaterial("taa");
31003063

31013064
PostProcessVariant const variant = colorGradingConfig.translucent ?
@@ -3106,17 +3069,37 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
31063069
FMaterialInstance* mi = getMaterialInstance(ma);
31073070
mi->setParameter("color", color, SamplerParams{}); // nearest
31083071
mi->setParameter("depth", depth, SamplerParams{}); // nearest
3109-
mi->setParameter("alpha", taaOptions.feedback);
31103072
mi->setParameter("history", history, SamplerParams{
31113073
.filterMag = SamplerMagFilter::LINEAR,
31123074
.filterMin = SamplerMinFilter::LINEAR
31133075
});
3114-
mi->setParameter("filterWeights", weights, 9);
3115-
mi->setParameter("jitter", current.jitter);
3076+
mi->setParameter("alpha", taaOptions.feedback);
3077+
3078+
// jitter is negated here because the material wants the sample jitter offset
3079+
// not the projection matrix offset
3080+
mi->setParameter("jitter", -current.jitter);
3081+
mi->setParameter("scale", taaOptions.upscaling);
3082+
31163083
mi->setParameter("reprojection",
31173084
mat4f{ historyProjection * inverse(current.projection) } *
31183085
normalizedToClip);
31193086

3087+
mi->setParameter("colorViewport",
3088+
float4{
3089+
float(xvp.left) / colorDesc.width,
3090+
float(xvp.bottom) / colorDesc.height,
3091+
float(xvp.width) / colorDesc.width,
3092+
float(xvp.height) / colorDesc.height,
3093+
});
3094+
3095+
mi->setParameter("colorResolution",
3096+
float4{ colorDesc.width, colorDesc.height,
3097+
1.0f / colorDesc.width, 1.0f / colorDesc.height });
3098+
3099+
mi->setParameter("historyResolution",
3100+
float4{ historyDesc.width, historyDesc.height,
3101+
1.0f / historyDesc.width, 1.0f / historyDesc.height });
3102+
31203103
mi->commit(driver, getUboManager());
31213104
mi->use(driver);
31223105

filament/src/PostProcessManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ class PostProcessManager {
235235
FrameGraphId<FrameGraphTexture> taa(FrameGraph& fg,
236236
FrameGraphId<FrameGraphTexture> input,
237237
FrameGraphId<FrameGraphTexture> depth,
238+
Viewport const& xvp,
239+
Viewport const& vp,
238240
FrameHistory& frameHistory,
239241
FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa,
240242
TemporalAntiAliasingOptions const& taaOptions,

filament/src/details/Renderer.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,9 @@ std::pair<float, float2> FRenderer::prepareUpscaler(float2 const scale,
263263
if (taaOptions.enabled) {
264264
bias += taaOptions.lodBias;
265265
if (taaOptions.upscaling) {
266-
derivativesScale = 0.5f;
266+
if (taaOptions.upscaling > 1.0f) {
267+
derivativesScale = 1.0f / taaOptions.upscaling;
268+
}
267269
}
268270
}
269271
return { bias, derivativesScale };
@@ -688,13 +690,13 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
688690
// This configures post-process materials by setting constant parameters
689691
if (taaOptions.enabled) {
690692
ppm.configureTemporalAntiAliasingMaterial(taaOptions);
691-
if (taaOptions.upscaling) {
693+
if (taaOptions.upscaling > 1.0f) {
692694
// for now TAA upscaling is incompatible with regular dsr
693695
dsrOptions.enabled = false;
694696
// also, upscaling doesn't work well with quater-resolution SSAO
695697
aoOptions.resolution = 1.0;
696698
// Currently we only support a fixed TAA upscaling ratio
697-
scale = 0.5f;
699+
scale = 1.0f / taaOptions.upscaling;
698700
}
699701
}
700702
}
@@ -781,14 +783,14 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
781783
// Without post-processing, we usually draw directly into
782784
// the SwapChain, and we might want to keep it this way.
783785

784-
auto round = [](uint32_t const x) {
786+
auto ceil16 = [](uint32_t const x) {
785787
constexpr uint32_t rounding = 16u;
786788
return (x + (rounding - 1u)) & ~(rounding - 1u);
787789
};
788790

789791
// compute the new rendering width and height, multiple of 16.
790-
const float width = float(round(svp.width )) + 2.0f * guardBand;
791-
const float height = float(round(svp.height)) + 2.0f * guardBand;
792+
const float width = float(ceil16(svp.width )) + 2.0f * guardBand;
793+
const float height = float(ceil16(svp.height)) + 2.0f * guardBand;
792794

793795
// scale the field-of-view up, so it covers exactly the extra pixels
794796
const float3 clipSpaceScaling{
@@ -1309,16 +1311,26 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
13091311

13101312
// TAA for color pass
13111313
if (taaOptions.enabled) {
1312-
input = ppm.taa(fg, input, depth, view.getFrameHistory(), &FrameHistoryEntry::taa,
1314+
input = ppm.taa(fg, input, depth, xvp, vp,
1315+
view.getFrameHistory(), &FrameHistoryEntry::taa,
13131316
taaOptions, colorGradingConfig);
1314-
if (taaOptions.upscaling) {
1317+
if (taaOptions.upscaling > 1.0f) {
13151318
scale = 1.0f;
13161319
scaled = false;
1320+
1321+
// xvp = vp;
1322+
// xvp.left = xvp.bottom = 0;
1323+
// svp = xvp;
1324+
13171325
UTILS_UNUSED_IN_RELEASE auto const& inputDesc = fg.getDescriptor(input);
13181326
svp.width = inputDesc.width;
13191327
svp.height = inputDesc.height;
1320-
xvp.width *= 2;
1321-
xvp.height *= 2;
1328+
// FIXME: this rounds xvp incorrectly
1329+
1330+
xvp.left *= taaOptions.upscaling;
1331+
xvp.bottom *= taaOptions.upscaling;
1332+
xvp.width *= taaOptions.upscaling;
1333+
xvp.height *= taaOptions.upscaling;
13221334
}
13231335
}
13241336

filament/src/details/View.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,9 +320,9 @@ float2 FView::updateScale(FEngine& engine,
320320
// relative scaling ("velocity" control)
321321
const float scale = mScale.x * mScale.y * command;
322322

323-
const float w = float(mViewport.width);
324-
const float h = float(mViewport.height);
325323
if (scale < 1.0f && !options.homogeneousScaling) {
324+
const float w = float(mViewport.width);
325+
const float h = float(mViewport.height);
326326
// figure out the major and minor axis
327327
const float major = std::max(w, h);
328328
const float minor = std::min(w, h);
@@ -351,7 +351,7 @@ float2 FView::updateScale(FEngine& engine,
351351
const auto s = mScale;
352352
mScale = clamp(s, options.minScale, options.maxScale);
353353

354-
// disable the integration term when we're outside the controllable range
354+
// Disable the integration term when we're outside the controllable range
355355
// (i.e. we clamped). This help not to have to wait too long for the Integral term
356356
// to kick in after a clamping event.
357357
mPidController.setIntegralInhibitionEnabled(mScale != s);

0 commit comments

Comments
 (0)