diff --git a/filament/src/FrameHistory.h b/filament/src/FrameHistory.h index 035ca4dfb8..ce4a696f1c 100644 --- a/filament/src/FrameHistory.h +++ b/filament/src/FrameHistory.h @@ -28,18 +28,18 @@ namespace filament { // when adding things here, please update: // FView::commitFrameHistory() struct FrameHistoryEntry { - struct { + struct TemporalAA{ FrameGraphTexture color; FrameGraphTexture::Descriptor desc; math::mat4f projection; // world space to clip space math::float2 jitter{}; + uint32_t frameId = 0; // used for halton sequence } taa; struct { FrameGraphTexture color; FrameGraphTexture::Descriptor desc; math::mat4f projection; } ssr; - uint32_t frameId = 0; }; /* @@ -72,6 +72,14 @@ public: return mCurrentEntry; } + T& getPrevious() noexcept { + return mContainer[0]; + } + + const T& getPrevious() const noexcept { + return mContainer[0]; + } + // This pushes the current frame info to the FIFO, effectively destroying // the oldest state (note: only the structure is destroyed, handles stored in it may // have to be destroyed prior to calling this). diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 6b5105da22..a2526e9352 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -2459,33 +2459,54 @@ FrameGraphId PostProcessManager::fxaa(FrameGraph& fg, return ppFXAA->output; } -void PostProcessManager::prepareTaa(FrameHistory& frameHistory, - CameraInfo const& cameraInfo, - TemporalAntiAliasingOptions const& taaOptions) const noexcept { - auto const& previous = frameHistory[0]; - auto& current = frameHistory.getCurrent(); - // get sample position within a pixel [-0.5, 0.5] +void PostProcessManager::prepareTaa(FrameGraph& fg, filament::Viewport const& svp, + FrameHistory& frameHistory, + FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa, + CameraInfo* inoutCameraInfo, + PerViewUniforms& uniforms) const noexcept { + auto const& previous = frameHistory.getPrevious().*pTaa; + auto& current = frameHistory.getCurrent().*pTaa; + + // compute projection + current.projection = inoutCameraInfo->projection * (inoutCameraInfo->view * inoutCameraInfo->worldOrigin); + current.frameId = previous.frameId + 1; + + // sample position within a pixel [-0.5, 0.5] const float2 jitter = halton(previous.frameId) - 0.5f; - // save this frame's sample position - current.taa.jitter = jitter; + current.jitter = jitter; + + float2 jitterInClipSpace = jitter * (2.0f / float2{ svp.width, svp.height }); + + // update projection matrix + inoutCameraInfo->projection[2].xy -= jitterInClipSpace; + + fg.addTrivialSideEffectPass("Jitter Camera", + [=, &uniforms] (DriverApi& driver) { + uniforms.prepareCamera(*inoutCameraInfo); + uniforms.commit(driver); + }); } FrameGraphId PostProcessManager::taa(FrameGraph& fg, - FrameGraphId input, FrameHistory& frameHistory, + FrameGraphId input, + FrameHistory& frameHistory, + FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa, TemporalAntiAliasingOptions const& taaOptions, ColorGradingConfig colorGradingConfig) noexcept { - FrameHistoryEntry const& entry = frameHistory[0]; + auto const& previous = frameHistory.getPrevious().*pTaa; + auto& current = frameHistory.getCurrent().*pTaa; + FrameGraphId colorHistory; - mat4f const* historyProjection = nullptr; - if (UTILS_UNLIKELY(!entry.taa.color.handle)) { + mat4f historyProjection; + if (UTILS_UNLIKELY(!previous.color.handle)) { // if we don't have a history yet, just use the current color buffer as history colorHistory = input; - historyProjection = &frameHistory.getCurrent().taa.projection; + historyProjection = current.projection; } else { - colorHistory = fg.import("TAA history", entry.taa.desc, - FrameGraphTexture::Usage::SAMPLEABLE, entry.taa.color); - historyProjection = &entry.taa.projection; + colorHistory = fg.import("TAA history", previous.desc, + FrameGraphTexture::Usage::SAMPLEABLE, previous.color); + historyProjection = previous.projection; } Blackboard& blackboard = fg.getBlackboard(); @@ -2499,7 +2520,7 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, FrameGraphId output; FrameGraphId tonemappedOutput; }; - auto& taa = fg.addPass("TAA", + auto& taaPass = fg.addPass("TAA", [&](FrameGraph::Builder& builder, auto& data) { auto desc = fg.getDescriptor(input); data.color = builder.sample(input); @@ -2521,7 +2542,7 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, .attachments = { .color = { data.output, data.tonemappedOutput }} }); }, - [=, &frameHistory](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { + [=, ¤t](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { constexpr mat4f normalizedToClip{mat4f::row_major_init{ 2, 0, 0, -1, @@ -2536,8 +2557,6 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, { -1.0f, 1.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f }, }; - FrameHistoryEntry& current = frameHistory.getCurrent(); - float sum = 0.0; float weights[9]; @@ -2545,7 +2564,7 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, // unrolling it. #pragma nounroll for (size_t i = 0; i < 9; i++) { - float2 d = sampleOffsets[i] - current.taa.jitter; + float2 d = sampleOffsets[i] - current.jitter; d *= 1.0f / taaOptions.filterWidth; // this is a gaussian fit of a 3.3 Blackman Harris window // see: "High Quality Temporal Supersampling" by Bruan Karis @@ -2572,8 +2591,8 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, }); mi->setParameter("filterWeights", weights, 9); mi->setParameter("reprojection", - *historyProjection * - inverse(current.taa.projection) * + historyProjection * + inverse(current.projection) * normalizedToClip); mi->commit(driver); @@ -2592,7 +2611,26 @@ FrameGraphId PostProcessManager::taa(FrameGraph& fg, } driver.endRenderPass(); }); - return colorGradingConfig.asSubpass ? taa->tonemappedOutput : taa->output; + + input = colorGradingConfig.asSubpass ? taaPass->tonemappedOutput : taaPass->output; + + struct ExportColorHistoryData { + FrameGraphId color; + }; + auto& exportHistoryPass = fg.addPass("Export TAA history", + [&](FrameGraph::Builder& builder, auto& data) { + // We need to use sideEffect here to ensure this pass won't be culled. + // The "output" of this pass is going to be used during the next frame as + // an "import". + builder.sideEffect(); + data.color = builder.sample(input); // FIXME: an access must be declared for detach(), why? + }, [¤t](FrameGraphResources const& resources, auto const& data, + backend::DriverApi&) { + resources.detach(data.color, + ¤t.color, ¤t.desc); + }); + + return exportHistoryPass->color; } FrameGraphId PostProcessManager::opaqueBlit(FrameGraph& fg, diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index 47cd5d871e..07d5017f9c 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -139,11 +139,16 @@ public: bool translucent) noexcept; // Temporal Anti-aliasing - void prepareTaa(FrameHistory& frameHistory, CameraInfo const& cameraInfo, - TemporalAntiAliasingOptions const& taaOptions) const noexcept; + void prepareTaa(FrameGraph& fg, filament::Viewport const& svp, + FrameHistory& frameHistory, + FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa, + CameraInfo* inoutCameraInfo, + PerViewUniforms& uniforms) const noexcept; FrameGraphId taa(FrameGraph& fg, - FrameGraphId input, FrameHistory& frameHistory, + FrameGraphId input, + FrameHistory& frameHistory, + FrameHistoryEntry::TemporalAA FrameHistoryEntry::*pTaa, TemporalAntiAliasingOptions const& taaOptions, ColorGradingConfig colorGradingConfig) noexcept; diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index ef7fa57d6a..ebd905e3d6 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -463,28 +463,9 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { // Store this frame's camera projection in the frame history. if (UTILS_UNLIKELY(taaOptions.enabled)) { - auto& history = view.getFrameHistory(); - auto& current = history.getCurrent(); - auto const& previous = history[0]; - current.taa.projection = cameraInfo.projection * (cameraInfo.view * cameraInfo.worldOrigin); - // update frame id - current.frameId = previous.frameId + 1; // TODO: should probably be done somewhere else - } - - // Apply the TAA jitter to everything after the structure pass, starting with the color pass. - if (taaOptions.enabled) { - auto& history = view.getFrameHistory(); - ppm.prepareTaa(history, cameraInfo, taaOptions); - // convert the sample position to jitter in clip-space - float2 jitterInClipSpace = - history.getCurrent().taa.jitter * (2.0f / float2{ svp.width, svp.height }); - // update projection matrix - cameraInfo.projection[2].xy -= jitterInClipSpace; - - fg.addTrivialSideEffectPass("Jitter Camera", [=, &view] (DriverApi& driver) { - view.prepareCamera(cameraInfo); - view.commitUniforms(driver); - }); + // Apply the TAA jitter to everything after the structure pass, starting with the color pass. + ppm.prepareTaa(fg, svp, view.getFrameHistory(), &FrameHistoryEntry::taa, + &cameraInfo, view.getPerViewUniforms()); } // -------------------------------------------------------------------------------------------- @@ -635,24 +616,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { // TAA for color pass if (taaOptions.enabled) { - input = ppm.taa(fg, input, view.getFrameHistory(), taaOptions, colorGradingConfig); - - struct ExportColorHistoryData { - FrameGraphId color; - }; - fg.addPass("Export TAA history", - [&](FrameGraph::Builder& builder, auto& data) { - // We need to use sideEffect here to ensure this pass won't be culled. - // The "output" of this pass is going to be used during the next frame as - // an "import". - builder.sideEffect(); - data.color = builder.sample(input); // FIXME: an access must be declared for detach(), why? - }, [&view](FrameGraphResources const& resources, auto const& data, - backend::DriverApi&) { - FrameHistoryEntry& current = view.getFrameHistory().getCurrent(); - resources.detach(data.color, - ¤t.taa.color, ¤t.taa.desc); - }); + input = ppm.taa(fg, input, view.getFrameHistory(), &FrameHistoryEntry::taa, + taaOptions, colorGradingConfig); } // --------------------------------------------------------------------------------------------