Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

FragmentProgram constructed asynchronously #29513

Merged
merged 4 commits into from
Nov 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions lib/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3768,13 +3768,15 @@ class FragmentProgram extends NativeFieldWrapperClass1 {
///
/// [A current specification of valid SPIR-V is here.](https://github.com/flutter/engine/blob/master/lib/spirv/README.md)
/// SPIR-V not meeting this specification will throw an exception.
///
/// Performance of shader-compilation is platform dependent and is not
/// well-specified. Because of this, it is reccommended to construct
/// `FragmentProgram` asynchronously, outside of a widget's `build`
/// method; this will minimize the chance of UI jank.
static Future<FragmentProgram> compile({
required ByteBuffer spirv,
bool debugPrint = false,
}) {
return Future<FragmentProgram>(() => FragmentProgram._(spirv: spirv, debugPrint: debugPrint));
}

@pragma('vm:entry-point')
FragmentProgram({
FragmentProgram._({
required ByteBuffer spirv,
bool debugPrint = false,
}) {
Expand Down
8 changes: 5 additions & 3 deletions lib/web_ui/lib/src/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -790,13 +790,15 @@ class ImageDescriptor {
}

class FragmentProgram {
FragmentProgram({
required ByteBuffer spirv, // ignore: avoid_unused_constructor_parameters
bool debugPrint = false, // ignore: avoid_unused_constructor_parameters
static Future<FragmentProgram> compile({
required ByteBuffer spirv,
bool debugPrint = false,
}) {
throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.');
}

FragmentProgram._();

Shader shader({
required Float32List floatUniforms,
}) => throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.');
Expand Down
30 changes: 17 additions & 13 deletions testing/dart/fragment_shader_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@ import 'package:path/path.dart' as path;
import 'shader_test_file_utils.dart';

void main() {
test('throws exception for invalid shader', () {
test('throws exception for invalid shader', () async {
final ByteBuffer invalidBytes = Uint8List.fromList(<int>[1, 2, 3, 4, 5]).buffer;
expect(() => FragmentProgram(spirv: invalidBytes), throws);
try {
await FragmentProgram.compile(spirv: invalidBytes);
fail('expected compile to throw an exception');
} catch (_) {
}
});

test('simple shader renders correctly', () async {
final Uint8List shaderBytes = await spvFile('general_shaders', 'functions.spv').readAsBytes();
final FragmentProgram program = FragmentProgram(
final FragmentProgram program = await FragmentProgram.compile(
spirv: shaderBytes.buffer,
);
final Shader shader = program.shader(
Expand All @@ -30,9 +34,9 @@ void main() {
_expectShaderRendersGreen(shader);
});

test('shader with functions renders green', () {
test('shader with functions renders green', () async {
final ByteBuffer spirv = spvFile('general_shaders', 'functions.spv').readAsBytesSync().buffer;
final FragmentProgram program = FragmentProgram(
final FragmentProgram program = await FragmentProgram.compile(
spirv: spirv,
);
final Shader shader = program.shader(
Expand All @@ -43,7 +47,7 @@ void main() {

test('shader with uniforms renders correctly', () async {
final Uint8List shaderBytes = await spvFile('general_shaders', 'uniforms.spv').readAsBytes();
final FragmentProgram program = FragmentProgram(spirv: shaderBytes.buffer);
final FragmentProgram program = await FragmentProgram.compile(spirv: shaderBytes.buffer);

final Shader shader = program.shader(
floatUniforms: Float32List.fromList(<double>[
Expand Down Expand Up @@ -80,10 +84,10 @@ void main() {
_expectShadersRenderGreen(supportedOpShaders);
_expectShadersHaveOp(supportedOpShaders, false /* glsl ops */);

test('equality depends on floatUniforms', () {
test('equality depends on floatUniforms', () async {
final ByteBuffer spirv = spvFile('general_shaders', 'simple.spv')
.readAsBytesSync().buffer;
final FragmentProgram program = FragmentProgram(spirv: spirv);
final FragmentProgram program = await FragmentProgram.compile(spirv: spirv);
final Float32List ones = Float32List.fromList(<double>[1]);
final Float32List zeroes = Float32List.fromList(<double>[0]);

Expand All @@ -102,13 +106,13 @@ void main() {
}
});

test('equality depends on spirv', () {
test('equality depends on spirv', () async {
final ByteBuffer spirvA = spvFile('general_shaders', 'simple.spv')
.readAsBytesSync().buffer;
final ByteBuffer spirvB = spvFile('general_shaders', 'uniforms.spv')
.readAsBytesSync().buffer;
final FragmentProgram programA = FragmentProgram(spirv: spirvA);
final FragmentProgram programB = FragmentProgram(spirv: spirvB);
final FragmentProgram programA = await FragmentProgram.compile(spirv: spirvA);
final FragmentProgram programB = await FragmentProgram.compile(spirv: spirvB);
final a = programA.shader();
final b = programB.shader();

Expand All @@ -122,8 +126,8 @@ void main() {
// of the file name within the test case.
void _expectShadersRenderGreen(Map<String, ByteBuffer> shaders) {
for (final String key in shaders.keys) {
test('$key renders green', () {
final FragmentProgram program = FragmentProgram(
test('$key renders green', () async {
final FragmentProgram program = await FragmentProgram.compile(
spirv: shaders[key]!,
);
final Shader shader = program.shader(
Expand Down