From 1114e625cddd70dd9a5a606110ca95f912f1a974 Mon Sep 17 00:00:00 2001 From: xuty Date: Thu, 24 Nov 2022 14:47:49 +0800 Subject: [PATCH 01/12] Implement addTexture --- lib/web_ui/lib/initialization.dart | 29 ++++++ lib/web_ui/lib/src/engine.dart | 2 + .../src/engine/canvaskit/canvaskit_api.dart | 2 +- .../lib/src/engine/canvaskit/layer.dart | 30 ++++++ .../engine/canvaskit/layer_scene_builder.dart | 4 +- .../lib/src/engine/canvaskit/layer_tree.dart | 23 ++++- .../lib/src/engine/canvaskit/rasterizer.dart | 8 +- .../lib/src/engine/canvaskit/renderer.dart | 4 + .../lib/src/engine/canvaskit/texture.dart | 92 +++++++++++++++++++ lib/web_ui/lib/src/engine/html/renderer.dart | 3 + lib/web_ui/lib/src/engine/renderer.dart | 3 + .../engine/skwasm/skwasm_impl/renderer.dart | 4 + .../engine/skwasm/skwasm_stub/renderer.dart | 4 + lib/web_ui/lib/src/engine/texture.dart | 11 +++ lib/web_ui/test/canvaskit/texture_test.dart | 36 ++++++++ 15 files changed, 246 insertions(+), 9 deletions(-) create mode 100644 lib/web_ui/lib/src/engine/canvaskit/texture.dart create mode 100644 lib/web_ui/lib/src/engine/texture.dart create mode 100644 lib/web_ui/test/canvaskit/texture_test.dart diff --git a/lib/web_ui/lib/initialization.dart b/lib/web_ui/lib/initialization.dart index 3cb2a8835242a..5ed9875535715 100644 --- a/lib/web_ui/lib/initialization.dart +++ b/lib/web_ui/lib/initialization.dart @@ -141,3 +141,32 @@ class PlatformViewRegistry { /// The platform view registry for this app. final PlatformViewRegistry platformViewRegistry = PlatformViewRegistry(); + +/// A registry for textures. +class TextureRegistry { + /// Registers a texture. + /// + /// Valid [texture] can be any object that that webGL's texImage2D supports. + /// For example, HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, + /// ImageData, ImageBitmap and VideoFrame. + /// + /// The returned id can be used to refer to the texture in Texture widgets. + int registerTexture(Object texture) { + return engine.renderer.textureRegistry?.registerTexture(texture) ?? -1; + } + + /// Unregisters the texture with the given id. + void unregisterTexture(int id) { + engine.renderer.textureRegistry?.unregisterTexture(id); + } + + /// Notifies Flutter that the content of the previously registered texture + /// has been updated. + void textureFrameAvailable(int id) { + engine.renderer.textureRegistry?.textureFrameAvailable(id); + engine.EnginePlatformDispatcher.instance.scheduleFrame(); + } +} + +/// The texture registry for this app. +final TextureRegistry textureRegistry = TextureRegistry(); diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index e86ffb97942ff..d32c826c63c70 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -53,6 +53,7 @@ export 'engine/canvaskit/skia_object_cache.dart'; export 'engine/canvaskit/surface.dart'; export 'engine/canvaskit/surface_factory.dart'; export 'engine/canvaskit/text.dart'; +export 'engine/canvaskit/texture.dart'; export 'engine/canvaskit/util.dart'; export 'engine/canvaskit/vertices.dart'; export 'engine/clipboard.dart'; @@ -168,6 +169,7 @@ export 'engine/text_editing/input_action.dart'; export 'engine/text_editing/input_type.dart'; export 'engine/text_editing/text_capitalization.dart'; export 'engine/text_editing/text_editing.dart'; +export 'engine/texture.dart'; export 'engine/util.dart'; export 'engine/validators.dart'; export 'engine/vector_math.dart'; diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index fc226bfa7632f..05509aad42313 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -134,7 +134,7 @@ extension CanvasKitExtension on CanvasKit { ); external SkImage? MakeLazyImageFromTextureSource( Object src, - SkPartialImageInfo info, + SkPartialImageInfo? info, ); /// Retrieve the RuntimeEffect namespace for null checking. diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer.dart b/lib/web_ui/lib/src/engine/canvaskit/layer.dart index 3f09e27e0bff8..005332736e077 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer.dart @@ -13,6 +13,7 @@ import 'painting.dart'; import 'path.dart'; import 'picture.dart'; import 'raster_cache.dart'; +import 'texture.dart'; import 'util.dart'; /// A layer to be composed into a scene. @@ -87,6 +88,7 @@ class PaintContext { this.leafNodesCanvas, this.rasterCache, this.viewEmbedder, + this.textureRegistry, ); /// A multi-canvas that applies clips, transforms, and opacity @@ -102,6 +104,8 @@ class PaintContext { /// A compositor for embedded HTML views. final HtmlViewEmbedder? viewEmbedder; + + final CkTextureRegistry? textureRegistry; } /// A layer that contains child layers. @@ -617,3 +621,29 @@ class PlatformViewLayer extends Layer { } } } + +/// A layer which renders a texture backed by [textureId]. +class TextureLayer extends Layer { + TextureLayer(this.textureId, this.offset, this.width, this.height, + this.freeze, this.filterQuality); + + final int textureId; + final ui.Offset offset; + final double width; + final double height; + final bool freeze; + final ui.FilterQuality filterQuality; + + @override + void preroll(PrerollContext prerollContext, Matrix4 matrix) { + paintBounds = ui.Rect.fromLTWH(offset.dx, offset.dy, width, height); + } + + @override + void paint(PaintContext paintContext) { + final CkTexture? texture = + paintContext.textureRegistry?.getTexture(textureId); + + texture?.paint(paintContext, offset, width, height, freeze, filterQuality); + } +} diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart index addd3aa5b992b..ecfe290ec7e05 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart @@ -72,7 +72,9 @@ class LayerSceneBuilder implements ui.SceneBuilder { bool freeze = false, ui.FilterQuality filterQuality = ui.FilterQuality.low, }) { - // TODO(hterkelsen): implement addTexture, b/128315641 + currentLayer.add( + TextureLayer(textureId, offset, width, height, freeze, filterQuality), + ); } @override diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart index 576e1b2533221..f22e673c302f0 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart @@ -13,6 +13,7 @@ import 'layer.dart'; import 'n_way_canvas.dart'; import 'picture_recorder.dart'; import 'raster_cache.dart'; +import 'texture.dart'; /// A tree of [Layer]s that, together with a [Size] compose a frame. class LayerTree { @@ -58,6 +59,7 @@ class LayerTree { frame.canvas, ignoreRasterCache ? null : frame.rasterCache, frame.viewEmbedder, + frame.textureRegistry, ); if (rootLayer.needsPainting) { rootLayer.paint(context); @@ -75,8 +77,13 @@ class LayerTree { final CkNWayCanvas internalNodesCanvas = CkNWayCanvas(); internalNodesCanvas.addCanvas(canvas); - final PaintContext paintContext = - PaintContext(internalNodesCanvas, canvas, null, null); + final PaintContext paintContext = PaintContext( + internalNodesCanvas, + canvas, + null, + null, + CkTextureRegistry.instance, + ); if (rootLayer.needsPainting) { rootLayer.paint(paintContext); } @@ -86,7 +93,7 @@ class LayerTree { /// A single frame to be rendered. class Frame { - Frame(this.canvas, this.rasterCache, this.viewEmbedder); + Frame(this.canvas, this.rasterCache, this.viewEmbedder, this.textureRegistry); /// The canvas to render this frame to. final CkCanvas canvas; @@ -97,6 +104,8 @@ class Frame { /// The platform view embedder. final HtmlViewEmbedder? viewEmbedder; + final CkTextureRegistry? textureRegistry; + /// Rasterize the given layer tree into this frame. bool raster(LayerTree layerTree, {bool ignoreRasterCache = false}) { timeAction(kProfilePrerollFrame, () { @@ -115,7 +124,11 @@ class CompositorContext { RasterCache? rasterCache; /// Acquire a frame using this compositor's settings. - Frame acquireFrame(CkCanvas canvas, HtmlViewEmbedder? viewEmbedder) { - return Frame(canvas, rasterCache, viewEmbedder); + Frame acquireFrame( + CkCanvas canvas, + HtmlViewEmbedder? viewEmbedder, + CkTextureRegistry? textureRegistry, + ) { + return Frame(canvas, rasterCache, viewEmbedder, textureRegistry); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart index b8b420bb829a6..c728b7819c3ec 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart @@ -11,6 +11,7 @@ import 'embedded_views.dart'; import 'layer_tree.dart'; import 'surface.dart'; import 'surface_factory.dart'; +import 'texture.dart'; /// A class that can rasterize [LayerTree]s into a given [Surface]. class Rasterizer { @@ -33,8 +34,11 @@ class Rasterizer { SurfaceFactory.instance.baseSurface.acquireFrame(layerTree.frameSize); HtmlViewEmbedder.instance.frameSize = layerTree.frameSize; final CkCanvas canvas = frame.skiaCanvas; - final Frame compositorFrame = - context.acquireFrame(canvas, HtmlViewEmbedder.instance); + final Frame compositorFrame = context.acquireFrame( + canvas, + HtmlViewEmbedder.instance, + CkTextureRegistry.instance, + ); compositorFrame.raster(layerTree, ignoreRasterCache: true); SurfaceFactory.instance.baseSurface.addToScene(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index 0dba09e70e588..573b23b2354c3 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -26,6 +26,7 @@ import 'picture_recorder.dart'; import 'rasterizer.dart'; import 'shader.dart'; import 'text.dart'; +import 'texture.dart'; import 'vertices.dart'; class CanvasKitRenderer implements Renderer { @@ -40,6 +41,9 @@ class CanvasKitRenderer implements Renderer { @override SkiaFontCollection get fontCollection => _fontCollection; + @override + final CkTextureRegistry textureRegistry = CkTextureRegistry.instance; + /// The scene host, where the root canvas and overlay canvases are added to. DomElement? _sceneHost; DomElement? get sceneHost => _sceneHost; diff --git a/lib/web_ui/lib/src/engine/canvaskit/texture.dart b/lib/web_ui/lib/src/engine/canvaskit/texture.dart new file mode 100644 index 0000000000000..33143963c0f1a --- /dev/null +++ b/lib/web_ui/lib/src/engine/canvaskit/texture.dart @@ -0,0 +1,92 @@ +import 'package:ui/ui.dart' as ui; + +// import '../platform_dispatcher.dart'; +import '../texture.dart'; +import 'canvaskit_api.dart'; +import 'image.dart'; +import 'layer.dart'; +import 'painting.dart'; + +class CkTexture { + CkTexture(this.source); + + final Object source; + + CkImage? _ckImage; + + bool _newFrameReady = false; + + void markNewFrameAvailable() { + _newFrameReady = true; + } + + void paint( + PaintContext context, + ui.Offset offset, + double width, + double height, + bool freeze, + ui.FilterQuality filterQuality, + ) { + if (_ckImage == null || _newFrameReady && !freeze) { + final SkImage? skImage = + canvasKit.MakeLazyImageFromTextureSource(source, null); + + if (skImage == null) { + return; + } + + _ckImage?.dispose(); + _ckImage = CkImage(skImage); + } + + context.leafNodesCanvas?.drawImageRect( + _ckImage!.clone(), + ui.Rect.fromLTWH( + 0, + 0, + _ckImage!.width.toDouble(), + _ckImage!.height.toDouble(), + ), + ui.Rect.fromLTWH(offset.dx, offset.dy, width, height), + CkPaint()..filterQuality = filterQuality, + ); + } + + void dispose() { + _ckImage?.dispose(); + } +} + +class CkTextureRegistry implements TextureRegistry { + CkTextureRegistry._(); + + static final CkTextureRegistry instance = CkTextureRegistry._(); + + final Map _textures = {}; + + @override + int registerTexture(Object source) { + final int id = _textures.length; + _textures[id] = CkTexture(source); + return id; + } + + @override + void unregisterTexture(int id) { + final CkTexture? texture = _textures.remove(id); + texture?.dispose(); + } + + CkTexture? getTexture(int id) { + return _textures[id]; + } + + @override + void textureFrameAvailable(int id) { + final CkTexture? texture = _textures[id]; + if (texture != null) { + texture.markNewFrameAvailable(); + } + } +} diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart index dd155f2fc0efb..74a48a9320193 100644 --- a/lib/web_ui/lib/src/engine/html/renderer.dart +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -23,6 +23,9 @@ class HtmlRenderer implements Renderer { @override HtmlFontCollection get fontCollection => _fontCollection; + @override + TextureRegistry? get textureRegistry => null; + @override void initialize() { scheduleMicrotask(() { diff --git a/lib/web_ui/lib/src/engine/renderer.dart b/lib/web_ui/lib/src/engine/renderer.dart index cc715bb510386..2db3a84da8a13 100644 --- a/lib/web_ui/lib/src/engine/renderer.dart +++ b/lib/web_ui/lib/src/engine/renderer.dart @@ -16,6 +16,7 @@ import 'fonts.dart'; import 'html/renderer.dart'; import 'html_image_codec.dart'; import 'skwasm/skwasm_stub/renderer.dart' if (dart.library.ffi) 'skwasm/skwasm_impl/renderer.dart'; +import 'texture.dart'; final Renderer _renderer = Renderer._internal(); Renderer get renderer => _renderer; @@ -49,6 +50,8 @@ abstract class Renderer { String get rendererTag; FontCollection get fontCollection; + TextureRegistry? get textureRegistry; + FutureOr initialize(); void reset(FlutterViewEmbedder embedder); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart index 00f3108af1b24..05c69f75892e2 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -12,6 +12,7 @@ import '../../embedder.dart'; import '../../fonts.dart'; import '../../html_image_codec.dart'; import '../../renderer.dart'; +import '../../texture.dart'; // TODO(jacksongardner): Actually implement skwasm renderer. class SkwasmRenderer implements Renderer { @@ -138,6 +139,9 @@ class SkwasmRenderer implements Renderer { @override FontCollection get fontCollection => throw UnimplementedError('Not yet implemented'); + @override + TextureRegistry? get textureRegistry => throw UnimplementedError('Not yet implemented'); + @override FutureOr initialize() { throw UnimplementedError('Not yet implemented'); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart index 4a3f5621c7e5c..3de52bcfc4a6d 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart @@ -12,6 +12,7 @@ import '../../embedder.dart'; import '../../fonts.dart'; import '../../html_image_codec.dart'; import '../../renderer.dart'; +import '../../texture.dart'; class SkwasmRenderer implements Renderer { @override @@ -137,6 +138,9 @@ class SkwasmRenderer implements Renderer { @override FontCollection get fontCollection => throw UnimplementedError('Skwasm not implemented on this platform.'); + @override + TextureRegistry? get textureRegistry => throw UnimplementedError('Skwasm not implemented on this platform.'); + @override FutureOr initialize() { throw UnimplementedError('Skwasm not implemented on this platform.'); diff --git a/lib/web_ui/lib/src/engine/texture.dart b/lib/web_ui/lib/src/engine/texture.dart new file mode 100644 index 0000000000000..7959e51bbfc71 --- /dev/null +++ b/lib/web_ui/lib/src/engine/texture.dart @@ -0,0 +1,11 @@ +abstract class TextureRegistry { + /// Registers a texture. + int registerTexture(Object source); + + /// Unregisters the texture with the given id. + void unregisterTexture(int id); + + /// Notifies Flutter that the content of the previously registered texture + /// has been updated. + void textureFrameAvailable(int id); +} diff --git a/lib/web_ui/test/canvaskit/texture_test.dart b/lib/web_ui/test/canvaskit/texture_test.dart new file mode 100644 index 0000000000000..d67047f5dfa67 --- /dev/null +++ b/lib/web_ui/test/canvaskit/texture_test.dart @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; + +import 'common.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + group('$CkTextureRegistry', () { + setUpCanvasKitTest(); + + setUp(() { + window.debugOverrideDevicePixelRatio(1); + }); + + test('can register and unregister a texture', () async { + final CkTextureRegistry registry = CanvasKitRenderer.instance.textureRegistry; + + final DomHTMLImageElement image = createDomHTMLImageElement(); + final int id = registry.registerTexture(image); + + expect(id, isNotNull); + expect(registry.getTexture(id), isNotNull); + + registry.unregisterTexture(id); + expect(registry.getTexture(id), isNull); + }); + }); +} From 98104b1c3527c2c5a7b8d858b3c8e25293badc89 Mon Sep 17 00:00:00 2001 From: xuty Date: Thu, 24 Nov 2022 14:49:40 +0800 Subject: [PATCH 02/12] Fix format --- lib/web_ui/lib/initialization.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/web_ui/lib/initialization.dart b/lib/web_ui/lib/initialization.dart index 5ed9875535715..c161d249a6fc5 100644 --- a/lib/web_ui/lib/initialization.dart +++ b/lib/web_ui/lib/initialization.dart @@ -145,9 +145,9 @@ final PlatformViewRegistry platformViewRegistry = PlatformViewRegistry(); /// A registry for textures. class TextureRegistry { /// Registers a texture. - /// + /// /// Valid [texture] can be any object that that webGL's texImage2D supports. - /// For example, HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, + /// For example, HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, /// ImageData, ImageBitmap and VideoFrame. /// /// The returned id can be used to refer to the texture in Texture widgets. From d3fe2473429597c4f39b2e95002a30b181aaa678 Mon Sep 17 00:00:00 2001 From: xuty Date: Thu, 24 Nov 2022 20:16:08 +0800 Subject: [PATCH 03/12] Fix id generation logic --- .../lib/src/engine/canvaskit/texture.dart | 4 +++- lib/web_ui/test/canvaskit/texture_test.dart | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/texture.dart b/lib/web_ui/lib/src/engine/canvaskit/texture.dart index 33143963c0f1a..64bdf4653c5f4 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/texture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/texture.dart @@ -65,9 +65,11 @@ class CkTextureRegistry implements TextureRegistry { final Map _textures = {}; + int _nextTextureId = 0; + @override int registerTexture(Object source) { - final int id = _textures.length; + final int id = _nextTextureId++; _textures[id] = CkTexture(source); return id; } diff --git a/lib/web_ui/test/canvaskit/texture_test.dart b/lib/web_ui/test/canvaskit/texture_test.dart index d67047f5dfa67..0e364929d21b4 100644 --- a/lib/web_ui/test/canvaskit/texture_test.dart +++ b/lib/web_ui/test/canvaskit/texture_test.dart @@ -32,5 +32,29 @@ void testMain() { registry.unregisterTexture(id); expect(registry.getTexture(id), isNull); }); + + test('can register multiple textures with different ids', () async { + final CkTextureRegistry registry = CanvasKitRenderer.instance.textureRegistry; + + final DomHTMLImageElement image1 = createDomHTMLImageElement(); + final int id1 = registry.registerTexture(image1); + + final DomHTMLImageElement image2 = createDomHTMLImageElement(); + final int id2 = registry.registerTexture(image2); + + expect(id1, isNotNull); + expect(id2, isNotNull); + expect(id2, isNot(id1)); + + registry.unregisterTexture(id1); + expect(registry.getTexture(id1), isNull); + + final DomHTMLImageElement image3 = createDomHTMLImageElement(); + final int id3 = registry.registerTexture(image3); + + expect(id3, isNotNull); + expect(id3, isNot(id1)); + expect(id3, isNot(id2)); + }); }); } From c1305342ec473fca242c364d5d8a11399b346759 Mon Sep 17 00:00:00 2001 From: xuty Date: Fri, 25 Nov 2022 10:48:40 +0800 Subject: [PATCH 04/12] Fix license header --- lib/web_ui/lib/src/engine/canvaskit/texture.dart | 5 ++++- lib/web_ui/lib/src/engine/texture.dart | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/texture.dart b/lib/web_ui/lib/src/engine/canvaskit/texture.dart index 64bdf4653c5f4..57f8168839d85 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/texture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/texture.dart @@ -1,6 +1,9 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + import 'package:ui/ui.dart' as ui; -// import '../platform_dispatcher.dart'; import '../texture.dart'; import 'canvaskit_api.dart'; import 'image.dart'; diff --git a/lib/web_ui/lib/src/engine/texture.dart b/lib/web_ui/lib/src/engine/texture.dart index 7959e51bbfc71..bddbfcdd3f5e4 100644 --- a/lib/web_ui/lib/src/engine/texture.dart +++ b/lib/web_ui/lib/src/engine/texture.dart @@ -1,3 +1,7 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + abstract class TextureRegistry { /// Registers a texture. int registerTexture(Object source); From 216902866ee0ceb0ca1df62abdda9234423cf17f Mon Sep 17 00:00:00 2001 From: xuty Date: Fri, 25 Nov 2022 11:30:54 +0800 Subject: [PATCH 05/12] Update license_flutter --- ci/licenses_golden/licenses_flutter | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 2a31b9f945b4b..7e55c4883ab6f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -4392,6 +4392,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dar FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/texture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/util.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/vertices.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/clipboard.dart @@ -4514,6 +4515,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/texture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/ulps.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/util.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart From dba4dfbcdf42a4ad3f8c69a7e0db8c2b5dcb1c79 Mon Sep 17 00:00:00 2001 From: xuty Date: Fri, 25 Nov 2022 11:55:15 +0800 Subject: [PATCH 06/12] Add comments --- lib/web_ui/lib/src/engine/texture.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/web_ui/lib/src/engine/texture.dart b/lib/web_ui/lib/src/engine/texture.dart index bddbfcdd3f5e4..3784d7e6805ec 100644 --- a/lib/web_ui/lib/src/engine/texture.dart +++ b/lib/web_ui/lib/src/engine/texture.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/// A collection of textures available to the engine. abstract class TextureRegistry { /// Registers a texture. int registerTexture(Object source); From 897be9d7efeba7d1c9458b7a35e054ba7517873b Mon Sep 17 00:00:00 2001 From: xuty Date: Wed, 11 Jan 2023 08:24:13 +0800 Subject: [PATCH 07/12] Update licenses_flutter --- ci/licenses_golden/licenses_flutter | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7e55c4883ab6f..63f60904f54a6 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1911,6 +1911,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.d ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/texture.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/util.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/vertices.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/clipboard.dart + ../../../flutter/LICENSE @@ -2033,6 +2034,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dar ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/texture.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/ulps.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/util.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart + ../../../flutter/LICENSE From de8ce4e55391a7f49ba0793540c666b1df88767e Mon Sep 17 00:00:00 2001 From: xuty Date: Fri, 3 Feb 2023 15:57:59 +0800 Subject: [PATCH 08/12] Remove unnecessary clone() on ckImage --- lib/web_ui/lib/src/engine/canvaskit/texture.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/texture.dart b/lib/web_ui/lib/src/engine/canvaskit/texture.dart index 57f8168839d85..5ed47ebce0ce4 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/texture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/texture.dart @@ -44,7 +44,7 @@ class CkTexture { } context.leafNodesCanvas?.drawImageRect( - _ckImage!.clone(), + _ckImage!, ui.Rect.fromLTWH( 0, 0, From b43bf488de82eb644e9643e76bf28e71cd7f1bc6 Mon Sep 17 00:00:00 2001 From: xuty Date: Fri, 3 Feb 2023 16:46:01 +0800 Subject: [PATCH 09/12] Reuse CkPaint in texture paint --- lib/web_ui/lib/src/engine/canvaskit/texture.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/texture.dart b/lib/web_ui/lib/src/engine/canvaskit/texture.dart index 5ed47ebce0ce4..acbf2435954d4 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/texture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/texture.dart @@ -19,6 +19,8 @@ class CkTexture { bool _newFrameReady = false; + final CkPaint _paint = CkPaint(); + void markNewFrameAvailable() { _newFrameReady = true; } @@ -52,7 +54,7 @@ class CkTexture { _ckImage!.height.toDouble(), ), ui.Rect.fromLTWH(offset.dx, offset.dy, width, height), - CkPaint()..filterQuality = filterQuality, + _paint..filterQuality = filterQuality, ); } From 6cd871e59c199500420c9edd4f824cb3786f8e57 Mon Sep 17 00:00:00 2001 From: xuty Date: Fri, 3 Feb 2023 19:47:08 +0800 Subject: [PATCH 10/12] Add more comments --- lib/web_ui/lib/src/engine/texture.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/lib/src/engine/texture.dart b/lib/web_ui/lib/src/engine/texture.dart index 3784d7e6805ec..0b8218eecd2c7 100644 --- a/lib/web_ui/lib/src/engine/texture.dart +++ b/lib/web_ui/lib/src/engine/texture.dart @@ -4,13 +4,16 @@ /// A collection of textures available to the engine. abstract class TextureRegistry { - /// Registers a texture. + /// Registers a texture, returns an id that can be used to reference that + /// texture in subsequent calls. int registerTexture(Object source); - /// Unregisters the texture with the given id. + /// Unregisters a texture that was previously registered with + /// [registerTexture]. void unregisterTexture(int id); /// Notifies Flutter that the content of the previously registered texture - /// has been updated. + /// has been updated. [id] is the id of the texture that was previously + /// returned by [registerTexture]. void textureFrameAvailable(int id); } From 4fb05e55bc9a52d25f11a7cf8cd846c0e5cfaa5f Mon Sep 17 00:00:00 2001 From: xuty Date: Sun, 5 Feb 2023 23:17:34 +0800 Subject: [PATCH 11/12] Add golden tests --- .../test/canvaskit/texture_golden_test.dart | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 lib/web_ui/test/canvaskit/texture_golden_test.dart diff --git a/lib/web_ui/test/canvaskit/texture_golden_test.dart b/lib/web_ui/test/canvaskit/texture_golden_test.dart new file mode 100644 index 0000000000000..145fd2a953586 --- /dev/null +++ b/lib/web_ui/test/canvaskit/texture_golden_test.dart @@ -0,0 +1,87 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; +import 'package:web_engine_tester/golden_tester.dart'; + +import 'common.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + group('CanvasKit Texture', () { + setUpCanvasKitTest(); + + setUp(() { + window.debugOverrideDevicePixelRatio(1); + }); + + test('can take an image as a texture', () async { + final DomHTMLImageElement image = createDomHTMLImageElement() + ..src = '/test_images/mandrill_128.png'; + + await _waitImageLoaded(image); + + final int textureId = ui.textureRegistry.registerTexture(image); + + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + sb.addTexture(textureId, width: 50, height: 50); + + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); + await matchGoldenFile( + 'canvaskit_texture_image.png', + region: const ui.Rect.fromLTRB(0, 0, 128, 128), + ); + }); + + test('can mark a texture as updated', () async { + final DomHTMLImageElement image = createDomHTMLImageElement() + ..src = '/test_images/mandrill_128.png'; + + await _waitImageLoaded(image); + + final DomCanvasElement canvas = createDomCanvasElement( + width: 128, + height: 128, + ); + + final int textureId = ui.textureRegistry.registerTexture(canvas); + + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + sb.addTexture(textureId, width: 128, height: 128); + + canvas.context2D.drawImage(image, 0, 0); + ui.textureRegistry.textureFrameAvailable(textureId); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); + + canvas.context2D.drawImage(image, 50, 50); + ui.textureRegistry.textureFrameAvailable(textureId); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); + + await matchGoldenFile( + 'canvaskit_texture_canvas.png', + region: const ui.Rect.fromLTRB(0, 0, 128, 128), + ); + }); + }); +} + +Future _waitImageLoaded(DomHTMLImageElement image) { + final Completer imageLoaded = Completer(); + + image.addEventListener('load', allowInterop((_) { + imageLoaded.complete(); + })); + + return imageLoaded.future; +} From c726e29040eba31f79b2885aa09a6dc851b93750 Mon Sep 17 00:00:00 2001 From: xuty Date: Sun, 5 Feb 2023 23:35:06 +0800 Subject: [PATCH 12/12] Update licenses --- ci/licenses_golden/licenses_flutter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index cf3cbb2bb6ca8..6407cb3be713c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -4551,7 +4551,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/ulps.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/texture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/util.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart