Skip to content

Fragment shaders fail to render using uniform arrays on Android with Impeller GLES. #170647

@heyarny

Description

@heyarny

Steps to reproduce

I would like to create dynamic shaders with array of data.
Note the use of uniform float uRadii[8]; inside shaders file.
This works fine on iOS, but using Android there is simply nothing.
Tried with Impella enabled & disabled.

Tried with versions 3.29.3, 3.32.4 & 3.33.0-1.0.pre.477.

Expected results

Shader should draw circles.

Actual results

Nothing.

Code sample

Shader example
#include <flutter/runtime_effect.glsl>

// 0..1 : canvas size in logical px
uniform vec2  u_size;
// 2    : how many circles to draw (as float)
uniform float uCount;
// 3..10: up to 8 radii in logical px
uniform float uRadii[8];

out vec4 fragColor;

// draw a red circle with hard edge
vec4 drawCircle(vec2 p, vec2 center, float r) {
    float m = step(length(p - center), r);
    return vec4(1.0, 0.0, 0.0, m);
}

void main() {
    vec2 p   = FlutterFragCoord().xy;       // logical px
    float cy = 0.5 * u_size.y;              // vertical center
    vec4 col = vec4(0.0);

    // loop unrolled to max 8
    for (int i = 0; i < 8; i++) {
        if (float(i) < uCount) {
            // evenly spaced X
            float cx = (float(i) + 1.0) / (uCount + 1.0) * u_size.x;
            float r  = uRadii[i];
            col = max(col, drawCircle(p, vec2(cx, cy), r));
        }
    }

    fragColor = col;
}
Flutter sample
import 'dart:ui';
import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: LogicalCirclesDemo()));

class LogicalCirclesDemo extends StatefulWidget {
  const LogicalCirclesDemo({super.key});
  @override
  State<LogicalCirclesDemo> createState() => _LogicalCirclesDemoState();
}

class _LogicalCirclesDemoState extends State<LogicalCirclesDemo> {
  late final FragmentProgram _prog;
  bool _ready = false;

  // your desired radii in **logical** pixels:
  final List<double> _radii = [50, 30, 70, 40, 60];

  @override
  void initState() {
    super.initState();
    FragmentProgram.fromAsset('shaders/circle.frag')
      .then((p) => setState(() {
        _prog = p;
        _ready = true;
      }));
  }

  @override
  Widget build(BuildContext context) {
    if (!_ready) {
      return const Scaffold(
        body: Center(child: CircularProgressIndicator()),
      );
    }

    // **Logical** size of the canvas:
    final sizeLogical = MediaQuery.of(context).size;

    return Scaffold(
      body: CustomPaint(
        size: sizeLogical,
        painter: _LogicalCirclesPainter(
          program: _prog,
          size:    sizeLogical,
          radii:   _radii,
        ),
      ),
    );
  }
}

class _LogicalCirclesPainter extends CustomPainter {
  final FragmentProgram program;
  final Size           size;
  final List<double>   radii;

  _LogicalCirclesPainter({
    required this.program,
    required this.size,
    required this.radii,
  });

  @override
  void paint(Canvas canvas, Size _) {
    // configure the shader with **logical** dimensions
    final shader = program.fragmentShader()
      // u_size.xy in logical px
      ..setFloat(0, size.width)
      ..setFloat(1, size.height)
      // uCount
      ..setFloat(2, radii.length.toDouble());

    // uRadius0..uRadius7 → slots 3..10
    for (int i = 0; i < radii.length && i < 8; i++) {
      shader.setFloat(3 + i, radii[i]);
    }
    // zero out any unused
    for (int i = radii.length; i < 8; i++) {
      shader.setFloat(3 + i, 0.0);
    }

    // draw a full‐screen quad in logical space:
    final paint = Paint()..shader = shader;
    canvas.drawRect(Offset.zero & size, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter old) => false;
}

Screenshots or Video

On iOS (Working) Image

Logs

No response

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.32.4, on macOS 15.5 24F74 darwin-arm64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
[!] Xcode - develop for iOS and macOS (Xcode 16.4)
    ! CocoaPods 1.15.2 out of date (1.16.2 is recommended).
        CocoaPods is a package manager for iOS or macOS platform code.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/to/platform-plugins
      To update CocoaPods, see https://guides.cocoapods.org/using/getting-started.html#updating-cocoapods
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.3)
[✓] VS Code (version 1.101.0)
[✓] Connected device (6 available)
[✓] Network resources

Metadata

Metadata

Assignees

Labels

P2Important issues not 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.found in release: 3.32Found to occur in 3.32found in release: 3.33Found to occur in 3.33has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyr: fixedIssue is closed as already fixed in a newer versionteam-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