Skip to content

[Impeller] [Flutter GPU] flutter_gpu shader usage conflicts with Impeller internal shaders #175464

Description

@jamesgreen26

Steps to reproduce

  • Register shaders with filenames that match builtin Impeller shaders (e.g., line.vert, line.frag)
  • Create a render pass using flutter_gpu and the above shaders
  • Call Draw() with the render pipeline
  • Observe that the Impeller internal shader is used instead of the registered custom shader

Expected results

A custom shader added to a shader bundle should maintain its defined behaviour when it is retrieved for rendering. Developers using the flutter_gpu library should not need to be aware of internal Impeller shader filenames while authoring shaders.

Actual results

Attempting to retrieve a shader from a user-defined shader bundle will return an internal Impeller shader if there exists one with the same filename. The compiled shaderbundle file appears correct, but the shader loaded at runtime is incorrect.

Code sample

Code sample
import 'dart:typed_data';
import 'package:flutter_gpu/gpu.dart';

void main() {
  final commandBuffer = gpuContext.createCommandBuffer();

  final vertexShader = shaderLibrary["LineVertex"]!;
  final fragmentShader = shaderLibrary["LineFragment"]!;


  final renderTarget = _setupRenderTarget();
  final renderPass = commandBuffer.createRenderPass(renderTarget);

  final pipeline = gpuContext.createRenderPipeline(vertexShader, fragmentShader);
  renderPass.bindPipeline(pipeline);

  setupVertices(renderPass);
  setupUniform(renderPass, fragmentShader);

  renderPass.draw();
  commandBuffer.submit();
}

void setupUniform(RenderPass renderPass, Shader fragmentShader) {
  final uniform = Float32List.fromList([1.0, 0.0, 0.0, 1.0]).buffer.asByteData();

  final transientBuffer = gpuContext.createHostBuffer();
  final uniformBufferView = transientBuffer.emplace(uniform);

  final uniformSlot = fragmentShader.getUniformSlot('Paint');
  renderPass.bindUniform(uniformSlot, uniformBufferView);
}

void setupVertices(RenderPass renderPass) {

  final vertices = Float32List.fromList([
    -1, -1, 0,
    1, -1, 0,
    -1,  1, 0,
    1, -1, 0,
    1, 1, 0,
    -1, 1, 0,
  ]);

  final vertexBuffer = gpuContext.createDeviceBufferWithCopy(ByteData.sublistView(vertices));

  final vertexBufferView = BufferView(
    vertexBuffer,
    offsetInBytes: 0,
    lengthInBytes: vertices.buffer.lengthInBytes,
  );

  renderPass.bindVertexBuffer(vertexBufferView, vertices.length ~/ 3);
}

_setupRenderTarget() {
  final outputTexture = gpuContext.createTexture(StorageMode.hostVisible, 256, 256);

  return RenderTarget.singleColor(
    ColorAttachment(texture: outputTexture),
  );
}


const String _shaderBundlePath =
    'build/shaderbundles/demo_shaders.shaderbundle';

ShaderLibrary? _shaderLibrary;
ShaderLibrary get shaderLibrary {
  if (_shaderLibrary != null) {
    return _shaderLibrary!;
  }
  _shaderLibrary = ShaderLibrary.fromAsset(_shaderBundlePath);
  if (_shaderLibrary != null) {
    return _shaderLibrary!;
  }

  throw Exception("Failed to load shader bundle! ($_shaderBundlePath)");
}

line.vert:

in vec3 position;

void main() {
  gl_Position = vec4(position, 1.0);
}

line.frag:

uniform Paint {
  vec4 color;
}
paint;

out vec4 frag_color;

void main() {
  frag_color = paint.color;
}

demo_shaders.shaderbundle.json:

{
    "LineVertex": {
        "type": "vertex",
        "file": "shaders/line.vert"
    },
    "LineFragment": {
        "type": "fragment",
        "file": "shaders/line.frag"
    }
}

Screenshots or Video

Screenshots / Video demonstration

Screenshot from Metal Frame Capture, showing that the vertex format at runtime of the line.vert shader matches the internal impeller one: impeller line.vert

This was captured while debugging vector_tile_renderer, which defines a custom shader called line.vert: custom line.vert

Image

Logs

Console commands & Logs
flutter clean && flutter pub get && flutter run -d macos

Output:

Launching lib/main.dart on macOS in debug mode...
warning: Run script build phase 'Run Script' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'Flutter Assemble' from project 'Runner')
Building macOS application...                                           
✓ Built build/macos/Build/Products/Debug/flutter_gpu_learning.app
2025-09-16 16:39:24.629 flutter_gpu_learning[33085:7074540] Running with merged UI and platform thread. Experimental.
[IMPORTANT:flutter/shell/platform/embedder/embedder_surface_metal_impeller.mm(51)] Using the Impeller rendering backend (Metal).
[ERROR:flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm(158)] Break on 'ImpellerValidationBreak' to inspect point of failure: Could not create render pipeline for  :Vertex attribute e0(1) is missing from the vertex descriptor (thread: main)
Connecting to the VM Service is taking longer than expected...

Flutter Doctor output

Doctor output
[✓] Flutter (Channel main, 3.37.0-1.0.pre-137, on macOS 15.6.1 24G90 darwin-arm64, locale en-CA) [6.1s]
    • Flutter version 3.37.0-1.0.pre-137 on channel main at /Users/epicjames/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 5ecb23afdb (5 hours ago), 2025-09-16 09:49:11 -0700
    • Engine revision 5ecb23afdb
    • Dart version 3.10.0 (build 3.10.0-206.0.dev)
    • DevTools version 2.50.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets,
      omit-legacy-version-file, enable-lldb-debugging

[!] Android toolchain - develop for Android devices (Android SDK version 35.0.1) [865ms]
    • Android SDK at /Users/epicjames/Library/Android/sdk
    • Emulator version 35.2.10.0 (build_id 12414864) (CL:N/A)
    ✗ cmdline-tools component is missing.
      Try installing or updating Android Studio.
      Alternatively, download the tools from https://developer.android.com/studio#command-line-tools-only and make sure to set the ANDROID_HOME environment variable.
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/to/macos-android-setup for more details.

[!] Xcode - develop for iOS and macOS (Xcode 26.0) [1,770ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 17A324
    ! iOS 26.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 (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome) [7ms]
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Connected device (2 available) [6.2s]
    • James’s iPhone (wireless) (mobile) • [device id] • ios          • iOS 18.6.2 22G100
    • macOS (desktop)                    • macos                     • darwin-arm64 • macOS 15.6.1 24G90 darwin-arm64

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

! Doctor found issues in 3 categories.

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work liste: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.flutter-gpufound in release: 3.37Found to occur in 3.37has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

Type

No type
No fields configured for issues without a type.

Projects

Status
✅ Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions