Repository navigation
Closed
Labels
e: impellerImpeller rendering backend issues and features requestsImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.team-fluttergpuOwned by Flutter GPU teamOwned by Flutter GPU team
Description
Steps to reproduce
- Create a macOS app from the code sample below and enable Flutter GPU (
FLTEnableFlutterGPUinInfo.plist). - Run it with a ThreadSanitizer engine (
tools/gn ... --tsan).
Expected results
Flutter GPU and Impeller can request samplers at the same time without a race.
Actual results
GetSampler scans the plain samplers_ vector and then calls push_back, with no lock. Flutter GPU calls it on the UI thread (RenderPass.bindTexture), and Impeller calls it on the raster thread (for example FramebufferBlendContents::Render). A scan can read a buffer that push_back is reallocating. Two inserts at once can corrupt the vector or drop a sampler that was already returned.
- Metal (macOS): TSan reports the race in the code sample in 4 of 6 runs on master.
- All three backends: an engine test that requests samplers from four threads fails or crashes in 39 or more of 40 runs on Metal, Vulkan (SwiftShader, Linux) and OpenGL ES (Mesa, Linux). TSan reports the race in
SamplerLibraryMTL,SamplerLibraryVKandSamplerLibraryGLES. - Vulkan and OpenGL ES are confirmed only with that test, not with an app.
We have not seen it crash a release app. It is a sibling of the pipeline library race in #193721 (PR #193722).
Code sample
pubspec.yaml and lib/main.dart
pubspec.yaml:
name: gpu_pipeline_race
publish_to: none
environment:
sdk: ^3.13.0
dependencies:
flutter:
sdk: flutter
flutter_scene: 0.23.0
vector_math: ^2.4.3
flutter:
uses-material-design: truelib/main.dart:
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_scene/scene.dart';
import 'package:vector_math/vector_math.dart' as vm;
void main() => runApp(const MaterialApp(home: Repro()));
class Repro extends StatefulWidget {
const Repro({super.key});
@override
State<Repro> createState() => _ReproState();
}
class _ReproState extends State<Repro> with SingleTickerProviderStateMixin {
final Scene scene = Scene();
late final Ticker ticker;
int frame = 0;
@override
void initState() {
super.initState();
final geometry = CuboidGeometry(vm.Vector3.all(0.4));
final materials = [UnlitMaterial(), PhysicallyBasedMaterial()];
for (var i = 0; i < 400; i++) {
scene.add(
Node(mesh: Mesh(geometry, materials[i % 2]))
..localTransform = vm.Matrix4.translation(
vm.Vector3((i % 20 - 10) * 0.6, 0, (i ~/ 20 - 10) * 0.6),
),
);
}
ticker = createTicker((_) => setState(() => frame++))..start();
}
@override
void dispose() {
ticker.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final mode = BlendMode.values[frame % BlendMode.values.length];
return Stack(
children: [
Positioned.fill(
child: SceneView(
scene,
camera: PerspectiveCamera(
position: vm.Vector3(0, 10, 14),
target: vm.Vector3.zero(),
),
),
),
Positioned(
left: 20,
top: 20,
width: 300,
height: 200,
child: ColorFiltered(
colorFilter: ColorFilter.mode(Colors.teal, mode),
child: ClipRect(
child: BackdropFilter(
filter: ui.ImageFilter.blur(
sigmaX: 1.0 + frame % 20,
sigmaY: 1.0 + frame % 20,
),
blendMode: mode,
child: Text(
'frame $frame',
style: TextStyle(
fontSize: 40,
color: Colors.white,
shadows: [
Shadow(blurRadius: 1.0 + frame % 40, color: Colors.black),
],
),
),
),
),
),
),
],
);
}
}Screenshots or Video
N/A
Logs
TSan, code sample on master d03768e (macOS)
WARNING: ThreadSanitizer: data race
Read by main thread:
#0 std::vector<pair<uint64_t, shared_ptr<const Sampler>>>::end()
#1 impeller::SamplerLibraryMTL::GetSampler()
#2 BindTextureBinding()
#3 InternalFlutterGpu_RenderPass_BindTextureIndexed
Previous write by thread T6 (raster):
#4 std::vector<pair<uint64_t, shared_ptr<const Sampler>>>::push_back()
#5 impeller::SamplerLibraryMTL::GetSampler()
#6 impeller::FramebufferBlendContents::Render()Flutter Doctor output
flutter doctor -v
[✓] Flutter (Channel stable, 3.47.1, on macOS 26.7 25G229 darwin-arm64, locale en-CA) [1,710ms]
• Flutter version 3.47.1 on channel stable at /Users/<user>/development/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 6655482ec0 (6 weeks ago), 2026-08-19 10:07:23 -0700
• Engine revision 5d53178869
• Dart version 3.13.1
• DevTools version 2.60.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, enable-record-use, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration
[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [4.4s]
• Android SDK at /Users/<user>/Library/Android/sdk
• Emulator version 36.6.11.0 (build_id 15507667) (CL:N/A)
• Platform android-36.1, build-tools 36.1.0
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.10+-117844308-b1163.108)
• All Android licenses accepted.
[!] Xcode - develop for iOS and macOS (Xcode 27.0) [4.5s]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 27A266a
! iOS 27.0 Simulator not installed; this may be necessary for iOS and macOS development.
To download and install the platform, open Xcode, select Xcode > Settings > Components,
and click the GET button for the required platform.
For more information, please visit:
https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [7ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Connected device (3 available) [7.3s]
• iPhone 17 Pro (mobile) • <simulator-udid> • ios • com.apple.CoreSimulator.SimRuntime.iOS-26-4 (simulator)
• macOS (desktop) • macos • darwin-arm64 • macOS 26.7 25G229 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 154.0.8037.95
[✓] Network resources [1,093ms]
• All expected network resources are available.
! Doctor found issues in 1 category.Metadata
Metadata
Assignees
Labels
e: impellerImpeller rendering backend issues and features requestsImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.team-fluttergpuOwned by Flutter GPU teamOwned by Flutter GPU team
Activity
[Impeller] Guard the sampler library caches with a mutex (flutter#193738
github-actions commentedon Oct 25, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.[Impeller] Guard the sampler library caches with a mutex (flutter#193738