Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[skwasm] Change default FilterQuality to None for image shaders. #52468

Merged
merged 5 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
));
});
Expand All @@ -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,
));
}
Expand Down
114 changes: 89 additions & 25 deletions lib/web_ui/test/ui/image_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,23 @@ Future<void> testMain() async {
// `imageGenerator` should produce an image that is 150x150 pixels.
void emitImageTests(String name, Future<ui.Image> Function() imageGenerator) {
group(name, () {
late ui.Image image;
setUp(() async {
image = await imageGenerator();
});
final List<ui.Image> images = <ui.Image>[];

Future<ui.Image> 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);
Expand All @@ -111,7 +117,7 @@ Future<void> 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);
Expand Down Expand Up @@ -147,7 +153,7 @@ Future<void> 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);
Expand All @@ -164,29 +170,42 @@ Future<void> 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<void> 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();
Expand All @@ -210,16 +229,61 @@ Future<void> 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<ui.Offset> vertexValues = <ui.Offset>[
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: <int>[
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);
expect(rgbaData!.lengthInBytes, isNonZero);
});

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);
Expand Down