Skip to content

[Impeller] re-enable runtime mipmap generation on Adreno GPU. #161283

Description

@jonahwilliams

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.

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

  1. Generate mips on the CPU. This will be slow, and additionally require readback in places that we previously didnt need it. Last choice.
  2. 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.
  3. Use a render pass chain to do the downsizing. Less bad than 1.
  4. 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:

Activity

  1. added
    e: impellerImpeller rendering backend issues and features requests
    P3Issues that are less important to the Flutter project
    on Jan 8, 2025
  2. jonahwilliams commented on Jan 16, 2025

    @jonahwilliams
    ContributorAuthor

    From testing, most of the remaining artifacts go away if I force all textures to have square dimensions.

  3. github-actions commented on Apr 1, 2025

    @github-actions

    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 -v and a minimal reproduction of the issue.

  4. locked as resolved and limited conversation to collaborators on Apr 1, 2025
  5. reopened this on Jul 29, 2026
  6. bdero commented on Jul 29, 2026

    @bdero
    Member

    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_generation workaround does not fix generation, it disables mip sampling. On any Adreno device SamplerLibraryVK::GetSampler rewrites every sampler to MipFilter::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 vkCmdBlitImage

    Replace 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.

    • Color attachments already address a single mip level (Attachment::mip_level), so no new attachment HAL is needed.
    • A cross-backend box downsample shader already exists (entity/shaders/downsample.glsl with texture_downsample*.frag, including a GLES variant), used today by the blur path.
    • This is the same approach WebGPU implementations use to generate mips on Adreno in production, since WebGPU has no blit-based generation. Render-pass draws are the most exercised and least driver-buggy path on these devices, which is exactly what you want when routing around a driver bug.

    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.

  7. self-assigned this
    on Jul 29, 2026
  8. unlocked this conversation on Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P3Issues that are less important to the Flutter projecte: impellerImpeller rendering backend issues and features requeststeam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions