Skip to content

[Impeller] Support instanced rendering across all backends#186653

Merged
auto-submit[bot] merged 8 commits into
flutter:masterfrom
bdero:bdero/impeller-gles-instanced-draw
May 28, 2026
Merged

[Impeller] Support instanced rendering across all backends#186653
auto-submit[bot] merged 8 commits into
flutter:masterfrom
bdero:bdero/impeller-gles-instanced-draw

Conversation

@bdero

@bdero bdero commented May 17, 2026

Copy link
Copy Markdown
Member

Progress on #154145.

Instanced drawing was started in Impeller long ago but remains incomplete to today. A command could carry an instance count, Metal and Vulkan honored it, but OpenGL ES ignored it, no backend had per-instance vertex data, and there was zero test coverage.

This fills those gaps in a fully portable way that works everywhere, including emulation on rare GLES 2 drivers that don't support the required extensions! No capability checks required to safely use.

Super useful for Flutter GPU-based renderers, but I think some stuff in Impeller's 2D renderer may be able benefit from this too. One of the original early motivations we started implementing this years ago was to reduce the vertex load for glyph atlas rendering, for example.

Example usage

On the shader side there is nothing instancing-specific. Per-instance values are declared as ordinary vertex in attributes, identical to per-vertex ones; the shader does no indexing and never references gl_InstanceIndex.

uniform FrameInfo {
  mat4 mvp;
}
frame_info;

in vec2 vertex_position;  // supplied per vertex
in vec2 instance_offset;  // supplied per instance
in vec4 instance_color;   // supplied per instance

out vec4 v_color;

void main() {
  gl_Position = frame_info.mvp * vec4(vertex_position + instance_offset, 0.0, 1.0);
  v_color = instance_color;
}

On the Impeller side, instancing is driven through the existing pipeline and render pass APIs. The only new surface is the per-binding input rate: a binding is marked instance-rate on the VertexDescriptor, geometry and per-instance data are bound as separate vertex buffers, and the draw carries an instance count.

// Binding 0 advances once per vertex; binding 1 advances once per instance.
auto vertex_desc = std::make_shared<VertexDescriptor>();
vertex_desc->SetStageInputs(
    /*inputs=*/{position_slot, instance_offset_slot, instance_color_slot},
    /*layouts=*/{
        ShaderStageBufferLayout{.stride = sizeof(Vector2),
                                .binding = 0,
                                .input_rate = VertexInputRate::kVertex},
        ShaderStageBufferLayout{.stride = sizeof(InstanceData),
                                .binding = 1,
                                .input_rate = VertexInputRate::kInstance},
    });
pipeline_desc->SetVertexDescriptor(std::move(vertex_desc));

// One draw call renders `instance_count` copies of the geometry.
pass.SetVertexBuffer({geometry_view, instance_data_view});
pass.SetElementCount(vertex_count);
pass.SetInstanceCount(instance_count);
pass.Draw();

A complete, runnable version is the new CanRenderInstancedWithVertexAttributes test, paired with the instanced_attributes.vert fixture shown above.

Note that the VertexDescriptor is assembled by hand rather than from impellerc's reflected shader structs. Whether a binding is per-instance is pipeline state, not something expressible in shader source, so there is no static codegen for it: generating it would first require deciding how to annotate which shader inputs are per-instance, which is something we could add down the road if we find it'd be convenient for stuff in the entities framework.

Pre-launch Checklist

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 17, 2026
@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels May 17, 2026
@bdero bdero marked this pull request as ready for review May 17, 2026 23:33
@bdero bdero requested a review from gaaclarke May 17, 2026 23:33

@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 implements support for instance-rate vertex attributes across Impeller's backends, enabling portable instancing for OpenGL ES by utilizing hardware divisors or emulating the draw calls. The changes introduce a VertexInputRate enum to ShaderStageBufferLayout and update the GLES, Metal, and Vulkan backends to handle per-instance data. Feedback suggests adding an early exit in the GLES backend when the instance count is zero to ensure behavior consistent with the Vulkan and Metal backends.

@github-actions github-actions Bot removed the CICD Run CI/CD label May 18, 2026
@bdero bdero added the CICD Run CI/CD label May 18, 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.

Nice, thanks brandon, it's looking good. I just have one question about the integration test. I want to make sure we have a golden test for it. Otherwise, just some minor nits.

Comment thread engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h Outdated
Comment thread engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc Outdated
Comment thread engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles_unittests.cc Outdated
data_host_buffer->Reset();
return result;
};
OpenPlaygroundHere(callback);

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.

Is a golden being generated here? Can we put this test somewhere where a golden will be checked? A manual integration test isn't going to be the sort of backstop we want.

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.

Yeah true... the golden harness isn't set up to work in this test layer, but maybe it's time to get it working now that I'm doing a lot of surgery down here again.

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.

Adding harness support here: #186735

@github-actions github-actions Bot removed the CICD Run CI/CD label May 19, 2026
@bdero bdero added the CICD Run CI/CD label May 19, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label May 19, 2026
@bdero bdero added the CICD Run CI/CD label May 19, 2026
@bdero bdero force-pushed the bdero/impeller-gles-instanced-draw branch from e0e88b3 to 1e8832c Compare May 19, 2026 10:51
@github-actions github-actions Bot removed the CICD Run CI/CD label May 19, 2026
@bdero bdero added the CICD Run CI/CD label May 19, 2026
@fluttergithubbot

Copy link
Copy Markdown
Contributor

An existing Git SHA, 1e8832c990c40e8fb3e5ded4f3f3b448e7a7b3f2, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

guanzi008 pushed a commit to Flutter-Dart-loong64/flutter that referenced this pull request May 22, 2026
…tter#186735)

Renderer-layer unittests (`impeller/renderer/renderer_unittests.cc`)
open an interactive playground but never produce a checked image, so
renderer-level rendering has no automated golden coverage.

This adds golden support to that layer:

- `GoldenPlaygroundTest` gets a render-pass `OpenPlaygroundHere`
overload that renders a callback into an offscreen target and
screenshots it, reusing the existing screenshotters and Skia Gold upload
path.
- A new `renderer_golden_unittests.cc` holds renderer golden tests, so
they are opted in one at a time rather than all at once. It starts with
a single triangle test ported from `renderer_unittests.cc`.

This is test infrastructure with no dedicated tracking issue. The need
came up in flutter#186653, where a
renderer-layer instancing test had no golden coverage.

## 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].
- [ ] 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.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- 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
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
@bdero bdero force-pushed the bdero/impeller-gles-instanced-draw branch from 1e8832c to ea2072f Compare May 23, 2026 08:32
@github-actions github-actions Bot removed the CICD Run CI/CD label May 23, 2026
@bdero bdero requested a review from gaaclarke May 26, 2026 22:44
gabrimatic pushed a commit to gabrimatic/flutter that referenced this pull request May 27, 2026
Moves the vertex and index count off the buffer-binding calls and onto
the draw call.

A simple (breaking) change that fixes a very silly design flaw that I
built into the API near the very beginning. Moves Flutter GPU draws
towards a design that matches virtually all modern graphics APIs,
including today's Impeller!
Now is the right time to make changes like this to Flutter GPU, since
the API is not yet considered stable.

Before, `bindVertexBuffer` and `bindIndexBuffer` each took a count, and
a single argument-less `draw()` guessed vertex versus index based on
whether an index buffer happened to be bound.

Sooooo many reasons this was the wrong design:

- **Wrong object.** A draw count belongs on the draw, not on a buffer
binding.
- **Implicit kind.** Indexed vs. non-indexed was inferred from what
happened to be bound, not stated.
- **Colliding counts.** Vertex and index counts shared one field; the
vertex count was dropped when an index buffer was bound.
- **Slot-0-only.** The count came from vertex slot 0; values on other
slots were silently ignored.
- **Opaque draws.** `draw()` told you nothing; you had to trace every
bind to know what it drew.
- **Sticky state.** The count leaked across draws in a pass.
- **Redundant re-binds.** Changing only the count forced re-binding the
buffer.
- **No room to grow.** Nowhere natural for per-draw params like
`instanceCount` or `baseVertex`.
- **Unconventional.** WebGPU, Vulkan, Metal, and D3D all put counts on
the draw.
- **Late errors.** Bad counts failed at `draw()` time, far from the
mistaken line.

Now:
- `bindVertexBuffer` and `bindIndexBuffer` only bind buffers.
- `draw(vertexCount)` does a non-indexed draw.
- `drawIndexed(indexCount)` does an indexed draw.

Instanced draws can be landed later via `draw` and `drawIndexed` gaining
an `instanceCount` parameter later on, assuming the Impeller-side
instancing support in flutter#186653 lands.

## 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/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
pull Bot pushed a commit to AbhiShake1/flutter that referenced this pull request May 27, 2026
…utter#187170)

<!-- start_original_pr_link -->
Reverts: flutter#186639
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: cbracken
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: doesn't compile on mac, or Linux.

Mac:
```
../../flutter/testing/dart/gpu_shader_reload_test.dart:64:36: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
  state.renderPass.bindVertexBuffer(
                                   ^
../../flutter/testing/dart/gpu_shader_reload_test.dart:72:24: Error: Too few positional arguments: 1 requ
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: bdero
<!-- end_original_pr_author -->

<!-- start_reviewers -->
Reviewed By: {walley892}
<!-- end_reviewers -->

<!-- start_revert_body -->
This change reverts the following previous change:
Moves the vertex and index count off the buffer-binding calls and onto the draw call.

A simple (breaking) change that fixes a very silly design flaw that I built into the API near the very beginning. Moves Flutter GPU draws towards a design that matches virtually all modern graphics APIs, including today's Impeller!
Now is the right time to make changes like this to Flutter GPU, since the API is not yet considered stable.

Before, `bindVertexBuffer` and `bindIndexBuffer` each took a count, and a single argument-less `draw()` guessed vertex versus index based on whether an index buffer happened to be bound.

Sooooo many reasons this was the wrong design:

- **Wrong object.** A draw count belongs on the draw, not on a buffer binding.
- **Implicit kind.** Indexed vs. non-indexed was inferred from what happened to be bound, not stated.
- **Colliding counts.** Vertex and index counts shared one field; the vertex count was dropped when an index buffer was bound.
- **Slot-0-only.** The count came from vertex slot 0; values on other slots were silently ignored.
- **Opaque draws.** `draw()` told you nothing; you had to trace every bind to know what it drew.
- **Sticky state.** The count leaked across draws in a pass.
- **Redundant re-binds.** Changing only the count forced re-binding the buffer.
- **No room to grow.** Nowhere natural for per-draw params like `instanceCount` or `baseVertex`.
- **Unconventional.** WebGPU, Vulkan, Metal, and D3D all put counts on the draw.
- **Late errors.** Bad counts failed at `draw()` time, far from the mistaken line.

Now:
- `bindVertexBuffer` and `bindIndexBuffer` only bind buffers.
- `draw(vertexCount)` does a non-indexed draw.
- `drawIndexed(indexCount)` does an indexed draw.

Instanced draws can be landed later via `draw` and `drawIndexed` gaining an `instanceCount` parameter later on, assuming the Impeller-side instancing support in flutter#186653 lands.

## 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/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

<!-- end_revert_body -->

Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
@gaaclarke

Copy link
Copy Markdown
Member

/gemini review

@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 introduces support for instance-rate vertex attributes in the Impeller renderer, enabling portable instanced drawing down to OpenGL ES 2.0. It adds a VertexInputRate enum to ShaderStageBufferLayout and updates the GLES, Metal, and Vulkan backends to respect this rate. For GLES drivers lacking hardware instancing, an emulation fallback is implemented by repeating the draw call and re-pointing instance-rate attributes. New unit tests and a golden test have been added to verify the functionality. The review feedback highlights potential 64-bit truncation issues when casting offsets to GLsizei instead of uintptr_t, and suggests an optimization to avoid redundant vertex attribute updates during emulated instanced draws.

Comment thread engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc Outdated
Comment thread engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc Outdated
@gaaclarke gaaclarke added the CICD Run CI/CD label May 27, 2026
bdero added 4 commits May 27, 2026 18:21
Rename the VertexAttribPointer divisor field to vertex_attrib_divisor,
hoist the instanced draw branching out of the per-instance loop, and add
argument name comments to the draw mock call tests.
Move CanRenderInstancedWithVertexAttributes from renderer_unittests.cc
into renderer_golden_unittests.cc so the instanced draw is captured as a
Skia Gold image. Reduce the pipeline to the golden render target
(single-sampled, no depth/stencil) and reset the host buffer per pass.
Drop the now-unused instanced_attributes includes from the playground
test.
Cast buffer offsets through uintptr_t instead of GLsizei when reinterpreting them as GL pointer offsets, avoiding 32-bit truncation and sign-extension on 64-bit platforms. For emulated instanced draws, skip re-binding a vertex buffer across instances when it has only vertex-rate attributes, since its state does not change between instances.
A Command that never bound an index buffer leaves index_type at its kUnknown default. The GLES backend treated any index_type other than kNone as indexed, so a non-indexed draw (such as the instanced-attributes golden test running on OpenGL ES) dereferenced a null index buffer and crashed; on drivers exposing hardware instancing it instead reached ToIndexType(kUnknown), which is unreachable. Treat kUnknown the same as kNone (non-indexed), matching the Metal and Vulkan backends, which decide based on the presence of the index buffer.
@bdero bdero force-pushed the bdero/impeller-gles-instanced-draw branch from e2251e5 to 8ce228c Compare May 28, 2026 01:45
@github-actions github-actions Bot removed the CICD Run CI/CD label May 28, 2026
@bdero bdero added the CICD Run CI/CD label May 28, 2026
@flutter-dashboard

Copy link
Copy Markdown

Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change).

If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #186653 at sha 8ce228c

@flutter-dashboard flutter-dashboard Bot added the will affect goldens Changes to golden files label May 28, 2026
@bdero bdero requested a review from gaaclarke May 28, 2026 04:47
@bdero

bdero commented May 28, 2026

Copy link
Copy Markdown
Member Author

@gaaclarke Goldens are lookin correct. 🫡

@gaaclarke gaaclarke added the autosubmit Merge PR when tree becomes green via auto submit App label May 28, 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 brandon

@auto-submit auto-submit Bot added this pull request to the merge queue May 28, 2026
Merged via the queue into flutter:master with commit 1d9d637 May 28, 2026
210 of 211 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label May 28, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request May 29, 2026
flutter/flutter@e70534d...b05a9d7

2026-05-29 engine-flutter-autoroll@skia.org Roll Skia from 47155534833e to d9d6b440c4e7 (1 revision) (flutter/flutter#187301)
2026-05-29 engine-flutter-autoroll@skia.org Roll Skia from f93ed13d77fb to 47155534833e (4 revisions) (flutter/flutter#187291)
2026-05-29 kevmoo@users.noreply.github.com [web_ui] Optimize skwasm text layout and path decoding to eliminate dynamic boxing churn under Wasm (flutter/flutter#186978)
2026-05-29 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from SBpmmPxqx3lAvGojE... to jMR_VXQi07kAk8vbR... (flutter/flutter#187279)
2026-05-29 burak.karahan@mail.ru Remove Material import from sliver tree rendering test (flutter/flutter#187000)
2026-05-29 bdero@google.com [Impeller] Remove the y_coord_scale Y-flip plumbing (flutter/flutter#187224)
2026-05-29 31859944+LongCatIsLooong@users.noreply.github.com Add/remove overlay child RenderObject from the tree in `attach`/`detach` (flutter/flutter#186564)
2026-05-29 engine-flutter-autoroll@skia.org Roll Skia from fcfe5975c945 to f93ed13d77fb (4 revisions) (flutter/flutter#187273)
2026-05-28 evanwall@buffalo.edu Handle complex RSE rendering in the uber SDF pipeline (flutter/flutter#186434)
2026-05-28 engine-flutter-autoroll@skia.org Roll Dart SDK from 082191101fcc to 683322426411 (2 revisions) (flutter/flutter#187270)
2026-05-28 mvincentong@gmail.com Clarify route transition animations (flutter/flutter#186552)
2026-05-28 116356835+AbdeMohlbi@users.noreply.github.com document that the default Key is null and explain proper usage in list diffing (flutter/flutter#185197)
2026-05-28 srawlins@google.com [flutter_tools] Use super parameters in missed spots (flutter/flutter#186197)
2026-05-28 mr_nadeem_iqbal@yahoo.com docs: Document MediaQueryData.alwaysUse24HourFormat on macOS, Windows, Linux, web (#160664) (flutter/flutter#186642)
2026-05-28 engine-flutter-autoroll@skia.org Roll Skia from 5493e4c144cd to fcfe5975c945 (3 revisions) (flutter/flutter#187256)
2026-05-28 30870216+gaaclarke@users.noreply.github.com Shares opengles golden context (flutter/flutter#187243)
2026-05-28 jason-simmons@users.noreply.github.com Update the Curl CIPD package in .ci.yaml to version 8.20.0 (flutter/flutter#187133)
2026-05-28 737941+loic-sharma@users.noreply.github.com Improve SizedBox's docs (flutter/flutter#187208)
2026-05-28 bdero@google.com [Impeller] Support instanced rendering across all backends (flutter/flutter#186653)
2026-05-28 43054281+camsim99@users.noreply.github.com [Android] Reset system UI visibility flags when setting edge-to-edge mode (flutter/flutter#187207)
2026-05-28 engine-flutter-autoroll@skia.org Roll Skia from a38708fb7926 to 5493e4c144cd (7 revisions) (flutter/flutter#187241)
2026-05-28 30870216+gaaclarke@users.noreply.github.com Turned on impeller by default on macos (flutter/flutter#186546)
2026-05-28 mvincentong@gmail.com Clarify lazy scroll extent docs (flutter/flutter#186864)
2026-05-28 mdebbar@google.com [web] Fix WebParagraph locales test (flutter/flutter#186813)
2026-05-28 engine-flutter-autoroll@skia.org Roll Packages from 4b424d7 to 10cbdc5 (3 revisions) (flutter/flutter#187238)
2026-05-28 engine-flutter-autoroll@skia.org Roll Dart SDK from f3db7b7d9801 to 082191101fcc (8 revisions) (flutter/flutter#187235)
2026-05-28 engine-flutter-autoroll@skia.org Roll Skia from 32acea791248 to a38708fb7926 (1 revision) (flutter/flutter#187221)
2026-05-28 bdero@google.com [Flutter GPU] Add r32Float and remove Apple-only XR pixel formats (flutter/flutter#187069)

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 boetger@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
jason-simmons added a commit to jason-simmons/flutter that referenced this pull request May 31, 2026
…orEXT on GLES2 with the extension

OpenGL ES 3.0 includes support for glVertexAttribDivisor.
The glVertexAttribDivisorEXT API is available on OpenGL ES 2.0 devices
with the GL_EXT_instanced_arrays extension.

GLES3 devices may be able to resolve a glVertexAttribDivisorEXT
function that is not actually implemented.  This PR uses the
glVertexAttribDivisor API if available and otherwise falls back to
glVertexAttribDivisorEXT.

See flutter#186653
pull Bot pushed a commit to AbhiShake1/flutter that referenced this pull request Jun 2, 2026
…orEXT on GLES2 with the extension (flutter#187313)

OpenGL ES 3.0 includes support for glVertexAttribDivisor. The
glVertexAttribDivisorEXT API is available on OpenGL ES 2.0 devices with
the GL_EXT_instanced_arrays extension.

GLES3 devices may be able to resolve a glVertexAttribDivisorEXT function
that is not actually implemented. This PR uses the glVertexAttribDivisor
API if available and otherwise falls back to glVertexAttribDivisorEXT.

See flutter#186653
creatorpiyush pushed a commit to creatorpiyush/packages that referenced this pull request Jun 10, 2026
…r#11803)

flutter/flutter@e70534d...b05a9d7

2026-05-29 engine-flutter-autoroll@skia.org Roll Skia from 47155534833e to d9d6b440c4e7 (1 revision) (flutter/flutter#187301)
2026-05-29 engine-flutter-autoroll@skia.org Roll Skia from f93ed13d77fb to 47155534833e (4 revisions) (flutter/flutter#187291)
2026-05-29 kevmoo@users.noreply.github.com [web_ui] Optimize skwasm text layout and path decoding to eliminate dynamic boxing churn under Wasm (flutter/flutter#186978)
2026-05-29 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from SBpmmPxqx3lAvGojE... to jMR_VXQi07kAk8vbR... (flutter/flutter#187279)
2026-05-29 burak.karahan@mail.ru Remove Material import from sliver tree rendering test (flutter/flutter#187000)
2026-05-29 bdero@google.com [Impeller] Remove the y_coord_scale Y-flip plumbing (flutter/flutter#187224)
2026-05-29 31859944+LongCatIsLooong@users.noreply.github.com Add/remove overlay child RenderObject from the tree in `attach`/`detach` (flutter/flutter#186564)
2026-05-29 engine-flutter-autoroll@skia.org Roll Skia from fcfe5975c945 to f93ed13d77fb (4 revisions) (flutter/flutter#187273)
2026-05-28 evanwall@buffalo.edu Handle complex RSE rendering in the uber SDF pipeline (flutter/flutter#186434)
2026-05-28 engine-flutter-autoroll@skia.org Roll Dart SDK from 082191101fcc to 683322426411 (2 revisions) (flutter/flutter#187270)
2026-05-28 mvincentong@gmail.com Clarify route transition animations (flutter/flutter#186552)
2026-05-28 116356835+AbdeMohlbi@users.noreply.github.com document that the default Key is null and explain proper usage in list diffing (flutter/flutter#185197)
2026-05-28 srawlins@google.com [flutter_tools] Use super parameters in missed spots (flutter/flutter#186197)
2026-05-28 mr_nadeem_iqbal@yahoo.com docs: Document MediaQueryData.alwaysUse24HourFormat on macOS, Windows, Linux, web (#160664) (flutter/flutter#186642)
2026-05-28 engine-flutter-autoroll@skia.org Roll Skia from 5493e4c144cd to fcfe5975c945 (3 revisions) (flutter/flutter#187256)
2026-05-28 30870216+gaaclarke@users.noreply.github.com Shares opengles golden context (flutter/flutter#187243)
2026-05-28 jason-simmons@users.noreply.github.com Update the Curl CIPD package in .ci.yaml to version 8.20.0 (flutter/flutter#187133)
2026-05-28 737941+loic-sharma@users.noreply.github.com Improve SizedBox's docs (flutter/flutter#187208)
2026-05-28 bdero@google.com [Impeller] Support instanced rendering across all backends (flutter/flutter#186653)
2026-05-28 43054281+camsim99@users.noreply.github.com [Android] Reset system UI visibility flags when setting edge-to-edge mode (flutter/flutter#187207)
2026-05-28 engine-flutter-autoroll@skia.org Roll Skia from a38708fb7926 to 5493e4c144cd (7 revisions) (flutter/flutter#187241)
2026-05-28 30870216+gaaclarke@users.noreply.github.com Turned on impeller by default on macos (flutter/flutter#186546)
2026-05-28 mvincentong@gmail.com Clarify lazy scroll extent docs (flutter/flutter#186864)
2026-05-28 mdebbar@google.com [web] Fix WebParagraph locales test (flutter/flutter#186813)
2026-05-28 engine-flutter-autoroll@skia.org Roll Packages from 4b424d7 to 10cbdc5 (3 revisions) (flutter/flutter#187238)
2026-05-28 engine-flutter-autoroll@skia.org Roll Dart SDK from f3db7b7d9801 to 082191101fcc (8 revisions) (flutter/flutter#187235)
2026-05-28 engine-flutter-autoroll@skia.org Roll Skia from 32acea791248 to a38708fb7926 (1 revision) (flutter/flutter#187221)
2026-05-28 bdero@google.com [Flutter GPU] Add r32Float and remove Apple-only XR pixel formats (flutter/flutter#187069)

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 boetger@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
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
…tter#186735)

Renderer-layer unittests (`impeller/renderer/renderer_unittests.cc`)
open an interactive playground but never produce a checked image, so
renderer-level rendering has no automated golden coverage.

This adds golden support to that layer:

- `GoldenPlaygroundTest` gets a render-pass `OpenPlaygroundHere`
overload that renders a callback into an offscreen target and
screenshots it, reusing the existing screenshotters and Skia Gold upload
path.
- A new `renderer_golden_unittests.cc` holds renderer golden tests, so
they are opted in one at a time rather than all at once. It starts with
a single triangle test ported from `renderer_unittests.cc`.

This is test infrastructure with no dedicated tracking issue. The need
came up in flutter#186653, where a
renderer-layer instancing test had no golden coverage.

## 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].
- [ ] 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.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- 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
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
Moves the vertex and index count off the buffer-binding calls and onto
the draw call.

A simple (breaking) change that fixes a very silly design flaw that I
built into the API near the very beginning. Moves Flutter GPU draws
towards a design that matches virtually all modern graphics APIs,
including today's Impeller!
Now is the right time to make changes like this to Flutter GPU, since
the API is not yet considered stable.

Before, `bindVertexBuffer` and `bindIndexBuffer` each took a count, and
a single argument-less `draw()` guessed vertex versus index based on
whether an index buffer happened to be bound.

Sooooo many reasons this was the wrong design:

- **Wrong object.** A draw count belongs on the draw, not on a buffer
binding.
- **Implicit kind.** Indexed vs. non-indexed was inferred from what
happened to be bound, not stated.
- **Colliding counts.** Vertex and index counts shared one field; the
vertex count was dropped when an index buffer was bound.
- **Slot-0-only.** The count came from vertex slot 0; values on other
slots were silently ignored.
- **Opaque draws.** `draw()` told you nothing; you had to trace every
bind to know what it drew.
- **Sticky state.** The count leaked across draws in a pass.
- **Redundant re-binds.** Changing only the count forced re-binding the
buffer.
- **No room to grow.** Nowhere natural for per-draw params like
`instanceCount` or `baseVertex`.
- **Unconventional.** WebGPU, Vulkan, Metal, and D3D all put counts on
the draw.
- **Late errors.** Bad counts failed at `draw()` time, far from the
mistaken line.

Now:
- `bindVertexBuffer` and `bindIndexBuffer` only bind buffers.
- `draw(vertexCount)` does a non-indexed draw.
- `drawIndexed(indexCount)` does an indexed draw.

Instanced draws can be landed later via `draw` and `drawIndexed` gaining
an `instanceCount` parameter later on, assuming the Impeller-side
instancing support in flutter#186653 lands.

## 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/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
…utter#187170)

<!-- start_original_pr_link -->
Reverts: flutter#186639
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: cbracken
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: doesn't compile on mac, or Linux.

Mac:
```
../../flutter/testing/dart/gpu_shader_reload_test.dart:64:36: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
  state.renderPass.bindVertexBuffer(
                                   ^
../../flutter/testing/dart/gpu_shader_reload_test.dart:72:24: Error: Too few positional arguments: 1 requ
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: bdero
<!-- end_original_pr_author -->

<!-- start_reviewers -->
Reviewed By: {walley892}
<!-- end_reviewers -->

<!-- start_revert_body -->
This change reverts the following previous change:
Moves the vertex and index count off the buffer-binding calls and onto the draw call.

A simple (breaking) change that fixes a very silly design flaw that I built into the API near the very beginning. Moves Flutter GPU draws towards a design that matches virtually all modern graphics APIs, including today's Impeller!
Now is the right time to make changes like this to Flutter GPU, since the API is not yet considered stable.

Before, `bindVertexBuffer` and `bindIndexBuffer` each took a count, and a single argument-less `draw()` guessed vertex versus index based on whether an index buffer happened to be bound.

Sooooo many reasons this was the wrong design:

- **Wrong object.** A draw count belongs on the draw, not on a buffer binding.
- **Implicit kind.** Indexed vs. non-indexed was inferred from what happened to be bound, not stated.
- **Colliding counts.** Vertex and index counts shared one field; the vertex count was dropped when an index buffer was bound.
- **Slot-0-only.** The count came from vertex slot 0; values on other slots were silently ignored.
- **Opaque draws.** `draw()` told you nothing; you had to trace every bind to know what it drew.
- **Sticky state.** The count leaked across draws in a pass.
- **Redundant re-binds.** Changing only the count forced re-binding the buffer.
- **No room to grow.** Nowhere natural for per-draw params like `instanceCount` or `baseVertex`.
- **Unconventional.** WebGPU, Vulkan, Metal, and D3D all put counts on the draw.
- **Late errors.** Bad counts failed at `draw()` time, far from the mistaken line.

Now:
- `bindVertexBuffer` and `bindIndexBuffer` only bind buffers.
- `draw(vertexCount)` does a non-indexed draw.
- `drawIndexed(indexCount)` does an indexed draw.

Instanced draws can be landed later via `draw` and `drawIndexed` gaining an `instanceCount` parameter later on, assuming the Impeller-side instancing support in flutter#186653 lands.

## 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/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

<!-- end_revert_body -->

Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
Relands flutter#186639, which was reverted in flutter#187170.

The original PR landed clean, but broke the macOS and Linux builds
because `engine/src/flutter/testing/dart/gpu_shader_reload_test.dart`
(added concurrently by flutter#186793, which was in the merge queue at the same
time) still called the old `bindVertexBuffer(view, count)` / `draw()`
API. This reland is identical to flutter#186639 plus a one-spot migration of
that test to `bindVertexBuffer(view)` + `draw(3)`.

---

Moves the vertex and index count off the buffer-binding calls and onto
the draw call.

A simple (breaking) change that fixes a very silly design flaw that I
built into the API near the very beginning. Moves Flutter GPU draws
towards a design that matches virtually all modern graphics APIs,
including today's Impeller! Now is the right time to make changes like
this to Flutter GPU, since the API is not yet considered stable.

Before, `bindVertexBuffer` and `bindIndexBuffer` each took a count, and
a single argument-less `draw()` guessed vertex versus index based on
whether an index buffer happened to be bound.

Sooooo many reasons this was the wrong design:

- **Wrong object.** A draw count belongs on the draw, not on a buffer
binding.
- **Implicit kind.** Indexed vs. non-indexed was inferred from what
happened to be bound, not stated.
- **Colliding counts.** Vertex and index counts shared one field; the
vertex count was dropped when an index buffer was bound.
- **Slot-0-only.** The count came from vertex slot 0; values on other
slots were silently ignored.
- **Opaque draws.** `draw()` told you nothing; you had to trace every
bind to know what it drew.
- **Sticky state.** The count leaked across draws in a pass.
- **Redundant re-binds.** Changing only the count forced re-binding the
buffer.
- **No room to grow.** Nowhere natural for per-draw params like
`instanceCount` or `baseVertex`.
- **Unconventional.** WebGPU, Vulkan, Metal, and D3D all put counts on
the draw.
- **Late errors.** Bad counts failed at `draw()` time, far from the
mistaken line.

Now:
- `bindVertexBuffer` and `bindIndexBuffer` only bind buffers.
- `draw(vertexCount)` does a non-indexed draw.
- `drawIndexed(indexCount)` does an indexed draw.

Instanced draws can be landed later via `draw` and `drawIndexed` gaining
an `instanceCount` parameter later on, assuming the Impeller-side
instancing support in flutter#186653 lands.

## 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/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
…86653)

Progress on flutter#154145.

Instanced drawing was started in Impeller long ago but remains
incomplete to today. A command could carry an instance count, Metal and
Vulkan honored it, but OpenGL ES ignored it, no backend had per-instance
vertex data, and there was zero test coverage.

This fills those gaps in a fully portable way that works _everywhere_,
including emulation on rare GLES 2 drivers that don't support the
required extensions! No capability checks required to safely use.

Super useful for Flutter GPU-based renderers, but I think some stuff in
Impeller's 2D renderer may be able benefit from this too. One of the
original early motivations we started implementing this years ago was to
reduce the vertex load for glyph atlas rendering, for example.

## Example usage

On the shader side there is nothing instancing-specific. Per-instance
values are declared as ordinary vertex `in` attributes, identical to
per-vertex ones; the shader does no indexing and never references
`gl_InstanceIndex`.

```glsl
uniform FrameInfo {
  mat4 mvp;
}
frame_info;

in vec2 vertex_position;  // supplied per vertex
in vec2 instance_offset;  // supplied per instance
in vec4 instance_color;   // supplied per instance

out vec4 v_color;

void main() {
  gl_Position = frame_info.mvp * vec4(vertex_position + instance_offset, 0.0, 1.0);
  v_color = instance_color;
}
```

On the Impeller side, instancing is driven through the existing pipeline
and render pass APIs. The only new surface is the per-binding input
rate: a binding is marked instance-rate on the `VertexDescriptor`,
geometry and per-instance data are bound as separate vertex buffers, and
the draw carries an instance count.

```cpp
// Binding 0 advances once per vertex; binding 1 advances once per instance.
auto vertex_desc = std::make_shared<VertexDescriptor>();
vertex_desc->SetStageInputs(
    /*inputs=*/{position_slot, instance_offset_slot, instance_color_slot},
    /*layouts=*/{
        ShaderStageBufferLayout{.stride = sizeof(Vector2),
                                .binding = 0,
                                .input_rate = VertexInputRate::kVertex},
        ShaderStageBufferLayout{.stride = sizeof(InstanceData),
                                .binding = 1,
                                .input_rate = VertexInputRate::kInstance},
    });
pipeline_desc->SetVertexDescriptor(std::move(vertex_desc));

// One draw call renders `instance_count` copies of the geometry.
pass.SetVertexBuffer({geometry_view, instance_data_view});
pass.SetElementCount(vertex_count);
pass.SetInstanceCount(instance_count);
pass.Draw();
```

A complete, runnable version is the new
[`CanRenderInstancedWithVertexAttributes`](https://github.com/bdero/flutter/blob/8f835895165add4f0e628d775b9d28c55ae3663a/engine/src/flutter/impeller/renderer/renderer_unittests.cc#L545-L640)
test, paired with the
[`instanced_attributes.vert`](https://github.com/bdero/flutter/blob/8f835895165add4f0e628d775b9d28c55ae3663a/engine/src/flutter/impeller/fixtures/instanced_attributes.vert)
fixture shown above.

Note that the `VertexDescriptor` is assembled by hand rather than from
`impellerc`'s reflected shader structs. Whether a binding is
per-instance is pipeline state, not something expressible in shader
source, so there is no static codegen for it: generating it would first
require deciding how to annotate which shader inputs are per-instance,
which is something we could add down the road if we find it'd be
convenient for stuff in the entities framework.

## 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.
- [x] 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/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
…orEXT on GLES2 with the extension (flutter#187313)

OpenGL ES 3.0 includes support for glVertexAttribDivisor. The
glVertexAttribDivisorEXT API is available on OpenGL ES 2.0 devices with
the GL_EXT_instanced_arrays extension.

GLES3 devices may be able to resolve a glVertexAttribDivisorEXT function
that is not actually implemented. This PR uses the glVertexAttribDivisor
API if available and otherwise falls back to glVertexAttribDivisorEXT.

See flutter#186653
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. will affect goldens Changes to golden files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants