Repository navigation
Description
Based on a large number of issue reports and my own testing, generating mipmaps on Adreno GPU can occassionally corrupt the image - though this depends on the exact dimensions and number of mips. This can happen on 6XX, 7XX, and 8XX series.
- Image Rendering error on Redmi K80Pro. #160441
- [Impeller] Rendering glitches on Android Qualcomm Adreno 830 GPU devices #159876
- Image Rendering artifacts on OnePlus 13. #160587
The strategy we use is essentially the same as https://docs.vulkan.org/samples/latest/samples/api/texture_mipmap_generation/README.html (and even then, I replaced our code with a copy paste of that one and still reproduced the same problems). I am also fairly certain that it is not a synchronization problem, as I've tested with "everything" barrier between blits and can still reproduce the problems.
My current best guess is a bug in the driver. We have a few options to work around it
- Generate mips on the CPU. This will be slow, and additionally require readback in places that we previously didnt need it. Last choice.
- Test and determine if there are magic numbers that work consistently. Surely the driver can't be that broken right? Maybe with a square power of two texture we can guarantee no corruption. Then we could blit regions onto a correctly sized texture.
- Use a render pass chain to do the downsizing. Less bad than 1.
- Use a compute pass to do the downsizing. If this is how well blit passes work on adreno I don't even want to touch compute lmao.
I'm going to try a bit of 2. and then probably do 3. But not until higher priority issues are solved.
Potentially related issues:
- https://issuetracker.unity3d.com/issues/vulkan-qualcomm-855-mipmaps-of-the-render-texture-are-wrote-to-incorrect-areas-of-a-texture
- https://issuetracker.unity3d.com/issues/vulkan-adreno-630-gpu-renders-black-artifacts-on-the-terrain-when-draw-instanced-is-enabled
Activity
jonahwilliams commentedon Jan 16, 2025
From testing, most of the remaining artifacts go away if I force all textures to have square dimensions.
[Impeller] limit mipmap generation (#165357)
github-actions commentedon Apr 1, 2025
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.[Impeller] limit mipmap generation (flutter#165357)
bdero commentedon Jul 29, 2026
Reopening this and bumping priority. We're going to fix mip generation properly on Adreno instead of keeping the sampling workaround.
Current state and why it needs to go
The
broken_mipmap_generationworkaround does not fix generation, it disables mip sampling. On any Adreno deviceSamplerLibraryVK::GetSamplerrewrites every sampler toMipFilter::kBase, so nothing samples past the base level. That hides the corrupt blit-generated mips, but it also breaks textures whose mip chains were uploaded by hand (those never touched the broken blit), and it quietly turns off mipmapped sampling everywhere on Adreno. It surfaced downstream in bdero/flutter_scene#241 and spawned two patches that work around the workaround rather than the cause (#189897 to report the capability honestly, #189966 to add a per-sampler opt-out). Both become unnecessary once generation is correct.The plan, render-pass downsample instead of
vkCmdBlitImageReplace the Vulkan blit chain (
BlitPassVK::OnGenerateMipmapCommand) with a fragment-shader downsample on the affected device class. For each level N from 1 to mip_count-1, run a render pass that writes into mip N while sampling mip N-1 through a linear box downsample.The building blocks are already here.
Attachment::mip_level), so no new attachment HAL is needed.entity/shaders/downsample.glslwithtexture_downsample*.frag, including a GLES variant), used today by the blur path.The one new piece is a source image view scoped to a single mip level, so a level can be sampled while the next is rendered into the same image without a feedback hazard. Standard pattern.
Metal (
generateMipmapsForTexture) and GLES (glGenerateMipmap) are separate driver paths and are not implicated, so they stay as they are. This change is scoped to Adreno Vulkan.[Impeller] Scope the broken mipmap workaround to the textures it affe…