Skip to content
Boring Doc
BreakingHigh impactOfficial migration guidesince 3.47.0landed 3.46.0-0.1.pre

OpenGL ES render-to-texture content is stored top-down

Framework · Official source

Impeller's OpenGL ES backend now stores render-to-texture content top-down, the same as the Metal and Vulkan backends. A fragment shader or Flutter GPU app that sampled a render-target texture on OpenGL ES and added a vertical flip to compensate for the old bottom-up orientation now renders that content upside down.

Who is affected
Applications and packages relying on the previous behaviour or signature. Code that uses FragmentShader.
Practical impact
Behaviour or API differences that can break builds or change runtime behaviour.
What action should I take?
Follow the official migration guide below, update affected call sites, run `dart fix --apply` where a fix is available, then run your tests.
APIs mentioned:FragmentShader

Before and after (from the official guide)

dart+0−3
Before
1 void main() {
2 vec2 uv = FlutterFragCoord().xy / u_size;
3−#ifdef IMPELLER_TARGET_OPENGLES
4− uv.y = 1.0 - uv.y;
5−#endif
6 fragColor = texture(u_texture, uv);
7 }
After
1 void main() {
2 vec2 uv = FlutterFragCoord().xy / u_size;
 
 
 
3 fragColor = texture(u_texture, uv);
4 }
Raw before / after
void main() {
  vec2 uv = FlutterFragCoord().xy / u_size;
#ifdef IMPELLER_TARGET_OPENGLES
  uv.y = 1.0 - uv.y;
#endif
  fragColor = texture(u_texture, uv);
}
void main() {
  vec2 uv = FlutterFragCoord().xy / u_size;
  fragColor = texture(u_texture, uv);
}
Official migration guide (excerpt, © The Flutter Authors, CC BY 3.0)

Shaders written for OpenGL ES often flipped the Y coordinate inside an IMPELLER_TARGET_OPENGLES block to make render-target textures match the other backends. Render-target textures are now top-down on every backend, so that flip is no longer needed.

Code before migration:

void main() {
  vec2 uv = FlutterFragCoord().xy / u_size;
#ifdef IMPELLER_TARGET_OPENGLES
  uv.y = 1.0 - uv.y;
#endif
  fragColor = texture(u_texture, uv);
}

If the shader only needs to run on a Flutter release that includes this change, remove the flip.

Code after migration:

void main() {
  vec2 uv = FlutterFragCoord().xy / u_size;
  fragColor = texture(u_texture, uv);
}

To keep one source working across releases, guard the flip with the IMPELLER_OPENGLES_UNFLIPPED_DEPRECATED macro. That macro is only defined on releases that store render-target textures top-down, so the flip still runs on older releases that need it.

void main() {
  vec2 uv = FlutterFragCoord().xy / u_size;
#if defined(IMPELLER_TARGET_OPENGLES) && !defined(IMPELLER_OPENGLES_UNFLIPPED_DEPRECATED)
  uv.y = 1.0 - uv.y;
#endif
  fragColor = texture(u_texture, uv);
}
Migration assistantAI-generated · grounded in cited sources
AI explanations are not configured
Set AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.
Official migration guide·Verified classification (95%)

Listed in the official breaking-changes index (docs.flutter.dev/release/breaking-changes).

An official announcement or migration guide documents an intended behaviour or API change. A verified source change (git diff) shows code changed but does not by itself prove a public API is breaking. AI interpretations are labelled and never used to classify a change.

Source commit
b3045439b7c0
Source last updated
Oct 21, 2026
Last synchronized
Oct 21, 2026
Publication status
published
Publication history
  • Oct 21, 2026, 8:31 PM: new → published (ingestion) — Backed by an official breaking-change/migration guide.
AI explanationAI-generated · grounded in cited sources
AI explanations are not configured
Set AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.
Was this useful?