Skip to content

[Impeller] New Gaussian blur optimization: Add a utility for generating specific mip levels. #140940

Closed as not planned
@bdero

Description

@bdero

This is an optimization idea for reducing the overhead of mipmap generation for EntityPass textures. When using the new Gaussian blur, we need to generate mipmaps for EntityPass textures which are blurred (by way of backdrop filters or image filters) in order to render with acceptable quality. See also #140949.

This optimization builds on #140949 and relies on EntityPass backdrop textures receiving an appropriate mip_count when allocated.

Listed below are a couple of possible routes we could take for generating only the specific mip levels we need to sample from (in stead of generating all mip levels via a blit pass with pass->GenerateMipmap()).
For guidance on how to calculate the specific mip levels that need to be generated for a given texture input, see the "How to compute the max mip level for a given Gaussian blur invocation" section of #140949.

Possible approaches for generating mip levels

Note

I haven't experimentally verified whether these techniques would use less energy than the regular blit pass route to generate a full mipmap. Results will almost certainly vary across different drivers and hardware, so we should profile against some representative set of real hardware before concluding that these approaches are faster.

Use a raster pipeline

We can create a raster pipeline designed to read from mip level 0 and output a higher mip level.

The fragment shader should average together all texels in a rectangular kernel with a radius of ~ { floor(width / 2^miplevel), floor(height / 2^miplevel) }.

Reading from mip level 0

Bind the texture as normal and explicitly sample from mip level 0. In GLSL terms, this can be done with textureLod, for example. Sampling from specific LoDs is supported by Vulkan, Metal, and OpenGLES 3.0. However, I'm not sure if there's a viable route when the device is limited to OpenGLES 2.0 & GLSL ES 1.0.

Output to a higher mip level

We can add support for outputting to a specified mip level by adding the mip level to the RenderTarget color attachment state:

  • OpenGLES 3.0 supports this via the level parameter of glFramebufferTexture2D. OpenGLES 2.0 also has a level parameter, but the spec says it must always be set to 0. Not sure what's going on there.
  • Metal supports this via MTLRenderPassAttachmentDescriptor::level.
  • Vulkan supports this. I think the correct way is to set VkFramebufferCreateInfo::layers to 1 and VkImageViewCreateInfo::subresourceRange.baseMipLevel to the desired mip level (for the framebuffer attachment handed to VkFramebufferCreateInfo::pAttachments). The framebuffer is part of the state for beginning a render pass vkCmdBeginRenderPass.

Note

Even though we're technically reading from the attached (output) texture resource, I don't think the SupportsReadFromResolve capability restriction applies to this case, since we're actually reading from and writing to different mip levels and thus different memory.

Use a compute pipeline

Metal and Vulkan compute shaders support sampling and writing to bound texture mip levels. So it's possible to perform the same work as the downsample raster pipeline described above with a compute shader.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecte: impellerImpeller rendering backend issues and features requestsengineflutter/engine repository. See also e: labels.team-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions