Skip to content

Commit

Permalink
FragmentProgram constructed asynchronously (#29513)
Browse files Browse the repository at this point in the history
  • Loading branch information
chriscraws committed Nov 5, 2021
1 parent 47dab8a commit 83ccad7
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 22 deletions.
14 changes: 8 additions & 6 deletions lib/ui/painting.dart
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
Expand Up @@ -802,13 +802,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
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

0 comments on commit 83ccad7

Please sign in to comment.