From 507aeb1e342742ebd5cf0bb266b09359becc16d5 Mon Sep 17 00:00:00 2001 From: Pixelflinger Date: Wed, 22 May 2019 23:10:19 -0700 Subject: [PATCH] ssao is now done in quarter resolution - this means that we cannot share the depth pass between ssao and color passes, so all this code is removed, which simplify things a lot. - the depth pass code is moved into the ssao codepath since they're now intimately linked. - and finals ssao shader can't rely on frameUniform which is set up with the main buffer's size (instead of 1/4 res). --- filament/src/PostProcessManager.cpp | 37 +++++++++- filament/src/PostProcessManager.h | 4 +- filament/src/RenderPass.h | 2 +- filament/src/Renderer.cpp | 109 +++++----------------------- filament/src/materials/sao.mat | 8 +- filament/src/materials/ssao.mat | 4 + 6 files changed, 68 insertions(+), 96 deletions(-) diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 9490be3091..dc2e73fee5 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -20,6 +20,8 @@ #include "fg/FrameGraph.h" +#include "RenderPass.h" + #include "details/Material.h" #include "details/MaterialInstance.h" #include "generated/resources/materials.h" @@ -285,12 +287,40 @@ FrameGraphResource PostProcessManager::dynamicScaling(FrameGraph& fg, } -FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource depth, - View::AmbientOcclusionOptions const& options) noexcept { +FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, RenderPass& pass, + filament::Viewport const& svp, View::AmbientOcclusionOptions const& options) noexcept { FEngine* engine = mEngine; Handle fullScreenRenderPrimitive = engine->getFullScreenRenderPrimitive(); + // SSAO depth pass -- automatically culled if not used + struct DepthPassData { + FrameGraphResource depth; + }; + + RenderPass::Command const* first = pass.getCommands().begin(); + RenderPass::Command const* last = pass.getCommands().end(); + + // SSAO generates its own depth path at 1/4 resolution + auto& ssaoDepthPass = fg.addPass("SSAO Depth Pass", + [&svp](FrameGraph::Builder& builder, DepthPassData& data) { + + data.depth = builder.createTexture("Depth Buffer", { + .width = svp.width / 2, .height = svp.height / 2, + .format = TextureFormat::DEPTH24 }); + + data.depth = builder.useRenderTarget("SSAO Depth Target", + { .attachments.depth = data.depth }, TargetBufferFlags::DEPTH).depth; + }, + [&pass, first, last](FrameGraphPassResources const& resources, + DepthPassData const& data, DriverApi& driver) { + assert(depthPassBegin && depthPassEnd); + auto out = resources.getRenderTarget(data.depth); + pass.execute(resources.getPassName(), out.target, out.params, first, last); + }); + + FrameGraphResource depth = ssaoDepthPass.getData().depth; + struct SSAOPassData { FrameGraphResource depth; FrameGraphResource ssao; @@ -316,10 +346,13 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource d SSAOPassData const& data, DriverApi& driver) { auto depth = resources.getTexture(data.depth); auto ssao = resources.getRenderTarget(data.ssao); + auto const& desc = resources.getDescriptor(data.ssao); SamplerParams params; FMaterialInstance* const pInstance = mSSAOMaterialInstance; pInstance->setParameter("depth", depth, params); + pInstance->setParameter("resolution", + float4{ desc.width, desc.height, 1.0f / desc.width, 1.0f / desc.height }); pInstance->setParameter("radius", data.options.radius); pInstance->setParameter("invRadiusSquared", 1.0f / (data.options.radius * data.options.radius)); pInstance->setParameter("projectionScaleRadius", 500.0f * data.options.radius); diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index 178624300d..4bcef0c701 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -33,6 +33,7 @@ class FMaterial; class FMaterialInstance; class FEngine; class FView; +class RenderPass; } // namespace details class PostProcessManager { @@ -58,7 +59,8 @@ public: FrameGraph& fg, FrameGraphResource input) noexcept; - FrameGraphResource ssao(FrameGraph& fg, FrameGraphResource depth, + FrameGraphResource ssao(FrameGraph& fg, details::RenderPass& pass, + filament::Viewport const& svp, View::AmbientOcclusionOptions const& options) noexcept; backend::Handle getNoSSAOTexture() const { diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 0a71de05c3..806e7d8b9b 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -225,7 +225,7 @@ public: void setRenderFlags(RenderFlags flags) noexcept; Command const* appendSortedCommands(CommandTypeFlags const commandTypeFlags) noexcept; void execute(const char* name, - backend::Handle renderTarget, + backend::Handle renderTarget, backend::RenderPassParams params, Command const* first, Command const* last) const noexcept; diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index e026f9f3b4..19a3275ed8 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -255,93 +255,26 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { view.commitUniforms(driver); - RenderPass::CommandTypeFlags commandType = getCommandType(view.getDepthPrepass()); - - // It's unclear if it's always better to reuse the depth pass, as it has to be saved and - // reloaded from memory -- as opposed to just regenerating it. Skinning is not an added concern, - // because either way, we have to go through the geometry twice. - constexpr bool REUSE_SSAO_DEPTH = true; + // -------------------------------------------------------------------------------------------- const bool useSSAO = view.getAmbientOcclusion() != View::AmbientOcclusion::NONE; - Command const* depthPassBegin = nullptr; - Command const* depthPassEnd = nullptr; - Command const* colorPassBegin = nullptr; - Command const* colorPassEnd = nullptr; - - // We need an extra pass for SSAO if SSAO is enabled and: - // - we don't want to reuse the regular depth path for SSAO, or - // - we have MSAA (because SSAO is never done in MSAA), or - // - we don't have a depth prepass in the first place - const bool extraDepthPassForSSAO = useSSAO && - (!REUSE_SSAO_DEPTH || msaa > 1 || !(commandType & RenderPass::CommandTypeFlags::DEPTH)); - - // depth buffer is shared between SSAO and the color pass - const bool sharedDepthPass = useSSAO && !extraDepthPassForSSAO; - if (sharedDepthPass) { - // When SSAO is active and it's sharing the depth pass with the color pass - // (meaning that we don't have MSAA), we add alpha tested objects to the scene, they're - // needed for SSAO and they won't hurt the color pass. - commandType = RenderPass::CommandTypeFlags(commandType & - ~RenderPass::CommandTypeFlags::DEPTH_FILTER_ALPHA_MASKED_OBJECTS); - } - - if (extraDepthPassForSSAO) { - // We don't have a depth prepass, so we need to generate the depth for the SSAO pass - depthPassBegin = commands.end(); - depthPassEnd = pass.appendSortedCommands(RenderPass::CommandTypeFlags::DEPTH); - } - - // generate the normal commands - colorPassBegin = commands.end(); - colorPassEnd = pass.appendSortedCommands(commandType); - - if (sharedDepthPass) { - assert(commandType & RenderPass::CommandTypeFlags::DEPTH); - // isolate the depth-only commands - depthPassBegin = commands.begin(); - depthPassEnd = std::partition_point(commands.begin(), commands.end(), - [](Command const& command) { - return (command.key & RenderPass::PASS_MASK) == uint64_t(RenderPass::Pass::DEPTH); - }); - } - - // -------------------------------------------------------------------------------------------- - - // SSAO depth pass -- automatically culled if not used - struct DepthPassData { - FrameGraphResource depth; - }; - - auto& ssaoDepthPass = fg.addPass("SSAO Depth Pass", - [&svp](FrameGraph::Builder& builder, DepthPassData& data) { - - data.depth = builder.createTexture("Depth Buffer", { - .width = svp.width, .height = svp.height, - .format = TextureFormat::DEPTH24 }); - - data.depth = builder.useRenderTarget("SSAO Depth Target", - { .attachments.depth = data.depth }, TargetBufferFlags::DEPTH).depth; - }, - [&pass, depthPassBegin, depthPassEnd](FrameGraphPassResources const& resources, - DepthPassData const& data, DriverApi& driver) { - assert(depthPassBegin && depthPassEnd); - auto out = resources.getRenderTarget(data.depth); - pass.execute(resources.getPassName(), out.target, out.params, - depthPassBegin, depthPassEnd); - }); - - FrameGraphResource depth = ssaoDepthPass.getData().depth; // SSAO pass -- automatically culled if not used - FrameGraphResource ssao = ppm.ssao(fg, depth, view.getAmbientOcclusionOptions()); + if (useSSAO) { + pass.appendSortedCommands(RenderPass::CommandTypeFlags::DEPTH); + } + + FrameGraphResource ssao = ppm.ssao(fg, pass, svp, view.getAmbientOcclusionOptions()); // -------------------------------------------------------------------------------------------- + // generate the normal commands + RenderPass::CommandTypeFlags commandType = getCommandType(view.getDepthPrepass()); + Command const* colorPassBegin = commands.end(); + Command const* colorPassEnd = pass.appendSortedCommands(commandType); + // We only honor the view's color buffer clear flags, depth/stencil are handled by the framefraph - TargetBufferFlags clearFlags = view.getClearFlags() & TargetBufferFlags::COLOR; - if (!sharedDepthPass) { - clearFlags |= TargetBufferFlags::DEPTH; - } + TargetBufferFlags clearFlags = view.getClearFlags() & TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH; struct ColorPassData { FrameGraphResource color; @@ -350,7 +283,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { }; auto& colorPass = fg.addPass("Color Pass", - [&svp, hdrFormat, colorPassNeedsDepthBuffer, msaa, clearFlags, depth, useSSAO, ssao, sharedDepthPass] + [&svp, hdrFormat, colorPassNeedsDepthBuffer, msaa, clearFlags, useSSAO, ssao] (FrameGraph::Builder& builder, ColorPassData& data) { if (useSSAO) { @@ -360,16 +293,12 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { data.color = builder.createTexture("Color Buffer", { .width = svp.width, .height = svp.height, .format = hdrFormat, .samples = msaa }); - if (sharedDepthPass) { - data.depth = depth; - } else { - if (colorPassNeedsDepthBuffer) { - data.depth = builder.createTexture("Depth Buffer", { - .width = svp.width, .height = svp.height, - .format = TextureFormat::DEPTH24, - .samples = msaa - }); - } + if (colorPassNeedsDepthBuffer) { + data.depth = builder.createTexture("Depth Buffer", { + .width = svp.width, .height = svp.height, + .format = TextureFormat::DEPTH24, + .samples = msaa + }); } FrameGraphRenderTarget::Descriptor desc{ diff --git a/filament/src/materials/sao.mat b/filament/src/materials/sao.mat index 0a73594892..997a868ca5 100644 --- a/filament/src/materials/sao.mat +++ b/filament/src/materials/sao.mat @@ -6,6 +6,10 @@ material { name : depth, precision: high }, + { + type : float4, + name : resolution + }, { type : float, name : radius @@ -166,7 +170,7 @@ fragment { float ssRadius = max(1.0, tap.z * ssDiskRadius); // at least 1 pixel screen-space radius ivec2 ssSamplePos = ssOrigin + ivec2(ssRadius * tap.xy); - vec2 uvSamplePos = (vec2(ssSamplePos) + vec2(0.5)) * frameUniforms.resolution.zw; + vec2 uvSamplePos = (vec2(ssSamplePos) + vec2(0.5)) * materialParams.resolution.zw; highp float occlusionDepth = linearizeDepth(texelFetch(materialParams_depth, clampToEdge(ssSamplePos), 0).r); highp vec3 p = computeViewSpacePositionFromDepth(uvSamplePos * 2.0 - 1.0, occlusionDepth); @@ -211,7 +215,7 @@ fragment { } normal = normalize(normal); - ivec2 ssOrigin = ivec2(uv * frameUniforms.resolution.xy); + ivec2 ssOrigin = ivec2(uv * materialParams.resolution.xy); float occlusion = 0.0; for (uint i = 0u; i < kSpiralSampleCount; i++) { occlusion += computeAmbientOcclusionSAO(i, ssDiskRadius, ssOrigin, origin, normal, noise); diff --git a/filament/src/materials/ssao.mat b/filament/src/materials/ssao.mat index 81879d8b2b..eb7600b942 100644 --- a/filament/src/materials/ssao.mat +++ b/filament/src/materials/ssao.mat @@ -6,6 +6,10 @@ material { name : depth, precision: high }, + { + type : float4, + name : resolution + }, { type : float, name : radius