Skip to content

[impeller]: runtime effect has no vertex shader when name overlaps builtin shader #178766

@gaaclarke

Description

@gaaclarke

description

The following code crashes with the error:

validateWithDevice, line 4704: error 'Render Pipeline Descriptor Validation
vertexFunction must not be nil.

If you step through with the debugger the runtime_effect_vertex_main doesn't exist in the shader libraries for some reason.

reproduction

Details
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SDF Demo',
      theme: ThemeData.dark(),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    Widget child = const PictureCanvas(key: Key('picture_canvas'));
    return Scaffold(
      body: Center(child: SizedBox(height: 512, width: 512, child: child)),
    );
  }
}

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

  @override
  State<PictureCanvas> createState() => _PictureCanvasState();
}

class _PictureCanvasState extends State<PictureCanvas> {
  ui.Image? _image;
  ui.FragmentShader? _circle;

  @override
  void initState() {
    super.initState();
    _loadShader().then((ui.FragmentShader shader) {
      setState(() {
        _circle = shader;
      });
    });
  }

  Future<ui.FragmentShader> _loadShader() async {
    // TODO(): There is a bug where if this isn't loaded the vertex shader fails
    // to load.
    await ui.FragmentProgram.fromAsset('shaders/sdf.frag');
    final program = await ui.FragmentProgram.fromAsset('shaders/circle.frag');
    return program.fragmentShader();
  }

  ui.Image _loadImage(ui.FragmentShader shader) {
    const Size size = Size(512, 512);
    final ui.PictureRecorder recorder = ui.PictureRecorder();
    final Canvas canvas = Canvas(recorder);
    shader.setFloat(0, size.width);
    shader.setFloat(1, size.height);
    final Paint paint = Paint()..shader = _circle;
    canvas.drawRect(Offset.zero & size, paint);
    final ui.Picture picture = recorder.endRecording();
    return picture.toImageSync(
      size.width.toInt(),
      size.height.toInt(),
    );
  }

  @override
  Widget build(BuildContext context) {
    if (_circle == null) {
      return const Center(child: CircularProgressIndicator());
    }
    _image ??= _loadImage(_circle!);
    return SizedBox(
      width: 512,
      height: 512,
      child: CustomPaint(painter: CirclePainter(_image!)),
    );
  }
}

class CirclePainter extends CustomPainter {
  CirclePainter(this.image);

  final ui.Image image;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawImage(image, Offset.zero, Paint());
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}
name: high_bitrate_images
description: "A new Flutter project."
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: ^3.11.0-88.0.dev

resolution: workspace

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test:
    sdk: flutter

flutter:
  uses-material-design: true
  shaders:
    - shaders/circle.frag
    - shaders/sdf.frag

# PUBSPEC CHECKSUM: vrimb3
#version 320 es

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <flutter/runtime_effect.glsl>

out vec4 fragColor;

uniform vec2 uSize;
uniform sampler2D uTex;

void main() {
    vec2 p = FlutterFragCoord().xy / uSize;
    float d = texture(uTex, p).r;
    vec3 col = d > 0.0 ? vec3(0.0) : vec3(1.0);
    fragColor = vec4(col, 1.0);
}
#version 320 es

#include <flutter/runtime_effect.glsl>

out vec4 fragColor;
uniform vec2 uSize;

void main() {
    vec2 p = FlutterFragCoord().xy / uSize;
    vec2 center = vec2(0.5, 0.5);
    float radius = 0.25;
    float d = length(p - center) - radius;
    fragColor = vec4(d, 0.0, 0.0, 1.0);
}

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work liste: impellerImpeller rendering backend issues and features requeststeam-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