From 83ccad723dadcda01e395cc01d278e9f6b1413bb Mon Sep 17 00:00:00 2001 From: Christopher Crawford Date: Fri, 5 Nov 2021 00:58:01 -0400 Subject: [PATCH] FragmentProgram constructed asynchronously (#29513) --- lib/ui/painting.dart | 14 ++++++------ lib/web_ui/lib/src/ui/painting.dart | 8 ++++--- testing/dart/fragment_shader_test.dart | 30 +++++++++++++++----------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 408390625a132..d03efd85b4cc9 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -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 compile({ + required ByteBuffer spirv, + bool debugPrint = false, + }) { + return Future(() => FragmentProgram._(spirv: spirv, debugPrint: debugPrint)); + } + @pragma('vm:entry-point') - FragmentProgram({ + FragmentProgram._({ required ByteBuffer spirv, bool debugPrint = false, }) { diff --git a/lib/web_ui/lib/src/ui/painting.dart b/lib/web_ui/lib/src/ui/painting.dart index 05b976614f9d9..8082670085a95 100644 --- a/lib/web_ui/lib/src/ui/painting.dart +++ b/lib/web_ui/lib/src/ui/painting.dart @@ -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 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.'); diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index 81d4bc3a9fc6e..502a033ac41fb 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -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([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( @@ -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( @@ -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([ @@ -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([1]); final Float32List zeroes = Float32List.fromList([0]); @@ -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(); @@ -122,8 +126,8 @@ void main() { // of the file name within the test case. void _expectShadersRenderGreen(Map 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(