Skip to content

CanvasKit FragmentShaders do not update uniforms when reusing a Paint object. #149800

@Moncader

Description

@Moncader

Steps to reproduce

  1. Have some kind of Fragment shader that uses a uniform to show something graphically.
  2. Inside a paint() function, create a new Paint object that uses that shader and cache it.
  3. Also in the paint function, if there is a cached version of the Paint object, use that instead of making a new one.
  4. Update the uniforms of the shader
  5. Notice how in the cached version's paint, the changed value is not reflected in the render

Expected results

Each time you update a uniform via setFloat and friends, the value should be reflected in the shader's uniform.

Actual results

The updated uniform simply isn't sent to the shader.

Code sample

Code sample

pubspec.yaml

flutter:
  shaders:
    - shaders/animate_colors.frag

shaders/animate_colors.frag

#include <flutter/runtime_effect.glsl>

uniform float uTime;

out vec4 fragColor;

void main() {
    vec3 tColor = vec3(sin(uTime) * 0.5 + 0.5);
    fragColor = vec4(tColor, 1.0);
}

main.dart

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'dart:ui' as ui;

late final ui.FragmentProgram _shaderProgram;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  _shaderProgram =
      await ui.FragmentProgram.fromAsset('shaders/animate_colors.frag');

  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  late final MyPainter _painter;
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 1),
      vsync: this,
    )..repeat();

    _painter = MyPainter(_controller);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: 400,
            height: 400,
            child: CustomPaint(
              painter: _painter,
              isComplex: false,
              willChange: true,
            ),
          ),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  MyPainter(Listenable listenable) : super(repaint: listenable);

  ui.FragmentShader? _shader;
  ui.Paint? _paint;

  @override
  void paint(Canvas canvas, Size size) {
    // Get the current time from flutter
    final tTime =
        SchedulerBinding.instance.currentFrameTimeStamp.inMilliseconds / 1000;

    final ui.FragmentShader tShader;

    if (_shader == null) {
      tShader = _shader ??= _shaderProgram.fragmentShader();
      _paint = Paint()..shader = tShader;
    } else {
      tShader = _shader!;
    }

    tShader.setFloat(0, tTime); // uTime in seconds

    final tRect = Rect.fromLTWH(0, 0, size.width, size.height);
    canvas.drawRect(tRect, _paint!);
  }

  @override
  bool shouldRepaint(MyPainter oldDelegate) {
    return true;
  }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
flutter doctor -v
[✓] Flutter (Channel stable, 3.22.1, on macOS 13.6.3 22G436 darwin-arm64, locale
    en-CA)
    • Flutter version 3.22.1 on channel stable at
      XXXXXX
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision a14f74ff3a (2 weeks ago), 2024-05-22 11:08:21 -0500
    • Engine revision 55eae6864b
    • Dart version 3.4.1
    • DevTools version 2.34.3

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at XXXXX/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = XXXXXX/Library/Android/sdk
    • ANDROID_SDK_ROOT = XXXXXX/Library/Android/sdk
    • Java binary at: /Applications/Android
      Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      17.0.7+0-17.0.7b1000.6-10550314)
    • All Android licenses accepted.

[!] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode-15.0.1.app/Contents/Developer
    • Build 15A507
    ✗ Unable to get list of installed Simulator runtimes.
    • CocoaPods version 1.14.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build
      17.0.7+0-17.0.7b1000.6-10550314)

[✓] VS Code (version 1.90.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.91.20240529

[✓] Connected device (3 available)
    • macOS (desktop)                 • macos                 • darwin-arm64   •
      macOS 13.6.3 22G436 darwin-arm64
    • Mac Designed for iPad (desktop) • mac-designed-for-ipad • darwin         •
      macOS 13.6.3 22G436 darwin-arm64
    • Chrome (web)                    • chrome                • web-javascript •
      Google Chrome 125.0.6422.142

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work liste: web_canvaskitCanvasKit (a.k.a. Skia-on-WebGL) rendering backend for Webengineflutter/engine related. See also e: labels.found in release: 3.22Found to occur in 3.22found in release: 3.23Found to occur in 3.23has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyr: fixedIssue is closed as already fixed in a newer versionteam-webOwned by Web platform teamtriaged-webTriaged by Web platform team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions