Skip to content

Impeller SDF gradient shader overflows mediump precision resulting in abrupt color transition #195159

Open

Description

@richyo-codes

Issue

When Impeller enabled, rendering a gradient abruptly changes color instead of transitioning smoothly. The shader’s dot product overflows the FP16 exponent range on llvmpipe before normalization. Using highp fixes the output.

Image

Reproduction

Issue verified using Fedora 44 Linux and Flutter 3.50.0-1.0.pre-209 • channel master

flutter-shader-compare-gradient-fix.zip

Extract the attached reproduction and run:

./setup.sh
./compile.sh
python3 render.py compare

This compiles the original and fixed Flutter shaders using impellerc, then compares their rendered output. Verified on Mesa llvmpipe; and AMD GPU.

For the integrated Flutter regression test and proposed fix, see #195036.

or try this

import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(
  home: Scaffold(
    body: SafeArea(
      child: SingleChildScrollView(
        child: SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('Linear'),
              SizedBox(
                width: 400,
                height: 100,
                child: DecoratedBox(
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                      begin: Alignment.centerLeft,
                      end: Alignment.centerRight,
                      colors: [Colors.red, Colors.blue],
                    ),
                  ),
                ),
              ),
              SizedBox(height: 24),
              Text('Radial'),
              SizedBox(
                width: 1100,
                height: 100,
                child: DecoratedBox(
                  decoration: BoxDecoration(
                    gradient: RadialGradient(
                      center: Alignment.centerLeft,
                      // Radius is relative to the shortest side:
                      // 10 × 100 = 1000 logical pixels.
                      radius: 10,
                      colors: [Colors.red, Colors.blue],
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    ),
  ),
));

Proposed fix

References

GLSL ES precision guarantees. mediump does not guarantee 32-bit arithmetic.

Activity

  1. richyo-codes commented on Oct 23, 2026

    @richyo-codes
    ContributorAuthor

    I am wondering if only noticing this now because Impeller started on Android / mobile with smaller screens that may not have triggered or been noticable. Now with Desktop impeller enabled in Flutter easier to render bigger gradients.

  2. added
    engineflutter/engine related. See also e: labels.
    c: renderingUI glitches reported at the engine/skia or impeller rendering level
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    e: impellerImpeller rendering backend issues and features requests
    on Oct 23, 2026
  3. mbcorona commented on Oct 23, 2026

    @mbcorona
    Member

    Hi @richyo-codes, thanks for the analysis and the PR.
    Related to the broader precision inconsistency tracked in #172846, and your fix is up as a draft in #195036 with a regression test.

    Routing to team-engine.

  4. richyo-codes commented on Oct 26, 2026

    @richyo-codes
    ContributorAuthor

    According to my research Impeller + Vulkan rendering is the main problem with the inconsistent precision. Because with mediump the Vulkan driver can decide on 16bit or 32bit float. I've been working on GTK4 support which defaults to Vulkan rendering, so that might be why I am noticing this issue sooner than others. There is also a GTK3 branch working on merging a Vulkan renderer for Impeller.

    Regardless of the precision inconsistency ticket you mention. If mediump sometimes fails with gradient due to lack of precision. Then I think my Draft PR changing gradient shaders to explicitly use highp is correct because it will always work.

    I will note that precision inconsistency issue #172846 was reported using a external demo shader toy, where as the shaders I am reporting are built into flutter. So can't be corrected / worked around without framework fix.

  5. added
    P1High-priority issues at the top of the work list
    on Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work listc: renderingUI glitches reported at the engine/skia or impeller rendering levele: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions