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..504aa6eec1f1e 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); @@ -164,29 +170,42 @@ 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 generateImage(); + 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); }); 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(); @@ -210,8 +229,53 @@ 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 generateImage(); + + final Float64List matrix = Matrix4.rotationZ(pi / 6).toFloat64(); + final ui.ImageShader shader = ui.ImageShader( + image, + ui.TileMode.decal, + ui.TileMode.decal, + matrix, + ); + + // 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); + }, skip: isHtml); // https://github.com/flutter/flutter/issues/127454; + 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); @@ -219,7 +283,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);