From efbfb0a4769bb76bd93004d0270a919bd662e1b1 Mon Sep 17 00:00:00 2001 From: Curt Date: Thu, 25 Apr 2019 18:55:52 -0500 Subject: [PATCH 1/3] Picture Shader --- lib/stub_ui/lib/painting.dart | 9 ++++ lib/ui/painting.dart | 17 ++++++++ lib/ui/painting/picture.cc | 79 +++++++++++++++++++++++++++++++++++ lib/ui/painting/picture.h | 16 +++++++ lib/ui/snapshot_delegate.h | 7 +++- 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/lib/stub_ui/lib/painting.dart b/lib/stub_ui/lib/painting.dart index 22312ae0281d5..c2469e2b788af 100644 --- a/lib/stub_ui/lib/painting.dart +++ b/lib/stub_ui/lib/painting.dart @@ -3312,6 +3312,15 @@ class Picture { Future toImage(int width, int height) { throw UnimplementedError(); } + + /// Creates a shader from this picture. + /// + /// The picture is drawn using the number of pixels specified by the + /// given width and height. + Future toShader(int width, int height, TileMode tmx, TileMode tmy, Float64List matrix4) { + throw UnimplementedError(); + } + /// Release the resources used by this object. The object is no longer usable /// after this method is called. void dispose() { diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 605396acdac4a..bcc0c13d78db2 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3763,7 +3763,24 @@ class Picture extends NativeFieldWrapperClass2 { ); } + /// Creates a shader from this picture. + /// + /// The picture is drawn using the number of pixels specified by the + /// given width and height. + Future toShader(int width, int height, TileMode tmx, TileMode tmy, Float64List matrix4) { + if (width <= 0 || height <= 0) + throw new Exception('Invalid image dimensions.'); + if(tmx == null || tmy == null) + throw new Exception('Invalid tile modes.'); + if (matrix4.length != 16) + throw new ArgumentError('"matrix4" must have 16 entries.'); + return _futurize( + (_Callback callback) => _toShader(width, height, tmx, tmy, matrix4, callback) + ); + } + String _toImage(int width, int height, _Callback callback) native 'Picture_toImage'; + String _toShader(int width, int height, TileMode tmx, TileMode tmy, Float64List matrix4, _Callback callback) native 'Picture_toShader'; /// Release the resources used by this object. The object is no longer usable /// after this method is called. diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 98c37edc115f7..379c0ca773530 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -21,6 +21,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); #define FOR_EACH_BINDING(V) \ V(Picture, toImage) \ + V(Picture, toShader) \ V(Picture, dispose) \ V(Picture, GetAllocationSize) @@ -46,6 +47,19 @@ Dart_Handle Picture::toImage(uint32_t width, return RasterizeToImage(picture_.get(), width, height, raw_image_callback); } +Dart_Handle Picture::toShader(uint32_t width, + uint32_t height, + SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback) { + if (!picture_.get()) { + return tonic::ToDart("Picture is null"); + } + + return TransferToShader(picture_.get(), width, height, tmx, tmy, matrix4, raw_shader_callback); +} + void Picture::dispose() { ClearDartWrapper(); } @@ -126,4 +140,69 @@ Dart_Handle Picture::RasterizeToImage(sk_sp picture, return Dart_Null(); } +Dart_Handle Picture::TransferToShader(sk_sp picture, + uint32_t width, + uint32_t height, + SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback) { + if (Dart_IsNull(raw_shader_callback) || !Dart_IsClosure(raw_shader_callback)) { + return tonic::ToDart("Shader callback was invalid"); + } + + if (width == 0 || height == 0) { + return tonic::ToDart("Shader dimensions for scene were invalid."); + } + + auto* dart_state = UIDartState::Current(); + tonic::DartPersistentValue* shader_callback = new tonic::DartPersistentValue(dart_state, raw_shader_callback); + auto unref_queue = dart_state->GetSkiaUnrefQueue(); + auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); + auto gpu_task_runner = dart_state->GetTaskRunners().GetGPUTaskRunner(); + auto snapshot_delegate = dart_state->GetSnapshotDelegate(); + + auto picture_bounds = SkISize::Make(width, height); + auto matrix = ToSkMatrix(matrix4); + + auto ui_task = fml::MakeCopyable([shader_callback, unref_queue]( + sk_sp shader) mutable { + auto dart_state = shader_callback->dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + + if (!shader) { + tonic::DartInvoke(shader_callback->Get(), {Dart_Null()}); + return; + } + + auto dart_shader = ImageShader::Create(); + dart_shader->set_shader({std::move(shader), std::move(unref_queue)}); + auto* raw_dart_shader = tonic::ToDart(std::move(dart_shader)); + + tonic::DartInvoke(shader_callback->Get(), {raw_dart_shader}); + + delete shader_callback; + }); + + fml::TaskRunner::RunNowOrPostTask( + gpu_task_runner, + [ui_task_runner, snapshot_delegate, picture, picture_bounds, tmx, tmy, matrix, ui_task] { + sk_sp shader; + + sk_sp surface_image = snapshot_delegate->MakeSnapshot(picture, picture_bounds, false); + + if(surface_image) + shader = surface_image->makeShader(tmx, tmy, &matrix); + + fml::TaskRunner::RunNowOrPostTask( + ui_task_runner, + [ui_task, shader]() { ui_task(shader); }); + }); + + return Dart_Null(); +} + } // namespace flutter diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index a800f920c48a0..90d937ef6a21d 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -8,6 +8,7 @@ #include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" +#include "flutter/lib/ui/painting/image_shader.h" #include "third_party/skia/include/core/SkPicture.h" namespace tonic { @@ -31,6 +32,13 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + Dart_Handle toShader(uint32_t width, + uint32_t height, + SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback); + void dispose(); size_t GetAllocationSize() override; @@ -42,6 +50,14 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + static Dart_Handle TransferToShader(sk_sp picture, + uint32_t width, + uint32_t height, + SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback); + private: explicit Picture(flutter::SkiaGPUObject picture); diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 9a771f1219cd8..47277a40fb96e 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -12,8 +12,11 @@ namespace flutter { class SnapshotDelegate { public: - virtual sk_sp MakeRasterSnapshot(sk_sp picture, - SkISize picture_size) = 0; + virtual sk_sp MakeSnapshot(sk_sp picture, + SkISize picture_size, + bool rasterize) = 0; + inline sk_sp MakeRasterSnapshot(sk_sp picture, + SkISize picture_size) { return MakeSnapshot(picture, picture_size, true); }; }; } // namespace flutter From 26b592519024996925460b1aee1ef95a7c748660 Mon Sep 17 00:00:00 2001 From: Curt Date: Fri, 3 May 2019 13:06:48 -0500 Subject: [PATCH 2/3] Picture Shader --- lib/stub_ui/lib/painting.dart | 16 ++++++-- lib/ui/BUILD.gn | 2 + lib/ui/painting.dart | 31 +++++++++------ lib/ui/painting/picture.cc | 66 +++++++++++++++++++------------ lib/ui/painting/picture.h | 11 +++--- lib/ui/painting/picture_shader.cc | 19 +++++++++ lib/ui/painting/picture_shader.h | 27 +++++++++++++ 7 files changed, 125 insertions(+), 47 deletions(-) create mode 100644 lib/ui/painting/picture_shader.cc create mode 100644 lib/ui/painting/picture_shader.h diff --git a/lib/stub_ui/lib/painting.dart b/lib/stub_ui/lib/painting.dart index c2469e2b788af..acfe007f437f5 100644 --- a/lib/stub_ui/lib/painting.dart +++ b/lib/stub_ui/lib/painting.dart @@ -1318,6 +1318,7 @@ class Paint { /// /// * [Gradient], a shader that paints a color gradient. /// * [ImageShader], a shader that tiles an [Image]. + /// * [PictureShader], a shader that tiles a [Picture]. /// * [colorFilter], which overrides [shader]. /// * [color], which is used if [shader] and [colorFilter] are null. Shader get shader { @@ -2669,6 +2670,13 @@ class ImageShader extends Shader { super._(); } +/// A shader (as used by [Paint.shader]) that tiles a picture. +class PictureShader extends Shader { + /// This class is created by the engine, and should not be instantiated + /// or extended directly. + PictureShader._() : super._(); +} + /// Defines how a list of points is interpreted when drawing a set of triangles. /// /// Used by [Canvas.drawVertices]. @@ -3313,11 +3321,11 @@ class Picture { throw UnimplementedError(); } - /// Creates a shader from this picture. + /// Creates a picture shader from this picture. /// - /// The picture is drawn using the number of pixels specified by the - /// given width and height. - Future toShader(int width, int height, TileMode tmx, TileMode tmy, Float64List matrix4) { + /// The shader is returned asynchronously to allow time for the gpu to + /// draw the picture and compile a shader. + Future toShader(TileMode tmx, TileMode tmy, Float64List matrix4) { throw UnimplementedError(); } diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index bef50753a4b9e..6b6b642d5a674 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -48,6 +48,8 @@ source_set("ui") { "painting/picture.h", "painting/picture_recorder.cc", "painting/picture_recorder.h", + "painting/picture_shader.cc", + "painting/picture_shader.h", "painting/rrect.cc", "painting/rrect.h", "painting/shader.cc", diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index bcc0c13d78db2..530c2fe3c4630 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1319,6 +1319,7 @@ class Paint { /// /// * [Gradient], a shader that paints a color gradient. /// * [ImageShader], a shader that tiles an [Image]. + /// * [PictureShader], a shader that tiles a [Picture]. /// * [colorFilter], which overrides [shader]. /// * [color], which is used if [shader] and [colorFilter] are null. Shader get shader { @@ -2875,6 +2876,14 @@ class ImageShader extends Shader { void _initWithImage(Image image, int tmx, int tmy, Float64List matrix4) native 'ImageShader_initWithImage'; } +/// A shader (as used by [Paint.shader]) that tiles a picture. +class PictureShader extends Shader { + /// This class is created by the engine, and should not be instantiated + /// or extended directly. + @pragma('vm:entry-point') + PictureShader._() : super._(); +} + /// Defines how a list of points is interpreted when drawing a set of triangles. /// /// Used by [Canvas.drawVertices]. @@ -3763,24 +3772,24 @@ class Picture extends NativeFieldWrapperClass2 { ); } - /// Creates a shader from this picture. + String _toImage(int width, int height, _Callback callback) native 'Picture_toImage'; + + /// Creates a picture shader from this picture. /// - /// The picture is drawn using the number of pixels specified by the - /// given width and height. - Future toShader(int width, int height, TileMode tmx, TileMode tmy, Float64List matrix4) { - if (width <= 0 || height <= 0) - throw new Exception('Invalid image dimensions.'); - if(tmx == null || tmy == null) - throw new Exception('Invalid tile modes.'); + /// The shader is returned asynchronously to allow time for the gpu to + /// draw the picture and compile a shader. + Future toShader(TileMode tmx, TileMode tmy, Float64List matrix4) { + assert(tmx != null); + assert(tmy != null); + assert(matrix4 != null); if (matrix4.length != 16) throw new ArgumentError('"matrix4" must have 16 entries.'); return _futurize( - (_Callback callback) => _toShader(width, height, tmx, tmy, matrix4, callback) + (_Callback callback) => _toShader(tmx, tmy, matrix4, callback) ); } - String _toImage(int width, int height, _Callback callback) native 'Picture_toImage'; - String _toShader(int width, int height, TileMode tmx, TileMode tmy, Float64List matrix4, _Callback callback) native 'Picture_toShader'; + String _toShader(TileMode tmx, TileMode tmy, Float64List matrix4, _Callback callback) native 'Picture_toShader'; /// Release the resources used by this object. The object is no longer usable /// after this method is called. diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 379c0ca773530..5b20edc5193d0 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -21,7 +21,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); #define FOR_EACH_BINDING(V) \ V(Picture, toImage) \ - V(Picture, toShader) \ + V(Picture, toShader) \ V(Picture, dispose) \ V(Picture, GetAllocationSize) @@ -47,17 +47,19 @@ Dart_Handle Picture::toImage(uint32_t width, return RasterizeToImage(picture_.get(), width, height, raw_image_callback); } -Dart_Handle Picture::toShader(uint32_t width, - uint32_t height, - SkTileMode tmx, - SkTileMode tmy, - const tonic::Float64List& matrix4, - Dart_Handle raw_shader_callback) { +Dart_Handle Picture::toShader(SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback) { if (!picture_.get()) { return tonic::ToDart("Picture is null"); } - return TransferToShader(picture_.get(), width, height, tmx, tmy, matrix4, raw_shader_callback); + if (picture_.get()->cullRect().isEmpty()) { + return tonic::ToDart("Picture cull rect is null"); + } + + return TransferToShader(picture_.get(), tmx, tmy, matrix4, raw_shader_callback); } void Picture::dispose() { @@ -141,18 +143,12 @@ Dart_Handle Picture::RasterizeToImage(sk_sp picture, } Dart_Handle Picture::TransferToShader(sk_sp picture, - uint32_t width, - uint32_t height, - SkTileMode tmx, - SkTileMode tmy, - const tonic::Float64List& matrix4, - Dart_Handle raw_shader_callback) { + SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback) { if (Dart_IsNull(raw_shader_callback) || !Dart_IsClosure(raw_shader_callback)) { - return tonic::ToDart("Shader callback was invalid"); - } - - if (width == 0 || height == 0) { - return tonic::ToDart("Shader dimensions for scene were invalid."); + return tonic::ToDart("Picture shader callback was invalid"); } auto* dart_state = UIDartState::Current(); @@ -160,9 +156,7 @@ Dart_Handle Picture::TransferToShader(sk_sp picture, auto unref_queue = dart_state->GetSkiaUnrefQueue(); auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); auto gpu_task_runner = dart_state->GetTaskRunners().GetGPUTaskRunner(); - auto snapshot_delegate = dart_state->GetSnapshotDelegate(); - auto picture_bounds = SkISize::Make(width, height); auto matrix = ToSkMatrix(matrix4); auto ui_task = fml::MakeCopyable([shader_callback, unref_queue]( @@ -178,7 +172,7 @@ Dart_Handle Picture::TransferToShader(sk_sp picture, return; } - auto dart_shader = ImageShader::Create(); + auto dart_shader = PictureShader::Create(); dart_shader->set_shader({std::move(shader), std::move(unref_queue)}); auto* raw_dart_shader = tonic::ToDart(std::move(dart_shader)); @@ -189,13 +183,33 @@ Dart_Handle Picture::TransferToShader(sk_sp picture, fml::TaskRunner::RunNowOrPostTask( gpu_task_runner, - [ui_task_runner, snapshot_delegate, picture, picture_bounds, tmx, tmy, matrix, ui_task] { + [ui_task_runner, picture, tmx, tmy, matrix, ui_task] { sk_sp shader; - sk_sp surface_image = snapshot_delegate->MakeSnapshot(picture, picture_bounds, false); + SkRect tile = picture->cullRect(); + + SkPoint scale; + + scale.set(SkScalarSqrt(matrix.getScaleX() * matrix.getScaleX() + matrix.getSkewX() * matrix.getSkewX()), + SkScalarSqrt(matrix.getScaleY() * matrix.getScaleY() + matrix.getSkewY() * matrix.getSkewY())); + + SkSize scaledSize = SkSize::Make(SkScalarAbs(scale.x() * tile.width()), + SkScalarAbs(scale.y() * tile.height())); + + const SkISize tileSize = scaledSize.toCeil(); + + if (!tileSize.isEmpty()) { + SkMatrix tileMatrix; + tileMatrix.setRectToRect(tile, SkRect::MakeIWH(tileSize.width(), tileSize.height()), SkMatrix::kFill_ScaleToFit); + + SkImage::BitDepth bitDepth = SkImage::BitDepth::kU8; + sk_sp colorSpace = SkColorSpace::MakeSRGB(); + + sk_sp tileImage = SkImage::MakeFromPicture(picture, tileSize, &tileMatrix, nullptr, bitDepth, std::move(colorSpace)); - if(surface_image) - shader = surface_image->makeShader(tmx, tmy, &matrix); + if(tileImage) + shader = tileImage->makeShader(tmx, tmy); + } fml::TaskRunner::RunNowOrPostTask( ui_task_runner, diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 90d937ef6a21d..41c9681115535 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -8,8 +8,11 @@ #include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" -#include "flutter/lib/ui/painting/image_shader.h" +#include "flutter/lib/ui/painting/matrix.h" +#include "flutter/lib/ui/painting/picture_shader.h" +#include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/tonic/typed_data/float64_list.h" namespace tonic { class DartLibraryNatives; @@ -32,9 +35,7 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); - Dart_Handle toShader(uint32_t width, - uint32_t height, - SkTileMode tmx, + Dart_Handle toShader(SkTileMode tmx, SkTileMode tmy, const tonic::Float64List& matrix4, Dart_Handle raw_shader_callback); @@ -51,8 +52,6 @@ class Picture : public RefCountedDartWrappable { Dart_Handle raw_image_callback); static Dart_Handle TransferToShader(sk_sp picture, - uint32_t width, - uint32_t height, SkTileMode tmx, SkTileMode tmy, const tonic::Float64List& matrix4, diff --git a/lib/ui/painting/picture_shader.cc b/lib/ui/painting/picture_shader.cc new file mode 100644 index 0000000000000..3a0558743258c --- /dev/null +++ b/lib/ui/painting/picture_shader.cc @@ -0,0 +1,19 @@ +// 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. + +#include "flutter/lib/ui/painting/picture_shader.h" + +namespace flutter { + +IMPLEMENT_WRAPPERTYPEINFO(ui, PictureShader); + +fml::RefPtr PictureShader::Create() { + return fml::MakeRefCounted(); +} + +PictureShader::PictureShader() = default; + +PictureShader::~PictureShader() = default; + +} // namespace flutter diff --git a/lib/ui/painting/picture_shader.h b/lib/ui/painting/picture_shader.h new file mode 100644 index 0000000000000..51619ace0abbc --- /dev/null +++ b/lib/ui/painting/picture_shader.h @@ -0,0 +1,27 @@ +// 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. + +#ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_SHADER_H_ +#define FLUTTER_LIB_UI_PAINTING_PICTURE_SHADER_H_ + +#include "flutter/lib/ui/dart_wrapper.h" +#include "flutter/lib/ui/painting/shader.h" + +namespace flutter { + +class PictureShader : public Shader { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(PictureShader); + + public: + ~PictureShader() override; + static fml::RefPtr Create(); + + private: + PictureShader(); +}; + +} // namespace flutter + +#endif // FLUTTER_LIB_UI_PAINTING_PICTURE_SHADER_H_ From 6bbb13a529692eaf6ed07b89d1afcadd05a3324d Mon Sep 17 00:00:00 2001 From: Curt Date: Fri, 3 May 2019 13:11:47 -0500 Subject: [PATCH 3/3] Picture Shader --- lib/ui/snapshot_delegate.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 47277a40fb96e..9a771f1219cd8 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -12,11 +12,8 @@ namespace flutter { class SnapshotDelegate { public: - virtual sk_sp MakeSnapshot(sk_sp picture, - SkISize picture_size, - bool rasterize) = 0; - inline sk_sp MakeRasterSnapshot(sk_sp picture, - SkISize picture_size) { return MakeSnapshot(picture, picture_size, true); }; + virtual sk_sp MakeRasterSnapshot(sk_sp picture, + SkISize picture_size) = 0; }; } // namespace flutter