From 9c857f64aeef948b6ddb1c78a25ea56fce6f48ff Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 16 Aug 2024 20:57:58 -0700 Subject: [PATCH 1/3] improve split-view mode - side panel doesn't overlap with content anymore --- libs/filamentapp/src/FilamentApp.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/libs/filamentapp/src/FilamentApp.cpp b/libs/filamentapp/src/FilamentApp.cpp index 84071b4261..8ffc4c0f34 100644 --- a/libs/filamentapp/src/FilamentApp.cpp +++ b/libs/filamentapp/src/FilamentApp.cpp @@ -907,9 +907,7 @@ void FilamentApp::Window::configureCamerasForWindow() { const bool splitview = mViews.size() > 2; - // To trigger a floating-point exception, users could shrink the window to be smaller than - // the sidebar. To prevent this we simply clamp the width of the main viewport. - const uint32_t mainWidth = splitview ? width : std::max(1, (int) width - sidebar); + const uint32_t mainWidth = std::max(2, (int) width - sidebar); double near = mFilamentApp->mCameraNear; double far = mFilamentApp->mCameraFar; @@ -924,7 +922,7 @@ void FilamentApp::Window::configureCamerasForWindow() { } else { mMainCamera->setLensProjection(mFilamentApp->mCameraFocalLength, 1.0, near, far); } - mDebugCamera->setProjection(45.0, double(width) / height, 0.0625, 4096, Camera::Fov::VERTICAL); + mDebugCamera->setProjection(45.0, double(mainWidth) / height, 0.0625, 4096, Camera::Fov::VERTICAL); auto aspectRatio = double(mainWidth) / height; if (mMainView->getView()->getStereoscopicOptions().enabled) { @@ -935,12 +933,12 @@ void FilamentApp::Window::configureCamerasForWindow() { // We're in split view when there are more views than just the Main and UI views. if (splitview) { - uint32_t vpw = width / 2; - uint32_t vph = height / 2; - mMainView->setViewport ({ 0, 0, vpw, vph }); - mDepthView->setViewport({ int32_t(vpw), 0, width - vpw, vph }); - mGodView->setViewport ({ int32_t(vpw), int32_t(vph), width - vpw, height - vph }); - mOrthoView->setViewport({ 0, int32_t(vph), vpw, height - vph }); + uint32_t const vpw = mainWidth / 2; + uint32_t const vph = height / 2; + mMainView->setViewport ({ sidebar + 0, 0, vpw, vph }); + mDepthView->setViewport({ sidebar + int32_t(vpw), 0, vpw, vph }); + mGodView->setViewport ({ sidebar + int32_t(vpw), int32_t(vph), vpw, vph }); + mOrthoView->setViewport({ sidebar + 0, int32_t(vph), vpw, vph }); } else { mMainView->setViewport({ sidebar, 0, mainWidth, height }); } From 063affb61261a366225b44a7f03c76f0b2210d32 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 16 Aug 2024 23:54:55 -0700 Subject: [PATCH 2/3] more improvement of csm display --- filament/include/filament/View.h | 3 +- filament/src/ShadowMapManager.cpp | 11 +++ filament/src/ShadowMapManager.h | 13 ++-- filament/src/View.cpp | 4 +- filament/src/details/View.h | 6 +- libs/filamentapp/include/filamentapp/Cube.h | 10 ++- .../include/filamentapp/FilamentApp.h | 8 +- libs/filamentapp/src/Cube.cpp | 16 +++- libs/filamentapp/src/FilamentApp.cpp | 75 ++++++++++++------- 9 files changed, 102 insertions(+), 44 deletions(-) diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index 5264cdae49..d4c9848de8 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -24,6 +24,7 @@ #include #include +#include #include @@ -727,7 +728,7 @@ public: void setDebugCamera(Camera* UTILS_NULLABLE camera) noexcept; //! debugging: returns a Camera from the point of view of *the* dominant directional light used for shadowing. - Camera const* UTILS_NULLABLE getDirectionalShadowCamera() const noexcept; + utils::FixedCapacityVector getDirectionalShadowCameras() const noexcept; /** Result of a picking query */ diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index 63a1bb900e..a6f4a9fa3c 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -1076,4 +1076,15 @@ void ShadowMapManager::updateNearFarPlanes(mat4f* projection, p[3].z = (sf * F.w - sn * N.w) * 0.5f; } +utils::FixedCapacityVector +ShadowMapManager::getDirectionalShadowCameras() const noexcept { + if (!mInitialized) return {}; + auto const csm = getCascadedShadowMap(); + auto result = utils::FixedCapacityVector::with_capacity(csm.size()); + for (ShadowMap const& sm : csm) { + result.push_back(sm.hasVisibleShadows() ? sm.getDebugCamera() : nullptr); + } + return result; +} + } // namespace filament diff --git a/filament/src/ShadowMapManager.h b/filament/src/ShadowMapManager.h index 8b12eaa6a0..18b4a24e19 100644 --- a/filament/src/ShadowMapManager.h +++ b/filament/src/ShadowMapManager.h @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,7 @@ namespace filament { +class Camera; class FCamera; class FView; class FrameGraph; @@ -138,10 +140,7 @@ public: bool hasSpotShadows() const { return !mSpotShadowMapCount; } // for debugging only - FCamera const* getDirectionalShadowCamera() const noexcept { - if (!mInitialized) return nullptr; - return getShadowMap(0).getDebugCamera(); - } + utils::FixedCapacityVector getDirectionalShadowCameras() const noexcept; private: explicit ShadowMapManager(FEngine& engine); @@ -245,10 +244,14 @@ private: } utils::Slice getCascadedShadowMap() noexcept { - ShadowMap* const p = &getShadowMap(0); + ShadowMap const* const p = &getShadowMap(0); return { p, mDirectionalShadowMapCount }; } + utils::Slice getCascadedShadowMap() const noexcept { + return const_cast(this)->getCascadedShadowMap(); + } + utils::Slice getSpotShadowMaps() noexcept { ShadowMap* const p = &getShadowMap(CONFIG_MAX_SHADOW_CASCADES); return { p, mSpotShadowMapCount }; diff --git a/filament/src/View.cpp b/filament/src/View.cpp index abdd615ab8..65635f3f64 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -73,8 +73,8 @@ const char* View::getName() const noexcept { return downcast(this)->getName(); } -Camera const* View::getDirectionalShadowCamera() const noexcept { - return downcast(this)->getDirectionalShadowCamera(); +utils::FixedCapacityVector View::getDirectionalShadowCameras() const noexcept { + return downcast(this)->getDirectionalShadowCameras(); } void View::setShadowingEnabled(bool enabled) noexcept { diff --git a/filament/src/details/View.h b/filament/src/details/View.h index e24f150a2d..2a2f9a414f 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -201,9 +201,9 @@ public: void setStereoscopicOptions(StereoscopicOptions const& options) noexcept; - FCamera const* getDirectionalShadowCamera() const noexcept { - if (!mShadowMapManager) return nullptr; - return mShadowMapManager->getDirectionalShadowCamera(); + utils::FixedCapacityVector getDirectionalShadowCameras() const noexcept { + if (!mShadowMapManager) return {}; + return mShadowMapManager->getDirectionalShadowCameras(); } void setRenderTarget(FRenderTarget* renderTarget) noexcept { diff --git a/libs/filamentapp/include/filamentapp/Cube.h b/libs/filamentapp/include/filamentapp/Cube.h index 778c645fd0..53a8ef36d1 100644 --- a/libs/filamentapp/include/filamentapp/Cube.h +++ b/libs/filamentapp/include/filamentapp/Cube.h @@ -28,8 +28,14 @@ class Cube { public: + Cube(filament::Engine& engine, filament::Material const* material, filament::math::float3 linearColor, bool culling = true); + Cube(Cube const&) = delete; + Cube& operator=(Cube const&) = delete; + + Cube(Cube&& rhs) noexcept; + utils::Entity getSolidRenderable() { return mSolidRenderable; } @@ -55,8 +61,8 @@ private: filament::Material const* mMaterial = nullptr; filament::MaterialInstance* mMaterialInstanceSolid = nullptr; filament::MaterialInstance* mMaterialInstanceWireFrame = nullptr; - utils::Entity mSolidRenderable; - utils::Entity mWireFrameRenderable; + utils::Entity mSolidRenderable{}; + utils::Entity mWireFrameRenderable{}; }; diff --git a/libs/filamentapp/include/filamentapp/FilamentApp.h b/libs/filamentapp/include/filamentapp/FilamentApp.h index d7087d0f0b..e50f312cd3 100644 --- a/libs/filamentapp/include/filamentapp/FilamentApp.h +++ b/libs/filamentapp/include/filamentapp/FilamentApp.h @@ -211,11 +211,11 @@ private: filament::Camera* mOrthoCamera; std::vector> mViews; - CView* mMainView; - CView* mUiView; + CView* mMainView; // well, the main view + CView* mUiView; // the imgui ui CView* mDepthView; - GodView* mGodView; - CView* mOrthoView; + GodView* mGodView; // the debug view with "god" camera + CView* mOrthoView; // directional shadow map view size_t mWidth = 0; size_t mHeight = 0; diff --git a/libs/filamentapp/src/Cube.cpp b/libs/filamentapp/src/Cube.cpp index cd2faa0bc0..a8027b6953 100644 --- a/libs/filamentapp/src/Cube.cpp +++ b/libs/filamentapp/src/Cube.cpp @@ -104,11 +104,23 @@ Cube::Cube(Engine& engine, filament::Material const* material, float3 linearColo .build(engine, mWireFrameRenderable); } +Cube::Cube(Cube&& rhs) noexcept + : mEngine(rhs.mEngine) { + using std::swap; + swap(rhs.mVertexBuffer, mVertexBuffer); + swap(rhs.mIndexBuffer, mIndexBuffer); + swap(rhs.mMaterial, mMaterial); + swap(rhs.mMaterialInstanceSolid, mMaterialInstanceSolid); + swap(rhs.mMaterialInstanceWireFrame, mMaterialInstanceWireFrame); + swap(rhs.mSolidRenderable, mSolidRenderable); + swap(rhs.mWireFrameRenderable, mWireFrameRenderable); +} + void Cube::mapFrustum(filament::Engine& engine, Camera const* camera) { // the Camera far plane is at infinity, but we want it closer for display const mat4 vm(camera->getModelMatrix()); mat4 p(vm * inverse(camera->getCullingProjectionMatrix())); - return mapFrustum(engine, p); + mapFrustum(engine, p); } void Cube::mapFrustum(filament::Engine& engine, filament::math::mat4 const& transform) { @@ -122,7 +134,7 @@ void Cube::mapFrustum(filament::Engine& engine, filament::math::mat4 const& tran void Cube::mapAabb(filament::Engine& engine, filament::Box const& box) { mat4 p = mat4::translation(box.center) * mat4::scaling(box.halfExtent); - return mapFrustum(engine, p); + mapFrustum(engine, p); } Cube::~Cube() { diff --git a/libs/filamentapp/src/FilamentApp.cpp b/libs/filamentapp/src/FilamentApp.cpp index 8ffc4c0f34..d4e4b44ac3 100644 --- a/libs/filamentapp/src/FilamentApp.cpp +++ b/libs/filamentapp/src/FilamentApp.cpp @@ -1,4 +1,3 @@ -#include /* * Copyright (C) 2015 The Android Open Source Project @@ -56,6 +55,13 @@ #include +#include +#include +#include +#include + +#include + #include "generated/resources/filamentapp.h" using namespace filament; @@ -138,10 +144,17 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, .package(FILAMENTAPP_TRANSPARENTCOLOR_DATA, FILAMENTAPP_TRANSPARENTCOLOR_SIZE) .build(*mEngine); - std::unique_ptr cameraCube(new Cube(*mEngine, mTransparentMaterial, {1,0,0})); + std::unique_ptr cameraCube{ new Cube(*mEngine, mTransparentMaterial, { 1, 0, 0 }) }; + // we can't cull the light-frustum because it's not applied a rigid transform // and currently, filament assumes that for culling - std::unique_ptr lightmapCube(new Cube(*mEngine, mTransparentMaterial, {0,1,0}, false)); + std::vector lightmapCubes; + lightmapCubes.reserve(4); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 0, 1, 0 }, false); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 0, 0, 1 }, false); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 1, 1, 0 }, false); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 1, 0, 0 }, false); + mScene = mEngine->createScene(); window->mMainView->getView()->setVisibleLayers(0x4, 0x4); @@ -151,16 +164,15 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, rcm.setLayerMask(rcm.getInstance(cameraCube->getSolidRenderable()), 0x3, 0x2); rcm.setLayerMask(rcm.getInstance(cameraCube->getWireFrameRenderable()), 0x3, 0x2); - - rcm.setLayerMask(rcm.getInstance(lightmapCube->getSolidRenderable()), 0x3, 0x2); - rcm.setLayerMask(rcm.getInstance(lightmapCube->getWireFrameRenderable()), 0x3, 0x2); - - // Create the camera mesh mScene->addEntity(cameraCube->getWireFrameRenderable()); mScene->addEntity(cameraCube->getSolidRenderable()); - mScene->addEntity(lightmapCube->getWireFrameRenderable()); - mScene->addEntity(lightmapCube->getSolidRenderable()); + for (auto&& cube : lightmapCubes) { + rcm.setLayerMask(rcm.getInstance(cube.getSolidRenderable()), 0x3, 0x2); + rcm.setLayerMask(rcm.getInstance(cube.getWireFrameRenderable()), 0x3, 0x2); + mScene->addEntity(cube.getWireFrameRenderable()); + mScene->addEntity(cube.getSolidRenderable()); + } window->mDepthView->getView()->setVisibleLayers(0x4, 0x4); window->mGodView->getView()->setVisibleLayers(0x6, 0x6); @@ -425,10 +437,26 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, window->mDebugCamera->lookAt(eye, center, up); // Update the cube distortion matrix used for frustum visualization. - const Camera* lightmapCamera = window->mMainView->getView()->getDirectionalShadowCamera(); - if (lightmapCamera) { - lightmapCube->mapFrustum(*mEngine, lightmapCamera); + auto& rcm = mEngine->getRenderableManager(); + auto const csm = window->mMainView->getView()->getDirectionalShadowCameras(); + // show/hide the cascades + for (size_t i = 0 ; i < 4; i++) { + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getSolidRenderable()), 0x3, 0x0); + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getWireFrameRenderable()), 0x3, 0x0); } + if (!csm.empty()) { + for (size_t i = 0, c = csm.size(); i < c; i++) { + if (csm[i]) { + lightmapCubes[i].mapFrustum(*mEngine, csm[i]); + } + uint8_t const layer = csm[i] ? 0x2 : 0x0; + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getSolidRenderable()), + 0x3, layer); + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getWireFrameRenderable()), + 0x3, layer); + } + } + cameraCube->mapFrustum(*mEngine, window->mMainCamera); // Delay rendering for roughly one monitor refresh interval @@ -452,11 +480,14 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, if (config.splitView) { if(!window->mOrthoView->getView()->hasCamera()) { - Camera const* debugDirectionalShadowCamera = - window->mMainView->getView()->getDirectionalShadowCamera(); - if (debugDirectionalShadowCamera) { - window->mOrthoView->setCamera( - const_cast(debugDirectionalShadowCamera)); + auto const csm = window->mMainView->getView()->getDirectionalShadowCameras(); + if (!csm.empty()) { + // here we could choose the cascade + Camera const* debugDirectionalShadowCamera = csm[0]; + if (debugDirectionalShadowCamera) { + window->mOrthoView->setCamera( + const_cast(debugDirectionalShadowCamera)); + } } } } @@ -484,7 +515,7 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, cleanupCallback(mEngine, window->mMainView->getView(), mScene); cameraCube.reset(); - lightmapCube.reset(); + lightmapCubes.clear(); window.reset(); mIBL.reset(); @@ -736,12 +767,6 @@ FilamentApp::Window::Window(FilamentApp* filamentApp, mGodView->setCamera(mMainCamera); mGodView->setGodCamera(mDebugCamera); mGodView->setCameraManipulator(mDebugCameraMan); - - // Ortho view obviously uses an ortho camera - Camera const* debugDirectionalShadowCamera = mMainView->getView()->getDirectionalShadowCamera(); - if (debugDirectionalShadowCamera) { - mOrthoView->setCamera(const_cast(debugDirectionalShadowCamera)); - } } // configure the cameras From 6c0bd360b309a46a603668531e85baa845000826 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 22 Nov 2022 12:58:32 -0800 Subject: [PATCH 3/3] Add support for depth clamp and use it for shadows vk, metal and desktop gl all support depth clamp, GLES/android also does with ANGLE. Add support for it in the backends. use depth clamp to improve directional shadow quality; this allows to render everything that's behind the camera at the same "zero" depth, so we can reduce the depth range we need. Fixes #6293 --- .../backend/include/backend/DriverEnums.h | 2 +- .../include/private/backend/DriverAPI.inc | 1 + filament/backend/src/metal/MetalContext.h | 1 + filament/backend/src/metal/MetalDriver.mm | 11 +++++++++ filament/backend/src/metal/MetalState.h | 1 + filament/backend/src/noop/NoopDriver.cpp | 4 ++++ filament/backend/src/opengl/OpenGLContext.cpp | 2 ++ filament/backend/src/opengl/OpenGLContext.h | 10 ++++---- filament/backend/src/opengl/OpenGLDriver.cpp | 12 ++++++++++ filament/backend/src/opengl/gl_headers.h | 6 +++++ filament/backend/src/vulkan/VulkanContext.h | 4 ++++ filament/backend/src/vulkan/VulkanDriver.cpp | 6 +++++ .../src/vulkan/VulkanPipelineCache.cpp | 1 + .../backend/src/vulkan/VulkanPipelineCache.h | 4 +++- .../src/vulkan/platform/VulkanPlatform.cpp | 1 + filament/src/RenderPass.cpp | 11 +++++++-- filament/src/RenderPass.h | 3 ++- filament/src/ShadowMap.cpp | 12 +++++----- filament/src/ShadowMapManager.cpp | 20 ++++++++++++---- filament/src/ShadowMapManager.h | 1 + filament/src/details/DebugRegistry.cpp | 24 +++++++------------ filament/src/details/Engine.h | 1 + samples/gltf_viewer.cpp | 2 ++ 23 files changed, 104 insertions(+), 36 deletions(-) diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index 8da0cfb02f..35cd89a57e 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -1058,7 +1058,7 @@ struct RasterState { bool inverseFrontFaces : 1; // 31 //! padding, must be 0 - uint8_t padding : 1; // 32 + bool depthClamp : 1; // 32 }; uint32_t u = 0; }; diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index b92a07f37b..d27cea8f4c 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -305,6 +305,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isParallelShaderCompileSupported) DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported) DECL_DRIVER_API_SYNCHRONOUS_N(bool, isDepthStencilBlitSupported, backend::TextureFormat, format) DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported) +DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported) DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers) DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize) DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams) diff --git a/filament/backend/src/metal/MetalContext.h b/filament/backend/src/metal/MetalContext.h index f771ca5b41..fc8cfc12b4 100644 --- a/filament/backend/src/metal/MetalContext.h +++ b/filament/backend/src/metal/MetalContext.h @@ -112,6 +112,7 @@ struct MetalContext { std::array ssboState; CullModeStateTracker cullModeState; WindingStateTracker windingState; + DepthClampStateTracker depthClampState; Handle currentRenderPrimitive; // State caches. diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index a9a0df24ed..397a159933 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -834,6 +834,10 @@ bool MetalDriver::isProtectedTexturesSupported() { return false; } +bool MetalDriver::isDepthClampSupported() { + return true; +} + bool MetalDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: @@ -1751,6 +1755,13 @@ void MetalDriver::bindPipeline(PipelineState const& ps) { [mContext->currentRenderPassEncoder setFrontFacingWinding:winding]; } + // depth clip mode + MTLDepthClipMode depthClipMode = rs.depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip; + mContext->depthClampState.updateState(depthClipMode); + if (mContext->depthClampState.stateChanged()) { + [mContext->currentRenderPassEncoder setDepthClipMode:depthClipMode]; + } + // Set the depth-stencil state, if a state change is needed. DepthStencilState depthState; if (depthAttachment) { diff --git a/filament/backend/src/metal/MetalState.h b/filament/backend/src/metal/MetalState.h index 83579cb5d5..1d541cc006 100644 --- a/filament/backend/src/metal/MetalState.h +++ b/filament/backend/src/metal/MetalState.h @@ -382,6 +382,7 @@ using SamplerStateCache = StateCache, SamplerS using CullModeStateTracker = StateTracker; using WindingStateTracker = StateTracker; +using DepthClampStateTracker = StateTracker; // Argument encoder diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index ea5c526402..a692cfce83 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -202,6 +202,10 @@ bool NoopDriver::isProtectedTexturesSupported() { return true; } +bool NoopDriver::isDepthClampSupported() { + return false; +} + bool NoopDriver::isWorkaroundNeeded(Workaround) { return false; } diff --git a/filament/backend/src/opengl/OpenGLContext.cpp b/filament/backend/src/opengl/OpenGLContext.cpp index 423f8865cc..9654545825 100644 --- a/filament/backend/src/opengl/OpenGLContext.cpp +++ b/filament/backend/src/opengl/OpenGLContext.cpp @@ -679,6 +679,7 @@ void OpenGLContext::initExtensionsGLES(Extensions* ext, GLint major, GLint minor #ifndef __EMSCRIPTEN__ ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv); #endif + ext->EXT_depth_clamp = exts.has("GL_EXT_depth_clamp"sv); ext->EXT_discard_framebuffer = exts.has("GL_EXT_discard_framebuffer"sv); #ifndef __EMSCRIPTEN__ ext->EXT_disjoint_timer_query = exts.has("GL_EXT_disjoint_timer_query"sv); @@ -749,6 +750,7 @@ void OpenGLContext::initExtensionsGL(Extensions* ext, GLint major, GLint minor) ext->EXT_color_buffer_half_float = true; // Assumes core profile. ext->EXT_clip_cull_distance = true; ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv); + ext->EXT_depth_clamp = true; ext->EXT_discard_framebuffer = false; ext->EXT_disjoint_timer_query = true; ext->EXT_multisampled_render_to_texture = false; diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index a4a43e8fe0..3b4724b095 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -220,8 +220,9 @@ public: bool EXT_color_buffer_float; bool EXT_color_buffer_half_float; bool EXT_debug_marker; - bool EXT_disjoint_timer_query; + bool EXT_depth_clamp; bool EXT_discard_framebuffer; + bool EXT_disjoint_timer_query; bool EXT_multisampled_render_to_texture2; bool EXT_multisampled_render_to_texture; bool EXT_protected_textures; @@ -239,10 +240,10 @@ public: bool KHR_parallel_shader_compile; bool KHR_texture_compression_astc_hdr; bool KHR_texture_compression_astc_ldr; - bool OES_depth_texture; - bool OES_depth24; - bool OES_packed_depth_stencil; bool OES_EGL_image_external_essl3; + bool OES_depth24; + bool OES_depth_texture; + bool OES_packed_depth_stencil; bool OES_rgb8_rgba8; bool OES_standard_derivatives; bool OES_texture_npot; @@ -636,6 +637,7 @@ constexpr size_t OpenGLContext::getIndexForCap(GLenum cap) noexcept { //NOLINT #ifdef BACKEND_OPENGL_VERSION_GL case GL_PROGRAM_POINT_SIZE: index = 10; break; #endif + case GL_DEPTH_CLAMP: index = 11; break; default: break; } assert_invariant(index < state.enables.caps.size()); diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 274e7b71d3..fdf567849e 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -451,6 +451,14 @@ void OpenGLDriver::setRasterState(RasterState rs) noexcept { } else { gl.disable(GL_SAMPLE_ALPHA_TO_COVERAGE); } + + if (gl.ext.EXT_depth_clamp) { + if (rs.depthClamp) { + gl.enable(GL_DEPTH_CLAMP); + } else { + gl.disable(GL_DEPTH_CLAMP); + } + } } void OpenGLDriver::setStencilState(StencilState ss) noexcept { @@ -2119,6 +2127,10 @@ bool OpenGLDriver::isProtectedTexturesSupported() { return getContext().ext.EXT_protected_textures; } +bool OpenGLDriver::isDepthClampSupported() { + return getContext().ext.EXT_depth_clamp; +} + bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: diff --git a/filament/backend/src/opengl/gl_headers.h b/filament/backend/src/opengl/gl_headers.h index 569c8ed285..04ad63ff6a 100644 --- a/filament/backend/src/opengl/gl_headers.h +++ b/filament/backend/src/opengl/gl_headers.h @@ -201,6 +201,12 @@ using namespace glext; # define GL_CLIP_DISTANCE1 0x3001 #endif +#if defined(GL_EXT_depth_clamp) +# define GL_DEPTH_CLAMP GL_DEPTH_CLAMP_EXT +#else +# define GL_DEPTH_CLAMP 0x864F +#endif + #if defined(GL_KHR_debug) # define GL_DEBUG_OUTPUT GL_DEBUG_OUTPUT_KHR # define GL_DEBUG_OUTPUT_SYNCHRONOUS GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index 9f506e03f7..46fe475612 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -125,6 +125,10 @@ public: return mPhysicalDeviceFeatures.imageCubeArray == VK_TRUE; } + inline bool isDepthClampSupported() const noexcept { + return mPhysicalDeviceFeatures.depthClamp == VK_TRUE; + } + inline bool isDebugMarkersSupported() const noexcept { return mDebugMarkersSupported; } diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index bf5604a0df..4602067663 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -944,6 +944,10 @@ bool VulkanDriver::isProtectedTexturesSupported() { return false; } +bool VulkanDriver::isDepthClampSupported() { + return mContext.isDepthClampSupported(); +} + bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: { @@ -1816,6 +1820,8 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { .dstAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionDstAlpha), .colorWriteMask = (VkColorComponentFlags) (rasterState.colorWrite ? 0xf : 0x0), .rasterizationSamples = rt->getSamples(), + .depthClamp = rasterState.depthClamp, + .reserved = 0, .colorTargetCount = rt->getColorTargetCount(mCurrentRenderPass), .colorBlendOp = rasterState.blendEquationRGB, .alphaBlendOp = rasterState.blendEquationAlpha, diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index 4c77525bd1..b3d09da86e 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -184,6 +184,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n vkRaster.polygonMode = VK_POLYGON_MODE_FILL; vkRaster.cullMode = raster.cullMode; vkRaster.frontFace = raster.frontFace; + vkRaster.depthClampEnable = raster.depthClamp; vkRaster.depthBiasEnable = raster.depthBiasEnable; vkRaster.depthBiasConstantFactor = raster.depthBiasConstantFactor; vkRaster.depthBiasClamp = 0.0f; diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.h b/filament/backend/src/vulkan/VulkanPipelineCache.h index e6816497c0..985574b74c 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineCache.h @@ -90,7 +90,9 @@ public: VkBlendFactor srcAlphaBlendFactor : 5; VkBlendFactor dstAlphaBlendFactor : 5; VkColorComponentFlags colorWriteMask : 4; - uint8_t rasterizationSamples; // offset = 4 bytes + uint8_t rasterizationSamples : 4;// offset = 4 bytes + uint8_t depthClamp : 1; + uint8_t reserved : 3; uint8_t colorTargetCount; // offset = 5 bytes BlendEquation colorBlendOp : 4; // offset = 6 bytes BlendEquation alphaBlendOp : 4; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp index b4152807cc..2e88542080 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp @@ -325,6 +325,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice, // We could simply enable all supported features, but since that may have performance // consequences let's just enable the features we need. VkPhysicalDeviceFeatures enabledFeatures{ + .depthClamp = features.depthClamp, .samplerAnisotropy = features.samplerAnisotropy, .textureCompressionETC2 = features.textureCompressionETC2, .textureCompressionBC = features.textureCompressionBC, diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 3dc95fa4f8..d9f4a74dc4 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -419,7 +419,8 @@ RenderPass::Command* RenderPass::instanceify(FEngine& engine, UTILS_ALWAYS_INLINE // This function exists only to make the code more readable. we want it inlined. inline // and we don't need it in the compilation unit void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant, - FMaterialInstance const* const UTILS_RESTRICT mi, bool inverseFrontFaces) noexcept { + FMaterialInstance const* const UTILS_RESTRICT mi, + bool inverseFrontFaces, bool hasDepthClamp) noexcept { FMaterial const * const UTILS_RESTRICT ma = mi->getMaterial(); variant = Variant::filterVariant(variant, ma->isVariantLit()); @@ -460,6 +461,7 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant, cmdDraw.info.rasterState.colorWrite = mi->isColorWriteEnabled(); cmdDraw.info.rasterState.depthWrite = mi->isDepthWriteEnabled(); cmdDraw.info.rasterState.depthFunc = mi->getDepthFunc(); + cmdDraw.info.rasterState.depthClamp = hasDepthClamp; cmdDraw.info.materialVariant = variant; // we keep "RasterState::colorWrite" to the value set by material (could be disabled) } @@ -558,6 +560,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla bool const hasInstancedStereo = renderFlags & IS_INSTANCED_STEREOSCOPIC; + bool const hasDepthClamp = + renderFlags & HAS_DEPTH_CLAMP; + float const cameraPositionDotCameraForward = dot(cameraPosition, cameraForward); auto const* const UTILS_RESTRICT soaWorldAABBCenter = soa.data(); @@ -577,6 +582,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla cmd.info.rasterState.depthWrite = true; cmd.info.rasterState.depthFunc = RasterState::DepthFunc::GE; cmd.info.rasterState.alphaToCoverage = false; + cmd.info.rasterState.depthClamp = hasDepthClamp; } for (uint32_t i = range.first; i < range.last; ++i) { @@ -691,7 +697,8 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla cmd.info.morphingOffset = primitive.getMorphingBufferOffset(); if constexpr (isColorPass) { - RenderPass::setupColorCommand(cmd, renderableVariant, mi, inverseFrontFaces); + RenderPass::setupColorCommand(cmd, renderableVariant, mi, + inverseFrontFaces, hasDepthClamp); const bool blendPass = Pass(cmd.key & PASS_MASK) == Pass::BLENDED; if (blendPass) { // TODO: at least for transparent objects, AABB should be per primitive diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index e729d67dd7..3cad6b5603 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -284,6 +284,7 @@ public: static constexpr RenderFlags HAS_SHADOWING = 0x01; static constexpr RenderFlags HAS_INVERSE_FRONT_FACES = 0x02; static constexpr RenderFlags IS_INSTANCED_STEREOSCOPIC = 0x04; + static constexpr RenderFlags HAS_DEPTH_CLAMP = 0x08; // Arena used for commands using Arena = utils::Arena< @@ -444,7 +445,7 @@ private: uint8_t instancedStereoEyeCount) noexcept; static void setupColorCommand(Command& cmdDraw, Variant variant, - FMaterialInstance const* mi, bool inverseFrontFaces) noexcept; + FMaterialInstance const* mi, bool inverseFrontFaces, bool hasDepthClamp) noexcept; static void updateSummedPrimitiveCounts( FScene::RenderableSoa& renderableData, utils::Range vr) noexcept; diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index 4c40668054..bbf008e4a0 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -829,13 +829,13 @@ ShadowMap::Corners ShadowMap::computeFrustumCorners( Corners const csViewFrustumCorners = { .vertices = { { -1, -1, far }, - { 1, -1, far }, - { -1, 1, far }, - { 1, 1, far }, + { 1, -1, far }, + { -1, 1, far }, + { 1, 1, far }, { -1, -1, near }, - { 1, -1, near }, - { -1, 1, near }, - { 1, 1, near }, + { 1, -1, near }, + { -1, 1, near }, + { 1, 1, near }, } }; diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index a6f4a9fa3c..1f3c902be5 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -66,15 +66,15 @@ namespace filament { using namespace backend; using namespace math; -// do this only if depth-clamp is available -static constexpr bool USE_DEPTH_CLAMP = false; - -ShadowMapManager::ShadowMapManager(FEngine& engine) { +ShadowMapManager::ShadowMapManager(FEngine& engine) + : mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()) { FDebugRegistry& debugRegistry = engine.getDebugRegistry(); debugRegistry.registerProperty("d.shadowmap.visualize_cascades", &engine.debug.shadowmap.visualize_cascades); debugRegistry.registerProperty("d.shadowmap.disable_light_frustum_align", &engine.debug.shadowmap.disable_light_frustum_align); + debugRegistry.registerProperty("d.shadowmap.depth_clamp", + &engine.debug.shadowmap.depth_clamp); } ShadowMapManager::~ShadowMapManager() { @@ -367,7 +367,16 @@ FrameGraphId ShadowMapManager::render(FEngine& engine, FrameG // generate and sort the commands for rendering the shadow map + RenderPass::RenderFlags renderPassFlags{}; + if (view.isFrontFaceWindingInverted()) { + renderPassFlags |= RenderPass::HAS_INVERSE_FRONT_FACES; + } + if (mIsDepthClampSupported && engine.debug.shadowmap.depth_clamp) { + renderPassFlags |= RenderPass::HAS_DEPTH_CLAMP; + } + RenderPass const pass = passBuilder + .renderFlags(renderPassFlags) .camera(cameraInfo) .visibilityMask(entry.visibilityMask) .geometry(scene->getRenderableData(), @@ -642,7 +651,8 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng updateNearFarPlanes(&cameraInfo.cullingProjection, cameraInfo.zn, cameraInfo.zf); auto shaderParameters = shadowMap.updateDirectional(engine, - lightData, 0, cameraInfo, shadowMapInfo, sceneInfo, USE_DEPTH_CLAMP); + lightData, 0, cameraInfo, shadowMapInfo, sceneInfo, + mIsDepthClampSupported && engine.debug.shadowmap.depth_clamp); if (shadowMap.hasVisibleShadows()) { const size_t shadowIndex = shadowMap.getShadowIndex(); diff --git a/filament/src/ShadowMapManager.h b/filament/src/ShadowMapManager.h index 18b4a24e19..95ad012774 100644 --- a/filament/src/ShadowMapManager.h +++ b/filament/src/ShadowMapManager.h @@ -232,6 +232,7 @@ private: ShadowMapCacheContainer mShadowMapCache; uint32_t mDirectionalShadowMapCount = 0; uint32_t mSpotShadowMapCount = 0; + bool const mIsDepthClampSupported; bool mInitialized = false; ShadowMap& getShadowMap(size_t index) noexcept { diff --git a/filament/src/details/DebugRegistry.cpp b/filament/src/details/DebugRegistry.cpp index c2f5d3d3fb..8915cf312e 100644 --- a/filament/src/details/DebugRegistry.cpp +++ b/filament/src/details/DebugRegistry.cpp @@ -28,12 +28,6 @@ #include #include -#ifndef NDEBUG -# define DEBUG_PROPERTIES_WRITABLE true -#else -# define DEBUG_PROPERTIES_WRITABLE false -#endif - using namespace filament::math; using namespace utils; @@ -79,17 +73,15 @@ bool FDebugRegistry::hasProperty(const char* name) const noexcept { template bool FDebugRegistry::setProperty(const char* name, T v) noexcept { - if constexpr (DEBUG_PROPERTIES_WRITABLE) { - auto info = getPropertyInfo(name); - T* const addr = static_cast(info.first); - if (addr) { - auto old = *addr; - *addr = v; - if (info.second && old != v) { - info.second(); - } - return true; + auto info = getPropertyInfo(name); + T* const addr = static_cast(info.first); + if (addr) { + auto old = *addr; + *addr = v; + if (info.second && old != v) { + info.second(); } + return true; } return false; } diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index d456a7b042..fa96370417 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -600,6 +600,7 @@ public: bool focus_shadowcasters = true; bool visualize_cascades = false; bool disable_light_frustum_align = false; + bool depth_clamp = true; float dzn = -1.0f; float dzf = 1.0f; float display_shadow_texture_scale = 0.25f; diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index 47d8c84369..b5c8e1b708 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -896,6 +896,8 @@ int main(int argc, char** argv) { debug.getPropertyAddress("d.shadowmap.focus_shadowcasters")); ImGui::Checkbox("Disable light frustum alignment", debug.getPropertyAddress("d.shadowmap.disable_light_frustum_align")); + ImGui::Checkbox("Depth clamp", + debug.getPropertyAddress("d.shadowmap.depth_clamp")); bool debugDirectionalShadowmap; if (debug.getProperty("d.shadowmap.debug_directional_shadowmap",