From fdc3f302d9371d0b3e2ebbaadbbd638d105380a2 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 5 Jun 2023 16:29:49 -0700 Subject: [PATCH] fix a crash on adreno when vsm is enabled fixes b/285928132 --- .../backend/include/backend/DriverEnums.h | 4 ++- filament/backend/src/metal/MetalDriver.mm | 2 ++ filament/backend/src/opengl/OpenGLContext.cpp | 6 ++-- filament/backend/src/opengl/OpenGLContext.h | 6 ++-- filament/backend/src/opengl/OpenGLDriver.cpp | 29 +++++++------------ filament/backend/src/vulkan/VulkanDriver.cpp | 2 ++ filament/src/ShadowMapManager.cpp | 7 +++-- filament/src/components/RenderableManager.cpp | 15 ++++++---- 8 files changed, 39 insertions(+), 32 deletions(-) diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index 4d6b16483d..302525ad7c 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -1130,7 +1130,9 @@ enum class Workaround : uint16_t { ADRENO_UNIFORM_ARRAY_CRASH, // Workaround a Metal pipeline compilation error with the message: // "Could not statically determine the target of a texture". See light_indirect.fs - A8X_STATIC_TEXTURE_TARGET_ERROR + A8X_STATIC_TEXTURE_TARGET_ERROR, + // Adreno drivers sometimes aren't able to blit into a layer of a texture array. + DISABLE_BLIT_INTO_TEXTURE_ARRAY, }; } // namespace filament::backend diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 2535103818..ba30cff170 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -724,6 +724,8 @@ bool MetalDriver::isWorkaroundNeeded(Workaround workaround) { return false; case Workaround::A8X_STATIC_TEXTURE_TARGET_ERROR: return mContext->bugs.a8xStaticTextureTargetError; + case Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY: + return false; } return false; } diff --git a/filament/backend/src/opengl/OpenGLContext.cpp b/filament/backend/src/opengl/OpenGLContext.cpp index 69efd2ecce..bf92dbb3d9 100644 --- a/filament/backend/src/opengl/OpenGLContext.cpp +++ b/filament/backend/src/opengl/OpenGLContext.cpp @@ -221,13 +221,13 @@ OpenGLContext::OpenGLContext() noexcept { // Blits to texture arrays are failing // This bug continues to reproduce, though at times we've seen it appear to "go away". // The standalone sample app that was written to show this problem still reproduces. - // The working hypthesis is that some other state affects this behavior. - bugs.disable_sidecar_blit_into_texture_array = true; + // The working hypothesis is that some other state affects this behavior. + bugs.disable_blit_into_texture_array = true; // early exit condition is flattened in EASU code bugs.split_easu = true; - // initialize the non used uniform array for adreno drivers. + // initialize the non-used uniform array for Adreno drivers. bugs.enable_initialize_non_used_uniform_array = true; int maj, min, driverMajor, driverMinor; diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 48902e24ec..2ba722e6fe 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -262,7 +262,7 @@ public: // Some drivers can't blit from a sidecar renderbuffer into a layer of a texture array. // This technique is used for VSM with MSAA turned on. - bool disable_sidecar_blit_into_texture_array; + bool disable_blit_into_texture_array; // Some drivers incorrectly flatten the early exit condition in the EASU code, in which // case we need an alternative algorithm @@ -446,8 +446,8 @@ private: { bugs.dont_use_timer_query, "dont_use_timer_query", ""}, - { bugs.disable_sidecar_blit_into_texture_array, - "disable_sidecar_blit_into_texture_array", + { bugs.disable_blit_into_texture_array, + "disable_blit_into_texture_array", ""}, { bugs.split_easu, "split_easu", diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 5843131fae..05e5c4ecab 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -968,9 +968,14 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo, break; } - // depth/stencil attachment must match the rendertarget sample count - // this is because EXT_multisampled_render_to_texture doesn't guarantee depth/stencil - // is resolved. + // depth/stencil attachments must match the rendertarget sample count + // because EXT_multisampled_render_to_texture[2] doesn't resolve the depth/stencil + // buffers: + // for EXT_multisampled_render_to_texture + // "the contents of the multisample buffer become undefined" + // for EXT_multisampled_render_to_texture2 + // "the contents of the multisample buffer is discarded rather than resolved - + // equivalent to the application calling InvalidateFramebuffer for this attachment" UTILS_UNUSED bool attachmentTypeNotSupportedByMSRTT = false; switch (attachment) { #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 @@ -1018,22 +1023,8 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo, attachmentTypeNotSupportedByMSRTT = true; } - // There's a bug with certain drivers preventing us from emulating - // EXT_multisampled_render_to_texture when the texture is a TEXTURE_2D_ARRAY, so we'll simply - // fall back to non-MSAA rendering for now. Also, MSRTT is never available for TEXTURE_2D_ARRAY, - // and since we are a 2D array, we know we're sampleable and therefore that a resolve will - // be needed. - // Note that this affects VSM shadows in particular. - // TODO: a better workaround would be to do the resolve by hand in that case - const bool disableMultisampling = - gl.bugs.disable_sidecar_blit_into_texture_array && - rt->gl.samples > 1 && t->samples <= 1 && - (target == GL_TEXTURE_2D_ARRAY || - target == GL_TEXTURE_CUBE_MAP_ARRAY); // implies MSRTT is not available - if (rt->gl.samples <= 1 || - (rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture) || - disableMultisampling) { + (rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture)) { // on GL3.2 / GLES3.1 and above multisample is handled when creating the texture. // If multisampled textures are not supported and we end-up here, things should // still work, albeit without MSAA. @@ -1876,6 +1867,8 @@ bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) { return mContext.bugs.allow_read_only_ancillary_feedback_loop; case Workaround::ADRENO_UNIFORM_ARRAY_CRASH: return mContext.bugs.enable_initialize_non_used_uniform_array; + case Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY: + return mContext.bugs.disable_blit_into_texture_array; default: return false; } diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index c68ec8ad1e..9d3f42bb27 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -780,6 +780,8 @@ bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) { return false; case Workaround::ADRENO_UNIFORM_ARRAY_CRASH: return false; + case Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY: + return false; default: return false; } diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index c77a442f4b..13610b367e 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -824,7 +824,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine return shadowTechnique; } -void ShadowMapManager::calculateTextureRequirements(FEngine&, FView& view, +void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view, FScene::LightSoa const&) noexcept { // Lay out the shadow maps. For now, we take the largest requested dimension and allocate a @@ -854,7 +854,10 @@ void ShadowMapManager::calculateTextureRequirements(FEngine&, FView& view, const bool useMipmapping = view.hasVSM() && ((vsmShadowOptions.anisotropy > 0) || vsmShadowOptions.mipmapping); - const uint8_t msaaSamples = vsmShadowOptions.msaaSamples; + uint8_t msaaSamples = vsmShadowOptions.msaaSamples; + if (engine.getDriverApi().isWorkaroundNeeded(Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY)) { + msaaSamples = 1; + } TextureFormat format = TextureFormat::DEPTH16; if (view.hasVSM()) { diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index b2b59ea2db..40213a534e 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -447,8 +447,10 @@ void FRenderableManager::create( } } else { - // When boneCount is 0, do an initialization for the bones uniform array to avoid crash on adreno gpu. - if (UTILS_UNLIKELY(driver.isWorkaroundNeeded(Workaround::ADRENO_UNIFORM_ARRAY_CRASH))) { + // When boneCount is 0, do an initialization for the bones uniform array to + // avoid crash on adreno gpu. + if (UTILS_UNLIKELY(driver.isWorkaroundNeeded( + Workaround::ADRENO_UNIFORM_ARRAY_CRASH))) { auto *initBones = driver.allocatePod(1); std::uninitialized_fill_n(initBones, 1, FSkinningBuffer::makeBone({})); driver.updateBufferObject(bones.handle, { @@ -458,7 +460,8 @@ void FRenderableManager::create( } } - // Create and initialize all needed MorphTargets. It's required to avoid branches in hot loops. + // Create and initialize all needed MorphTargets. + // It's required to avoid branches in hot loops. MorphTargets* morphTargets = new MorphTargets[entryCount]; for (size_t i = 0; i < entryCount; ++i) { morphTargets[i] = { mEngine.getDummyMorphTargetBuffer(), 0, 0 }; @@ -488,8 +491,10 @@ void FRenderableManager::create( (uint32_t)morphing.count }; } - // When targetCount equal 0, boneCount>0 in this case, do an initialization for the morphWeights uniform array to avoid crash on adreno gpu. - if (UTILS_UNLIKELY(targetCount == 0 && driver.isWorkaroundNeeded(Workaround::ADRENO_UNIFORM_ARRAY_CRASH))) { + // When targetCount equal 0, boneCount>0 in this case, do an initialization for the + // morphWeights uniform array to avoid crash on adreno gpu. + if (UTILS_UNLIKELY(targetCount == 0 && + driver.isWorkaroundNeeded(Workaround::ADRENO_UNIFORM_ARRAY_CRASH))) { float initWeights[1] = {0}; setMorphWeights(ci, initWeights, 1, 0); }