Skip to content

[Flutter GPU] Add automation to make importing Flutter GPU shaders easy. #144259

Closed
@bdero

Description

@bdero

Part of #130921

Option 1: Offer a library for making native_asset build hooks easy.

Proof of concept build hook lib: https://github.com/bdero/test_native_assets/blob/master/hook/build.dart#L9-L138

To set up automated shaderbundle compilation, the user would:

  1. Define special json or yaml files in their project.
  2. Add a hook/build.dart file that invokes an imported function from the flutter_gpu package:
void main(List<String> args) async {
  await build(args, (config, output) async {
    await buildShaderBundle(
        buildConfig: config,
        buildOutput: output,
        manifestFileName: 'mybundle.shaderbundle.json');
  });
}
  1. Add watch rules for assets in the project's build directory.

Option 2: Use an Asset Transformer.

Make a simple transformer package that just ingests a manifest text file and finds/invokes impellerc, replacing this temp solution.

A few thoughts:

  • I'm not sure what the current status is for hot reloading in asset transformers, but we'll eventually want to support hot reloading shader bundles (which would require somehow instructing the tool to watch a list of dependent files for changes), but I don't see that as a super high priority right now.
  • Same goes for model imports in Flutter Scene, which is usually a simpler 1-1 model import situation, but will sometimes require watching multiple files similar to the shader bundle case (for example, glTFs with separated image files, or OBJs with separated MTLs).
  • The importer is locked to a specific version of ImpellerC. Rather than publish it on pub.dev, we should ship it as an SDK package under the packages directory in the flutter/flutter repo with an integration test ensuring that it doesn't break against the version of impellerc shipping in the engine artifacts.
  • Not a huge deal, but it would be nice if we could implicitly activate this particular transformer for all projects when they depend on the flutter_gpu SDK package automatically. Without this, I believe users of Flutter GPU will need to both depend on and activate the asset transformer by adding configuration similar to the following in pubspec.yaml:
dependencies:
  flutter_gpu:
    sdk: flutter
dev_dependencies:
  flutter_gpu_shaders:
    sdk: flutter
flutter:
  assets:
    - path: *.shaderbundle.yaml
      transformers:
        - package: flutter_gpu_shaders

Option 3: Add support directly to the Flutter tool.

Flutter GPU shaders are stored in libraries, and these libraries can be deserialized from "shader bundle" files.
For this task, add support to the Flutter tool for importing a collection of shader files as a shader bundle.

Here's an example of a shader bundle defined in a package pubspec.yaml file:

### pubspec.yaml ###
  - shader_bundle:
    - CoolShaderBundle:
      - FlatShadeVertex:
          type: vertex
          file: assets/shaders/flatshade.vert
      - FlatShadeFragment:
          type: fragment
          file: assets/shaders/flatshade.frag

This creates one shader bundle called "CoolShaderBundle" with two shader inputs: "FlatShadeVertex" and "FlatShadeFragment".

To produce this shader bundle asset, the flutter tool should run impellerc with the --shader_bundle parameter. Taking the example above, the call should look like this:

impellerc --sl="CoolShaderBundle.shaderbundle" \
  --shader_bundle="{\
    \"FlatShadeVertex\": { \
        \"type\": \"vertex\", \
        \"file\": \"assets/shaders/flatshade.vert\" \
      }, \
    \"FlatShadeVertex\": { \
        \"type\": \"vertex\", \
        \"file\": \"assets/shaders/flatshade.vert\" \
      } \
    } \
  }";

If any of the input source shader files have change, then the output shader bundle file (CoolShaderBundle.shaderbundle) needs to be rebuilt.

See also the Flutter GPU doc.

The shader bundle spec

For Flutter GPU's MVP, ImpellerC's --shader_bundle accepts a JSON string in the following form:

{
  "$shader_name" {
    "type": "[vertex|fragment]",
    "file": "$file_name"
  }
}

Later on, other per-shader parameters can be supported, such as ("language" and "entry_point").

Building shader bundles manually

Up until now, I've been building shader bundles manually in order to bootstrap some renderer projects. These bundles are produced using the impellerc executable shipped in the engine artifacts.

Here's an example of a valid invocation of ImpellerC, which builds a shader bundle asset named "assets/base.shaderbundle" with 5 builtin shaders:

BUNDLE_OUTPUT_FILENAME="assets/base.shaderbundle"
BASE_BUNDLE_JSON='
{
    "SimpleVertex": {
        "type": "vertex",
        "file": "shaders/flutter_scene_simple.vert"
    },
    "SimpleFragment": {
        "type": "fragment",
        "file": "shaders/flutter_scene_simple.frag"
    },
    "UnskinnedVertex": {
        "type": "vertex",
        "file": "shaders/flutter_scene_unskinned.vert"
    },
    "SkinnedVertex": {
        "type": "vertex",
        "file": "shaders/flutter_scene_skinned.vert"
    },
    "UnlitFragment": {
        "type": "fragment",
        "file": "shaders/flutter_scene_unlit.frag"
    }
}'
SHADER_BUNDLE_JSON=$(echo $2 | tr -d '\n')
impellerc --sl="$BUNDLE_OUTPUT_FILENAME" --shader-bundle="$BASE_BUNDLE_JSON"

Note that the actual names of the shaders in the bundle (SimpleVertex, SimpleFragment, etc) are entirely the user's choice.

How manually built shader bundles are imported.

Here's a simplified example of a Flutter GPU ShaderLibrary being deserialized from a shader bundle (as seen in the flutter_scene package):

import 'package:flutter_gpu/gpu.dart' as gpu;

final String _kBaseShaderBundlePath =
    'packages/flutter_scene/assets/base.shaderbundle';
gpu.ShaderLibrary get baseShaderLibrary {
  gpu.ShaderLibrary? result = gpu.ShaderLibrary.fromAsset(_kBaseShaderBundlePath);
  if (result != null) {
    return result!;
  }
  throw Exception(
      "Failed to load base shader bundle! ($_kBaseShaderBundlePath)");
}

From here, a ShaderBundle can be used by looking up shader names

gpu.Shader? myVertexShader = baseShaderLibrary["UnlitVertex"];

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listc: proposalA detailed proposal for a change to Flutterflutter-gpur: fixedIssue is closed as already fixed in a newer versionteam-engineOwned by Engine teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-engineTriaged by Engine team

Type

No type

Projects

Status

✅ Done

Relationships

None yet

Development

No branches or pull requests

Issue actions