From e001ec804bdaa7a068731f42c08380bf37c19a49 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 30 Apr 2024 13:27:00 -0700 Subject: [PATCH 1/5] [skwasm] Change default `FilterQuality` to `None` for image shaders. --- .../engine/skwasm/skwasm_impl/shaders.dart | 4 +- lib/web_ui/test/ui/image_golden_test.dart | 88 ++++++++++++++++--- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart index 36fd442bbb878..378bc72be1043 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart @@ -186,7 +186,7 @@ class SkwasmImageShader extends SkwasmNativeShader implements ui.ImageShader { image.handle, tmx.index, tmy.index, - (filterQuality ?? ui.FilterQuality.medium).index, + (filterQuality ?? ui.FilterQuality.none).index, localMatrix, )); }); @@ -195,7 +195,7 @@ class SkwasmImageShader extends SkwasmNativeShader implements ui.ImageShader { image.handle, tmx.index, tmy.index, - (filterQuality ?? ui.FilterQuality.medium).index, + (filterQuality ?? ui.FilterQuality.none).index, nullptr, )); } diff --git a/lib/web_ui/test/ui/image_golden_test.dart b/lib/web_ui/test/ui/image_golden_test.dart index 9adad98c66ffd..cf259e8114621 100644 --- a/lib/web_ui/test/ui/image_golden_test.dart +++ b/lib/web_ui/test/ui/image_golden_test.dart @@ -11,6 +11,7 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import 'package:ui/src/engine/canvaskit/canvaskit_api.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; @@ -164,22 +165,35 @@ Future testMain() async { }); test('image_shader_cubic_rotated', () async { - final ui.Image image = await imageGenerator(); - - final Float64List matrix = Matrix4.rotationZ(pi / 6).toFloat64(); - final ui.ImageShader shader = ui.ImageShader( - image, - ui.TileMode.repeated, - ui.TileMode.repeated, - matrix, - filterQuality: ui.FilterQuality.high, - ); final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder, drawRegion); - canvas.drawOval( - const ui.Rect.fromLTRB(0, 50, 300, 250), - ui.Paint()..shader = shader - ); + final Float64List matrix = Matrix4.rotationZ(pi / 6).toFloat64(); + Future drawOvalWithShader(ui.Rect rect, ui.FilterQuality quality) async { + final ui.Image image = await imageGenerator(); + final ui.ImageShader shader = ui.ImageShader( + image, + ui.TileMode.repeated, + ui.TileMode.repeated, + matrix, + filterQuality: quality, + ); + canvas.drawOval( + rect, + ui.Paint()..shader = shader + ); + } + + // Draw image shader with all four qualities. + await drawOvalWithShader(const ui.Rect.fromLTRB(0, 0, 150, 100), ui.FilterQuality.none); + await drawOvalWithShader(const ui.Rect.fromLTRB(150, 0, 300, 100), ui.FilterQuality.low); + + // Note that for images that skia handles lazily (ones created via + // `createImageFromImageBitmap` or `instantiateImageCodecFromUrl`) + // there is a skia bug that this just renders a black oval instead of + // actually texturing it with the image. + // See https://g-issues.skia.org/issues/338095525 + await drawOvalWithShader(const ui.Rect.fromLTRB(0, 100, 150, 200), ui.FilterQuality.medium); + await drawOvalWithShader(const ui.Rect.fromLTRB(150, 100, 300, 200), ui.FilterQuality.high); await drawPictureUsingCurrentRenderer(recorder.endRecording()); await matchGoldenFile('${name}_image_shader_cubic_rotated.png', region: drawRegion); @@ -210,6 +224,52 @@ Future testMain() async { await matchGoldenFile('${name}_fragment_shader_sampler.png', region: drawRegion); }, skip: isHtml); // HTML doesn't support fragment shaders + test('drawVertices with image shader', () async { + final ui.Image image = await imageGenerator(); + + final Float64List matrix = Matrix4.rotationZ(pi / 6).toFloat64(); + final ui.ImageShader shader = ui.ImageShader( + image, + ui.TileMode.decal, + ui.TileMode.decal, + matrix, + filterQuality: ui.FilterQuality.medium, + ); + + // Draw an octagon + const List vertexValues = [ + ui.Offset(50, 0), + ui.Offset(100, 0), + ui.Offset(150, 50), + ui.Offset(150, 100), + ui.Offset(100, 150), + ui.Offset(50, 150), + ui.Offset(0, 100), + ui.Offset(0, 50), + ]; + final ui.Vertices vertices = ui.Vertices( + ui.VertexMode.triangles, + vertexValues, + textureCoordinates: vertexValues, + indices: [ + 0, 1, 2, // + 0, 2, 3, // + 0, 3, 4, // + 0, 4, 5, // + 0, 5, 6, // + 0, 6, 7, // + ], + ); + + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder, drawRegion); + canvas.drawVertices(vertices, ui.BlendMode.srcOver, ui.Paint()..shader = shader); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + + await matchGoldenFile('${name}_drawVertices_imageShader.png', region: drawRegion); + }); + test('toByteData_rgba', () async { final ui.Image image = await imageGenerator(); From 1da9028c9b61daccc1f7dddaeda2e2f83096446f Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 30 Apr 2024 13:48:48 -0700 Subject: [PATCH 2/5] Remove unused import. --- lib/web_ui/test/ui/image_golden_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/web_ui/test/ui/image_golden_test.dart b/lib/web_ui/test/ui/image_golden_test.dart index cf259e8114621..3e989e715f84d 100644 --- a/lib/web_ui/test/ui/image_golden_test.dart +++ b/lib/web_ui/test/ui/image_golden_test.dart @@ -11,7 +11,6 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; -import 'package:ui/src/engine/canvaskit/canvaskit_api.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; From 201b80025bb51c6823c2764942e4b56a94cd4aad Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 30 Apr 2024 14:57:19 -0700 Subject: [PATCH 3/5] Clean up images properly. --- lib/web_ui/test/ui/image_golden_test.dart | 32 ++++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/web_ui/test/ui/image_golden_test.dart b/lib/web_ui/test/ui/image_golden_test.dart index 3e989e715f84d..87ecc3805ed3e 100644 --- a/lib/web_ui/test/ui/image_golden_test.dart +++ b/lib/web_ui/test/ui/image_golden_test.dart @@ -86,17 +86,23 @@ Future testMain() async { // `imageGenerator` should produce an image that is 150x150 pixels. void emitImageTests(String name, Future Function() imageGenerator) { group(name, () { - late ui.Image image; - setUp(() async { - image = await imageGenerator(); - }); + final List images = []; + + Future generateImage() async { + final ui.Image image = await imageGenerator(); + images.add(image); + return image; + } tearDown(() { - image.dispose(); + for (final ui.Image image in images) { + image.dispose(); + } + images.clear(); }); test('drawImage', () async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder, drawRegion); @@ -111,7 +117,7 @@ Future testMain() async { }); test('drawImageRect', () async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder, drawRegion); @@ -147,7 +153,7 @@ Future testMain() async { }); test('drawImageNine', () async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder, drawRegion); @@ -168,7 +174,7 @@ Future testMain() async { final ui.Canvas canvas = ui.Canvas(recorder, drawRegion); final Float64List matrix = Matrix4.rotationZ(pi / 6).toFloat64(); Future drawOvalWithShader(ui.Rect rect, ui.FilterQuality quality) async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final ui.ImageShader shader = ui.ImageShader( image, ui.TileMode.repeated, @@ -199,7 +205,7 @@ Future testMain() async { }); test('fragment_shader_sampler', () async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final ui.FragmentProgram program = await renderer.createFragmentProgram('glitch_shader'); final ui.FragmentShader shader = program.fragmentShader(); @@ -224,7 +230,7 @@ Future testMain() async { }, skip: isHtml); // HTML doesn't support fragment shaders test('drawVertices with image shader', () async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final Float64List matrix = Matrix4.rotationZ(pi / 6).toFloat64(); final ui.ImageShader shader = ui.ImageShader( @@ -270,7 +276,7 @@ Future testMain() async { }); test('toByteData_rgba', () async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final ByteData? rgbaData = await image.toByteData(); expect(rgbaData, isNotNull); @@ -278,7 +284,7 @@ Future testMain() async { }); test('toByteData_png', () async { - final ui.Image image = await imageGenerator(); + final ui.Image image = await generateImage(); final ByteData? pngData = await image.toByteData(format: ui.ImageByteFormat.png); expect(pngData, isNotNull); From f40766a05bd9e07b8b99174cb854f62618bd2c41 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 30 Apr 2024 15:28:32 -0700 Subject: [PATCH 4/5] Disable vertices test on html renderer due to bug. --- lib/web_ui/test/ui/image_golden_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/test/ui/image_golden_test.dart b/lib/web_ui/test/ui/image_golden_test.dart index 87ecc3805ed3e..46f5391d38e25 100644 --- a/lib/web_ui/test/ui/image_golden_test.dart +++ b/lib/web_ui/test/ui/image_golden_test.dart @@ -273,7 +273,7 @@ Future testMain() async { await drawPictureUsingCurrentRenderer(recorder.endRecording()); await matchGoldenFile('${name}_drawVertices_imageShader.png', region: drawRegion); - }); + }, skip: isHtml); // https://github.com/flutter/flutter/issues/127454; test('toByteData_rgba', () async { final ui.Image image = await generateImage(); From 22c2eec12e92d7312ec6d114381efca549d2a50d Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 30 Apr 2024 16:31:04 -0700 Subject: [PATCH 5/5] Use default quality in drawVertices test for better coverage. --- lib/web_ui/test/ui/image_golden_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/web_ui/test/ui/image_golden_test.dart b/lib/web_ui/test/ui/image_golden_test.dart index 46f5391d38e25..504aa6eec1f1e 100644 --- a/lib/web_ui/test/ui/image_golden_test.dart +++ b/lib/web_ui/test/ui/image_golden_test.dart @@ -238,7 +238,6 @@ Future testMain() async { ui.TileMode.decal, ui.TileMode.decal, matrix, - filterQuality: ui.FilterQuality.medium, ); // Draw an octagon