From 6e85c387940ec65182ff5aec0e420753f88c96d4 Mon Sep 17 00:00:00 2001 From: Christopher Crawford Date: Wed, 3 Nov 2021 17:30:38 -0400 Subject: [PATCH 1/4] FragmentProgram constructed asynchronously --- lib/ui/painting.dart | 9 +++++++- lib/web_ui/lib/src/ui/painting.dart | 9 +++++++- testing/dart/fragment_shader_test.dart | 30 +++++++++++++++----------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 408390625a132..d7f6e4ada7655 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3773,8 +3773,15 @@ class FragmentProgram extends NativeFieldWrapperClass1 { /// 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, + }) async { + return 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 ccd4cc55903f0..d52f1fe8b12bf 100644 --- a/lib/web_ui/lib/src/ui/painting.dart +++ b/lib/web_ui/lib/src/ui/painting.dart @@ -790,7 +790,14 @@ class ImageDescriptor { } class FragmentProgram { - FragmentProgram({ + static Future compile({ + required ByteBuffer spirv, + bool debugPrint = false, + }) async { + throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); + } + + FragmentProgram._({ required ByteBuffer spirv, // ignore: avoid_unused_constructor_parameters bool debugPrint = false, // ignore: avoid_unused_constructor_parameters }) { 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( From 7019ee51a03b4f2b30117167cd5c8b3c50a71d8c Mon Sep 17 00:00:00 2001 From: Christopher Crawford Date: Wed, 3 Nov 2021 19:04:46 -0400 Subject: [PATCH 2/4] remove constructor args for web api --- lib/web_ui/lib/src/ui/painting.dart | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/web_ui/lib/src/ui/painting.dart b/lib/web_ui/lib/src/ui/painting.dart index d52f1fe8b12bf..4bcb46c750377 100644 --- a/lib/web_ui/lib/src/ui/painting.dart +++ b/lib/web_ui/lib/src/ui/painting.dart @@ -797,12 +797,7 @@ class FragmentProgram { throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); } - FragmentProgram._({ - required ByteBuffer spirv, // ignore: avoid_unused_constructor_parameters - bool debugPrint = false, // ignore: avoid_unused_constructor_parameters - }) { - throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); - } + FragmentProgram._(); Shader shader({ required Float32List floatUniforms, From 318777177218001d0afa177779f6cb8020be3228 Mon Sep 17 00:00:00 2001 From: Christopher Crawford Date: Wed, 3 Nov 2021 21:15:58 -0400 Subject: [PATCH 3/4] remove note about asynchronous usage, since that's default now --- lib/ui/painting.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index d7f6e4ada7655..a085d9b7f4796 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3768,11 +3768,6 @@ 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, From 06c0105ed135f9183d15ae28c434d66c4b3136be Mon Sep 17 00:00:00 2001 From: Christopher Crawford Date: Thu, 4 Nov 2021 17:56:08 -0400 Subject: [PATCH 4/4] stop using async and return a constructed Future --- lib/ui/painting.dart | 4 ++-- lib/web_ui/lib/src/ui/painting.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index a085d9b7f4796..d03efd85b4cc9 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3771,8 +3771,8 @@ class FragmentProgram extends NativeFieldWrapperClass1 { static Future compile({ required ByteBuffer spirv, bool debugPrint = false, - }) async { - return FragmentProgram._(spirv: spirv, debugPrint: debugPrint); + }) { + return Future(() => FragmentProgram._(spirv: spirv, debugPrint: debugPrint)); } @pragma('vm:entry-point') diff --git a/lib/web_ui/lib/src/ui/painting.dart b/lib/web_ui/lib/src/ui/painting.dart index 4bcb46c750377..910f092a2b50b 100644 --- a/lib/web_ui/lib/src/ui/painting.dart +++ b/lib/web_ui/lib/src/ui/painting.dart @@ -793,7 +793,7 @@ class FragmentProgram { static Future compile({ required ByteBuffer spirv, bool debugPrint = false, - }) async { + }) { throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); }