Repository navigation
[Impeller] Cache GLES sampler configuration in RenderPassStateCache - #193922
Merged
auto-submit[bot] merged 5 commits intoOct 14, 2026
Merged
Conversation
OpenGL ES does not expose standalone sampler objects on the paths used by SamplerGLES; instead, SamplerGLES::ConfigureBoundTexture emits up to 5 glTexParameteri calls (plus optional anisotropic filtering) on the bound GL texture object every time a texture is bound for a draw call. Cache the SamplerDescriptor::ToKey on non-wrapped TextureGLES instances so consecutive draws sampling the same texture with an identical sampler descriptor skip redundant glTexParameteri calls. External wrapped textures (IsWrapped()) continue to apply sampler parameters unconditionally. Fixes flutter#192147
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces an optimization in SamplerGLES to skip redundant sampler configuration calls by tracking the sampler state on non-wrapped textures using a new configured_sampler_key_ in TextureGLES. A corresponding unit test has been added to BufferBindingsGLESTest to verify this behavior. I have no further feedback to provide.
gaaclarke
requested changes
Oct 9, 2026
kevmoo
added a commit
to kevmoo/flutter
that referenced
this pull request
Oct 10, 2026
Move the per-texture sampler state cache out of `TextureGLES` and `SamplerGLES` into `SamplerStateCache` inside `RenderPassStateCache`, matching `BlendStateCache`, `StencilStateCache`, and `DepthStateCache`.
- Revert `sampler_gles.cc` to `master` and replace `configured_sampler_key_` on `TextureGLES` with a read-only `GetHandle()` accessor.
- Add `SamplerStateCache` in `buffer_bindings_gles.{h,cc}` keyed by `HandleGLES` (`HandleGLES::Hash` / `HandleGLES::Equal`).
- Own `SamplerStateCache sampler` inside `RenderPassStateCache` in `render_pass_gles.cc` and pass `&state_cache.sampler` into `BufferBindingsGLES::BindUniformData`.
- Expand `BufferBindingsGLESTest.SkipsRedundantSamplerConfigurationOnSameTexture` to verify cross-pipeline deduplication via a shared `SamplerStateCache`.
11 tasks done
gaaclarke
previously requested changes
Oct 12, 2026
gaaclarke
left a comment
Member
There was a problem hiding this comment.
Thanks, that's starting to look better.
… headers - Convert `SamplerStateCache` from `struct` to `class` with private `configured_samplers_` and deleted copy operations per the Google C++ Style Guide. - Replace forward declarations of `SamplerGLES` and `TextureGLES` in `buffer_bindings_gles.h` with direct `#include`s.
kevmoo
dismissed
gaaclarke’s stale review
October 13, 2026 17:58
Addressed in fac2aab (SamplerStateCache converted to class and forward declarations replaced with #includes); re-requesting review from @gaaclarke.
kevmoo
added a commit
to kevmoo/flutter
that referenced
this pull request
Oct 14, 2026
- Merge origin/master (including flutter#193922 SamplerStateCache) into wimp-track-b-gles3-state-dedup. - Convert struct VertexAttribStateCache to class VertexAttribStateCache with private data members and encapsulated state-tracking methods matching the review style from flutter#193922 and flutter#193427. - DelegateSamplerStateCache::IsTextureConfigured in BindAndConfigureTexture.
This was referenced Oct 14, 2026
auto-submit Bot
pushed a commit
to flutter/packages
that referenced
this pull request
Oct 14, 2026
Roll Flutter from 4249ccbc18a3 to 426be968b5eb (44 revisions) flutter/flutter@4249ccb...426be96 2026-10-14 [email protected] Allow color delta tolerance in in-memory fuzzy image comparator (flutter/flutter#193937) 2026-10-14 [email protected] [web] Drop stale composing range after text is replaced mid-composition (flutter/flutter#194096) 2026-10-14 [email protected] Roll Skia from 2a2bbea66844 to acde3755d2e2 (1 revision) (flutter/flutter#194376) 2026-10-14 [email protected] Roll Skia from 128c983b12de to 2a2bbea66844 (1 revision) (flutter/flutter#194371) 2026-10-14 [email protected] Roll Skia from 48a294ed4955 to 128c983b12de (3 revisions) (flutter/flutter#194353) 2026-10-14 [email protected] feat(flutter_tools): extract WebDebugConfig from DebuggingOptions (flutter/flutter#194312) 2026-10-14 [email protected] Roll Skia from ea6781c5b6d1 to 48a294ed4955 (2 revisions) (flutter/flutter#194349) 2026-10-14 [email protected] Include <vector> in Android proc_table.h. (flutter/flutter#194325) 2026-10-14 [email protected] Roll Dart SDK from 5933cb486b4a to 6b50116630d0 (28 revisions) (flutter/flutter#194341) 2026-10-14 [email protected] Move GLES3 instancing API entry points to FOR_EACH_IMPELLER_GLES3_PROC (flutter/flutter#194319) 2026-10-14 [email protected] feat(flutter_tools): extract AndroidGradleConfig and move toGradleConfig to AndroidBuildInfo (flutter/flutter#194016) 2026-10-14 [email protected] Roll Skia from ae297bec6012 to ea6781c5b6d1 (8 revisions) (flutter/flutter#194331) 2026-10-14 [email protected] [flutter_tools] Migrate gradle_errors and deferred_components_prebuild_validator away from globals (flutter/flutter#193649) 2026-10-14 [email protected] [Impeller] Cache GLES sampler configuration in RenderPassStateCache (flutter/flutter#193922) 2026-10-14 [email protected] Roll pub packages (flutter/flutter#194332) 2026-10-13 [email protected] [tool] Migrate RunCommand to modular dependency injection (flutter/flutter#190791) 2026-10-13 [email protected] Include `engine/src/flutter/.ci.yaml` in quarterly `goldctl` checklist (flutter/flutter#194316) 2026-10-13 [email protected] [flutter_tools] Remove the last AMD module system support (flutter/flutter#193607) 2026-10-13 [email protected] Roll Skia from 8b3394a60654 to ae297bec6012 (5 revisions) (flutter/flutter#194310) 2026-10-13 [email protected] [web] Remove the a11y placeholder only after the gesture ends (flutter/flutter#194109) 2026-10-13 [email protected] Upgrade goldctl to the latest version (flutter/flutter#193932) 2026-10-13 [email protected] [flutter_tools] Lazily initialize AndroidStudio validation and optimize candidate selection (flutter/flutter#191968) 2026-10-13 [email protected] [flutter_tools] Clean up outdated widget preview TODOs and refactor static state (flutter/flutter#189437) 2026-10-13 [email protected] Roll Skia from e5b5db6d0d6f to 8b3394a60654 (2 revisions) (flutter/flutter#194306) 2026-10-13 [email protected] Redistribute TESTOWNERS for Android team (flutter/flutter#193861) 2026-10-13 [email protected] feat(flutter_tools): introduce Test and Drive specification objects (flutter/flutter#194017) 2026-10-13 [email protected] [Impeller] Keep the aspect ratio when shrinking images to the max texture size (flutter/flutter#194010) 2026-10-13 [email protected] [flutter tool] preserve inherited `DASH__SUPPRESS_ANALYTICS=true` for sub-tools (flutter/flutter#194261) 2026-10-13 [email protected] Roll Packages from d8d9e97 to a1ed23c (9 revisions) (flutter/flutter#194302) 2026-10-13 [email protected] Use PE/COFF AOT snapshots for Windows x64 (flutter/flutter#187594) 2026-10-13 [email protected] Fix Expansible crash when PageStorage holds a non-bool value (flutter/flutter#192195) 2026-10-13 [email protected] Roll Skia from ffeccb3ca58a to e5b5db6d0d6f (1 revision) (flutter/flutter#194297) 2026-10-13 [email protected] Explain why initState() is too early to depend on an inherited widget (flutter/flutter#192727) 2026-10-13 [email protected] Refactor TestPlatformDispatcher (flutter/flutter#192747) 2026-10-13 [email protected] Roll Skia from 3de0984208ec to ffeccb3ca58a (2 revisions) (flutter/flutter#194291) 2026-10-13 [email protected] Roll Skia from 0580c2b780f6 to 3de0984208ec (2 revisions) (flutter/flutter#194281) 2026-10-13 [email protected] Roll Skia from f641d55e07a8 to 0580c2b780f6 (3 revisions) (flutter/flutter#194275) 2026-10-13 [email protected] Roll Skia from 0e5d8d1be81b to f641d55e07a8 (1 revision) (flutter/flutter#194266) 2026-10-13 [email protected] Scaffold view metrics overrides (flutter/flutter#192764) 2026-10-13 [email protected] [web] Add SemanticsRole.listBox and SemanticsRole.option (flutter/flutter#192971) 2026-10-13 [email protected] Pin mac_unopt to macOS 15 (flutter/flutter#194254) 2026-10-13 [email protected] Roll pub packages (flutter/flutter#194257) 2026-10-12 [email protected] Roll Skia from 17f6986c226c to 0e5d8d1be81b (4 revisions) (flutter/flutter#194249) 2026-10-12 [email protected] Make DisplayLists' use of DlPaint, SkPaint, and impeller::Paint agree on the default isAntiAlias (flutter/flutter#193939) If this roll has caused a breakage, revert this CL and set the roller ...
4 of 11 tasks
suryaKommana2662
pushed a commit
to suryaKommana2662/flutter
that referenced
this pull request
Oct 29, 2026
…lutter#193922) ### Rationale Split out from flutter#193427 per @gaaclarke's review feedback. OpenGL ES does not expose standalone sampler objects on the paths used by `SamplerGLES`; instead, `SamplerGLES::ConfigureBoundTexture` emits up to 5 `glTexParameteri` calls (`GL_TEXTURE_MIN_FILTER`, `GL_TEXTURE_MAG_FILTER`, `GL_TEXTURE_MAX_LEVEL`, `GL_TEXTURE_WRAP_S`, `GL_TEXTURE_WRAP_T`) plus optional `GL_TEXTURE_MAX_ANISOTROPY_EXT` on the bound GL texture object every time a texture is bound for a draw call. On glyph-atlas-heavy and tiled scenes (`bouncy@128`, `grid@1000`), hundreds or thousands of consecutive draw calls sample the same texture with an identical `SamplerDescriptor`, issuing up to `12,258` redundant `glTexParameteri`/`glTexParameterf` calls per frame after flutter#193427. Within a render pass, non-wrapped `TextureGLES` instances own an immutable `UniqueHandleGLES` (`HandleGLES`) and immutable `TextureDescriptor` / `mip_count`. Caching the last configured `SamplerDescriptor::ToKey` per `HandleGLES` in `SamplerStateCache` inside `RenderPassStateCache` (alongside `BlendStateCache`, `StencilStateCache`, and `DepthStateCache`) skips redundant `glTexParameter*` calls across draws and pipelines within the pass without storing mutable cached state on `TextureGLES`. ### Summary of Changes - [`engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h`](https://github.com/kevmoo/flutter/blob/f9f4ba51255/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h): Add a read-only `const HandleGLES& GetHandle() const` accessor matching `PipelineGLES::GetProgramHandle()`. - [`engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h`](https://github.com/kevmoo/flutter/blob/f9f4ba51255/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h) & [`engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc`](https://github.com/kevmoo/flutter/blob/f9f4ba51255/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc): Add `struct SamplerStateCache` (`absl::flat_hash_map<HandleGLES, uint64_t, HandleGLES::Hash, HandleGLES::Equal> configured_samplers;` + `ConfigureBoundTexture(...)`) and pass an optional `SamplerStateCache*` into `BufferBindingsGLES::BindUniformData` and `BufferBindingsGLES::BindTextures`. Wrapped external textures (`IsWrapped()`) bypass the cache so external callers mutating raw GL texture parameters are unaffected. - [`engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc`](https://github.com/kevmoo/flutter/blob/f9f4ba51255/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc): Add `SamplerStateCache sampler;` to `RenderPassStateCache` and pass `&state_cache.sampler` into `vertex_desc_gles->BindUniformData(...)`. - [`engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc`](https://github.com/kevmoo/flutter/blob/f9f4ba51255/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc): Add `BufferBindingsGLESTest.SkipsRedundantSamplerConfigurationOnSameTexture` covering repeated binds with an identical sampler descriptor, re-configuration when the sampler descriptor changes, cross-pipeline deduplication/invalidation via a shared `SamplerStateCache`, and cache bypass for wrapped external textures (`TextureGLES::WrapTexture`). ### Flow / Surface Delta #### 1. Deterministic WebGL2 Call-Count Reductions (`0%` Variance) Measured on top of merged flutter#193427 (`origin/master` @ `a554b8ac180` vs. `daad7727f54` across steady-state frames): | Workload (`1280x720`, `wimp_st`) | Metric | Pre-Change (post-`flutter#193427`) | Post-Change | Absolute Delta | Delta (%) | Reduction | | :--- | :--- | :---: | :---: | :---: | :---: | :--- | | **`bouncy` (`128` nodes, `441` draws, `247` textured)** | `glTexParameteri` + `glTexParameterf` / frame | `1,482` (`1,235` + `247`) | `~6` (`1` per pass) | `-1,476` | **`-99.6%`** | **Deduplicated per pass** | | | Total GL calls / frame | `7,827` | `6,336` | `-1,491` | **`-19.0%`** | **`1.24x` fewer calls** (`-52.2%` / `2.09x` cumulative w/ `flutter#193427`) | | **`grid` (`100` nodes, `660` draws, `245` textured)** | `glTexParameteri` + `glTexParameterf` / frame | `1,470` (`1,225` + `245`) | `~6` (`1` per pass) | `-1,464` | **`-99.6%`** | **Deduplicated per pass** | | | Total GL calls / frame | `10,674` | `9,213` | `-1,461` | **`-13.7%`** | **`1.16x` fewer calls** | | **`grid` (`1000` nodes, `5,908` draws, `2,043` textured)** | `glTexParameteri` + `glTexParameterf` / frame | `12,258` (`10,215` + `2,043`) | `~6` (`1` per pass) | `-12,252` | **`-99.95%`** | **Deduplicated per pass** | | | Total GL calls / frame | `93,669` | `81,285` | `-12,384` | **`-13.2%`** | **`1.15x` fewer calls** (`-47.4%` / `1.90x` cumulative w/ `flutter#193427`) | In `100us` V8/Wasm CPU profiling of the `DedicatedWorker` raster thread on `grid@1000` (`--profile --no-strip-wasm`), redundant `glTexParameteri` (`9.75 ms` Wasm self-time + `19.76 ms` JS binding) and `glTexParameterf` (`12.80 ms` JS binding) accounted for **`42.31 ms` (`2.09%` of total active worker CPU time)** across a `2.02s` steady-state window. #### 2. Hardware WebGL2 `rasterTimeMs` A/B (`AMD Radeon 780M`, `n=5` Interleaved ABBA Pairs) Measured on headed Chrome 154 (`ANGLE (AMD, AMD Radeon 780M Graphics (radeonsi phoenix ACO), OpenGL ES 3.2)`, `--disable-gpu-vsync --disable-frame-rate-limit`, `10` samples/run × `5` interleaved ABBA pairs per arm): | Workload (`1280x720`, `wimp_st`) | Pre-Change (`a554b8ac180`) | Post-Change (`daad7727f54`) | Absolute Delta | Delta (%) | Speedup | | :--- | :---: | :---: | :---: | :---: | :---: | | **`bouncy` (`64` nodes)** | `1.412 ms` | `1.382 ms` | `-0.030 ms` | `-2.15%` | `1.02x` | | **`bouncy` (`128` nodes)** | `1.842 ms` | `1.756 ms` | `-0.086 ms` | **`-4.66%`** | **`1.05x`** | | **`grid` (`100` nodes)** | `1.783 ms` | `1.727 ms` | `-0.057 ms` | **`-3.17%`** | **`1.03x`** | | **`grid` (`1000` nodes)** | `16.385 ms` | `15.996 ms` | `-0.389 ms` | **`-2.37%`** | **`1.02x`** | **How much to trust these numbers:** - **Call counts (Table 1) are exact (`0%` run-to-run variance)**: Every frame deterministically eliminates `1,464`–`12,252` redundant `glTexParameter*` calls across the boundary. - **Wall-clock `rasterTimeMs` (Table 2) has a `~1.2%–2.0%` run-to-run noise floor**: - **`bouncy@128` (`-4.66%`)** and **`grid@100` (`-3.17%`)** clear the noise floor consistently (`5/5` interleaved Post runs beat Pre). - **`grid@1000` (`-2.37%`, `-0.39 ms`)** sits just above the `~1.5%–2.0%` noise floor (`4/5` pairs faster) and aligns with the `2.09%` worker CPU profile share of `glTexParameter*` when `5,908` draw calls dominate frame time. - **`bouncy@64` (`-2.15%`, `-0.03 ms`)** is inside the noise floor at `<1.5 ms` frame times and should be treated as flat/within noise. ### Verification - Built and ran `host_debug_unopt:impeller_unittests --gtest_filter="*BufferBindingsGLES*:*RenderPassGLES*:*SamplerGLES*:*TextureGLES*"` locally (`37/37` passed, including `BufferBindingsGLESTest.SkipsRedundantSamplerConfigurationOnSameTexture`). - Built `wasm_release:skwasm/wimp.js` and verified both deterministic WebGL2 call counts and `n=5` interleaved hardware WebGL2 `rasterTimeMs` medians (`AMD Radeon 780M`) in Chrome 154 via `flutter-wasm-compare`. Related to flutter#192147 Towards flutter#174980 ## 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 in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [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 [flutter/website]: https://github.com/flutter/website [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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rationale
Split out from #193427 per @gaaclarke's review feedback.
OpenGL ES does not expose standalone sampler objects on the paths used by
SamplerGLES; instead,SamplerGLES::ConfigureBoundTextureemits up to 5glTexParametericalls (GL_TEXTURE_MIN_FILTER,GL_TEXTURE_MAG_FILTER,GL_TEXTURE_MAX_LEVEL,GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T) plus optionalGL_TEXTURE_MAX_ANISOTROPY_EXTon the bound GL texture object every time a texture is bound for a draw call. On glyph-atlas-heavy and tiled scenes (bouncy@128,grid@1000), hundreds or thousands of consecutive draw calls sample the same texture with an identicalSamplerDescriptor, issuing up to12,258redundantglTexParameteri/glTexParameterfcalls per frame after #193427.Within a render pass, non-wrapped
TextureGLESinstances own an immutableUniqueHandleGLES(HandleGLES) and immutableTextureDescriptor/mip_count. Caching the last configuredSamplerDescriptor::ToKeyperHandleGLESinSamplerStateCacheinsideRenderPassStateCache(alongsideBlendStateCache,StencilStateCache, andDepthStateCache) skips redundantglTexParameter*calls across draws and pipelines within the pass without storing mutable cached state onTextureGLES.Summary of Changes
engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h: Add a read-onlyconst HandleGLES& GetHandle() constaccessor matchingPipelineGLES::GetProgramHandle().engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h&engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc: Addstruct SamplerStateCache(absl::flat_hash_map<HandleGLES, uint64_t, HandleGLES::Hash, HandleGLES::Equal> configured_samplers;+ConfigureBoundTexture(...)) and pass an optionalSamplerStateCache*intoBufferBindingsGLES::BindUniformDataandBufferBindingsGLES::BindTextures. Wrapped external textures (IsWrapped()) bypass the cache so external callers mutating raw GL texture parameters are unaffected.engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc: AddSamplerStateCache sampler;toRenderPassStateCacheand pass&state_cache.samplerintovertex_desc_gles->BindUniformData(...).engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc: AddBufferBindingsGLESTest.SkipsRedundantSamplerConfigurationOnSameTexturecovering repeated binds with an identical sampler descriptor, re-configuration when the sampler descriptor changes, cross-pipeline deduplication/invalidation via a sharedSamplerStateCache, and cache bypass for wrapped external textures (TextureGLES::WrapTexture).Flow / Surface Delta
1. Deterministic WebGL2 Call-Count Reductions (
0%Variance)Measured on top of merged #193427 (
origin/master@a554b8ac180vs.daad7727f54across steady-state frames):1280x720,wimp_st)#193427)bouncy(128nodes,441draws,247textured)glTexParameteri+glTexParameterf/ frame1,482(1,235+247)~6(1per pass)-1,476-99.6%7,8276,336-1,491-19.0%1.24xfewer calls (-52.2%/2.09xcumulative w/#193427)grid(100nodes,660draws,245textured)glTexParameteri+glTexParameterf/ frame1,470(1,225+245)~6(1per pass)-1,464-99.6%10,6749,213-1,461-13.7%1.16xfewer callsgrid(1000nodes,5,908draws,2,043textured)glTexParameteri+glTexParameterf/ frame12,258(10,215+2,043)~6(1per pass)-12,252-99.95%93,66981,285-12,384-13.2%1.15xfewer calls (-47.4%/1.90xcumulative w/#193427)In
100usV8/Wasm CPU profiling of theDedicatedWorkerraster thread ongrid@1000(--profile --no-strip-wasm), redundantglTexParameteri(9.75 msWasm self-time +19.76 msJS binding) andglTexParameterf(12.80 msJS binding) accounted for42.31 ms(2.09%of total active worker CPU time) across a2.02ssteady-state window.2. Hardware WebGL2
rasterTimeMsA/B (AMD Radeon 780M,n=5Interleaved ABBA Pairs)Measured on headed Chrome 154 (
ANGLE (AMD, AMD Radeon 780M Graphics (radeonsi phoenix ACO), OpenGL ES 3.2),--disable-gpu-vsync --disable-frame-rate-limit,10samples/run ×5interleaved ABBA pairs per arm):1280x720,wimp_st)a554b8ac180)daad7727f54)bouncy(64nodes)1.412 ms1.382 ms-0.030 ms-2.15%1.02xbouncy(128nodes)1.842 ms1.756 ms-0.086 ms-4.66%1.05xgrid(100nodes)1.783 ms1.727 ms-0.057 ms-3.17%1.03xgrid(1000nodes)16.385 ms15.996 ms-0.389 ms-2.37%1.02xHow much to trust these numbers:
0%run-to-run variance): Every frame deterministically eliminates1,464–12,252redundantglTexParameter*calls across the boundary.rasterTimeMs(Table 2) has a~1.2%–2.0%run-to-run noise floor:bouncy@128(-4.66%) andgrid@100(-3.17%) clear the noise floor consistently (5/5interleaved Post runs beat Pre).grid@1000(-2.37%,-0.39 ms) sits just above the~1.5%–2.0%noise floor (4/5pairs faster) and aligns with the2.09%worker CPU profile share ofglTexParameter*when5,908draw calls dominate frame time.bouncy@64(-2.15%,-0.03 ms) is inside the noise floor at<1.5 msframe times and should be treated as flat/within noise.Verification
host_debug_unopt:impeller_unittests --gtest_filter="*BufferBindingsGLES*:*RenderPassGLES*:*SamplerGLES*:*TextureGLES*"locally (37/37passed, includingBufferBindingsGLESTest.SkipsRedundantSamplerConfigurationOnSameTexture).wasm_release:skwasm/wimp.jsand verified both deterministic WebGL2 call counts andn=5interleaved hardware WebGL2rasterTimeMsmedians (AMD Radeon 780M) in Chrome 154 viaflutter-wasm-compare.Related to #192147
Towards #174980
Pre-launch Checklist
///).