Skip to content

[Flutter GPU] Allow attaching specific texture mip levels and slices for rendering#187685

Merged
auto-submit[bot] merged 6 commits into
flutter:masterfrom
bdero:bdero/flutter-gpu-attach-mip-slice
Jun 9, 2026
Merged

[Flutter GPU] Allow attaching specific texture mip levels and slices for rendering#187685
auto-submit[bot] merged 6 commits into
flutter:masterfrom
bdero:bdero/flutter-gpu-attach-mip-slice

Conversation

@bdero

@bdero bdero commented Jun 8, 2026

Copy link
Copy Markdown
Member

Fixes #150455

Surfaces the Impeller HAL support for rendering into a specific texture mip level and slice (landed in #187470) to Flutter GPU.

  • Adds mipLevel and slice (both default 0) to ColorAttachment and DepthStencilAttachment. They select the subresource of the attachment texture to render into: a non-zero mip level, a cube map face, or both.
  • Validates, in Dart and unconditionally, that each attachment's mipLevel and slice are in range (including the MSAA resolve texture) and that all attachments resolve to the same size. Out-of-range subresources and size mismatches are undefined behavior in release, where the engine-side checks are compiled out.
  • Adds GpuContext.doesSupportFramebufferRenderMipmap, lifted onto the base Capabilities interface so it can be queried. Rendering into a cube face is always available. Rendering into a non-zero mip level returns true on Metal and Vulkan and false on GLES: the GLES texture storage path yields an incomplete framebuffer for a non-base mip attachment, so the capability is conservative until that is reworked (tracked separately). Cube face rendering on GLES is unaffected.

Tests cover rendering into a cube slice, rendering into a non-zero mip level (gated on the capability), and the range and size validation.

Pre-launch Checklist

…for rendering

Surfaces the Impeller HAL support for rendering into a specific texture
mip level and slice to Flutter GPU.

- Adds mipLevel and slice (default 0) to ColorAttachment and
  DepthStencilAttachment, selecting the subresource to render into.
- Validates the ranges in Dart against the texture's mipLevelCount and
  sliceCount.
- Adds GpuContext.doesSupportFramebufferRenderMipmap, lifting the GLES
  capability onto the base Capabilities interface. Metal and Vulkan
  always support it.

Fixes flutter#150455
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jun 8, 2026
@bdero bdero added engine flutter/engine related. See also e: labels. flutter-gpu team-fluttergpu Owned by Flutter GPU team e: impeller Impeller rendering backend issues and features requests labels Jun 8, 2026
@github-project-automation github-project-automation Bot moved this to 🤔 Needs Triage in Flutter GPU Jun 8, 2026
@bdero bdero marked this pull request as ready for review June 8, 2026 18:22

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for rendering into specific texture mipmap levels and slices within Flutter GPU. It introduces the SupportsFramebufferRenderMipmap capability check across GLES, Vulkan, and standard backends, exposes it to Dart via GpuContext.doesSupportFramebufferRenderMipmap, and updates ColorAttachment and DepthStencilAttachment to accept and validate mipLevel and slice parameters. The review feedback identifies compilation errors in the new tests due to the use of the undefined Colors.lime property, suggesting Colors.green as a replacement.

Comment thread engine/src/flutter/testing/dart/gpu_test.dart
Comment thread engine/src/flutter/testing/dart/gpu_test.dart
Move the mip/slice range checks into RenderTarget._validateAttachments
and add a cross-attachment size consistency check. These guard against
undefined behavior in release builds, where the engine-side checks are
compiled out, so they run unconditionally rather than under an assert.
Also validates the MSAA resolve texture's mip level and slice.
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 8, 2026
@bdero bdero added the CICD Run CI/CD label Jun 8, 2026
@bdero bdero marked this pull request as draft June 8, 2026 18:55
@bdero bdero requested a review from gaaclarke June 8, 2026 19:16
@bdero bdero marked this pull request as ready for review June 8, 2026 19:16

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for rendering into specific texture slices and non-zero mip levels in Flutter GPU. It updates backend capabilities, exposes the new properties through the C++ and Dart APIs, and implements attachment validation in RenderTarget. Feedback suggests refactoring the validation logic in Dart to avoid allocating records/tuples, thereby reducing garbage collection pressure during render pass creation.

Comment thread engine/src/flutter/lib/gpu/lib/src/render_pass.dart Outdated
Replace the (int, int) record in _validateAttachments with plain int
width/height locals and drop the _attachmentMipSize helper, avoiding
per-call allocations in this unconditionally-run path.
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 8, 2026
@bdero bdero added the CICD Run CI/CD label Jun 8, 2026

@gaaclarke gaaclarke left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor grievances, otherwise LGTM!

// Rendering into a non-zero mip level needs ES 3.0 or
// GL_OES_fbo_render_mipmap on the GLES backend.
if (!gpu.gpuContext.doesSupportFramebufferRenderMipmap) {
return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you want to skip, not return in this case

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 20ea63b.

}
if (slice < 0 || slice >= texture.sliceCount) {
throw Exception(
"$label slice ($slice) must be in the range [0, ${texture.sliceCount}) for textures of type ${texture.textureType}",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'[0, ${texture.sliceCount-1}]' is my clear imo

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These match the half-open [0, N) wording already used by Texture.overwrite's mip/slice validation, so I kept the two consistent.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, I agree and we should just use the simpler notation everywhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e5bd372

}
}, skip: !(impellerEnabled && flutterGpuEnabled));

test('ColorAttachment throws for an out-of-range slice', () async {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding these. I think it important we try to be a positive experience to work with despite (or especially because) it's a low level concept.

// |Capabilities|
/// Core ES 2.0 only allows mip level 0; ES 3.0+ and the
/// GL_OES_fbo_render_mipmap extension lift that restriction.
bool SupportsFramebufferRenderMipmap() const override;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Instead of having a virtual function, shouldn't we just have a protected bool we can set? I don't think we need to have custom logic that gets executed each time. We are just going to calculate it once. Virtual functions have higher overhead and worse locality.

If we are calling it only ever from Dart it's not a big deal. I didn't see us using it elsewhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This follows the existing Capabilities interface, where every capability is a virtual getter. GLES already caches it in supports_fbo_render_mipmap_ (computed once) and Metal/Vulkan just return true, and it's only queried from Dart at render-pass setup, so the virtual isn't on a hot path.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think this whole capabilities mechanism aught to just be simplified. We really don't need the dynamic dispatch at all. Added a cleanup issue to track here: #187704

When the backend cannot render into non-zero mip levels, report the
test as skipped via markTestSkipped rather than silently passing.
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 8, 2026
@bdero bdero added the CICD Run CI/CD label Jun 8, 2026
@bdero bdero requested a review from gaaclarke June 8, 2026 22:30
Switch the attachment and Texture.overwrite validation messages from
half-open [0, N) to inclusive [0, N-1], which states the maximum valid
value directly. Keeps the two validation paths consistent.
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 8, 2026
gaaclarke
gaaclarke previously approved these changes Jun 8, 2026

@gaaclarke gaaclarke left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! thanks

@bdero bdero added the CICD Run CI/CD label Jun 8, 2026
Rendering into a non-zero mip level aborts on the GLES backend with an
incomplete framebuffer: the texture storage path uses mutable, lazily
allocated glTexImage2D levels, which are not framebuffer-attachment
complete for a non-base level. This was never exercised before (the
renderer test skips GLES), and surfaced when the Flutter GPU tests ran
it on the ES 3.0 (SwiftShader) backend.

Make CapabilitiesGLES::SupportsFramebufferRenderMipmap return false so
the path is rejected gracefully and the capability is honest. Cube map
face (slice) rendering is unaffected. Metal and Vulkan are unchanged.
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 9, 2026
@bdero bdero added the CICD Run CI/CD label Jun 9, 2026
@bdero

bdero commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

CI surfaced that rendering into a non-zero mip level aborts on the GLES backend with an incomplete framebuffer, since Impeller's GLES texture storage isn't framebuffer-complete for a non-base mip level and it appears unsupported on some drivers... I've disabled SupportsFramebufferRenderMipmap on GLES for now so the path is rejected gracefully, with the real GLES support left as a follow-up.

@bdero bdero added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 9, 2026
@auto-submit auto-submit Bot added this pull request to the merge queue Jun 9, 2026
Merged via the queue into flutter:master with commit 00cf901 Jun 9, 2026
207 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jun 9, 2026
@github-project-automation github-project-automation Bot moved this from 🤔 Needs Triage to ✅ Done in Flutter GPU Jun 9, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Jun 11, 2026
flutter/flutter@66aaa9a...c0a1129

2026-06-10 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#187740)
2026-06-09 burak.karahan@mail.ru Remove Material import from view chrome style test (flutter/flutter#186994)
2026-06-09 jason-simmons@users.noreply.github.com [Impeller] Remove unused DeviceHolderVK reference from CommandBufferVK (flutter/flutter#187705)
2026-06-09 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from KNe93cf5wU4xG2d-m... to 8azSyvz57mKcPqTwk... (flutter/flutter#187745)
2026-06-09 1063596+reidbaker@users.noreply.github.com Add android-agent agent.json and update reidbaker-agent skills (flutter/flutter#187746)
2026-06-09 engine-flutter-autoroll@skia.org Roll Skia from aeed11c35004 to 9f02102df298 (9 revisions) (flutter/flutter#187744)
2026-06-09 bdero@google.com [Impeller] Remove the texture coordinate system Y-flip workaround (flutter/flutter#187686)
2026-06-09 41687333+rlueders@users.noreply.github.com [Impeller] Retry uncompressed when fixed-rate compression is exhausted (flutter/flutter#187586)
2026-06-09 burak.karahan@mail.ru Remove Material import from implicit animation tests (flutter/flutter#186673)
2026-06-09 engine-flutter-autoroll@skia.org Roll Packages from 13b49f4 to bd297cf (4 revisions) (flutter/flutter#187739)
2026-06-09 30870216+gaaclarke@users.noreply.github.com Updates dia_dll.py to support vs2026 (flutter/flutter#187714)
2026-06-09 bdero@google.com [Flutter GPU] Allow attaching specific texture mip levels and slices for rendering (flutter/flutter#187685)
2026-06-09 engine-flutter-autoroll@skia.org Roll Dart SDK from 39f1c44e294f to f3441f2067ae (1 revision) (flutter/flutter#187711)
2026-06-09 bdero@google.com [flutter_tools] Hot reload Flutter GPU shader bundles (flutter/flutter#187654)
2026-06-09 katelovett@google.com Update triage links (flutter/flutter#187709)
2026-06-09 engine-flutter-autoroll@skia.org Roll Skia from 43f135735152 to aeed11c35004 (11 revisions) (flutter/flutter#187721)
2026-06-09 jason-simmons@users.noreply.github.com Use workspace resolution for the meta package in dev/integration_tests/record_use_test_package (flutter/flutter#187733)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC louisehsu@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
bdero added a commit to bdero/flutter_scene that referenced this pull request Jun 13, 2026
The package only runs on the Flutter master channel, but pub.dev scores
packages by analyzing them on stable, so the flutter constraint has to be
satisfiable by stable to keep the pana score. Raise the lower bound from
the stale 3.29.0-1.0.pre.242 to the current latest stable 3.44.0, and
document the real requirement (a master build from 2026-06-09, which added
render-to-mip-level Flutter GPU support in flutter/flutter#187685) in the
README, the pubspec comment, and the CHANGELOG.
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
…for rendering (flutter#187685)

Fixes flutter#150455

Surfaces the Impeller HAL support for rendering into a specific texture
mip level and slice (landed in flutter#187470) to Flutter GPU.

- Adds `mipLevel` and `slice` (both default 0) to `ColorAttachment` and
`DepthStencilAttachment`. They select the subresource of the attachment
texture to render into: a non-zero mip level, a cube map face, or both.
- Validates, in Dart and unconditionally, that each attachment's
`mipLevel` and `slice` are in range (including the MSAA resolve texture)
and that all attachments resolve to the same size. Out-of-range
subresources and size mismatches are undefined behavior in release,
where the engine-side checks are compiled out.
- Adds `GpuContext.doesSupportFramebufferRenderMipmap`, lifted onto the
base `Capabilities` interface so it can be queried. Rendering into a
cube face is always available. Rendering into a non-zero mip level
returns true on Metal and Vulkan and false on GLES: the GLES texture
storage path yields an incomplete framebuffer for a non-base mip
attachment, so the capability is conservative until that is reworked
(tracked separately). Cube face rendering on GLES is unaffected.

Tests cover rendering into a cube slice, rendering into a non-zero mip
level (gated on the capability), and the range and size validation.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. flutter-gpu team-fluttergpu Owned by Flutter GPU team

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

[Flutter GPU] Allow specifying the mip level/slice for color attachments.

2 participants