From c393ee4591acf6bb7d09b1b4c061b3b3cfe6f441 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 27 Oct 2022 15:52:42 -0700 Subject: [PATCH] Each shadowmap now manages its own UBO Instead of constantly reusing the View's UBO, each shadowmap now manages it own. All UBOs for all shadow maps are updated together, then later during rendering, we're simply binding the correct UBO. This change will be needed later so that we can update several shadow maps in a single texture. There are two main changes to achieve this: 1. ShadowMap now has PerViewUniforms object 2. For point lights, each face now has a ShadowMap object One consequence is that ShadowMap is now very large (over 2KB). This will be addressed later. --- filament/src/PerViewUniforms.cpp | 9 +- filament/src/PerViewUniforms.h | 2 +- filament/src/RendererUtils.cpp | 3 +- filament/src/ShadowMap.cpp | 62 ++++++++++- filament/src/ShadowMap.h | 31 ++++-- filament/src/ShadowMapManager.cpp | 167 ++++++++++++++---------------- filament/src/ShadowMapManager.h | 6 +- filament/src/details/Renderer.cpp | 13 ++- filament/src/details/View.cpp | 26 +++-- filament/src/details/View.h | 16 ++- 10 files changed, 200 insertions(+), 135 deletions(-) diff --git a/filament/src/PerViewUniforms.cpp b/filament/src/PerViewUniforms.cpp index eabf34aef3..a7fad027be 100644 --- a/filament/src/PerViewUniforms.cpp +++ b/filament/src/PerViewUniforms.cpp @@ -91,14 +91,9 @@ void PerViewUniforms::prepareCamera(const CameraInfo& camera) noexcept { s.clipControl = mClipControl; } -void PerViewUniforms::prepareUpscaler(math::float2 scale, - DynamicResolutionOptions const& options) noexcept { +void PerViewUniforms::prepareLodBias(float bias) noexcept { auto& s = mUniforms.edit(); - if (options.quality >= QualityLevel::HIGH) { - s.lodBias = std::log2(std::min(scale.x, scale.y)); - } else { - s.lodBias = 0.0f; - } + s.lodBias = bias; } void PerViewUniforms::prepareExposure(float ev100) noexcept { diff --git a/filament/src/PerViewUniforms.h b/filament/src/PerViewUniforms.h index 11b0d20f71..bf08812fd9 100644 --- a/filament/src/PerViewUniforms.h +++ b/filament/src/PerViewUniforms.h @@ -64,7 +64,7 @@ public: void terminate(backend::DriverApi& driver); void prepareCamera(const CameraInfo& camera) noexcept; - void prepareUpscaler(math::float2 scale, DynamicResolutionOptions const& options) noexcept; + void prepareLodBias(float bias) noexcept; /* * @param viewport viewport (should be same as RenderPassParams::viewport) diff --git a/filament/src/RendererUtils.cpp b/filament/src/RendererUtils.cpp index e13023cb50..b27956baf8 100644 --- a/filament/src/RendererUtils.cpp +++ b/filament/src/RendererUtils.cpp @@ -173,7 +173,7 @@ FrameGraphId RendererUtils::colorPass( view.prepareSSAO(data.ssao ? resources.getTexture(data.ssao) : engine.getOneTextureArray()); - view.prepareShadowMap(view.getVsmShadowOptions().highPrecision); + view.prepareShadowMapping(view.getVsmShadowOptions().highPrecision); // set shadow sampler view.prepareShadow(data.shadows ? @@ -200,6 +200,7 @@ FrameGraphId RendererUtils::colorPass( view.prepareViewport(static_cast(out.params.viewport), config.xoffset, config.yoffset); + view.commitUniforms(driver); out.params.clearColor = data.clearColor; diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index 724a09a02d..f818fbfa74 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -41,8 +41,10 @@ using namespace backend; static constexpr bool USE_DEPTH_CLAMP = false; ShadowMap::ShadowMap(FEngine& engine) noexcept - : mShadowType(ShadowType::DIRECTIONAL), - mHasVisibleShadows(false) { + : mPerViewUniforms(engine), + mShadowType(ShadowType::DIRECTIONAL), + mHasVisibleShadows(false), + mFace(0) { Entity entities[2]; engine.getEntityManager().create(2, entities); mCamera = engine.createCamera(entities[0]); @@ -64,12 +66,14 @@ void ShadowMap::terminate(FEngine& engine) { ShadowMap::~ShadowMap() = default; -void ShadowMap::initialize(size_t lightIndex, ShadowType shadowType, uint16_t shadowIndex, +void ShadowMap::initialize(size_t lightIndex, ShadowType shadowType, + uint16_t shadowIndex, uint8_t face, LightManager::ShadowOptions const* options) { mLightIndex = lightIndex; mShadowIndex = shadowIndex; mOptions = options; mShadowType = shadowType; + mFace = face; } mat4f ShadowMap::getDirectionalLightViewMatrix(float3 direction, float3 position) noexcept { @@ -1238,4 +1242,56 @@ void ShadowMap::updateSceneInfoSpot(mat4f const& Mv, FScene const& scene, ); } +filament::Viewport ShadowMap::getViewport() const noexcept { + // We set a viewport with a 1-texel border for when we index outside the + // texture. + // DON'T CHANGE this unless ShadowMap::getTextureCoordsMapping() is updated too. + // see: ShadowMap::getTextureCoordsMapping() + // + // For floating-point depth textures, the 1-texel border could be set to + // FLOAT_MAX to avoid clamping in the shadow shader (see sampleDepth inside + // shadowing.fs). Unfortunately, the APIs don't seem let us clear depth + // attachments to anything greater than 1.0, so we'd need a way to do this other + // than clearing. + const uint32_t dim = mOptions->mapSize; + if (isPointShadow()) { + // for point-light we don't have a border + return { 0, 0, dim, dim }; + } else { + return { 1, 1, dim - 2, dim - 2 }; + } +} + +// ------------------------------------------------------------------------------------------------ + +void ShadowMap::prepareCamera(const CameraInfo& cameraInfo) noexcept { + mPerViewUniforms.prepareCamera(cameraInfo); + mPerViewUniforms.prepareLodBias(0.0f); +} + +void ShadowMap::prepareViewport(const filament::Viewport& viewport) noexcept { + mPerViewUniforms.prepareViewport(viewport, 0, 0); +} + +void ShadowMap::prepareTime(math::float4 const& userTime) noexcept { + mPerViewUniforms.prepareTime(userTime); +} + +void ShadowMap::prepareDirectionalLight(math::float3 const& sceneSpaceDirection, + LightManager::Instance instance) noexcept { + mPerViewUniforms.prepareDirectionalLight(1.0f, sceneSpaceDirection, instance); +} + +void ShadowMap::prepareShadowMapping(bool highPrecision) noexcept { + mPerViewUniforms.prepareShadowMapping(highPrecision); +} + +void ShadowMap::commitUniforms(backend::DriverApi& driver) const noexcept { + mPerViewUniforms.commit(driver); +} + +void ShadowMap::bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept { + mPerViewUniforms.bind(driver); +} + } // namespace filament diff --git a/filament/src/ShadowMap.h b/filament/src/ShadowMap.h index c6ff7d745f..28ccb4e6fb 100644 --- a/filament/src/ShadowMap.h +++ b/filament/src/ShadowMap.h @@ -19,12 +19,14 @@ #include "components/LightManager.h" +#include "PerViewUniforms.h" + #include "details/Camera.h" #include "details/Scene.h" -#include "backend/DriverApiForward.h" -#include "private/backend/SamplerGroup.h" -#include "math/mat4.h" +#include "private/backend/DriverApi.h" + +#include #include #include @@ -122,7 +124,7 @@ public: static math::mat4f getPointLightViewMatrix(backend::TextureCubemapFace face, math::float3 position) noexcept; - void initialize(size_t lightIndex, ShadowType shadowType, uint16_t shadowIndex, + void initialize(size_t lightIndex, ShadowType shadowType, uint16_t shadowIndex, uint8_t face, LightManager::ShadowOptions const* options); struct ShaderParameters { @@ -172,6 +174,8 @@ public: static void updateSceneInfoSpot(const math::mat4f& Mv, FScene const& scene, SceneInfo& sceneInfo); + filament::Viewport getViewport() const noexcept; + LightManager::ShadowOptions const* getShadowOptions() const noexcept { return mOptions; } size_t getLightIndex() const { return mLightIndex; } uint16_t getShadowIndex() const { return mShadowIndex; } @@ -181,6 +185,16 @@ public: bool isSpotShadow() const noexcept { return mShadowType == ShadowType::SPOT; } bool isPointShadow() const noexcept { return mShadowType == ShadowType::POINT; } ShadowType getShadowType() const noexcept { return mShadowType; } + uint8_t getFace() const noexcept { return mFace; } + + void prepareCamera(const CameraInfo& cameraInfo) noexcept; + void prepareViewport(const filament::Viewport& viewport) noexcept; + void prepareTime(math::float4 const& userTime) noexcept; + void prepareDirectionalLight(math::float3 const& sceneSpaceDirection, + LightManager::Instance instance) noexcept; + void prepareShadowMapping(bool highPrecision) noexcept; + void commitUniforms(backend::DriverApi& driver) const noexcept; + void bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept; private: struct Segment { @@ -278,6 +292,8 @@ private: { 2, 6, 7, 3 }, // top }; + mutable PerViewUniforms mPerViewUniforms; // 64 + 2048 + FCamera* mCamera = nullptr; // 8 FCamera* mDebugCamera = nullptr; // 8 @@ -287,10 +303,13 @@ private: uint32_t mLightIndex = 0; // which light are we shadowing // 4 uint16_t mShadowIndex = 0; // our index in the shadowMap vector // 2 uint8_t mLayer = 0; // our layer in the shadowMap texture // 1 - ShadowType mShadowType : 2; - bool mHasVisibleShadows : 2; + ShadowType mShadowType : 2; // :2 + bool mHasVisibleShadows : 2; // :2 + uint8_t mFace : 3; // :3 }; +static_assert(sizeof(ShadowMap) == 32 + 2048 + 64); + } // namespace filament #endif // TNT_FILAMENT_DETAILS_SHADOWMAP_H diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index 4128bc3970..227a89db6c 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -98,22 +98,34 @@ void ShadowMapManager::setDirectionalShadowMap(size_t lightIndex, assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES); for (size_t c = 0; c < options->shadowCascades; c++) { auto* pShadowMap = getCascadeShadowMap(c); - pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, c, options); + pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, c, 0, options); mCascadeShadowMaps.push_back(pShadowMap); } } void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight, LightManager::ShadowOptions const* options) noexcept { - const size_t c = mSpotShadowMaps.size(); - assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL); - auto* pShadowMap = getPointOrSpotShadowMap(c); - pShadowMap->initialize(lightIndex, spotlight ? ShadowType::SPOT : ShadowType::POINT, c, options); - mSpotShadowMaps.push_back(pShadowMap); + if (spotlight) { + const size_t c = mSpotShadowMaps.size(); + assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL); + auto* pShadowMap = getPointOrSpotShadowMap(c); + pShadowMap->initialize(lightIndex, ShadowType::SPOT, c, 0, options); + mSpotShadowMaps.push_back(pShadowMap); + } else { + // point-light + for (size_t face = 0; face < 6; face++) { + const size_t c = mSpotShadowMaps.size(); + assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL); + auto* pShadowMap = getPointOrSpotShadowMap(c); + pShadowMap->initialize(lightIndex, ShadowType::POINT, c, face, options); + mSpotShadowMaps.push_back(pShadowMap); + } + } } -FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine& engine, - RenderPass const& pass, FView& view, CameraInfo const& mainCameraInfo) noexcept { +FrameGraphId ShadowMapManager::render(FEngine& engine, FrameGraph& fg, + RenderPass const& pass, FView& view, CameraInfo const& mainCameraInfo, + float4 const& userTime) noexcept { const float moment2 = std::numeric_limits::max(); const float moment1 = std::sqrt(moment2); @@ -133,11 +145,9 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine struct PrepareShadowPassData { struct ShadowPass { mutable RenderPass::Executor executor; - mutable CameraInfo cameraInfo; ShadowMap* shadowMap; utils::Range range; FScene::VisibleMaskType visibilityMask; - uint8_t face = 0; }; // the actual shadow map atlas (currently a 2D texture array) FrameGraphId shadows; @@ -166,7 +176,7 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine // for the directional light, we already know if it has visible shadows. if (pShadowMap->hasVisibleShadows()) { passList.push_back({ - {}, {}, pShadowMap, directionalShadowCastersRange, + {}, pShadowMap, directionalShadowCastersRange, VISIBLE_DIR_SHADOW_RENDERABLE }); } } @@ -178,16 +188,8 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine for (auto* pShadowMap : mSpotShadowMaps) { assert_invariant(!pShadowMap->isDirectionalShadow()); passList.push_back({ - {}, {}, pShadowMap, spotShadowCastersRange, + {}, pShadowMap, spotShadowCastersRange, VISIBLE_DYN_SHADOW_RENDERABLE }); - if (pShadowMap->isPointShadow()) { - // add the 5 extra faces - for (uint8_t face = 1; face < 6; face++) { - passList.push_back({ - {}, {}, pShadowMap, spotShadowCastersRange, - VISIBLE_DYN_SHADOW_RENDERABLE, face }); - } - } } } @@ -197,10 +199,8 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine // "read" from one of its resource (only writes), so the FrameGraph culls it. builder.sideEffect(); }, - [this, &engine, &view, scene, &mainCameraInfo, &passTemplate = pass]( + [this, &engine, &view, scene, mainCameraInfo, userTime, passTemplate = pass]( FrameGraphResources const& resources, auto const& data, DriverApi& driver) { - // set uniforms needed to render this ShadowMap - view.prepareShadowMap(view.getVsmShadowOptions().highPrecision); // Note: we could almost parallel_for the loop below, the problem currently is // that updatePrimitivesLod() updates temporary global state. @@ -215,7 +215,9 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine // for spot shadow map, we need to do the culling switch (shadowMap.getShadowType()) { case ShadowType::DIRECTIONAL: - // nothing to do, it's been done already + shadowMap.prepareDirectionalLight( + scene->getLightData().elementAt(0), + scene->getLightData().elementAt(0)); break; case ShadowType::SPOT: prepareSpotShadowMap(shadowMap, engine, view, mainCameraInfo, @@ -225,7 +227,7 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine case ShadowType::POINT: preparePointShadowMap(shadowMap, engine, view, mainCameraInfo, scene->getRenderableData(), entry.range, - scene->getLightData(), entry.face, mSceneInfo); + scene->getLightData(), mSceneInfo); break; } @@ -243,6 +245,12 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine // cameraInfo only valid after calling update const CameraInfo cameraInfo{ shadowMap.getCamera() }; + shadowMap.prepareCamera(cameraInfo); + shadowMap.prepareViewport(shadowMap.getViewport()); + shadowMap.prepareTime(userTime); + shadowMap.prepareShadowMapping(view.getVsmShadowOptions().highPrecision); + shadowMap.commitUniforms(driver); + // updatePrimitivesLod must be run before RenderPass::appendCommands. view.updatePrimitivesLod(engine, cameraInfo, scene->getRenderableData(), entry.range); @@ -256,7 +264,24 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine pass.sortCommands(engine); entry.executor = pass.getExecutor(); - entry.cameraInfo = cameraInfo; + + if (!view.hasVSM()) { + auto li = scene->getLightData().elementAt( + entry.shadowMap->getLightIndex()); + + auto const& params = engine.getLightManager().getShadowParams(li); + + const PolygonOffset polygonOffset = { // handle reversed Z + .slope = -params.options.polygonOffsetSlope, + .constant = -params.options.polygonOffsetConstant + }; + entry.executor.overridePolygonOffset(&polygonOffset); + } + + constexpr const backend::Viewport disabledScissor{ 0, 0, + (uint32_t)std::numeric_limits::max(), + (uint32_t)std::numeric_limits::max() }; + entry.executor.overrideScissor(&disabledScissor); } } @@ -274,8 +299,7 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine struct ShadowPassData { FrameGraphId tempBlurSrc{}; // temporary shadowmap when blurring FrameGraphId output; - uint32_t blurRt{}; - uint32_t shadowRt{}; + uint32_t rt{}; }; auto const& passList = prepareShadowPass.getData().passList; @@ -284,7 +308,7 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine continue; } - const uint8_t layer = entry.shadowMap->getLayer() + entry.face; + const uint8_t layer = entry.shadowMap->getLayer(); const auto* options = entry.shadowMap->getShadowOptions(); auto& shadowPass = fg.addPass("Shadow Pass", @@ -333,7 +357,7 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine data.tempBlurSrc = builder.write(data.tempBlurSrc, FrameGraphTexture::Usage::COLOR_ATTACHMENT); - data.blurRt = builder.declareRenderPass("Temp Shadow RT", { + data.rt = builder.declareRenderPass("Temp Shadow RT", { .attachments = { .color = { data.tempBlurSrc }, .depth = depth }, @@ -352,9 +376,13 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine } // finally, create the shadowmap render target -- one per layer. - data.shadowRt = builder.declareRenderPass("Shadow RT", renderTargetDesc); + auto rt = builder.declareRenderPass("Shadow RT", renderTargetDesc); + + // render either directly into the shadowmap, or to the temporary texture for + // blurring. + data.rt = blur ? data.rt : rt; }, - [=, &engine, &entry, &view](FrameGraphResources const& resources, + [=, &engine, &entry](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { // Note: we capture entry by reference here. That's actually okay because @@ -364,62 +392,14 @@ FrameGraphId ShadowMapManager::render(FrameGraph& fg, FEngine // It wouldn't work to capture by copy because entry.pass wouldn't be // initialized, as this happens in an `execute` block. - auto& executor = entry.executor; - CameraInfo const& cameraInfo = entry.cameraInfo; + entry.shadowMap->bindPerViewUniformsAndSamplers(driver); - const bool blur = view.hasVSM() && options->vsm.blurWidth > 0.0f; - - // set uniforms relative to the camera - view.prepareCamera(cameraInfo); - - // We set a viewport with a 1-texel border for when we index outside the - // texture. - // DON'T CHANGE this unless ShadowMap::getTextureCoordsMapping() is updated too. - // see: ShadowMap::getTextureCoordsMapping() - // - // For floating-point depth textures, the 1-texel border could be set to - // FLOAT_MAX to avoid clamping in the shadow shader (see sampleDepth inside - // shadowing.fs). Unfortunately, the APIs don't seem let us clear depth - // attachments to anything greater than 1.0, so we'd need a way to do this other - // than clearing. - const uint32_t dim = options->mapSize; - filament::Viewport viewport{ 1, 1, dim - 2, dim - 2 }; - if (entry.shadowMap->isPointShadow()) { - // for point-light we don't have a border - viewport = { 0, 0, dim, dim }; - } - - view.prepareViewport(viewport, 0, 0); - - view.commitUniforms(driver); - - // render either directly into the shadowmap, or to the temporary texture for - // blurring. - auto rt = resources.getRenderPassInfo(blur ? data.blurRt : data.shadowRt); - rt.params.viewport = viewport; - - constexpr const backend::Viewport disabledScissor{ 0, 0, - (uint32_t)std::numeric_limits::max(), - (uint32_t)std::numeric_limits::max() }; - - if (!view.hasVSM()) { - auto li = scene->getLightData().elementAt( - entry.shadowMap->getLightIndex()); - - auto const& params = engine.getLightManager().getShadowParams(li); - - const PolygonOffset polygonOffset = { // handle reversed Z - .slope = -params.options.polygonOffsetSlope, - .constant = -params.options.polygonOffsetConstant - }; - executor.overridePolygonOffset(&polygonOffset); - } - - executor.overrideScissor(&disabledScissor); + auto rt = resources.getRenderPassInfo(data.rt); + rt.params.viewport = entry.shadowMap->getViewport(); engine.flush(); driver.beginRenderPass(rt.target, rt.params); - executor.execute(engine, "Shadow Pass"); + entry.executor.execute(engine, "Shadow Pass"); driver.endRenderPass(); }); @@ -710,9 +690,10 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap, void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap, FEngine& engine, FView& view, CameraInfo const& mainCameraInfo, FScene::RenderableSoa& renderableData, utils::Range range, - FScene::LightSoa& lightData, uint8_t face, + FScene::LightSoa& lightData, ShadowMap::SceneInfo const& sceneInfo) noexcept { + const uint8_t face = shadowMap.getFace(); const size_t lightIndex = shadowMap.getLightIndex(); FLightManager::ShadowOptions const* const options = shadowMap.getShadowOptions(); @@ -803,9 +784,15 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine shadowTechnique |= ShadowTechnique::SHADOW_MAP; for (auto const* pShadowMap : mSpotShadowMaps) { const size_t lightIndex = pShadowMap->getLightIndex(); - shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly? - shadowInfo[lightIndex].index = pShadowMap->getShadowIndex(); - shadowInfo[lightIndex].layer = pShadowMap->getLayer(); + + // FIXME: currently we have one slot per shadowmap in the UBO, but we now have up to + // 6 shadowmap per light. So for now, we only write the data of the face 0, + // and the shader will figure out where to find the other face (layer+face) + if (pShadowMap->getFace() == 0) { + shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly? + shadowInfo[lightIndex].index = pShadowMap->getShadowIndex(); + shadowInfo[lightIndex].layer = pShadowMap->getLayer(); + } } } @@ -846,10 +833,6 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view maxDimension = std::max(maxDimension, options->mapSize); elvsm = elvsm || options->vsm.elvsm; pShadowMap->setLayer(layer++); - if (pShadowMap->isPointShadow()) { - // FIXME: we need to make sure we don't exceed 256 - layer += 5; - } } const uint8_t layersNeeded = layer; diff --git a/filament/src/ShadowMapManager.h b/filament/src/ShadowMapManager.h index 52e0acf5c1..5f95314423 100644 --- a/filament/src/ShadowMapManager.h +++ b/filament/src/ShadowMapManager.h @@ -90,8 +90,8 @@ public: FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept; // Renders all the shadow maps. - FrameGraphId render(FrameGraph& fg, FEngine& engine, - RenderPass const& pass, FView& view, CameraInfo const& mainCameraInfo) noexcept; + FrameGraphId render(FEngine& engine, FrameGraph& fg, RenderPass const& pass, + FView& view, CameraInfo const& mainCameraInfo, math::float4 const& userTime) noexcept; ShadowMap* getCascadeShadowMap(size_t cascade) noexcept { assert_invariant(cascade < CONFIG_MAX_SHADOW_CASCADES); @@ -140,7 +140,7 @@ private: void preparePointShadowMap(ShadowMap& map, FEngine& engine, FView& view, CameraInfo const& mainCameraInfo, FScene::RenderableSoa& renderableData, utils::Range range, - FScene::LightSoa& lightData, uint8_t face, + FScene::LightSoa& lightData, ShadowMap::SceneInfo const& sceneInfo) noexcept; static void updateSpotVisibilityMasks( diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index e38b98a3a5..446a4337bc 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -656,7 +656,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { RenderPass shadowPass(pass); shadowPass.setVariant(shadowVariant); - auto shadows = view.renderShadowMaps(fg, engine, cameraInfo, shadowPass); + auto shadows = view.renderShadowMaps(engine, fg, cameraInfo, mShaderUserTime, shadowPass); blackboard["shadows"] = shadows; } @@ -740,8 +740,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { // view set-ups that need to happen before rendering fg.addTrivialSideEffectPass("Prepare View Uniforms", - [=, &uniforms = view.getPerViewUniforms()](DriverApi& driver) { - uniforms.prepareCamera(cameraInfo); + [=, &view](DriverApi& driver) { + view.prepareCamera(cameraInfo); // The code here is a little fragile. In theory, we need to call prepareViewport() // for each render pass, because the viewport parameters depend on the resolution. @@ -761,11 +761,14 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { // The reason why this bug is acceptable is that the viewport parameters are // currently only used for generating noise, so it's not too bad. - uniforms.prepareViewport(svp, + view.prepareViewport(svp, xvp.left * aoOptions.resolution, xvp.bottom * aoOptions.resolution); - uniforms.commit(driver); + view.commitUniforms(driver); + + // set uniforms and samplers for the color passes + view.bindPerViewUniformsAndSamplers(driver); }); // -------------------------------------------------------------------------------------------- diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp index 80fed63e84..c5f066bf9f 100644 --- a/filament/src/details/View.cpp +++ b/filament/src/details/View.cpp @@ -606,9 +606,19 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena, mPerViewUniforms.prepareFog(cameraInfo.getPosition(), mFogOptions); mPerViewUniforms.prepareTemporalNoise(mTemporalAntiAliasingOptions); mPerViewUniforms.prepareBlending(needsAlphaChannel); +} - // set uniforms and samplers - bindPerViewUniformsAndSamplers(driver); +void FView::bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept { + mPerViewUniforms.bind(driver); + + driver.bindUniformBuffer(+UniformBindingPoints::LIGHTS, + mLightUbh); + + driver.bindUniformBuffer(+UniformBindingPoints::SHADOW, + mShadowMapManager.getShadowUniformsHandle()); + + driver.bindUniformBuffer(+UniformBindingPoints::FROXEL_RECORDS, + mFroxelizer.getRecordBuffer()); } void FView::computeVisibilityMasks( @@ -656,7 +666,9 @@ UTILS_NOINLINE void FView::prepareUpscaler(float2 scale) const noexcept { SYSTRACE_CALL(); - mPerViewUniforms.prepareUpscaler(scale, mDynamicResolution); + const float bias = (mDynamicResolution.quality >= QualityLevel::HIGH) ? + std::log2(std::min(scale.x, scale.y)) : 0.0f; + mPerViewUniforms.prepareLodBias(bias); } void FView::prepareCamera(const CameraInfo& cameraInfo) const noexcept { @@ -711,7 +723,7 @@ void FView::prepareShadow(Handle texture) const noexcept { } } -void FView::prepareShadowMap(bool highPrecision) const noexcept { +void FView::prepareShadowMapping(bool highPrecision) const noexcept { mPerViewUniforms.prepareShadowMapping(highPrecision); } @@ -894,9 +906,9 @@ void FView::updatePrimitivesLod(FEngine& engine, const CameraInfo&, } } -FrameGraphId FView::renderShadowMaps(FrameGraph& fg, FEngine& engine, - CameraInfo const& cameraInfo, RenderPass const& pass) noexcept { - return mShadowMapManager.render(fg, engine, pass, *this, cameraInfo); +FrameGraphId FView::renderShadowMaps(FEngine& engine, FrameGraph& fg, + CameraInfo const& cameraInfo, float4 const& userTime, RenderPass const& pass) noexcept { + return mShadowMapManager.render(engine, fg, pass, *this, cameraInfo, userTime); } void FView::commitFrameHistory(FEngine& engine) noexcept { diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 4a23bc235c..8267ae8446 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -92,6 +92,8 @@ public: filament::Viewport const& viewport, CameraInfo const& cameraInfo, math::float4 const& userTime, bool needsAlphaChannel) noexcept; + void bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept; + void setScene(FScene* scene) { mScene = scene; } FScene const* getScene() const noexcept { return mScene; } FScene* getScene() noexcept { return mScene; } @@ -148,7 +150,7 @@ public: ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept; void prepareStructure(backend::Handle structure) const noexcept; void prepareShadow(backend::Handle structure) const noexcept; - void prepareShadowMap(bool highPrecision) const noexcept; + void prepareShadowMapping(bool highPrecision) const noexcept; void cleanupRenderPasses() const noexcept; void froxelize(FEngine& engine, math::mat4f const& viewMatrix) const noexcept; @@ -165,8 +167,9 @@ public: bool hasPCSS() const noexcept { return mShadowType == ShadowType::PCSS; } bool hasPicking() const noexcept { return mActivePickingQueriesList != nullptr; } - FrameGraphId renderShadowMaps(FrameGraph& fg, FEngine& engine, - CameraInfo const& cameraInfo, RenderPass const& pass) noexcept; + FrameGraphId renderShadowMaps(FEngine& engine, FrameGraph& fg, + CameraInfo const& cameraInfo, math::float4 const& userTime, + RenderPass const& pass) noexcept; void updatePrimitivesLod( FEngine& engine, const CameraInfo& camera, @@ -451,13 +454,6 @@ private: Culler::result_type* visibleMask, size_t count); - void bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept { - mPerViewUniforms.bind(driver); - driver.bindUniformBuffer(+UniformBindingPoints::LIGHTS, mLightUbh); - driver.bindUniformBuffer(+UniformBindingPoints::SHADOW, mShadowMapManager.getShadowUniformsHandle()); - driver.bindUniformBuffer(+UniformBindingPoints::FROXEL_RECORDS, mFroxelizer.getRecordBuffer()); - } - // Clean-up the whole history, free all resources. This is typically called when the View is // being terminated. void drainFrameHistory(FEngine& engine) noexcept;