From 74ae193587aba844789f162034079000d5e0f54f Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Wed, 24 Mar 2021 13:12:34 -0700 Subject: [PATCH 01/37] prototype of dart-level display list replacement for (Sk)Picture --- flow/BUILD.gn | 4 + flow/display_list.cc | 247 ++++ flow/display_list.h | 170 +++ flow/layers/display_list_layer.cc | 195 +++ flow/layers/display_list_layer.h | 46 + lib/ui/compositing.dart | 30 +- lib/ui/compositing/scene_builder.cc | 25 + lib/ui/compositing/scene_builder.h | 15 + lib/ui/painting.dart | 1812 +++++++++++++++++++++------ 9 files changed, 2131 insertions(+), 413 deletions(-) create mode 100644 flow/display_list.cc create mode 100644 flow/display_list.h create mode 100644 flow/layers/display_list_layer.cc create mode 100644 flow/layers/display_list_layer.h diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 1efd32e6cb622..139fe9efe04c1 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -12,6 +12,8 @@ source_set("flow") { "compositor_context.h", "diff_context.cc", "diff_context.h", + "display_list.cc", + "display_list.h", "embedded_views.cc", "embedded_views.h", "frame_timings.cc", @@ -30,6 +32,8 @@ source_set("flow") { "layers/color_filter_layer.h", "layers/container_layer.cc", "layers/container_layer.h", + "layers/display_list_layer.cc", + "layers/display_list_layer.h", "layers/image_filter_layer.cc", "layers/image_filter_layer.h", "layers/layer.cc", diff --git a/flow/display_list.cc b/flow/display_list.cc new file mode 100644 index 0000000000000..dbb7871116422 --- /dev/null +++ b/flow/display_list.cc @@ -0,0 +1,247 @@ +// 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/flow/display_list.h" + +// #include + +// #include "flutter/fml/make_copyable.h" +// #include "flutter/lib/ui/painting/canvas.h" +// #include "flutter/lib/ui/ui_dart_state.h" +// #include "third_party/skia/include/core/SkBlurTypes.h" +// #include "third_party/skia/include/core/SkImage.h" +// #include "third_party/tonic/converter/dart_converter.h" +// #include "third_party/tonic/dart_args.h" +// #include "third_party/tonic/dart_binding_macros.h" +// #include "third_party/tonic/dart_library_natives.h" +// #include "third_party/tonic/dart_persistent_value.h" +// #include "third_party/tonic/logging/dart_invoke.h" + +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkMaskFilter.h" +#include "third_party/skia/include/core/SkShader.h" + +namespace flutter { + +// IMPLEMENT_WRAPPERTYPEINFO(ui, DisplayList); + +// #define FOR_EACH_BINDING(V) \ +// V(DisplayList, toImage) \ +// V(DisplayList, dispose) \ +// V(DisplayList, GetAllocationSize) + +// DART_BIND_ALL(DisplayList, FOR_EACH_BINDING) + +// fml::RefPtr DisplayList::Create( +// Dart_Handle dart_handle, +// flutter::SkiaGPUObject picture) { +// auto canvas_picture = fml::MakeRefCounted(std::move(picture)); + +// canvas_picture->AssociateWithDartWrapper(dart_handle); +// return canvas_picture; +// } + +// DisplayList::DisplayList(flutter::SkiaGPUObject picture) +// : picture_(std::move(picture)) {} + +// DisplayList::~DisplayList() = default; + +DisplayListRasterizer::DisplayListRasterizer(std::vector ops, std::vector data) + : ops_it_(std::begin(ops)), + ops_end_(std::end(ops)), + data_it_(std::begin(data)) {} + +static const std::array filter_qualities = { + SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone), + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone), + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), + SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}), +}; + +void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { + SkPaint paint; + while (ops_it_ < ops_end_) { + switch (static_cast(*ops_it_++)) { + case cops_setAA: paint.setAntiAlias(true); break; + case cops_clearAA: paint.setAntiAlias(false); break; + case cops_setInvertColors: break; // TODO(flar): replaces colorfilter??? + case cops_clearInvertColors: paint.setColorFilter(nullptr); break; + case cops_setColor: paint.setColor(*data_it_++); break; + case cops_setFillStyle: paint.setStyle(SkPaint::Style::kFill_Style); break; + case cops_setStrokeStyle: paint.setStyle(SkPaint::Style::kStroke_Style); break; + case cops_setStrokeWidth: paint.setStrokeWidth(GetScalar()); break; + case cops_setMiterLimit: paint.setStrokeMiter(GetScalar()); break; + case cops_setCapsButt: paint.setStrokeCap(SkPaint::Cap::kButt_Cap); break; + case cops_setCapsRound: paint.setStrokeCap(SkPaint::Cap::kRound_Cap); break; + case cops_setCapsSquare: paint.setStrokeCap(SkPaint::Cap::kSquare_Cap); break; + case cops_setJoinsMiter: paint.setStrokeJoin(SkPaint::Join::kMiter_Join); break; + case cops_setJoinsRound: paint.setStrokeJoin(SkPaint::Join::kRound_Join); break; + case cops_setJoinsBevel: paint.setStrokeJoin(SkPaint::Join::kBevel_Join); break; + case cops_clearShader: paint.setShader(nullptr); break; + case cops_setShader: break; // TODO(flar) deal with Shader object + case cops_clearMaskFilter: paint.setMaskFilter(nullptr); break; + case cops_setMaskFilterInner: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kInner_SkBlurStyle, GetScalar())); break; + case cops_setMaskFilterOuter: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kOuter_SkBlurStyle, GetScalar())); break; + case cops_setMaskFilterSolid: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kSolid_SkBlurStyle, GetScalar())); break; + case cops_setMaskFilterNormal: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, GetScalar())); break; + case cops_clearColorFilter: paint.setColorFilter(nullptr); break; + case cops_setColorFilter: break; // TODO(flar) deal with Filter object + case cops_clearImageFilter: paint.setImageFilter(nullptr); break; + case cops_setImageFilter: break; // TODO(flar) deal with Filter object + case cops_setFilterQualityNearest: paint.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality); break; + case cops_setFilterQualityLinear: paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality); break; + case cops_setFilterQualityMipmap: paint.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); break; + case cops_setFilterQualityCubic: paint.setFilterQuality(SkFilterQuality::kHigh_SkFilterQuality); break; + case cops_setBlendMode: paint.setBlendMode(GetBlendMode()); break; + + case cops_save: canvas->save(); break; + case cops_saveLayer: canvas->saveLayer(nullptr, &paint); break; + case cops_saveLayerBounds: canvas->saveLayer(GetRect(), &paint); break; + case cops_restore: canvas->restore(); break; + + case cops_clipRect: canvas->clipRect(GetRect()); break; + case cops_clipRectAA: canvas->clipRect(GetRect(), true); break; + case cops_clipRectDiff: canvas->clipRect(GetRect(), SkClipOp::kDifference); break; + case cops_clipRectAADiff: canvas->clipRect(GetRect(), SkClipOp::kDifference, true); break; + + case cops_clipRRect: canvas->clipRRect(GetRoundRect()); break; + case cops_clipRRectAA: canvas->clipRRect(GetRoundRect(), true); break; + case cops_clipPath: break; // TODO(flar) deal with Path object + case cops_clipPathAA: break; // TODO(flar) deal with Path object + + case cops_translate: canvas->translate(GetScalar(), GetScalar()); break; + case cops_scale: canvas->scale(GetScalar(), GetScalar()); break; + case cops_rotate: canvas->rotate(GetScalar() * 180 / M_PI); break; + case cops_skew: canvas->skew(GetScalar(), GetScalar()); break; + case cops_transform: break; // TODO(flar) deal with Float64List + + case cops_drawColor: canvas->drawColor(GetColor(), paint.getBlendMode()); break; + case cops_drawPaint: canvas->drawPaint(paint); break; + + case cops_drawRect: canvas->drawRect(GetRect(), paint); break; + case cops_drawOval: canvas->drawOval(GetRect(), paint); break; + case cops_drawRRect: canvas->drawRRect(GetRoundRect(), paint); break; + case cops_drawDRRect: canvas->drawDRRect(GetRoundRect(), GetRoundRect(), paint); break; + case cops_drawCircle: canvas->drawCircle(GetPoint(), GetScalar(), paint); break; + case cops_drawArc: canvas->drawArc(GetRect(), GetScalar(), GetScalar(), false, paint); + case cops_drawArcCenter: canvas->drawArc(GetRect(), GetScalar(), GetScalar(), true, paint); + case cops_drawLine: canvas->drawLine(GetPoint(), GetPoint(), paint); break; + case cops_drawPath: break; // TODO(flar) deal with Path object + + case cops_drawLines: break; // TODO(flar) deal with List of points + case cops_drawPoints: break; // TODO(flar) deal with List of points + case cops_drawPolygon: break; // TODO(flar) deal with List of points + case cops_drawPicture: break; // TODO(flar) deal with Picture object + + case cops_drawImage: GetScalar(); GetScalar(); break; // TODO(flar) deal with image object + case cops_drawImageRect: GetRect(); GetRect(); break; // TODO(flar) deal with image object + case cops_drawImageNine: GetRect(); GetRect(); break; // TODO(flar) deal with image object + case cops_drawAtlas: + case cops_drawAtlasColored: + break; + case cops_drawAtlasCulled: + case cops_drawAtlasColoredCulled: + GetRect(); + break; + + case cops_drawParagraph: GetPoint(); break; // TODO(flar) deal with Paragraph object + case cops_drawShadow: GetScalar(); break; // TODO(flar) deal with Path object + case cops_drawShadowOccluded: GetScalar(); break; // TODO(flar) deal with Path object + } + } +} + +// Dart_Handle DisplayList::toImage(uint32_t width, +// uint32_t height, +// Dart_Handle raw_image_callback) { +// if (!picture_.get()) { +// return tonic::ToDart("Picture is null"); +// } + +// return RasterizeToImage(picture_.get(), width, height, raw_image_callback); +// } + +// void DisplayList::dispose() { +// picture_.reset(); +// ClearDartWrapper();ToSkRoundRect +// } + +// size_t DisplayList::GetAllocationSize() const { +// if (auto picture = picture_.get()) { +// return picture->approximateBytesUsed() + sizeof(Picture); +// } else { +// return sizeof(Picture); +// } +// } + +// Dart_Handle DisplayList::RasterizeToImage(sk_sp picture, +// uint32_t width, +// uint32_t height, +// Dart_Handle raw_image_callback) { +// if (Dart_IsNull(raw_image_callback) || !Dart_IsClosure(raw_image_callback)) { +// return tonic::ToDart("Image callback was invalid"); +// } + +// if (width == 0 || height == 0) { +// return tonic::ToDart("Image dimensions for scene were invalid."); +// } + +// auto* dart_state = UIDartState::Current(); +// auto image_callback = std::make_unique( +// dart_state, raw_image_callback); +// auto unref_queue = dart_state->GetSkiaUnrefQueue(); +// auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); +// auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); +// auto snapshot_delegate = dart_state->GetSnapshotDelegate(); + +// // We can't create an image on this task runner because we don't have a +// // graphics context. Even if we did, it would be slow anyway. Also, this +// // thread owns the sole reference to the layer tree. So we flatten the layer +// // tree into a picture and use that as the thread transport mechanism. + +// auto picture_bounds = SkISize::Make(width, height); + +// auto ui_task = fml::MakeCopyable([image_callback = std::move(image_callback), +// unref_queue]( +// sk_sp raster_image) mutable { +// auto dart_state = image_callback->dart_state().lock(); +// if (!dart_state) { +// // The root isolate could have died in the meantime. +// return; +// } +// tonic::DartState::Scope scope(dart_state); + +// if (!raster_image) { +// tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); +// return; +// } + +// auto dart_image = CanvasImage::Create(); +// dart_image->set_image({std::move(raster_image), std::move(unref_queue)}); +// auto* raw_dart_image = tonic::ToDart(std::move(dart_image)); + +// // All done! +// tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); + +// // image_callback is associated with the Dart isolate and must be deleted +// // on the UI thread. +// image_callback.reset(); +// }); + +// // Kick things off on the raster rask runner. +// fml::TaskRunner::RunNowOrPostTask( +// raster_task_runner, +// [ui_task_runner, snapshot_delegate, picture, picture_bounds, ui_task] { +// sk_sp raster_image = +// snapshot_delegate->MakeRasterSnapshot(picture, picture_bounds); + +// fml::TaskRunner::RunNowOrPostTask( +// ui_task_runner, +// [ui_task, raster_image]() { ui_task(raster_image); }); +// }); + +// return Dart_Null(); +// } + +} // namespace flutter diff --git a/flow/display_list.h b/flow/display_list.h new file mode 100644 index 0000000000000..307312a3122fd --- /dev/null +++ b/flow/display_list.h @@ -0,0 +1,170 @@ +// 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_FLOW_DISPLAY_LIST_H_ +#define FLUTTER_FLOW_DISPLAY_LIST_H_ + +#include "third_party/skia/include/core/SkColorFilter.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkRRect.h" + +// namespace tonic { +// class DartLibraryNatives; +// } // namespace tonic + +namespace flutter { + +enum CanvasOp { + cops_setAA, + cops_clearAA, + cops_setInvertColors, + cops_clearInvertColors, + cops_setFillStyle, + cops_setStrokeStyle, + + cops_setCapsButt, + cops_setCapsRound, + cops_setCapsSquare, + cops_setJoinsBevel, + cops_setJoinsMiter, + cops_setJoinsRound, + + cops_setStrokeWidth, + cops_setMiterLimit, + + cops_setFilterQualityNearest, + cops_setFilterQualityLinear, + cops_setFilterQualityMipmap, + cops_setFilterQualityCubic, + + cops_setColor, + cops_setBlendMode, + + cops_setShader, + cops_clearShader, + cops_setColorFilter, + cops_clearColorFilter, + cops_setImageFilter, + cops_clearImageFilter, + + cops_clearMaskFilter, + cops_setMaskFilterNormal, + cops_setMaskFilterSolid, + cops_setMaskFilterOuter, + cops_setMaskFilterInner, + + cops_save, + cops_saveLayer, + cops_saveLayerBounds, + cops_restore, + + cops_translate, + cops_scale, + cops_rotate, + cops_skew, + cops_transform, + + cops_clipRect, + cops_clipRectAA, + cops_clipRectDiff, + cops_clipRectAADiff, + cops_clipRRect, + cops_clipRRectAA, + cops_clipPath, + cops_clipPathAA, + + cops_drawPaint, + cops_drawColor, + + cops_drawLine, + cops_drawRect, + cops_drawOval, + cops_drawCircle, + cops_drawRRect, + cops_drawDRRect, + cops_drawArc, + cops_drawArcCenter, + cops_drawPath, + + cops_drawPoints, + cops_drawLines, + cops_drawPolygon, + + cops_drawImage, + cops_drawImageRect, + cops_drawImageNine, + cops_drawAtlas, + cops_drawAtlasColored, + cops_drawAtlasCulled, + cops_drawAtlasColoredCulled, + + cops_drawParagraph, + cops_drawPicture, + cops_drawShadow, + cops_drawShadowOccluded, +}; + +class DisplayListRasterizer { + public: + DisplayListRasterizer(std::vector ops, std::vector data); + + void Rasterize(SkCanvas *canvas); + + private: + std::vector::iterator ops_it_; + std::vector::iterator ops_end_; + std::vector::iterator data_it_; + + SkScalar GetScalar() { return static_cast(*data_it_++); } + SkBlendMode GetBlendMode() { return static_cast(*data_it_++); } + SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } + SkColor GetColor() { return *data_it_++; } + SkRect GetRect() { return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), GetScalar()); } + SkRRect GetRoundRect() { + SkRect rect = GetRect(); + SkVector radii[4] = { + { GetScalar(), GetScalar() }, + { GetScalar(), GetScalar() }, + { GetScalar(), GetScalar() }, + { GetScalar(), GetScalar() }, + }; + + SkRRect rrect; + rrect.setRectRadii(rect, radii); + return rrect; + } +}; + +// class DisplayList : public RefCountedDartWrappable { +// DEFINE_WRAPPERTYPEINFO(); +// FML_FRIEND_MAKE_REF_COUNTED(DisplayList); + +// public: + +// ~DisplayList() override; +// static fml::RefPtr Create(Dart_Handle dart_handle, +// flutter::SkiaGPUObject picture); + +// Dart_Handle toImage(uint32_t width, +// uint32_t height, +// Dart_Handle raw_image_callback); + +// void dispose(); + +// size_t GetAllocationSize() const override; + +// static void RegisterNatives(tonic::DartLibraryNatives* natives); + +// static Dart_Handle RasterizeToImage(sk_sp picture, +// uint32_t width, +// uint32_t height, +// Dart_Handle raw_image_callback); + +// private: +// Picture(flutter::SkiaGPUObject picture); +// }; + +} // namespace flutter + +#endif // FLUTTER_FLOW_DISPLAY_LIST_H_ diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc new file mode 100644 index 0000000000000..414bb1d8ea965 --- /dev/null +++ b/flow/layers/display_list_layer.cc @@ -0,0 +1,195 @@ +// 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/flow/layers/display_list_layer.h" + +#include "flutter/fml/logging.h" +#include "flutter/flow/display_list.h" +#include "third_party/skia/include/core/SkSerialProcs.h" + +namespace flutter { + +DisplayListLayer::DisplayListLayer(const SkPoint& offset, + const SkRect& cull_rect, + const SkRect& draw_rect, + bool is_complex, + bool will_change) + : offset_(offset), + cull_rect_(cull_rect), + draw_rect_(draw_rect), + is_complex_(is_complex), + will_change_(will_change) {} + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + +void DisplayListLayer::Diff(DiffContext* context, const Layer* old_layer) { + DiffContext::AutoSubtreeRestore subtree(context); + auto* prev = static_cast(old_layer); + if (!context->IsSubtreeDirty()) { + FML_DCHECK(prev); + if (offset_ != prev->offset_ || cull_rect_ != prev->cull_rect_) { + context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); + } + } + context->PushTransform(SkMatrix::Translate(offset_.x(), offset_.y())); + SkRect bounds = draw_rect_; + if (!bounds.intersect(cull_rect_)) { + bounds.setEmpty(); + } + context->AddLayerBounds(bounds); + context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); +} + +// bool DisplayListLayer::Compare(DiffContext::Statistics& statistics, +// const PictureLayer* l1, +// const PictureLayer* l2) { +// const auto& pic1 = l1->picture_.get(); +// const auto& pic2 = l2->picture_.get(); +// if (pic1.get() == pic2.get()) { +// statistics.AddSameInstancePicture(); +// return true; +// } +// auto op_cnt_1 = pic1->approximateOpCount(); +// auto op_cnt_2 = pic2->approximateOpCount(); +// if (op_cnt_1 != op_cnt_2 || pic1->cullRect() != pic2->cullRect()) { +// statistics.AddNewPicture(); +// return false; +// } + +// if (op_cnt_1 > 10) { +// statistics.AddPictureTooComplexToCompare(); +// return false; +// } + +// statistics.AddDeepComparePicture(); + +// // TODO(knopp) we don't actually need the data; this could be done without +// // allocations by implementing stream that calculates SHA hash and +// // comparing those hashes +// auto d1 = l1->SerializedPicture(); +// auto d2 = l2->SerializedPicture(); +// auto res = d1->equals(d2.get()); +// if (res) { +// statistics.AddDifferentInstanceButEqualPicture(); +// } else { +// statistics.AddNewPicture(); +// } +// return res; +// } + +// sk_sp PictureLayer::SerializedPicture() const { +// if (!cached_serialized_picture_) { +// SkSerialProcs procs = { +// nullptr, +// nullptr, +// [](SkImage* i, void* ctx) { +// auto id = i->uniqueID(); +// return SkData::MakeWithCopy(&id, sizeof(id)); +// }, +// nullptr, +// [](SkTypeface* tf, void* ctx) { +// auto id = tf->uniqueID(); +// return SkData::MakeWithCopy(&id, sizeof(id)); +// }, +// nullptr, +// }; +// cached_serialized_picture_ = picture_.get()->serialize(&procs); +// } +// return cached_serialized_picture_; +// } + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + +void DisplayListLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "DisplayListLayer::Preroll"); + +#if defined(LEGACY_FUCHSIA_EMBEDDER) + CheckForChildLayerBelow(context); +#endif + +// if (auto* cache = context->raster_cache) { +// TRACE_EVENT0("flutter", "DisplayListLayer::RasterCache (Preroll)"); + +// SkMatrix ctm = matrix; +// ctm.preTranslate(offset_.x(), offset_.y()); +// #ifndef SUPPORT_FRACTIONAL_TRANSLATION +// ctm = RasterCache::GetIntegralTransCTM(ctm); +// #endif +// cache->Prepare(context->gr_context, sk_picture, ctm, +// context->dst_color_space, is_complex_, will_change_); +// } + + FML_LOG(ERROR) << "display list cull rect is [" + << cull_rect_.left() << ", " + << cull_rect_.top() << ", " + << cull_rect_.right() << ", " + << cull_rect_.bottom() << "]"; + FML_LOG(ERROR) << "display list draw rect is [" + << draw_rect_.left() << ", " + << draw_rect_.top() << ", " + << draw_rect_.right() << ", " + << draw_rect_.bottom() << "]"; + SkRect bounds = draw_rect_; + if (bounds.intersect(cull_rect_)) { + bounds.offset(offset_.x(), offset_.y()); + } else { + bounds.setEmpty(); + } + FML_LOG(ERROR) << "display list paint bounds is [" + << bounds.left() << ", " + << bounds.top() << ", " + << bounds.right() << ", " + << bounds.bottom() << "]"; + set_paint_bounds(bounds); +} + +void DisplayListLayer::Paint(PaintContext& context) const { + TRACE_EVENT0("flutter", "DisplayListLayer::Paint"); + FML_DCHECK(needs_painting(context)); + + SkAutoCanvasRestore save(context.leaf_nodes_canvas, true); + context.leaf_nodes_canvas->translate(offset_.x(), offset_.y()); +#ifndef SUPPORT_FRACTIONAL_TRANSLATION + context.leaf_nodes_canvas->setMatrix(RasterCache::GetIntegralTransCTM( + context.leaf_nodes_canvas->getTotalMatrix())); +#endif + +// if (context.raster_cache && +// context.raster_cache->Draw(*picture(), *context.leaf_nodes_canvas)) { +// TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); +// return; +// } + + if (is_complex_ && will_change_ && is_complex_ != will_change_) { + // (for now, basically never) + std::vector ops; + std::vector data; + DisplayListRasterizer display_list(ops, data); + display_list.Rasterize(context.leaf_nodes_canvas); + } + + SkRect bounds = paint_bounds(); + SkPaint paint; + paint.setColor(is_complex_ + ? (will_change_ ? SkColors::kRed : SkColors::kYellow) + : (will_change_ ? SkColors::kBlue : SkColors::kGreen)); + paint.setAlphaf(0.125f); + context.leaf_nodes_canvas->drawRect(bounds, paint); + paint.setStyle(SkPaint::Style::kStroke_Style); +// paint.setAlphaf(1.0f); + paint.setAntiAlias(true); + paint.setColor(SkColors::kBlack); +// paint.setStrokeWidth(5.0f); + context.leaf_nodes_canvas->drawRect(bounds, paint); + context.leaf_nodes_canvas->drawLine( + SkPoint::Make(bounds.left(), bounds.top()), + SkPoint::Make(bounds.right(), bounds.bottom()), + paint); + context.leaf_nodes_canvas->drawLine( + SkPoint::Make(bounds.right(), bounds.top()), + SkPoint::Make(bounds.left(), bounds.bottom()), + paint); +} + +} // namespace flutter diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h new file mode 100644 index 0000000000000..8cad933c538f2 --- /dev/null +++ b/flow/layers/display_list_layer.h @@ -0,0 +1,46 @@ +// 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_FLOW_LAYERS_DISPLAY_LIST_LAYER_H_ +#define FLUTTER_FLOW_LAYERS_DISPLAY_LIST_LAYER_H_ + +#include + +#include "flutter/flow/layers/layer.h" +#include "flutter/flow/raster_cache.h" +#include "flutter/flow/skia_gpu_object.h" + +namespace flutter { + +class DisplayListLayer : public Layer { + public: + DisplayListLayer(const SkPoint& offset, + const SkRect& cull_rect, + const SkRect& draw_rect, + bool is_complex, + bool will_change); + +#ifdef FLUTTER_ENABLE_DIFF_CONTEXT + + void Diff(DiffContext* context, const Layer* old_layer) override; + +#endif // FLUTTER_ENABLE_DIFF_CONTEXT + + void Preroll(PrerollContext* frame, const SkMatrix& matrix) override; + + void Paint(PaintContext& context) const override; + + private: + SkPoint offset_; + SkRect cull_rect_; + SkRect draw_rect_; + bool is_complex_ = false; + bool will_change_ = false; + + FML_DISALLOW_COPY_AND_ASSIGN(DisplayListLayer); +}; + +} // namespace flutter + +#endif // FLUTTER_FLOW_LAYERS_DISPLAY_LIST_LAYER_H_ diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 5ad4693597d5d..d843384d2286a 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -706,12 +706,40 @@ class SceneBuilder extends NativeFieldWrapperClass2 { bool willChangeHint = false, }) { final int hints = (isComplexHint ? 1 : 0) | (willChangeHint ? 2 : 0); - _addPicture(offset.dx, offset.dy, picture, hints); + if (picture is _SkiaPicture) { + _addPicture(offset.dx, offset.dy, picture, hints); + } else { + _DisplayListPicture dlPicture = picture as _DisplayListPicture; + _addDisplayList( + offset.dx, offset.dy, + dlPicture._cullRect!.left, dlPicture._cullRect!.top, dlPicture._cullRect!.right, dlPicture._cullRect!.bottom, + dlPicture._drawBounds!.left, dlPicture._drawBounds!.top, dlPicture._drawBounds!.right, dlPicture._drawBounds!.bottom, + dlPicture._ops!, dlPicture._data!, dlPicture._objData!, + hints, + ); + } } void _addPicture(double dx, double dy, Picture picture, int hints) native 'SceneBuilder_addPicture'; + void _addDisplayList( + double dx, + double dy, + double cullLeft, + double cullTop, + double cullRight, + double cullBottom, + double drawLeft, + double drawTop, + double drawRight, + double drawBottom, + Uint8List ops, + ByteData data, + List objects, + int hints, + ) native 'SceneBuilder_addDisplayList'; + /// Adds a backend texture to the scene. /// /// The texture is scaled to the given size and rasterized at the given offset. diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 4acf0a3a1515c..6e29e52624efa 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -10,6 +10,7 @@ #include "flutter/flow/layers/clip_rrect_layer.h" #include "flutter/flow/layers/color_filter_layer.h" #include "flutter/flow/layers/container_layer.h" +#include "flutter/flow/layers/display_list_layer.h" #include "flutter/flow/layers/image_filter_layer.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/layers/layer_tree.h" @@ -59,6 +60,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, SceneBuilder); V(SceneBuilder, addPlatformView) \ V(SceneBuilder, addRetained) \ V(SceneBuilder, addPicture) \ + V(SceneBuilder, addDisplayList) \ V(SceneBuilder, addTexture) \ V(SceneBuilder, addPerformanceOverlay) \ V(SceneBuilder, setRasterizerTracingThreshold) \ @@ -282,6 +284,29 @@ void SceneBuilder::addPicture(double dx, AddLayer(std::move(layer)); } +void SceneBuilder::addDisplayList(double dx, + double dy, + double cullLeft, + double cullTop, + double cullRight, + double cullBottom, + double drawLeft, + double drawTop, + double drawRight, + double drawBottom, + Dart_Handle ops, + Dart_Handle data, + Dart_Handle objects, + int hints) { + auto layer = std::make_unique( + SkPoint::Make(dx, dy), + SkRect::MakeLTRB(cullLeft, cullTop, cullRight, cullBottom), + SkRect::MakeLTRB(drawLeft, drawTop, drawRight, drawBottom), + !!(hints & 1), !!(hints & 2)); + // ops.Release(); + AddLayer(std::move(layer)); +} + void SceneBuilder::addTexture(double dx, double dy, double width, diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h index 70d37f6123559..21cb0c08a52c4 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -103,6 +103,21 @@ class SceneBuilder : public RefCountedDartWrappable { void addPicture(double dx, double dy, Picture* picture, int hints); + void addDisplayList(double dx, + double dy, + double cullLeft, + double cullTop, + double cullRight, + double cullBottom, + double drawLeft, + double drawTop, + double drawRight, + double drawBottom, + Dart_Handle ops, + Dart_Handle data, + Dart_Handle objects, + int hints); + void addTexture(double dx, double dy, double width, diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 42df63d532386..a4ec4e48ed402 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3856,6 +3856,9 @@ enum ClipOp { intersect, } +/// A flag to enable use of the new DisplayList format for Picture objects. +bool useDisplayListPictures = true; + /// An interface for recording graphical operations. /// /// [Canvas] objects are used in creating [Picture] objects, which can @@ -3873,7 +3876,7 @@ enum ClipOp { /// /// The current transform and clip can be saved and restored using the stack /// managed by the [save], [saveLayer], and [restore] methods. -class Canvas extends NativeFieldWrapperClass2 { +abstract class Canvas { /// Creates a canvas for recording graphical operations into the /// given picture recorder. /// @@ -3886,25 +3889,11 @@ class Canvas extends NativeFieldWrapperClass2 { /// /// To end the recording, call [PictureRecorder.endRecording] on the /// given recorder. - @pragma('vm:entry-point') - Canvas(PictureRecorder recorder, [ Rect? cullRect ]) : assert(recorder != null) { - if (recorder.isRecording) - throw ArgumentError('"recorder" must not already be associated with another Canvas.'); - _recorder = recorder; - _recorder!._canvas = this; - cullRect ??= Rect.largest; - _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom); + factory Canvas(PictureRecorder recorder, [ Rect? cullRect ]) { + return useDisplayListPictures + ? _DisplayListCanvas(recorder, cullRect) + : _SkiaCanvas(recorder, cullRect); } - void _constructor(PictureRecorder recorder, - double left, - double top, - double right, - double bottom) native 'Canvas_constructor'; - - // The underlying Skia SkCanvas is owned by the PictureRecorder used to create this Canvas. - // The Canvas holds a reference to the PictureRecorder to prevent the recorder from being - // garbage collected until PictureRecorder.endRecording is called. - PictureRecorder? _recorder; /// Saves a copy of the current transform and clip on the save stack. /// @@ -3914,7 +3903,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// /// * [saveLayer], which does the same thing but additionally also groups the /// commands done until the matching [restore]. - void save() native 'Canvas_save'; + void save(); /// Saves a copy of the current transform and clip on the save stack, and then /// creates a new group which subsequent calls will become a part of. When the @@ -4025,24 +4014,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// for subsequent commands. /// * [BlendMode], which discusses the use of [Paint.blendMode] with /// [saveLayer]. - void saveLayer(Rect? bounds, Paint paint) { - assert(paint != null); - if (bounds == null) { - _saveLayerWithoutBounds(paint._objects, paint._data); - } else { - assert(_rectIsValid(bounds)); - _saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, - paint._objects, paint._data); - } - } - void _saveLayerWithoutBounds(List? paintObjects, ByteData paintData) - native 'Canvas_saveLayerWithoutBounds'; - void _saveLayer(double left, - double top, - double right, - double bottom, - List? paintObjects, - ByteData paintData) native 'Canvas_saveLayer'; + void saveLayer(Rect? bounds, Paint paint); /// Pops the current save stack, if there is anything to pop. /// Otherwise, does nothing. @@ -4051,7 +4023,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// /// If the state was pushed with with [saveLayer], then this call will also /// cause the new layer to be composited into the previous layer. - void restore() native 'Canvas_restore'; + void restore(); /// Returns the number of items on the save stack, including the /// initial state. This means it returns 1 for a clean canvas, and @@ -4059,11 +4031,11 @@ class Canvas extends NativeFieldWrapperClass2 { /// each matching call to [restore] decrements it. /// /// This number cannot go below 1. - int getSaveCount() native 'Canvas_getSaveCount'; + int getSaveCount(); /// Add a translation to the current transform, shifting the coordinate space /// horizontally by the first argument and vertically by the second argument. - void translate(double dx, double dy) native 'Canvas_translate'; + void translate(double dx, double dy); /// Add an axis-aligned scale to the current transform, scaling by the first /// argument in the horizontal direction and the second in the vertical @@ -4071,28 +4043,20 @@ class Canvas extends NativeFieldWrapperClass2 { /// /// If [sy] is unspecified, [sx] will be used for the scale in both /// directions. - void scale(double sx, [double? sy]) => _scale(sx, sy ?? sx); - - void _scale(double sx, double sy) native 'Canvas_scale'; + void scale(double sx, [double? sy]); /// Add a rotation to the current transform. The argument is in radians clockwise. - void rotate(double radians) native 'Canvas_rotate'; + void rotate(double radians); /// Add an axis-aligned skew to the current transform, with the first argument /// being the horizontal skew in rise over run units clockwise around the /// origin, and the second argument being the vertical skew in rise over run /// units clockwise around the origin. - void skew(double sx, double sy) native 'Canvas_skew'; + void skew(double sx, double sy); /// Multiply the current transform by the specified 4⨉4 transformation matrix /// specified as a list of values in column-major order. - void transform(Float64List matrix4) { - assert(matrix4 != null); - if (matrix4.length != 16) - throw ArgumentError('"matrix4" must have 16 entries.'); - _transform(matrix4); - } - void _transform(Float64List matrix4) native 'Canvas_transform'; + void transform(Float64List matrix4); /// Reduces the clip region to the intersection of the current clip and the /// given rectangle. @@ -4105,18 +4069,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// /// Use [ClipOp.difference] to subtract the provided rectangle from the /// current clip. - void clipRect(Rect rect, { ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true }) { - assert(_rectIsValid(rect)); - assert(clipOp != null); - assert(doAntiAlias != null); - _clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index, doAntiAlias); - } - void _clipRect(double left, - double top, - double right, - double bottom, - int clipOp, - bool doAntiAlias) native 'Canvas_clipRect'; + void clipRect(Rect rect, { ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true }); /// Reduces the clip region to the intersection of the current clip and the /// given rounded rectangle. @@ -4126,12 +4079,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// If multiple draw commands intersect with the clip boundary, this can result /// in incorrect blending at the clip boundary. See [saveLayer] for a /// discussion of how to address that and some examples of using [clipRRect]. - void clipRRect(RRect rrect, {bool doAntiAlias = true}) { - assert(_rrectIsValid(rrect)); - assert(doAntiAlias != null); - _clipRRect(rrect._value32, doAntiAlias); - } - void _clipRRect(Float32List rrect, bool doAntiAlias) native 'Canvas_clipRRect'; + void clipRRect(RRect rrect, {bool doAntiAlias = true}); /// Reduces the clip region to the intersection of the current clip and the /// given [Path]. @@ -4142,122 +4090,50 @@ class Canvas extends NativeFieldWrapperClass2 { /// multiple draw commands intersect with the clip boundary, this can result /// in incorrect blending at the clip boundary. See [saveLayer] for a /// discussion of how to address that. - void clipPath(Path path, {bool doAntiAlias = true}) { - assert(path != null); // path is checked on the engine side - assert(doAntiAlias != null); - _clipPath(path, doAntiAlias); - } - void _clipPath(Path path, bool doAntiAlias) native 'Canvas_clipPath'; + void clipPath(Path path, {bool doAntiAlias = true}); /// Paints the given [Color] onto the canvas, applying the given /// [BlendMode], with the given color being the source and the background /// being the destination. - void drawColor(Color color, BlendMode blendMode) { - assert(color != null); - assert(blendMode != null); - _drawColor(color.value, blendMode.index); - } - void _drawColor(int color, int blendMode) native 'Canvas_drawColor'; + void drawColor(Color color, BlendMode blendMode); /// Draws a line between the given points using the given paint. The line is /// stroked, the value of the [Paint.style] is ignored for this call. /// /// The `p1` and `p2` arguments are interpreted as offsets from the origin. - void drawLine(Offset p1, Offset p2, Paint paint) { - assert(_offsetIsValid(p1)); - assert(_offsetIsValid(p2)); - assert(paint != null); - _drawLine(p1.dx, p1.dy, p2.dx, p2.dy, paint._objects, paint._data); - } - void _drawLine(double x1, - double y1, - double x2, - double y2, - List? paintObjects, - ByteData paintData) native 'Canvas_drawLine'; + void drawLine(Offset p1, Offset p2, Paint paint); /// Fills the canvas with the given [Paint]. /// /// To fill the canvas with a solid color and blend mode, consider /// [drawColor] instead. - void drawPaint(Paint paint) { - assert(paint != null); - _drawPaint(paint._objects, paint._data); - } - void _drawPaint(List? paintObjects, ByteData paintData) native 'Canvas_drawPaint'; + void drawPaint(Paint paint); /// Draws a rectangle with the given [Paint]. Whether the rectangle is filled /// or stroked (or both) is controlled by [Paint.style]. - void drawRect(Rect rect, Paint paint) { - assert(_rectIsValid(rect)); - assert(paint != null); - _drawRect(rect.left, rect.top, rect.right, rect.bottom, - paint._objects, paint._data); - } - void _drawRect(double left, - double top, - double right, - double bottom, - List? paintObjects, - ByteData paintData) native 'Canvas_drawRect'; + void drawRect(Rect rect, Paint paint); /// Draws a rounded rectangle with the given [Paint]. Whether the rectangle is /// filled or stroked (or both) is controlled by [Paint.style]. - void drawRRect(RRect rrect, Paint paint) { - assert(_rrectIsValid(rrect)); - assert(paint != null); - _drawRRect(rrect._value32, paint._objects, paint._data); - } - void _drawRRect(Float32List rrect, - List? paintObjects, - ByteData paintData) native 'Canvas_drawRRect'; + void drawRRect(RRect rrect, Paint paint); /// Draws a shape consisting of the difference between two rounded rectangles /// with the given [Paint]. Whether this shape is filled or stroked (or both) /// is controlled by [Paint.style]. /// /// This shape is almost but not quite entirely unlike an annulus. - void drawDRRect(RRect outer, RRect inner, Paint paint) { - assert(_rrectIsValid(outer)); - assert(_rrectIsValid(inner)); - assert(paint != null); - _drawDRRect(outer._value32, inner._value32, paint._objects, paint._data); - } - void _drawDRRect(Float32List outer, - Float32List inner, - List? paintObjects, - ByteData paintData) native 'Canvas_drawDRRect'; + void drawDRRect(RRect outer, RRect inner, Paint paint); /// Draws an axis-aligned oval that fills the given axis-aligned rectangle /// with the given [Paint]. Whether the oval is filled or stroked (or both) is /// controlled by [Paint.style]. - void drawOval(Rect rect, Paint paint) { - assert(_rectIsValid(rect)); - assert(paint != null); - _drawOval(rect.left, rect.top, rect.right, rect.bottom, - paint._objects, paint._data); - } - void _drawOval(double left, - double top, - double right, - double bottom, - List? paintObjects, - ByteData paintData) native 'Canvas_drawOval'; + void drawOval(Rect rect, Paint paint); /// Draws a circle centered at the point given by the first argument and /// that has the radius given by the second argument, with the [Paint] given in /// the third argument. Whether the circle is filled or stroked (or both) is /// controlled by [Paint.style]. - void drawCircle(Offset c, double radius, Paint paint) { - assert(_offsetIsValid(c)); - assert(paint != null); - _drawCircle(c.dx, c.dy, radius, paint._objects, paint._data); - } - void _drawCircle(double x, - double y, - double radius, - List? paintObjects, - ByteData paintData) native 'Canvas_drawCircle'; + void drawCircle(Offset c, double radius, Paint paint); /// Draw an arc scaled to fit inside the given rectangle. /// @@ -4270,50 +4146,18 @@ class Canvas extends NativeFieldWrapperClass2 { /// not closed, forming a circle segment. /// /// This method is optimized for drawing arcs and should be faster than [Path.arcTo]. - void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) { - assert(_rectIsValid(rect)); - assert(paint != null); - _drawArc(rect.left, rect.top, rect.right, rect.bottom, startAngle, - sweepAngle, useCenter, paint._objects, paint._data); - } - void _drawArc(double left, - double top, - double right, - double bottom, - double startAngle, - double sweepAngle, - bool useCenter, - List? paintObjects, - ByteData paintData) native 'Canvas_drawArc'; + void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint); /// Draws the given [Path] with the given [Paint]. /// /// Whether this shape is filled or stroked (or both) is controlled by /// [Paint.style]. If the path is filled, then sub-paths within it are /// implicitly closed (see [Path.close]). - void drawPath(Path path, Paint paint) { - assert(path != null); // path is checked on the engine side - assert(paint != null); - _drawPath(path, paint._objects, paint._data); - } - void _drawPath(Path path, - List? paintObjects, - ByteData paintData) native 'Canvas_drawPath'; + void drawPath(Path path, Paint paint); /// Draws the given [Image] into the canvas with its top-left corner at the /// given [Offset]. The image is composited into the canvas using the given [Paint]. - void drawImage(Image image, Offset offset, Paint paint) { - assert(image != null); // image is checked on the engine side - assert(_offsetIsValid(offset)); - assert(paint != null); - _drawImage(image._image, offset.dx, offset.dy, paint._objects, paint._data, paint.filterQuality.index); - } - void _drawImage(_Image image, - double x, - double y, - List? paintObjects, - ByteData paintData, - int filterQualityIndex) native 'Canvas_drawImage'; + void drawImage(Image image, Offset offset, Paint paint); /// Draws the subset of the given image described by the `src` argument into /// the canvas in the axis-aligned rectangle given by the `dst` argument. @@ -4324,36 +4168,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// Multiple calls to this method with different arguments (from the same /// image) can be batched into a single call to [drawAtlas] to improve /// performance. - void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { - assert(image != null); // image is checked on the engine side - assert(_rectIsValid(src)); - assert(_rectIsValid(dst)); - assert(paint != null); - _drawImageRect(image._image, - src.left, - src.top, - src.right, - src.bottom, - dst.left, - dst.top, - dst.right, - dst.bottom, - paint._objects, - paint._data, - paint.filterQuality.index); - } - void _drawImageRect(_Image image, - double srcLeft, - double srcTop, - double srcRight, - double srcBottom, - double dstLeft, - double dstTop, - double dstRight, - double dstBottom, - List? paintObjects, - ByteData paintData, - int filterQualityIndex) native 'Canvas_drawImageRect'; + void drawImageRect(Image image, Rect src, Rect dst, Paint paint); /// Draws the given [Image] into the canvas using the given [Paint]. /// @@ -4368,44 +4183,11 @@ class Canvas extends NativeFieldWrapperClass2 { /// five regions are drawn by stretching them to fit such that they exactly /// cover the destination rectangle while maintaining their relative /// positions. - void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { - assert(image != null); // image is checked on the engine side - assert(_rectIsValid(center)); - assert(_rectIsValid(dst)); - assert(paint != null); - _drawImageNine(image._image, - center.left, - center.top, - center.right, - center.bottom, - dst.left, - dst.top, - dst.right, - dst.bottom, - paint._objects, - paint._data, - paint.filterQuality.index); - } - void _drawImageNine(_Image image, - double centerLeft, - double centerTop, - double centerRight, - double centerBottom, - double dstLeft, - double dstTop, - double dstRight, - double dstBottom, - List? paintObjects, - ByteData paintData, - int filterQualityIndex) native 'Canvas_drawImageNine'; + void drawImageNine(Image image, Rect center, Rect dst, Paint paint); /// Draw the given picture onto the canvas. To create a picture, see /// [PictureRecorder]. - void drawPicture(Picture picture) { - assert(picture != null); // picture is checked on the engine side - _drawPicture(picture); - } - void _drawPicture(Picture picture) native 'Canvas_drawPicture'; + void drawPicture(Picture picture); /// Draws the text in the given [Paragraph] into this canvas at the given /// [Offset]. @@ -4427,11 +4209,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// If the text is centered, the centering axis will be at the position /// described by adding half of the [ParagraphConstraints.width] given to /// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate. - void drawParagraph(Paragraph paragraph, Offset offset) { - assert(paragraph != null); - assert(_offsetIsValid(offset)); - paragraph._paint(this, offset.dx, offset.dy); - } + void drawParagraph(Paragraph paragraph, Offset offset); /// Draws a sequence of points according to the given [PointMode]. /// @@ -4441,12 +4219,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// /// * [drawRawPoints], which takes `points` as a [Float32List] rather than a /// [List]. - void drawPoints(PointMode pointMode, List points, Paint paint) { - assert(pointMode != null); - assert(points != null); - assert(paint != null); - _drawPoints(paint._objects, paint._data, pointMode.index, _encodePointList(points)); - } + void drawPoints(PointMode pointMode, List points, Paint paint); /// Draws a sequence of points according to the given [PointMode]. /// @@ -4457,19 +4230,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// /// * [drawPoints], which takes `points` as a [List] rather than a /// [List]. - void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) { - assert(pointMode != null); - assert(points != null); - assert(paint != null); - if (points.length % 2 != 0) - throw ArgumentError('"points" must have an even number of values.'); - _drawPoints(paint._objects, paint._data, pointMode.index, points); - } - - void _drawPoints(List? paintObjects, - ByteData paintData, - int pointMode, - Float32List points) native 'Canvas_drawPoints'; + void drawRawPoints(PointMode pointMode, Float32List points, Paint paint); /// Draws the set of [Vertices] onto the canvas. /// @@ -4479,17 +4240,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// * [new Vertices], which creates a set of vertices to draw on the canvas. /// * [Vertices.raw], which creates the vertices using typed data lists /// rather than unencoded lists. - void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) { - - assert(vertices != null); // vertices is checked on the engine side - assert(paint != null); - assert(blendMode != null); - _drawVertices(vertices, blendMode.index, paint._objects, paint._data); - } - void _drawVertices(Vertices vertices, - int blendMode, - List? paintObjects, - ByteData paintData) native 'Canvas_drawVertices'; + void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint); /// Draws many parts of an image - the [atlas] - onto the canvas. /// @@ -4624,49 +4375,7 @@ class Canvas extends NativeFieldWrapperClass2 { List? colors, BlendMode? blendMode, Rect? cullRect, - Paint paint) { - assert(atlas != null); // atlas is checked on the engine side - assert(transforms != null); - assert(rects != null); - assert(colors == null || colors.isEmpty || blendMode != null); - assert(paint != null); - - final int rectCount = rects.length; - if (transforms.length != rectCount) - throw ArgumentError('"transforms" and "rects" lengths must match.'); - if (colors != null && colors.isNotEmpty && colors.length != rectCount) - throw ArgumentError('If non-null, "colors" length must match that of "transforms" and "rects".'); - - final Float32List rstTransformBuffer = Float32List(rectCount * 4); - final Float32List rectBuffer = Float32List(rectCount * 4); - - for (int i = 0; i < rectCount; ++i) { - final int index0 = i * 4; - final int index1 = index0 + 1; - final int index2 = index0 + 2; - final int index3 = index0 + 3; - final RSTransform rstTransform = transforms[i]; - final Rect rect = rects[i]; - assert(_rectIsValid(rect)); - rstTransformBuffer[index0] = rstTransform.scos; - rstTransformBuffer[index1] = rstTransform.ssin; - rstTransformBuffer[index2] = rstTransform.tx; - rstTransformBuffer[index3] = rstTransform.ty; - rectBuffer[index0] = rect.left; - rectBuffer[index1] = rect.top; - rectBuffer[index2] = rect.right; - rectBuffer[index3] = rect.bottom; - } - - final Int32List? colorBuffer = (colors == null || colors.isEmpty) ? null : _encodeColorList(colors); - final Float32List? cullRectBuffer = cullRect?._value32; - final int qualityIndex = paint.filterQuality.index; - - _drawAtlas( - paint._objects, paint._data, qualityIndex, atlas._image, rstTransformBuffer, rectBuffer, - colorBuffer, (blendMode ?? BlendMode.src).index, cullRectBuffer - ); - } + Paint paint); /// Draws many parts of an image - the [atlas] - onto the canvas. /// @@ -4815,37 +4524,7 @@ class Canvas extends NativeFieldWrapperClass2 { Int32List? colors, BlendMode? blendMode, Rect? cullRect, - Paint paint) { - assert(atlas != null); // atlas is checked on the engine side - assert(rstTransforms != null); - assert(rects != null); - assert(colors == null || blendMode != null); - assert(paint != null); - - final int rectCount = rects.length; - if (rstTransforms.length != rectCount) - throw ArgumentError('"rstTransforms" and "rects" lengths must match.'); - if (rectCount % 4 != 0) - throw ArgumentError('"rstTransforms" and "rects" lengths must be a multiple of four.'); - if (colors != null && colors.length * 4 != rectCount) - throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".'); - final int qualityIndex = paint.filterQuality.index; - - _drawAtlas( - paint._objects, paint._data, qualityIndex, atlas._image, rstTransforms, rects, - colors, (blendMode ?? BlendMode.src).index, cullRect?._value32 - ); - } - - void _drawAtlas(List? paintObjects, - ByteData paintData, - int filterQualityIndex, - _Image atlas, - Float32List rstTransforms, - Float32List rects, - Int32List? colors, - int blendMode, - Float32List? cullRect) native 'Canvas_drawAtlas'; + Paint paint); /// Draws a shadow for a [Path] representing the given material elevation. /// @@ -4853,16 +4532,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// is not opaque. /// /// The arguments must not be null. - void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { - assert(path != null); // path is checked on the engine side - assert(color != null); - assert(transparentOccluder != null); - _drawShadow(path, color.value, elevation, transparentOccluder); - } - void _drawShadow(Path path, - int color, - double elevation, - bool transparentOccluder) native 'Canvas_drawShadow'; + void drawShadow(Path path, Color color, double elevation, bool transparentOccluder); } /// An object representing a sequence of recorded graphical operations. @@ -4872,15 +4542,7 @@ class Canvas extends NativeFieldWrapperClass2 { /// A [Picture] can be placed in a [Scene] using a [SceneBuilder], via /// the [SceneBuilder.addPicture] method. A [Picture] can also be /// drawn into a [Canvas], using the [Canvas.drawPicture] method. -@pragma('vm:entry-point') -class Picture extends NativeFieldWrapperClass2 { - /// This class is created by the engine, and should not be instantiated - /// or extended directly. - /// - /// To create a [Picture], use a [PictureRecorder]. - @pragma('vm:entry-point') - Picture._(); - +abstract class Picture { /// Creates an image from this picture. /// /// The returned image will be `width` pixels wide and `height` pixels high. @@ -4889,44 +4551,32 @@ class Picture extends NativeFieldWrapperClass2 { /// /// Although the image is returned synchronously, the picture is actually /// rasterized the first time the image is drawn and then cached. - Future toImage(int width, int height) { - if (width <= 0 || height <= 0) - throw Exception('Invalid image dimensions.'); - return _futurize( - (_Callback callback) => _toImage(width, height, (_Image? image) { - if (image == null) { - callback(null); - } else { - callback(Image._(image)); - } - }), - ); - } - - String? _toImage(int width, int height, _Callback<_Image?> callback) native 'Picture_toImage'; + Future toImage(int width, int height); /// Release the resources used by this object. The object is no longer usable /// after this method is called. - void dispose() native 'Picture_dispose'; + void dispose(); /// Returns the approximate number of bytes allocated for this object. /// /// The actual size of this picture may be larger, particularly if it contains /// references to image or other large objects. - int get approximateBytesUsed native 'Picture_GetAllocationSize'; + int get approximateBytesUsed; } /// Records a [Picture] containing a sequence of graphical operations. /// /// To begin recording, construct a [Canvas] to record the commands. /// To end recording, use the [PictureRecorder.endRecording] method. -class PictureRecorder extends NativeFieldWrapperClass2 { +abstract class PictureRecorder { /// Creates a new idle PictureRecorder. To associate it with a /// [Canvas] and begin recording, pass this [PictureRecorder] to the /// [Canvas] constructor. - @pragma('vm:entry-point') - PictureRecorder() { _constructor(); } - void _constructor() native 'PictureRecorder_constructor'; + factory PictureRecorder() { + return useDisplayListPictures + ? _DisplayListPictureRecorder() + : _SkiaPictureRecorder(); + } /// Whether this object is currently recording commands. /// @@ -4935,26 +4585,1364 @@ class PictureRecorder extends NativeFieldWrapperClass2 { /// call to [endRecording], and false if either this /// [PictureRecorder] has not yet been associated with a [Canvas], /// or the [endRecording] method has already been called. - bool get isRecording => _canvas != null; + bool get isRecording; /// Finishes recording graphical operations. /// /// Returns a picture containing the graphical operations that have been /// recorded thus far. After calling this function, both the picture recorder /// and the canvas objects are invalid and cannot be used further. - Picture endRecording() { - if (_canvas == null) - throw StateError('PictureRecorder did not start recording.'); - final Picture picture = Picture._(); - _endRecording(picture); - _canvas!._recorder = null; - _canvas = null; - return picture; + Picture endRecording(); +} + +class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { + @pragma('vm:entry-point') + _SkiaCanvas(PictureRecorder recorder, [ Rect? cullRect ]) : assert(recorder != null) { + if (recorder.isRecording) + throw ArgumentError('"recorder" must not already be associated with another Canvas.'); + _recorder = recorder as _SkiaPictureRecorder; + _recorder!._canvas = this; + cullRect ??= Rect.largest; + _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom); } + void _constructor(PictureRecorder recorder, + double left, + double top, + double right, + double bottom) native 'Canvas_constructor'; - void _endRecording(Picture outPicture) native 'PictureRecorder_endRecording'; + _SkiaPictureRecorder? _recorder; + + @override + void save() native 'Canvas_save'; + + @override + void saveLayer(Rect? bounds, Paint paint) { + assert(paint != null); + if (bounds == null) { + _saveLayerWithoutBounds(paint._objects, paint._data); + } else { + assert(_rectIsValid(bounds)); + _saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, + paint._objects, paint._data); + } + } + void _saveLayerWithoutBounds(List? paintObjects, ByteData paintData) + native 'Canvas_saveLayerWithoutBounds'; + void _saveLayer(double left, + double top, + double right, + double bottom, + List? paintObjects, + ByteData paintData) native 'Canvas_saveLayer'; + + @override + void restore() native 'Canvas_restore'; + + @override + int getSaveCount() native 'Canvas_getSaveCount'; + + @override + void translate(double dx, double dy) native 'Canvas_translate'; + + @override + void scale(double sx, [double? sy]) => _scale(sx, sy ?? sx); + + void _scale(double sx, double sy) native 'Canvas_scale'; + + @override + void rotate(double radians) native 'Canvas_rotate'; + + @override + void skew(double sx, double sy) native 'Canvas_skew'; + + @override + void transform(Float64List matrix4) { + assert(matrix4 != null); + if (matrix4.length != 16) + throw ArgumentError('"matrix4" must have 16 entries.'); + _transform(matrix4); + } + void _transform(Float64List matrix4) native 'Canvas_transform'; + + @override + void clipRect(Rect rect, { ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true }) { + assert(_rectIsValid(rect)); + assert(clipOp != null); + assert(doAntiAlias != null); + _clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index, doAntiAlias); + } + void _clipRect(double left, + double top, + double right, + double bottom, + int clipOp, + bool doAntiAlias) native 'Canvas_clipRect'; + + @override + void clipRRect(RRect rrect, {bool doAntiAlias = true}) { + assert(_rrectIsValid(rrect)); + assert(doAntiAlias != null); + _clipRRect(rrect._value32, doAntiAlias); + } + void _clipRRect(Float32List rrect, bool doAntiAlias) native 'Canvas_clipRRect'; + + @override + void clipPath(Path path, {bool doAntiAlias = true}) { + assert(path != null); // path is checked on the engine side + assert(doAntiAlias != null); + _clipPath(path, doAntiAlias); + } + void _clipPath(Path path, bool doAntiAlias) native 'Canvas_clipPath'; + + @override + void drawColor(Color color, BlendMode blendMode) { + assert(color != null); + assert(blendMode != null); + _drawColor(color.value, blendMode.index); + } + void _drawColor(int color, int blendMode) native 'Canvas_drawColor'; + + @override + void drawLine(Offset p1, Offset p2, Paint paint) { + assert(_offsetIsValid(p1)); + assert(_offsetIsValid(p2)); + assert(paint != null); + _drawLine(p1.dx, p1.dy, p2.dx, p2.dy, paint._objects, paint._data); + } + void _drawLine(double x1, + double y1, + double x2, + double y2, + List? paintObjects, + ByteData paintData) native 'Canvas_drawLine'; + + @override + void drawPaint(Paint paint) { + assert(paint != null); + _drawPaint(paint._objects, paint._data); + } + void _drawPaint(List? paintObjects, ByteData paintData) native 'Canvas_drawPaint'; + + @override + void drawRect(Rect rect, Paint paint) { + assert(_rectIsValid(rect)); + assert(paint != null); + _drawRect(rect.left, rect.top, rect.right, rect.bottom, + paint._objects, paint._data); + } + void _drawRect(double left, + double top, + double right, + double bottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawRect'; + + @override + void drawRRect(RRect rrect, Paint paint) { + assert(_rrectIsValid(rrect)); + assert(paint != null); + _drawRRect(rrect._value32, paint._objects, paint._data); + } + void _drawRRect(Float32List rrect, + List? paintObjects, + ByteData paintData) native 'Canvas_drawRRect'; + + @override + void drawDRRect(RRect outer, RRect inner, Paint paint) { + assert(_rrectIsValid(outer)); + assert(_rrectIsValid(inner)); + assert(paint != null); + _drawDRRect(outer._value32, inner._value32, paint._objects, paint._data); + } + void _drawDRRect(Float32List outer, + Float32List inner, + List? paintObjects, + ByteData paintData) native 'Canvas_drawDRRect'; + + @override + void drawOval(Rect rect, Paint paint) { + assert(_rectIsValid(rect)); + assert(paint != null); + _drawOval(rect.left, rect.top, rect.right, rect.bottom, + paint._objects, paint._data); + } + void _drawOval(double left, + double top, + double right, + double bottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawOval'; + + @override + void drawCircle(Offset c, double radius, Paint paint) { + assert(_offsetIsValid(c)); + assert(paint != null); + _drawCircle(c.dx, c.dy, radius, paint._objects, paint._data); + } + void _drawCircle(double x, + double y, + double radius, + List? paintObjects, + ByteData paintData) native 'Canvas_drawCircle'; + + @override + void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) { + assert(_rectIsValid(rect)); + assert(paint != null); + _drawArc(rect.left, rect.top, rect.right, rect.bottom, startAngle, + sweepAngle, useCenter, paint._objects, paint._data); + } + void _drawArc(double left, + double top, + double right, + double bottom, + double startAngle, + double sweepAngle, + bool useCenter, + List? paintObjects, + ByteData paintData) native 'Canvas_drawArc'; + + @override + void drawPath(Path path, Paint paint) { + assert(path != null); // path is checked on the engine side + assert(paint != null); + _drawPath(path, paint._objects, paint._data); + } + void _drawPath(Path path, + List? paintObjects, + ByteData paintData) native 'Canvas_drawPath'; + + @override + void drawImage(Image image, Offset offset, Paint paint) { + assert(image != null); // image is checked on the engine side + assert(_offsetIsValid(offset)); + assert(paint != null); + _drawImage(image._image, offset.dx, offset.dy, paint._objects, paint._data); + } + void _drawImage(_Image image, + double x, + double y, + List? paintObjects, + ByteData paintData) native 'Canvas_drawImage'; + + @override + void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { + assert(image != null); // image is checked on the engine side + assert(_rectIsValid(src)); + assert(_rectIsValid(dst)); + assert(paint != null); + _drawImageRect(image._image, + src.left, + src.top, + src.right, + src.bottom, + dst.left, + dst.top, + dst.right, + dst.bottom, + paint._objects, + paint._data); + } + void _drawImageRect(_Image image, + double srcLeft, + double srcTop, + double srcRight, + double srcBottom, + double dstLeft, + double dstTop, + double dstRight, + double dstBottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawImageRect'; + + @override + void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { + assert(image != null); // image is checked on the engine side + assert(_rectIsValid(center)); + assert(_rectIsValid(dst)); + assert(paint != null); + _drawImageNine(image._image, + center.left, + center.top, + center.right, + center.bottom, + dst.left, + dst.top, + dst.right, + dst.bottom, + paint._objects, + paint._data); + } + void _drawImageNine(_Image image, + double centerLeft, + double centerTop, + double centerRight, + double centerBottom, + double dstLeft, + double dstTop, + double dstRight, + double dstBottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawImageNine'; + + @override + void drawPicture(Picture picture) { + assert(picture != null); // picture is checked on the engine side + _drawPicture(picture); + } + void _drawPicture(Picture picture) native 'Canvas_drawPicture'; + + @override + void drawParagraph(Paragraph paragraph, Offset offset) { + assert(paragraph != null); + assert(_offsetIsValid(offset)); + paragraph._paint(this, offset.dx, offset.dy); + } + + @override + void drawPoints(PointMode pointMode, List points, Paint paint) { + assert(pointMode != null); + assert(points != null); + assert(paint != null); + _drawPoints(paint._objects, paint._data, pointMode.index, _encodePointList(points)); + } + + @override + void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) { + assert(pointMode != null); + assert(points != null); + assert(paint != null); + if (points.length % 2 != 0) + throw ArgumentError('"points" must have an even number of values.'); + _drawPoints(paint._objects, paint._data, pointMode.index, points); + } + + void _drawPoints(List? paintObjects, + ByteData paintData, + int pointMode, + Float32List points) native 'Canvas_drawPoints'; + + @override + void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) { + assert(vertices != null); // vertices is checked on the engine side + assert(paint != null); + assert(blendMode != null); + _drawVertices(vertices, blendMode.index, paint._objects, paint._data); + } + void _drawVertices(Vertices vertices, + int blendMode, + List? paintObjects, + ByteData paintData) native 'Canvas_drawVertices'; + + @override + void drawAtlas(Image atlas, + List transforms, + List rects, + List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { + assert(atlas != null); // atlas is checked on the engine side + assert(transforms != null); + assert(rects != null); + assert(colors == null || colors.isEmpty || blendMode != null); + assert(paint != null); + + final int rectCount = rects.length; + if (transforms.length != rectCount) + throw ArgumentError('"transforms" and "rects" lengths must match.'); + if (colors != null && colors.isNotEmpty && colors.length != rectCount) + throw ArgumentError('If non-null, "colors" length must match that of "transforms" and "rects".'); + + final Float32List rstTransformBuffer = Float32List(rectCount * 4); + final Float32List rectBuffer = Float32List(rectCount * 4); + + for (int i = 0; i < rectCount; ++i) { + final int index0 = i * 4; + final int index1 = index0 + 1; + final int index2 = index0 + 2; + final int index3 = index0 + 3; + final RSTransform rstTransform = transforms[i]; + final Rect rect = rects[i]; + assert(_rectIsValid(rect)); + rstTransformBuffer[index0] = rstTransform.scos; + rstTransformBuffer[index1] = rstTransform.ssin; + rstTransformBuffer[index2] = rstTransform.tx; + rstTransformBuffer[index3] = rstTransform.ty; + rectBuffer[index0] = rect.left; + rectBuffer[index1] = rect.top; + rectBuffer[index2] = rect.right; + rectBuffer[index3] = rect.bottom; + } + + final Int32List? colorBuffer = (colors == null || colors.isEmpty) ? null : _encodeColorList(colors); + final Float32List? cullRectBuffer = cullRect?._value32; + + _drawAtlas( + paint._objects, paint._data, atlas._image, rstTransformBuffer, rectBuffer, + colorBuffer, (blendMode ?? BlendMode.src).index, cullRectBuffer + ); + } + + @override + void drawRawAtlas(Image atlas, + Float32List rstTransforms, + Float32List rects, + Int32List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { + assert(atlas != null); // atlas is checked on the engine side + assert(rstTransforms != null); + assert(rects != null); + assert(colors == null || blendMode != null); + assert(paint != null); + + final int rectCount = rects.length; + if (rstTransforms.length != rectCount) + throw ArgumentError('"rstTransforms" and "rects" lengths must match.'); + if (rectCount % 4 != 0) + throw ArgumentError('"rstTransforms" and "rects" lengths must be a multiple of four.'); + if (colors != null && colors.length * 4 != rectCount) + throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".'); + + _drawAtlas( + paint._objects, paint._data, atlas._image, rstTransforms, rects, + colors, (blendMode ?? BlendMode.src).index, cullRect?._value32 + ); + } + + void _drawAtlas(List? paintObjects, + ByteData paintData, + _Image atlas, + Float32List rstTransforms, + Float32List rects, + Int32List? colors, + int blendMode, + Float32List? cullRect) native 'Canvas_drawAtlas'; + + @override + void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { + assert(path != null); // path is checked on the engine side + assert(color != null); + assert(transparentOccluder != null); + _drawShadow(path, color.value, elevation, transparentOccluder); + } + void _drawShadow(Path path, + int color, + double elevation, + bool transparentOccluder) native 'Canvas_drawShadow'; +} + +@pragma('vm:entry-point') +class _SkiaPicture extends NativeFieldWrapperClass2 implements Picture { + @pragma('vm:entry-point') + _SkiaPicture._(); + + @override + Future toImage(int width, int height) { + if (width <= 0 || height <= 0) + throw Exception('Invalid image dimensions.'); + return _futurize( + (_Callback callback) => _toImage(width, height, (_Image? image) { + if (image == null) { + callback(null); + } else { + callback(Image._(image)); + } + }), + ); + } + + String? _toImage(int width, int height, _Callback<_Image?> callback) native 'Picture_toImage'; + + @override + void dispose() native 'Picture_dispose'; + + @override + int get approximateBytesUsed native 'Picture_GetAllocationSize'; +} + +class _SkiaPictureRecorder extends NativeFieldWrapperClass2 implements PictureRecorder { + @pragma('vm:entry-point') + _SkiaPictureRecorder() { _constructor(); } + void _constructor() native 'PictureRecorder_constructor'; + + @override + bool get isRecording => _canvas != null; + + @override + Picture endRecording() { + if (_canvas == null) + throw StateError('PictureRecorder did not start recording.'); + final Picture picture = _SkiaPicture._(); + _endRecording(picture); + _canvas!._recorder = null; + _canvas = null; + return picture; + } + + void _endRecording(Picture outPicture) native 'PictureRecorder_endRecording'; + + _SkiaCanvas? _canvas; +} + +enum _CanvasOp { + setAA, + clearAA, + setInvertColors, + clearInvertColors, + setFillStyle, + setStrokeStyle, + + setCapsButt, + setCapsRound, + setCapsSquare, + setJoinsBevel, + setJoinsMiter, + setJoinsRound, + + setStrokeWidth, + setMiterLimit, + + setFilterQualityNearest, + setFilterQualityLinear, + setFilterQualityMipmap, + setFilterQualityCubic, + + setColor, + setBlendMode, + + setShader, + clearShader, + setColorFilter, + clearColorFilter, + setImageFilter, + clearImageFilter, + + clearMaskFilter, + setMaskFilterNormal, + setMaskFilterSolid, + setMaskFilterOuter, + setMaskFilterInner, + + save, + saveLayer, + saveLayerBounds, + restore, + + translate, + scale, + rotate, + skew, + transform, + + clipRect, + clipRectAA, + clipRectDiff, + clipRectAADiff, + clipRRect, + clipRRectAA, + clipPath, + clipPathAA, + + drawPaint, + drawColor, + + drawLine, + drawRect, + drawOval, + drawCircle, + drawRRect, + drawDRRect, + drawArc, + drawArcCenter, + drawPath, + + drawPoints, + drawLines, + drawPolygon, + + drawImage, + drawImageRect, + drawImageNine, + drawAtlas, + drawAtlasColored, + drawAtlasCulled, + drawAtlasColoredCulled, + + drawParagraph, + drawPicture, + drawShadow, + drawShadowOccluded, +} + +/// Local storage version of Canvas +class _DisplayListCanvas implements Canvas { + /// Make a Canvas2 + _DisplayListCanvas(PictureRecorder recorder, [Rect? cullRect]) + : _recorder = recorder as _DisplayListPictureRecorder, + _cullRect = cullRect ?? Rect.largest, + _minX = Rect._giantScalar, + _minY = Rect._giantScalar, + _maxX = -Rect._giantScalar, + _maxY = -Rect._giantScalar, + _ops = Uint8List(128), _numOps = 0, + _data = ByteData(128 * 4), _numDataBytes = 0, + _objData = [], + _saveCount = 0, + _lastPaintData = Paint() { + _recorder!._canvas = this; + } + + _DisplayListPictureRecorder? _recorder; + Rect _cullRect; + double _minX; + double _minY; + double _maxX; + double _maxY; + int _numOps; + Uint8List _ops; + int _numDataBytes; + ByteData _data; + List _objData; + int _saveCount; + + Rect get _drawBounds => Rect.fromLTRB(_minX, _minY, _maxX, _maxY); + + static const int _maxOpsDoubleSize = 1 << 20; + Uint8List _growOps(Uint8List src) { + Uint8List dst; + if (src.length <= _maxOpsDoubleSize) { + dst = Uint8List(src.length * 2); + } else { + dst = Uint8List(src.length + _maxOpsDoubleSize); + } + dst.replaceRange(0, src.length, src); + return dst; + } + + static const int _maxDataDoubleSize = 1 << 24; + ByteData _growData(ByteData src) { + ByteData dst; + if (src.lengthInBytes <= _maxDataDoubleSize) { + dst = ByteData(src.lengthInBytes * 2); + } else { + dst = ByteData(src.lengthInBytes + _maxDataDoubleSize); + } + for (int i = 0; i < src.lengthInBytes; i += 4) { + dst.setInt32(i, src.getInt32(i)); + } + return dst; + } + + Uint8List _trimmedOps() { + final Uint8List _trimmed = Uint8List(_numOps); + _trimmed.setRange(0, _numOps, _ops); + return UnmodifiableUint8ListView(_trimmed); + } + + ByteData _trimmedData() { + final ByteData _trimmed = ByteData(_numDataBytes); + for (int i = 0; i < _numDataBytes; i += 4) { + _trimmed.setInt32(i, _data.getInt32(i)); + } + return UnmodifiableByteDataView(_trimmed); + } + + List _trimmedObjects() { + return List.unmodifiable(_objData); + } + + void _addOp(_CanvasOp op) { + _addByte(op.index); + } + + void _addByte(int byte) { + if (_numOps + 1 > _ops.lengthInBytes) { + _ops = _growOps(_ops); + } + _ops[_numOps++] = byte; + } + + void _addInt(int value) { + if (_numDataBytes + 4 > _data.lengthInBytes) { + _data = _growData(_data); + } + _data.setInt32(_numDataBytes, value); + _numDataBytes += 4; + } + + void _addDouble(double value) { + if (_numDataBytes + 4 > _data.lengthInBytes) { + _data = _growData(_data); + } + _data.setFloat32(_numDataBytes, value); + _numDataBytes += 4; + } + + void _addDouble2(double v1, double v2) { + if (_numDataBytes + 8 > _data.lengthInBytes) { + _data = _growData(_data); + } + _data.setFloat32(_numDataBytes, v1); + _numDataBytes += 4; + _data.setFloat32(_numDataBytes, v2); + _numDataBytes += 4; + } + + void _addDouble4(double v1, double v2, double v3, double v4) { + if (_numDataBytes + 16 > _data.lengthInBytes) { + _data = _growData(_data); + } + _data.setFloat32(_numDataBytes, v1); + _numDataBytes += 4; + _data.setFloat32(_numDataBytes, v2); + _numDataBytes += 4; + _data.setFloat32(_numDataBytes, v3); + _numDataBytes += 4; + _data.setFloat32(_numDataBytes, v4); + _numDataBytes += 4; + } + + void _addOffset(Offset offset) { + _addDouble2(offset.dx, offset.dy); + } + + void _addRect(Rect r) { + _addDouble4(r.left, r.top, r.right, r.bottom); + } + + void _addRRect(RRect rrect) { + _addDouble4(rrect.left, rrect.top, rrect.right, rrect.bottom); + _addDouble4(rrect.tlRadiusX, rrect.tlRadiusY, rrect.trRadiusX, rrect.trRadiusY); + _addDouble4(rrect.blRadiusX, rrect.blRadiusY, rrect.brRadiusX, rrect.brRadiusY); + } + + void _addInt32List(Int32List data) { + _objData.add(data); + } + + void _addFloat32List(Float32List data) { + _objData.add(data); + } + + void _addFloat64List(Float64List data) { + _objData.add(data); + } + + void _addImageData(Image image) { + _objData.add(image._image); + } + + void _addPathData(Path path) { + _objData.add(path); + } + + void _addVertices(Vertices vertices) { + _objData.add(vertices); + } + + void _addPicture(Picture picture) { + _objData.add(picture); + } + + void _addShader(Shader shader) { + _objData.add(shader); + } + + void _addColorFilter(_ColorFilter filter) { + _objData.add(filter); + } + + void _addImageFilter(_ImageFilter filter) { + _objData.add(filter); + } + + void _addPointToBounds(double x, double y) { + if (_minX > x) + _minX = x; + if (_minY > y) + _minY = y; + if (_maxX < x) + _maxX = x; + if (_maxY < y) + _maxY = y; + } + + void _addLTRBToBounds(double l, double t, double r, double b, [ bool? isStroke ]) { + isStroke ??= _lastPaintData.style == PaintingStyle.stroke; + double pad = isStroke ? _lastPaintData.strokeWidth : 0; + _addPointToBounds(l - pad, t - pad); + _addPointToBounds(r + pad, b + pad); + } + + void _addBounds(Rect r, [ bool? isStroke ]) { + _addLTRBToBounds(r.left, r.top, r.right, r.bottom, isStroke); + } + + @override + void save() { + _addOp(_CanvasOp.save); + _saveCount++; + } + + @override + void saveLayer(Rect? bounds, Paint paint) { + _updatePaintData(paint, _saveLayerMask); + if (bounds == null) { + _addOp(_CanvasOp.saveLayer); + } else { + _addOp(_CanvasOp.saveLayerBounds); + _addRect(bounds); + } + } + + @override + int getSaveCount() => _saveCount; + + @override + void restore() { + if (_saveCount > 0) { + --_saveCount; + _addOp(_CanvasOp.restore); + } + } + @override + void translate(double dx, double dy) { + _addOp(_CanvasOp.translate); + _addDouble2(dx, dy); + } + + @override + void scale(double sx, [ double? sy ]) { + _addOp(_CanvasOp.scale); + _addDouble2(sx, sy ?? sx); + } + + @override + void rotate(double radians) { + _addOp(_CanvasOp.rotate); + _addDouble(radians); + } + + @override + void skew(double sx, double sy) { + _addOp(_CanvasOp.skew); + _addDouble2(sx, sy); + } + + @override + void transform(Float64List matrix4) { + if (matrix4.length != 16) + throw ArgumentError('"matrix4" must have 16 entries.'); + _addOp(_CanvasOp.transform); + _addFloat64List(matrix4); + } + + @override + void clipRect(Rect rect, {ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = false}) { + switch (clipOp) { + case ClipOp.intersect: + _addOp(doAntiAlias ? _CanvasOp.clipRectAA : _CanvasOp.clipRect); + break; + case ClipOp.difference: + _addOp(doAntiAlias ? _CanvasOp.clipRectAADiff : _CanvasOp.clipRectDiff); + break; + } + _addRect(rect); + } + + @override + void clipRRect(RRect rrect, {bool doAntiAlias = false}) { + if (rrect.isRect) { + clipRect(rrect.outerRect, doAntiAlias: doAntiAlias); + } else { + _addOp(doAntiAlias ? _CanvasOp.clipRRectAA : _CanvasOp.clipRRect); + _addRRect(rrect); + } + } + + @override + void clipPath(Path path, {bool doAntiAlias = false}) { + _addOp(doAntiAlias ? _CanvasOp.clipPathAA : _CanvasOp.clipPath); + _addPathData(path); + } + + Paint _lastPaintData; + + static const int _aaNeeded = 1; + static const int _colorNeeded = 2; + static const int _blendNeeded = 3; + static const int _invertColorsNeeded = 4; + static const int _filterQualityNeeded = 5; + static const int _paintStyleNeeded = 6; + static const int _strokeStyleNeeded = 7; + static const int _shaderNeeded = 8; + static const int _colorFilterNeeded = 9; + static const int _imageFilterNeeded = 10; + static const int _maskFilterNeeded = 11; + + static const int _drawMask = _aaNeeded | _colorNeeded | _blendNeeded; + static const int _imageMask = _blendNeeded; + static const int _saveLayerMask = _blendNeeded; + + static const List<_CanvasOp> _filterQualityOps = <_CanvasOp>[ + _CanvasOp.setFilterQualityNearest, + _CanvasOp.setFilterQualityLinear, + _CanvasOp.setFilterQualityMipmap, + _CanvasOp.setFilterQualityCubic, + ]; + + static const List<_CanvasOp> _strokeCapOps = <_CanvasOp>[ + _CanvasOp.setCapsButt, + _CanvasOp.setCapsRound, + _CanvasOp.setCapsSquare, + ]; + + static const List<_CanvasOp> _strokeJoinOps = <_CanvasOp>[ + _CanvasOp.setJoinsMiter, + _CanvasOp.setJoinsRound, + _CanvasOp.setJoinsBevel, + ]; + + static const List<_CanvasOp> _maskFilterOps = <_CanvasOp>[ + _CanvasOp.setMaskFilterNormal, + _CanvasOp.setMaskFilterSolid, + _CanvasOp.setMaskFilterOuter, + _CanvasOp.setMaskFilterInner, + ]; + + void _updatePaintData(Paint paint, int dataNeeded) { + if ((dataNeeded & _aaNeeded) != 0 && _lastPaintData.isAntiAlias != paint.isAntiAlias) { + _addOp(paint.isAntiAlias ? _CanvasOp.setAA : _CanvasOp.clearAA); + _lastPaintData.isAntiAlias = paint.isAntiAlias; + } + if ((dataNeeded & _colorNeeded) != 0) { + _updateColor(paint.color); + } + if ((dataNeeded & _blendNeeded) != 0) { + _updateBlendMode(paint.blendMode); + } + if ((dataNeeded & _invertColorsNeeded) != 0 && _lastPaintData.invertColors != paint.invertColors) { + _addOp(paint.invertColors ? _CanvasOp.setInvertColors : _CanvasOp.clearInvertColors); + _lastPaintData.invertColors = paint.invertColors; + } + if ((dataNeeded & _paintStyleNeeded) != 0) { + if (_lastPaintData.style != paint.style) { + _addOp(paint.style == PaintingStyle.fill ? _CanvasOp.setFillStyle : _CanvasOp.setStrokeStyle); + _lastPaintData.style = PaintingStyle.fill; + } + if (paint.style == PaintingStyle.stroke) { + dataNeeded |= _strokeStyleNeeded; + } + } + if ((dataNeeded & _strokeStyleNeeded) != 0) { + if (_lastPaintData.strokeWidth != paint.strokeWidth) { + _addOp(_CanvasOp.setStrokeWidth); + _addDouble(paint.strokeWidth); + _lastPaintData.strokeWidth = paint.strokeWidth; + } + if (_lastPaintData.strokeCap != paint.strokeCap) { + _addOp(_strokeCapOps[paint.strokeCap.index]); + _lastPaintData.strokeCap = paint.strokeCap; + } + if (_lastPaintData.strokeJoin != paint.strokeJoin) { + _addOp(_strokeJoinOps[paint.strokeJoin.index]); + _lastPaintData.strokeJoin = paint.strokeJoin; + } + if (_lastPaintData.strokeMiterLimit != paint.strokeMiterLimit) { + _addOp(_CanvasOp.setMiterLimit); + _addDouble(paint.strokeMiterLimit); + _lastPaintData.strokeMiterLimit = paint.strokeMiterLimit; + } + } + if ((dataNeeded & _filterQualityNeeded) != 0 && _lastPaintData.filterQuality != paint.filterQuality) { + _addOp(_filterQualityOps[paint.filterQuality.index]); + _lastPaintData.filterQuality = paint.filterQuality; + } + if ((dataNeeded & _shaderNeeded) != 0 && _lastPaintData.shader != paint.shader) { + final Shader? shader = paint.shader; + if (shader == null) { + _addOp(_CanvasOp.clearShader); + } else { + _addOp(_CanvasOp.setShader); + _addShader(shader); + } + _lastPaintData.shader = paint.shader; + } + if ((dataNeeded & _colorFilterNeeded) != 0 && _lastPaintData.colorFilter != paint.colorFilter) { + final _ColorFilter? filter = paint.colorFilter?._toNativeColorFilter(); + if (filter == null) { + _addOp(_CanvasOp.clearColorFilter); + } else { + _addOp(_CanvasOp.setColorFilter); + _addColorFilter(filter); + } + _lastPaintData.colorFilter = paint.colorFilter; + } + if ((dataNeeded & _imageFilterNeeded) != 0 && _lastPaintData.imageFilter != paint.imageFilter) { + final _ImageFilter? filter = paint.imageFilter?._toNativeImageFilter(); + if (filter == null) { + _addOp(_CanvasOp.clearImageFilter); + } else { + _addOp(_CanvasOp.setImageFilter); + _addImageFilter(filter); + } + _lastPaintData.imageFilter = paint.imageFilter; + } + if ((dataNeeded & _maskFilterNeeded) != 0 && _lastPaintData.maskFilter != paint.maskFilter) { + final MaskFilter? filter = paint.maskFilter; + if (filter == null) { + _addOp(_CanvasOp.clearMaskFilter); + } else { + _addOp(_maskFilterOps[filter._style.index]); + _addDouble(filter._sigma); + } + _lastPaintData.maskFilter = paint.maskFilter; + } + } + + void _updateColor(Color color) { + if (_lastPaintData.color != color) { + _addOp(_CanvasOp.setColor); + _addInt(color.value); + _lastPaintData.color = color; + } + } + + void _updateBlendMode(BlendMode blendMode) { + if (_lastPaintData.blendMode != blendMode) { + _addOp(_CanvasOp.setBlendMode); + _addByte(blendMode.index); + _lastPaintData.blendMode = blendMode; + } + } + + @override + void drawPaint(Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawPaint); + _addBounds(_cullRect, false); + } + + @override + void drawColor(Color color, BlendMode blendMode) { + _updateColor(color); + _updateBlendMode(blendMode); + _addOp(_CanvasOp.drawColor); + _addBounds(_cullRect, false); + } + + @override + void drawLine(Offset p1, Offset p2, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawLine); + _addOffset(p1); + _addOffset(p2); + _addBounds(Rect.fromPoints(p1, p2), true); + } + + @override + void drawRect(Rect rect, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawRect); + _addRect(rect); + _addBounds(rect); + } + + @override + void drawOval(Rect rect, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawOval); + _addRect(rect); + _addBounds(rect); + } + + @override + void drawCircle(Offset center, double radius, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawCircle); + _addOffset(center); + _addDouble(radius); + _addBounds(Rect.fromCenter(center: center, width: radius, height: radius)); + } + + @override + void drawRRect(RRect rrect, Paint paint) { + Rect outerRect = rrect.outerRect; + if (rrect.isRect) { + drawRect(outerRect, paint); + } else if (rrect.isEllipse) { + drawOval(outerRect, paint); + } else { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawRRect); + _addRRect(rrect); + } + _addBounds(outerRect); + } + + @override + void drawDRRect(RRect outer, RRect inner, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawDRRect); + _addRRect(outer); + _addRRect(inner); + _addBounds(outer.outerRect); + } + + @override + void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(useCenter ? _CanvasOp.drawArcCenter : _CanvasOp.drawArc); + _addRect(rect); + _addDouble2(startAngle, sweepAngle); + _addBounds(rect); + } + + @override + void drawPath(Path path, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_CanvasOp.drawPath); + _addPathData(path); + _addBounds(path.getBounds()); + } + + @override + void drawPoints(PointMode pointMode, List points, Paint paint) { + drawRawPoints(pointMode, _encodePointList(points), paint); + } + + static const List<_CanvasOp> _pointOps = <_CanvasOp>[ + _CanvasOp.drawPoints, + _CanvasOp.drawLines, + _CanvasOp.drawPolygon, + ]; + + @override + void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) { + _updatePaintData(paint, _drawMask); + _addOp(_pointOps[pointMode.index]); + _addFloat32List(points); + print('adding conservative bounds for drawPoints'); + _addBounds(_cullRect); + } + + @override + void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) { + _updatePaintData(paint, _drawMask); + _updateBlendMode(blendMode); + _addVertices(vertices); + print('adding conservative bounds for drawVertices'); + _addBounds(_cullRect); + } + + @override + void drawImage(Image image, Offset offset, Paint paint) { + _updatePaintData(paint, _imageMask); + _addOp(_CanvasOp.drawImage); + _addOffset(offset); + _addImageData(image); + _addBounds(Rect.fromLTWH(offset.dx, offset.dy, image.width.toDouble(), image.height.toDouble()), false); + } + + @override + void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { + _updatePaintData(paint, _imageMask); + _addOp(_CanvasOp.drawImageRect); + _addRect(src); + _addRect(dst); + _addImageData(image); + _addBounds(dst, false); + } + + @override + void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { + _updatePaintData(paint, _imageMask); + _addOp(_CanvasOp.drawImageNine); + _addRect(center); + _addRect(dst); + _addImageData(image); + _addBounds(dst, false); + } + + @override + void drawAtlas(Image atlas, + List transforms, + List rects, + List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { + final int rectCount = rects.length; + if (transforms.length != rectCount) + throw ArgumentError('"transforms" and "rects" lengths must match.'); + if (colors != null && colors.isNotEmpty && colors.length != rectCount) + throw ArgumentError('If non-null, "colors" length must match that of "transforms" and "rects".'); + + final Float32List rstTransformBuffer = Float32List(rectCount * 4); + final Float32List rectBuffer = Float32List(rectCount * 4); + + for (int i = 0; i < rectCount; ++i) { + final int index0 = i * 4; + final int index1 = index0 + 1; + final int index2 = index0 + 2; + final int index3 = index0 + 3; + final RSTransform rstTransform = transforms[i]; + final Rect rect = rects[i]; + assert(_rectIsValid(rect)); + rstTransformBuffer[index0] = rstTransform.scos; + rstTransformBuffer[index1] = rstTransform.ssin; + rstTransformBuffer[index2] = rstTransform.tx; + rstTransformBuffer[index3] = rstTransform.ty; + rectBuffer[index0] = rect.left; + rectBuffer[index1] = rect.top; + rectBuffer[index2] = rect.right; + rectBuffer[index3] = rect.bottom; + } + + final Int32List? colorBuffer = (colors == null || colors.isEmpty) ? null : _encodeColorList(colors); + + final _CanvasOp op = (cullRect == null) + ? (colorBuffer == null) ? _CanvasOp.drawAtlas : _CanvasOp.drawAtlasColored + : (colorBuffer == null) ? _CanvasOp.drawAtlasCulled : _CanvasOp.drawAtlasColoredCulled; + + _updatePaintData(paint, _imageMask); + _updateBlendMode(blendMode ?? BlendMode.src); + _addOp(op); + _addFloat32List(rstTransformBuffer); + _addFloat32List(rectBuffer); + if (colorBuffer != null) + _addInt32List(colorBuffer); + if (cullRect != null) + _addRect(cullRect); + _addImageData(atlas); + print('adding conservative bounds for drawAtlas'); + _addBounds(_cullRect, false); + } + + @override + void drawRawAtlas(Image atlas, + Float32List rstTransforms, + Float32List rects, + Int32List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { + final int rectCount = rects.length; + if (rstTransforms.length != rectCount) + throw ArgumentError('"rstTransforms" and "rects" lengths must match.'); + if (rectCount % 4 != 0) + throw ArgumentError('"rstTransforms" and "rects" lengths must be a multiple of four.'); + if (colors != null && colors.length * 4 != rectCount) + throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".'); + + final _CanvasOp op = (cullRect == null) + ? (colors == null) ? _CanvasOp.drawAtlas : _CanvasOp.drawAtlasColored + : (colors == null) ? _CanvasOp.drawAtlasCulled : _CanvasOp.drawAtlasColoredCulled; + + _updatePaintData(paint, _imageMask); + _updateBlendMode(blendMode ?? BlendMode.src); + _addOp(op); + _addFloat32List(rstTransforms); + _addFloat32List(rects); + if (colors != null) + _addInt32List(colors); + if (cullRect != null) + _addRect(cullRect); + _addImageData(atlas); + print('adding conservative bounds for drawAtlas'); + _addBounds(_cullRect, false); + } + + @override + void drawParagraph(Paragraph paragraph, Offset offset) { + _addOp(_CanvasOp.drawParagraph); + _addOffset(offset); + print('not really rendering: $paragraph'); + // TODO(flar): Implement drawParagraph + } + + @override + void drawPicture(Picture picture) { + _addOp(_CanvasOp.drawPicture); + _addPicture(picture); + print('adding conservative bounds for drawPicture'); + _addBounds(_cullRect, false); + } + + @override + void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { + _updateColor(color); + _addOp(transparentOccluder ? _CanvasOp.drawShadowOccluded : _CanvasOp.drawShadow); + _addDouble(elevation); + _addPathData(path); + print('adding conservative bounds for drawShadow'); + _addBounds(_cullRect, false); + } +} + +/// Local storage version of Picture. +class _DisplayListPicture implements Picture { + _DisplayListPicture._(Rect cullRect, Rect drawBounds, Uint8List ops, ByteData data, List objects) + : _cullRect = cullRect, + _drawBounds = drawBounds, + _ops = ops, + _data = data, + _objData = objects; + + @override + Future toImage(int width, int height) { + if (width <= 0 || height <= 0) + throw Exception('Invalid image dimensions.'); + if (_cullRect == null || _objData == null) + throw UnimplementedError('toImage called on disposed Picture'); + throw UnimplementedError('toImage not implemented'); + } + + @override + void dispose() { + _cullRect = null; + _drawBounds = null; + _ops = null; + _data = null; + _objData = null; + } + + Rect? _cullRect; + Rect? _drawBounds; + Uint8List? _ops; + ByteData? _data; + List? _objData; + + @override + int get approximateBytesUsed => (_ops?.lengthInBytes ?? 0) + (_data?.lengthInBytes ?? 0); +} + +/// Local storage version of PictureRecorder +class _DisplayListPictureRecorder implements PictureRecorder { + @override + bool get isRecording => _canvas != null; + + @override + Picture endRecording() { + final _DisplayListCanvas? canvas = _canvas; + if (canvas == null) + throw StateError('PictureRecorder did not start recording.'); + canvas._recorder = null; + _canvas = null; + return _DisplayListPicture._( + canvas._cullRect, + canvas._drawBounds, + canvas._trimmedOps(), + canvas._trimmedData(), + canvas._trimmedObjects(), + ); + } - Canvas? _canvas; + _DisplayListCanvas? _canvas; } /// A single shadow. From 3d8f8a95700ad8325d22bef8d0251bebe128817e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 25 Mar 2021 04:24:37 -0700 Subject: [PATCH 02/37] partially working for most canvas calls, but corrupts after a while --- flow/BUILD.gn | 1 + flow/display_list.cc | 51 +++++- flow/display_list.h | 232 +++++++++++++++---------- flow/layers/display_list_layer.cc | 101 ++++++----- flow/layers/display_list_layer.h | 7 + lib/ui/compositing.dart | 2 +- lib/ui/compositing/scene_builder.cc | 7 +- lib/ui/compositing/scene_builder.h | 5 +- lib/ui/painting.dart | 259 +++++++++++++++++++--------- 9 files changed, 443 insertions(+), 222 deletions(-) diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 139fe9efe04c1..1c43c29eac32d 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -82,6 +82,7 @@ source_set("flow") { "//flutter/common", "//flutter/common/graphics", "//flutter/fml", + "//flutter/third_party/tonic", "//third_party/skia", ] diff --git a/flow/display_list.cc b/flow/display_list.cc index dbb7871116422..730ccf24d2da0 100644 --- a/flow/display_list.cc +++ b/flow/display_list.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/flow/display_list.h" +#include "flutter/fml/logging.h" // #include @@ -47,10 +48,27 @@ namespace flutter { // DisplayList::~DisplayList() = default; -DisplayListRasterizer::DisplayListRasterizer(std::vector ops, std::vector data) - : ops_it_(std::begin(ops)), - ops_end_(std::end(ops)), - data_it_(std::begin(data)) {} +#define CANVAS_OP_MAKE_STRING(name, count, imask) #name +#define CANVAS_OP_MAKE_COUNT(name, count, imask) count +#define CANVAS_OP_MAKE_IMASK(name, count, imask) imask + +const std::vector DisplayListRasterizer::opNames = { + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_STRING), +}; + +const std::vector DisplayListRasterizer::opArgCounts = { + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_COUNT), +}; + +const std::vector DisplayListRasterizer::opArgImask = { + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_IMASK), +}; + +DisplayListRasterizer::DisplayListRasterizer(std::vector ops_vector, std::vector data_vector) + : ops_it_(ops_vector.begin()), + ops_end_(ops_vector.end()), + data_it_(data_vector.begin()), + data_end_(data_vector.end()) {} static const std::array filter_qualities = { SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone), @@ -59,15 +77,33 @@ static const std::array filter_qualities = { SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}), }; +void DisplayListRasterizer::Describe() { + FML_LOG(ERROR) << "Starting ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); + while(HasOp()) { + FML_LOG(ERROR) << DescribeNextOp(); + CanvasOp op = GetOp(); + for (int i = 0; i < opArgCounts[op]; i++) { + GetScalar(); + } + } + FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); +} + void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { SkPaint paint; - while (ops_it_ < ops_end_) { - switch (static_cast(*ops_it_++)) { + paint.setAntiAlias(true); + FML_LOG(ERROR) << "Starting ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); + while (HasOp()) { + FML_LOG(INFO) << DescribeNextOp(); + CanvasOp op = GetOp(); + switch (op) { case cops_setAA: paint.setAntiAlias(true); break; case cops_clearAA: paint.setAntiAlias(false); break; + case cops_setDither: paint.setDither(true); break; + case cops_clearDither: paint.setDither(false); break; case cops_setInvertColors: break; // TODO(flar): replaces colorfilter??? case cops_clearInvertColors: paint.setColorFilter(nullptr); break; - case cops_setColor: paint.setColor(*data_it_++); break; + case cops_setColor: paint.setColor(GetColor()); break; case cops_setFillStyle: paint.setStyle(SkPaint::Style::kFill_Style); break; case cops_setStrokeStyle: paint.setStyle(SkPaint::Style::kStroke_Style); break; case cops_setStrokeWidth: paint.setStrokeWidth(GetScalar()); break; @@ -150,6 +186,7 @@ void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { case cops_drawShadowOccluded: GetScalar(); break; // TODO(flar) deal with Path object } } + FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); } // Dart_Handle DisplayList::toImage(uint32_t width, diff --git a/flow/display_list.h b/flow/display_list.h index 307312a3122fd..7b7cfef6dbdd7 100644 --- a/flow/display_list.h +++ b/flow/display_list.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_FLOW_DISPLAY_LIST_H_ #define FLUTTER_FLOW_DISPLAY_LIST_H_ +#include + #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRRect.h" @@ -15,111 +17,157 @@ namespace flutter { +#define FOR_EACH_CANVAS_OP(V) \ + V(setAA, 0, 0), \ + V(clearAA, 0, 0), \ + V(setDither, 0, 0), \ + V(clearDither, 0, 0), \ + V(setInvertColors, 0, 0), \ + V(clearInvertColors, 0, 0), \ + V(setFillStyle, 0, 0), \ + V(setStrokeStyle, 0, 0), \ + \ + V(setCapsButt, 0, 0), \ + V(setCapsRound, 0, 0), \ + V(setCapsSquare, 0, 0), \ + V(setJoinsBevel, 0, 0), \ + V(setJoinsMiter, 0, 0), \ + V(setJoinsRound, 0, 0), \ + \ + V(setStrokeWidth, 1, 0), \ + V(setMiterLimit, 1, 0), \ + \ + V(setFilterQualityNearest, 0, 0), \ + V(setFilterQualityLinear, 0, 0), \ + V(setFilterQualityMipmap, 0, 0), \ + V(setFilterQualityCubic, 0, 0), \ + \ + V(setColor, 1, 0x1), \ + V(setBlendMode, 1, 0x1), \ + \ + V(setShader, 0, 0), \ + V(clearShader, 0, 0), \ + V(setColorFilter, 0, 0), \ + V(clearColorFilter, 0, 0), \ + V(setImageFilter, 0, 0), \ + V(clearImageFilter, 0, 0), \ + \ + V(clearMaskFilter, 0, 0), \ + V(setMaskFilterNormal, 1, 0), \ + V(setMaskFilterSolid, 1, 0), \ + V(setMaskFilterOuter, 1, 0), \ + V(setMaskFilterInner, 1, 0), \ + \ + V(save, 0, 0), \ + V(saveLayer, 0, 0), \ + V(saveLayerBounds, 4, 0), \ + V(restore, 0, 0), \ + \ + V(translate, 2, 0), \ + V(scale, 2, 0), \ + V(rotate, 1, 0), \ + V(skew, 2, 0), \ + V(transform, 0, 0), \ + \ + V(clipRect, 4, 0), \ + V(clipRectAA, 4, 0), \ + V(clipRectDiff, 4, 0), \ + V(clipRectAADiff, 4, 0), \ + V(clipRRect, 12, 0), \ + V(clipRRectAA, 12, 0), \ + V(clipPath, 0, 0), \ + V(clipPathAA, 0, 0), \ + \ + V(drawPaint, 0, 0), \ + V(drawColor, 2, 0x3), \ + \ + V(drawLine, 4, 0), \ + V(drawRect, 4, 0), \ + V(drawOval, 4, 0), \ + V(drawCircle, 3, 0), \ + V(drawRRect, 12, 0), \ + V(drawDRRect, 24, 0), \ + V(drawArc, 6, 0), \ + V(drawArcCenter, 6, 0), \ + V(drawPath, 0, 0), \ + \ + V(drawPoints, 0, 0), \ + V(drawLines, 0, 0), \ + V(drawPolygon, 0, 0), \ + \ + V(drawImage, 2, 0), \ + V(drawImageRect, 8, 0), \ + V(drawImageNine, 8, 0), \ + V(drawAtlas, 0, 0), \ + V(drawAtlasColored, 0, 0), \ + V(drawAtlasCulled, 4, 0), \ + V(drawAtlasColoredCulled, 4, 0), \ + \ + V(drawParagraph, 2, 0), \ + V(drawPicture, 0, 0), \ + V(drawShadow, 1, 0), \ + V(drawShadowOccluded, 1, 0) + +#define CANVAS_OP_MAKE_ENUM(name, count, imask) cops_##name enum CanvasOp { - cops_setAA, - cops_clearAA, - cops_setInvertColors, - cops_clearInvertColors, - cops_setFillStyle, - cops_setStrokeStyle, - - cops_setCapsButt, - cops_setCapsRound, - cops_setCapsSquare, - cops_setJoinsBevel, - cops_setJoinsMiter, - cops_setJoinsRound, - - cops_setStrokeWidth, - cops_setMiterLimit, - - cops_setFilterQualityNearest, - cops_setFilterQualityLinear, - cops_setFilterQualityMipmap, - cops_setFilterQualityCubic, - - cops_setColor, - cops_setBlendMode, - - cops_setShader, - cops_clearShader, - cops_setColorFilter, - cops_clearColorFilter, - cops_setImageFilter, - cops_clearImageFilter, - - cops_clearMaskFilter, - cops_setMaskFilterNormal, - cops_setMaskFilterSolid, - cops_setMaskFilterOuter, - cops_setMaskFilterInner, - - cops_save, - cops_saveLayer, - cops_saveLayerBounds, - cops_restore, - - cops_translate, - cops_scale, - cops_rotate, - cops_skew, - cops_transform, - - cops_clipRect, - cops_clipRectAA, - cops_clipRectDiff, - cops_clipRectAADiff, - cops_clipRRect, - cops_clipRRectAA, - cops_clipPath, - cops_clipPathAA, - - cops_drawPaint, - cops_drawColor, - - cops_drawLine, - cops_drawRect, - cops_drawOval, - cops_drawCircle, - cops_drawRRect, - cops_drawDRRect, - cops_drawArc, - cops_drawArcCenter, - cops_drawPath, - - cops_drawPoints, - cops_drawLines, - cops_drawPolygon, - - cops_drawImage, - cops_drawImageRect, - cops_drawImageNine, - cops_drawAtlas, - cops_drawAtlasColored, - cops_drawAtlasCulled, - cops_drawAtlasColoredCulled, - - cops_drawParagraph, - cops_drawPicture, - cops_drawShadow, - cops_drawShadowOccluded, + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM), }; class DisplayListRasterizer { public: - DisplayListRasterizer(std::vector ops, std::vector data); + DisplayListRasterizer(std::vector ops, std::vector data); void Rasterize(SkCanvas *canvas); + void Describe(); + + static const std::vector opNames; + static const std::vector opArgCounts; + static const std::vector opArgImask; + private: std::vector::iterator ops_it_; - std::vector::iterator ops_end_; - std::vector::iterator data_it_; + const std::vector::iterator ops_end_; + std::vector::iterator data_it_; + const std::vector::iterator data_end_; + + bool HasOp() { return ops_it_ < ops_end_; } + CanvasOp GetOp() { return static_cast(*ops_it_++); } + + std::string DescribeNextOp() { + if (!HasOp()) { + return "END-OF-LIST"; + } + std::stringstream ss; + int op_index = *ops_it_; + ss << opNames[op_index] << "(" << std::hex; + for (int i = 0; i < opArgCounts[op_index]; i++) { + if (i > 0) { + ss << ", "; + } + if (data_it_ + i < data_end_) { + union { float f; uint32_t i; } data; + data.f = data_it_[i]; + if ((opArgImask[op_index] & (1 << i)) == 0) { + ss << data.f; + } else { + ss << "0x" << data.i; + } + } else { + ss << "... UNDEFINED ..."; + break; + } + } + ss << ")"; + return ss.str(); + } SkScalar GetScalar() { return static_cast(*data_it_++); } - SkBlendMode GetBlendMode() { return static_cast(*data_it_++); } + uint32_t GetUint32() { union { float f; uint32_t i; } data; data.f = *data_it_++; return data.i; } + + SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } - SkColor GetColor() { return *data_it_++; } + SkColor GetColor() { return GetUint32(); } SkRect GetRect() { return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), GetScalar()); } SkRRect GetRoundRect() { SkRect rect = GetRect(); diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 414bb1d8ea965..95bffeb5acb07 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -4,22 +4,38 @@ #include "flutter/flow/layers/display_list_layer.h" -#include "flutter/fml/logging.h" #include "flutter/flow/display_list.h" -#include "third_party/skia/include/core/SkSerialProcs.h" +#include "third_party/tonic/typed_data/dart_byte_data.h" namespace flutter { DisplayListLayer::DisplayListLayer(const SkPoint& offset, const SkRect& cull_rect, const SkRect& draw_rect, + const tonic::Uint8List& ops, + const tonic::DartByteData& data, + Dart_Handle objects, bool is_complex, bool will_change) : offset_(offset), cull_rect_(cull_rect), draw_rect_(draw_rect), is_complex_(is_complex), - will_change_(will_change) {} + will_change_(will_change) { + if (/* Dart_IsNull(data) || */ Dart_IsNull(objects)) { + ops_vector_ = std::vector(0); + data_vector_ = std::vector(0); + FML_LOG(ERROR) << "Dart display list objects released before use"; + return; + } + + // FML_LOG(ERROR) << "Extracting DL data"; + const uint8_t* ops_ptr = ops.data(); + ops_vector_ = std::vector(ops_ptr, ops_ptr + ops.num_elements()); + + const float* data_ptr = static_cast(data.data()); + data_vector_ = std::vector(data_ptr, data_ptr + (data.length_in_bytes() / sizeof(float))); +} #ifdef FLUTTER_ENABLE_DIFF_CONTEXT @@ -120,18 +136,18 @@ void DisplayListLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) // context->dst_color_space, is_complex_, will_change_); // } - FML_LOG(ERROR) << "display list cull rect is [" - << cull_rect_.left() << ", " - << cull_rect_.top() << ", " - << cull_rect_.right() << ", " - << cull_rect_.bottom() << "]"; - FML_LOG(ERROR) << "display list draw rect is [" - << draw_rect_.left() << ", " - << draw_rect_.top() << ", " - << draw_rect_.right() << ", " - << draw_rect_.bottom() << "]"; + // FML_LOG(ERROR) << "display list cull rect is [" + // << cull_rect_.left() << ", " + // << cull_rect_.top() << ", " + // << cull_rect_.right() << ", " + // << cull_rect_.bottom() << "]"; + // FML_LOG(ERROR) << "display list draw rect is [" + // << draw_rect_.left() << ", " + // << draw_rect_.top() << ", " + // << draw_rect_.right() << ", " + // << draw_rect_.bottom() << "]"; SkRect bounds = draw_rect_; - if (bounds.intersect(cull_rect_)) { + if (true || bounds.intersect(cull_rect_)) { bounds.offset(offset_.x(), offset_.y()); } else { bounds.setEmpty(); @@ -140,7 +156,13 @@ void DisplayListLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) << bounds.left() << ", " << bounds.top() << ", " << bounds.right() << ", " - << bounds.bottom() << "]"; + << bounds.bottom() << "] " + << ops_vector_.size() << " ops"; + if (bounds.isEmpty()) { + FML_LOG(ERROR) << "Contents of empty display list:"; + DisplayListRasterizer rasterizer(ops_vector_, data_vector_); + rasterizer.Describe(); + } set_paint_bounds(bounds); } @@ -161,35 +183,36 @@ void DisplayListLayer::Paint(PaintContext& context) const { // return; // } - if (is_complex_ && will_change_ && is_complex_ != will_change_) { - // (for now, basically never) - std::vector ops; - std::vector data; - DisplayListRasterizer display_list(ops, data); - display_list.Rasterize(context.leaf_nodes_canvas); - } + // FML_LOG(ERROR) << "painting [" + // << paint_bounds().left() << ", " + // << paint_bounds().top() << ", " + // << paint_bounds().right() << ", " + // << paint_bounds().bottom() << "] " + // << ops_vector_.size() << " ops"; + DisplayListRasterizer rasterizer(ops_vector_, data_vector_); + rasterizer.Rasterize(context.leaf_nodes_canvas); - SkRect bounds = paint_bounds(); + // SkRect bounds = paint_bounds(); SkPaint paint; paint.setColor(is_complex_ ? (will_change_ ? SkColors::kRed : SkColors::kYellow) : (will_change_ ? SkColors::kBlue : SkColors::kGreen)); - paint.setAlphaf(0.125f); - context.leaf_nodes_canvas->drawRect(bounds, paint); - paint.setStyle(SkPaint::Style::kStroke_Style); -// paint.setAlphaf(1.0f); - paint.setAntiAlias(true); - paint.setColor(SkColors::kBlack); -// paint.setStrokeWidth(5.0f); - context.leaf_nodes_canvas->drawRect(bounds, paint); - context.leaf_nodes_canvas->drawLine( - SkPoint::Make(bounds.left(), bounds.top()), - SkPoint::Make(bounds.right(), bounds.bottom()), - paint); - context.leaf_nodes_canvas->drawLine( - SkPoint::Make(bounds.right(), bounds.top()), - SkPoint::Make(bounds.left(), bounds.bottom()), - paint); +// paint.setAlphaf(0.125f); +// context.leaf_nodes_canvas->drawRect(bounds, paint); +// paint.setStyle(SkPaint::Style::kStroke_Style); +// // paint.setAlphaf(1.0f); +// paint.setAntiAlias(true); +// paint.setColor(SkColors::kBlack); +// // paint.setStrokeWidth(5.0f); +// context.leaf_nodes_canvas->drawRect(bounds, paint); +// context.leaf_nodes_canvas->drawLine( +// SkPoint::Make(bounds.left(), bounds.top()), +// SkPoint::Make(bounds.right(), bounds.bottom()), +// paint); +// context.leaf_nodes_canvas->drawLine( +// SkPoint::Make(bounds.right(), bounds.top()), +// SkPoint::Make(bounds.left(), bounds.bottom()), +// paint); } } // namespace flutter diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h index 8cad933c538f2..3f67da64b3374 100644 --- a/flow/layers/display_list_layer.h +++ b/flow/layers/display_list_layer.h @@ -10,6 +10,8 @@ #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/skia_gpu_object.h" +#include "third_party/tonic/typed_data/typed_list.h" +#include "third_party/tonic/typed_data/dart_byte_data.h" namespace flutter { @@ -18,6 +20,9 @@ class DisplayListLayer : public Layer { DisplayListLayer(const SkPoint& offset, const SkRect& cull_rect, const SkRect& draw_rect, + const tonic::Uint8List& ops, + const tonic::DartByteData& data, + Dart_Handle objects, bool is_complex, bool will_change); @@ -35,6 +40,8 @@ class DisplayListLayer : public Layer { SkPoint offset_; SkRect cull_rect_; SkRect draw_rect_; + std::vector ops_vector_; + std::vector data_vector_; bool is_complex_ = false; bool will_change_ = false; diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index d843384d2286a..8bae1fd8df32a 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -709,7 +709,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 { if (picture is _SkiaPicture) { _addPicture(offset.dx, offset.dy, picture, hints); } else { - _DisplayListPicture dlPicture = picture as _DisplayListPicture; + final _DisplayListPicture dlPicture = picture as _DisplayListPicture; _addDisplayList( offset.dx, offset.dy, dlPicture._cullRect!.left, dlPicture._cullRect!.top, dlPicture._cullRect!.right, dlPicture._cullRect!.bottom, diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 6e29e52624efa..706ea5dee51bf 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -30,6 +30,7 @@ #include "third_party/tonic/dart_args.h" #include "third_party/tonic/dart_binding_macros.h" #include "third_party/tonic/dart_library_natives.h" +#include "third_party/tonic/typed_data/dart_byte_data.h" #if defined(LEGACY_FUCHSIA_EMBEDDER) #include "flutter/flow/layers/child_scene_layer.h" // nogncheck @@ -294,16 +295,16 @@ void SceneBuilder::addDisplayList(double dx, double drawTop, double drawRight, double drawBottom, - Dart_Handle ops, - Dart_Handle data, + tonic::Uint8List& ops, + tonic::DartByteData& data, Dart_Handle objects, int hints) { auto layer = std::make_unique( SkPoint::Make(dx, dy), SkRect::MakeLTRB(cullLeft, cullTop, cullRight, cullBottom), SkRect::MakeLTRB(drawLeft, drawTop, drawRight, drawBottom), + ops, data, objects, !!(hints & 1), !!(hints & 2)); - // ops.Release(); AddLayer(std::move(layer)); } diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h index 21cb0c08a52c4..455e0ef129056 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -20,6 +20,7 @@ #include "flutter/lib/ui/painting/rrect.h" #include "flutter/lib/ui/painting/shader.h" #include "third_party/tonic/typed_data/typed_list.h" +#include "third_party/tonic/typed_data/dart_byte_data.h" #if defined(LEGACY_FUCHSIA_EMBEDDER) #include "flutter/lib/ui/compositing/scene_host.h" // nogncheck @@ -113,8 +114,8 @@ class SceneBuilder : public RefCountedDartWrappable { double drawTop, double drawRight, double drawBottom, - Dart_Handle ops, - Dart_Handle data, + tonic::Uint8List& ops, + tonic::DartByteData& data, Dart_Handle objects, int hints); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index a4ec4e48ed402..96633e19269eb 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5091,6 +5091,8 @@ class _SkiaPictureRecorder extends NativeFieldWrapperClass2 implements PictureRe enum _CanvasOp { setAA, clearAA, + setDither, + clearDither, setInvertColors, clearInvertColors, setFillStyle, @@ -5178,6 +5180,69 @@ enum _CanvasOp { drawShadowOccluded, } +class _MatrixTransform { + _MatrixTransform._identity() + : mxx = 1.0, + mxy = 0.0, + mxt = 0.0, + myx = 0.0, + myy = 1.0, + myt = 0.0; + _MatrixTransform._copy(_MatrixTransform other) + : mxx = other.mxx, + mxy = other.mxy, + mxt = other.mxt, + myx = other.myx, + myy = other.myy, + myt = other.myt; + + double mxx; double mxy; double mxt; + double myx; double myy; double myt; + + double transformX(double x, double y) { + return x * mxx + y * mxy + mxt; + } + + double transformY(double x, double y) { + return x * myx + y * myy + myt; + } + + void mul(double mxx, double mxy, double mxt, double myx, double myy, double myt) { + final double mxxNew = this.mxx * mxx + this.mxy * myx; + final double mxyNew = this.mxx * mxy + this.mxy * myy; + final double mxtNew = this.mxx * mxt + this.mxy * myt + this.mxt; + final double myxNew = this.myx * mxx + this.myy * myx; + final double myyNew = this.myx * mxy + this.myy * myy; + final double mytNew = this.myx * mxt + this.myy * myt + this.myt; + this.mxx = mxxNew; + this.mxy = mxyNew; + this.mxt = mxtNew; + this.myx = myxNew; + this.myy = myyNew; + this.myt = mytNew; + } + + void translate(double tx, double ty) { + mul(1.0, 0.0, tx, + 0.0, 1.0, ty); + } + + void scale(double sx, double sy) { + mul(sx, 0.0, 0.0, + 0.0, sy, 0.0); + } + + void rotate(double radians) { + mul(math.cos(radians), -math.sin(radians), 0.0, + math.sin(radians), math.cos(radians), 0.0); + } + + void skew(double sx, double sy) { + mul(1.0, sx, 0.0, + sy, 1.0, 0.0); + } +} + /// Local storage version of Canvas class _DisplayListCanvas implements Canvas { /// Make a Canvas2 @@ -5191,8 +5256,8 @@ class _DisplayListCanvas implements Canvas { _ops = Uint8List(128), _numOps = 0, _data = ByteData(128 * 4), _numDataBytes = 0, _objData = [], - _saveCount = 0, - _lastPaintData = Paint() { + _ctm = _MatrixTransform._identity(), + _ctmStack = <_MatrixTransform>[] { _recorder!._canvas = this; } @@ -5207,7 +5272,8 @@ class _DisplayListCanvas implements Canvas { int _numDataBytes; ByteData _data; List _objData; - int _saveCount; + _MatrixTransform _ctm; + List<_MatrixTransform> _ctmStack; Rect get _drawBounds => Rect.fromLTRB(_minX, _minY, _maxX, _maxY); @@ -5219,7 +5285,10 @@ class _DisplayListCanvas implements Canvas { } else { dst = Uint8List(src.length + _maxOpsDoubleSize); } - dst.replaceRange(0, src.length, src); + dst.setRange(0, _numOps, src); + // for (int i = 0; i < _numOps; i++) { + // dst[i] = src[i]; + // } return dst; } @@ -5231,8 +5300,8 @@ class _DisplayListCanvas implements Canvas { } else { dst = ByteData(src.lengthInBytes + _maxDataDoubleSize); } - for (int i = 0; i < src.lengthInBytes; i += 4) { - dst.setInt32(i, src.getInt32(i)); + for (int i = 0; i < _numDataBytes; i += 4) { + dst.setInt32(i, src.getInt32(i, _kFakeHostEndian), _kFakeHostEndian); } return dst; } @@ -5240,7 +5309,7 @@ class _DisplayListCanvas implements Canvas { Uint8List _trimmedOps() { final Uint8List _trimmed = Uint8List(_numOps); _trimmed.setRange(0, _numOps, _ops); - return UnmodifiableUint8ListView(_trimmed); + return _trimmed; } ByteData _trimmedData() { @@ -5248,17 +5317,13 @@ class _DisplayListCanvas implements Canvas { for (int i = 0; i < _numDataBytes; i += 4) { _trimmed.setInt32(i, _data.getInt32(i)); } - return UnmodifiableByteDataView(_trimmed); + return _trimmed; } List _trimmedObjects() { return List.unmodifiable(_objData); } - void _addOp(_CanvasOp op) { - _addByte(op.index); - } - void _addByte(int byte) { if (_numOps + 1 > _ops.lengthInBytes) { _ops = _growOps(_ops); @@ -5266,11 +5331,15 @@ class _DisplayListCanvas implements Canvas { _ops[_numOps++] = byte; } + void _addOp(_CanvasOp op) { + _addByte(op.index); + } + void _addInt(int value) { if (_numDataBytes + 4 > _data.lengthInBytes) { _data = _growData(_data); } - _data.setInt32(_numDataBytes, value); + _data.setInt32(_numDataBytes, value, _kFakeHostEndian); _numDataBytes += 4; } @@ -5278,7 +5347,7 @@ class _DisplayListCanvas implements Canvas { if (_numDataBytes + 4 > _data.lengthInBytes) { _data = _growData(_data); } - _data.setFloat32(_numDataBytes, value); + _data.setFloat32(_numDataBytes, value, _kFakeHostEndian); _numDataBytes += 4; } @@ -5286,9 +5355,9 @@ class _DisplayListCanvas implements Canvas { if (_numDataBytes + 8 > _data.lengthInBytes) { _data = _growData(_data); } - _data.setFloat32(_numDataBytes, v1); + _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v2); + _data.setFloat32(_numDataBytes, v2, _kFakeHostEndian); _numDataBytes += 4; } @@ -5296,13 +5365,13 @@ class _DisplayListCanvas implements Canvas { if (_numDataBytes + 16 > _data.lengthInBytes) { _data = _growData(_data); } - _data.setFloat32(_numDataBytes, v1); + _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v2); + _data.setFloat32(_numDataBytes, v2, _kFakeHostEndian); _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v3); + _data.setFloat32(_numDataBytes, v3, _kFakeHostEndian); _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v4); + _data.setFloat32(_numDataBytes, v4, _kFakeHostEndian); _numDataBytes += 4; } @@ -5360,20 +5429,22 @@ class _DisplayListCanvas implements Canvas { _objData.add(filter); } - void _addPointToBounds(double x, double y) { - if (_minX > x) - _minX = x; - if (_minY > y) - _minY = y; - if (_maxX < x) - _maxX = x; - if (_maxY < y) - _maxY = y; + void _addPointToBounds(double ux, double uy) { + final double dx = _ctm.transformX(ux, uy); + final double dy = _ctm.transformY(ux, uy); + if (_minX > dx) + _minX = dx; + if (_minY > dy) + _minY = dy; + if (_maxX < dx) + _maxX = dx; + if (_maxY < dy) + _maxY = dy; } void _addLTRBToBounds(double l, double t, double r, double b, [ bool? isStroke ]) { - isStroke ??= _lastPaintData.style == PaintingStyle.stroke; - double pad = isStroke ? _lastPaintData.strokeWidth : 0; + isStroke ??= _curPaintStyle == PaintingStyle.stroke; + final double pad = isStroke ? _curStrokeWidth : 0; _addPointToBounds(l - pad, t - pad); _addPointToBounds(r + pad, b + pad); } @@ -5385,7 +5456,7 @@ class _DisplayListCanvas implements Canvas { @override void save() { _addOp(_CanvasOp.save); - _saveCount++; + _ctmStack.add(_MatrixTransform._copy(_ctm)); } @override @@ -5397,15 +5468,16 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.saveLayerBounds); _addRect(bounds); } + _ctmStack.add(_MatrixTransform._copy(_ctm)); } @override - int getSaveCount() => _saveCount; + int getSaveCount() => _ctmStack.length; @override void restore() { - if (_saveCount > 0) { - --_saveCount; + if (_ctmStack.isNotEmpty) { + _ctm = _ctmStack.removeLast(); _addOp(_CanvasOp.restore); } } @@ -5413,24 +5485,28 @@ class _DisplayListCanvas implements Canvas { void translate(double dx, double dy) { _addOp(_CanvasOp.translate); _addDouble2(dx, dy); + _ctm.translate(dx, dy); } @override void scale(double sx, [ double? sy ]) { _addOp(_CanvasOp.scale); _addDouble2(sx, sy ?? sx); + _ctm.scale(sx, sy ?? sx); } @override void rotate(double radians) { _addOp(_CanvasOp.rotate); _addDouble(radians); + _ctm.rotate(radians); } @override void skew(double sx, double sy) { _addOp(_CanvasOp.skew); _addDouble2(sx, sy); + _ctm.skew(sx, sy); } @override @@ -5439,6 +5515,12 @@ class _DisplayListCanvas implements Canvas { throw ArgumentError('"matrix4" must have 16 entries.'); _addOp(_CanvasOp.transform); _addFloat64List(matrix4); + _ctm.mul(matrix4[0], matrix4[1], matrix4[3], + matrix4[4], matrix4[5], matrix4[7]); + print('transform [${matrix4[ 0]}, ${matrix4[ 1]}, ${matrix4[ 2]}, ${matrix4[ 3]},'); + print(' ${matrix4[ 4]}, ${matrix4[ 5]}, ${matrix4[ 6]}, ${matrix4[ 7]},'); + print(' ${matrix4[ 8]}, ${matrix4[ 9]}, ${matrix4[10]}, ${matrix4[11]},'); + print(' ${matrix4[12]}, ${matrix4[13]}, ${matrix4[14]}, ${matrix4[15]}]'); } @override @@ -5470,7 +5552,22 @@ class _DisplayListCanvas implements Canvas { _addPathData(path); } - Paint _lastPaintData; + // These fields track the SkPaint defaults in SkPaint::SkPaint() + Color _curColor = const Color(0xFF000000); + double _curStrokeWidth = 0.0; + double _curMiterLimit = 4.0; + bool _curAA = false; + bool _curDither = false; + bool _curInvertColors = false; + StrokeCap _curStrokeCap = StrokeCap.butt; + StrokeJoin _curStrokeJoin = StrokeJoin.miter; + PaintingStyle _curPaintStyle = PaintingStyle.fill; + FilterQuality _curFilterQuality = FilterQuality.none; + BlendMode _curBlendMode = BlendMode.srcOver; + Shader? _curShader; + ColorFilter? _curColorFilter; + MaskFilter? _curMaskFilter; + ImageFilter? _curImageFilter; static const int _aaNeeded = 1; static const int _colorNeeded = 2; @@ -5483,9 +5580,11 @@ class _DisplayListCanvas implements Canvas { static const int _colorFilterNeeded = 9; static const int _imageFilterNeeded = 10; static const int _maskFilterNeeded = 11; + static const int _ditherNeeded = 12; - static const int _drawMask = _aaNeeded | _colorNeeded | _blendNeeded; - static const int _imageMask = _blendNeeded; + static const int _paintMask = _aaNeeded | _colorNeeded | _blendNeeded; + static const int _drawMask = _paintMask | _paintStyleNeeded; + static const int _imageMask = _blendNeeded | _filterQualityNeeded; static const int _saveLayerMask = _blendNeeded; static const List<_CanvasOp> _filterQualityOps = <_CanvasOp>[ @@ -5515,9 +5614,13 @@ class _DisplayListCanvas implements Canvas { ]; void _updatePaintData(Paint paint, int dataNeeded) { - if ((dataNeeded & _aaNeeded) != 0 && _lastPaintData.isAntiAlias != paint.isAntiAlias) { - _addOp(paint.isAntiAlias ? _CanvasOp.setAA : _CanvasOp.clearAA); - _lastPaintData.isAntiAlias = paint.isAntiAlias; + if ((dataNeeded & _aaNeeded) != 0 && _curAA != paint.isAntiAlias) { + _curAA = paint.isAntiAlias; + _addOp(_curAA ? _CanvasOp.setAA : _CanvasOp.clearAA); + } + if ((dataNeeded & _ditherNeeded) != 0 && _curDither != paint._dither) { + _curDither = paint._dither; + _addOp(_curDither ? _CanvasOp.setDither : _CanvasOp.clearDither); } if ((dataNeeded & _colorNeeded) != 0) { _updateColor(paint.color); @@ -5525,44 +5628,44 @@ class _DisplayListCanvas implements Canvas { if ((dataNeeded & _blendNeeded) != 0) { _updateBlendMode(paint.blendMode); } - if ((dataNeeded & _invertColorsNeeded) != 0 && _lastPaintData.invertColors != paint.invertColors) { - _addOp(paint.invertColors ? _CanvasOp.setInvertColors : _CanvasOp.clearInvertColors); - _lastPaintData.invertColors = paint.invertColors; + if ((dataNeeded & _invertColorsNeeded) != 0 && _curInvertColors != paint.invertColors) { + _curInvertColors = paint.invertColors; + _addOp(_curInvertColors ? _CanvasOp.setInvertColors : _CanvasOp.clearInvertColors); } if ((dataNeeded & _paintStyleNeeded) != 0) { - if (_lastPaintData.style != paint.style) { - _addOp(paint.style == PaintingStyle.fill ? _CanvasOp.setFillStyle : _CanvasOp.setStrokeStyle); - _lastPaintData.style = PaintingStyle.fill; + if (_curPaintStyle != paint.style) { + _curPaintStyle = paint.style; + _addOp(_curPaintStyle == PaintingStyle.fill ? _CanvasOp.setFillStyle : _CanvasOp.setStrokeStyle); } - if (paint.style == PaintingStyle.stroke) { + if (_curPaintStyle == PaintingStyle.stroke) { dataNeeded |= _strokeStyleNeeded; } } if ((dataNeeded & _strokeStyleNeeded) != 0) { - if (_lastPaintData.strokeWidth != paint.strokeWidth) { + if (_curStrokeWidth != paint.strokeWidth) { + _curStrokeWidth = paint.strokeWidth; _addOp(_CanvasOp.setStrokeWidth); - _addDouble(paint.strokeWidth); - _lastPaintData.strokeWidth = paint.strokeWidth; + _addDouble(_curStrokeWidth); } - if (_lastPaintData.strokeCap != paint.strokeCap) { - _addOp(_strokeCapOps[paint.strokeCap.index]); - _lastPaintData.strokeCap = paint.strokeCap; + if (_curStrokeCap != paint.strokeCap) { + _curStrokeCap = paint.strokeCap; + _addOp(_strokeCapOps[_curStrokeCap.index]); } - if (_lastPaintData.strokeJoin != paint.strokeJoin) { - _addOp(_strokeJoinOps[paint.strokeJoin.index]); - _lastPaintData.strokeJoin = paint.strokeJoin; + if (_curStrokeJoin != paint.strokeJoin) { + _curStrokeJoin = paint.strokeJoin; + _addOp(_strokeJoinOps[_curStrokeJoin.index]); } - if (_lastPaintData.strokeMiterLimit != paint.strokeMiterLimit) { + if (_curMiterLimit != paint.strokeMiterLimit) { + _curMiterLimit = paint.strokeMiterLimit; _addOp(_CanvasOp.setMiterLimit); - _addDouble(paint.strokeMiterLimit); - _lastPaintData.strokeMiterLimit = paint.strokeMiterLimit; + _addDouble(_curMiterLimit); } } - if ((dataNeeded & _filterQualityNeeded) != 0 && _lastPaintData.filterQuality != paint.filterQuality) { - _addOp(_filterQualityOps[paint.filterQuality.index]); - _lastPaintData.filterQuality = paint.filterQuality; + if ((dataNeeded & _filterQualityNeeded) != 0 && _curFilterQuality != paint.filterQuality) { + _curFilterQuality = paint.filterQuality; + _addOp(_filterQualityOps[_curFilterQuality.index]); } - if ((dataNeeded & _shaderNeeded) != 0 && _lastPaintData.shader != paint.shader) { + if ((dataNeeded & _shaderNeeded) != 0 && _curShader != paint.shader) { final Shader? shader = paint.shader; if (shader == null) { _addOp(_CanvasOp.clearShader); @@ -5570,9 +5673,9 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.setShader); _addShader(shader); } - _lastPaintData.shader = paint.shader; + _curShader = paint.shader; } - if ((dataNeeded & _colorFilterNeeded) != 0 && _lastPaintData.colorFilter != paint.colorFilter) { + if ((dataNeeded & _colorFilterNeeded) != 0 && _curColorFilter != paint.colorFilter) { final _ColorFilter? filter = paint.colorFilter?._toNativeColorFilter(); if (filter == null) { _addOp(_CanvasOp.clearColorFilter); @@ -5580,9 +5683,9 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.setColorFilter); _addColorFilter(filter); } - _lastPaintData.colorFilter = paint.colorFilter; + _curColorFilter = paint.colorFilter; } - if ((dataNeeded & _imageFilterNeeded) != 0 && _lastPaintData.imageFilter != paint.imageFilter) { + if ((dataNeeded & _imageFilterNeeded) != 0 && _curImageFilter != paint.imageFilter) { final _ImageFilter? filter = paint.imageFilter?._toNativeImageFilter(); if (filter == null) { _addOp(_CanvasOp.clearImageFilter); @@ -5590,9 +5693,9 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.setImageFilter); _addImageFilter(filter); } - _lastPaintData.imageFilter = paint.imageFilter; + _curImageFilter = paint.imageFilter; } - if ((dataNeeded & _maskFilterNeeded) != 0 && _lastPaintData.maskFilter != paint.maskFilter) { + if ((dataNeeded & _maskFilterNeeded) != 0 && _curMaskFilter != paint.maskFilter) { final MaskFilter? filter = paint.maskFilter; if (filter == null) { _addOp(_CanvasOp.clearMaskFilter); @@ -5600,23 +5703,23 @@ class _DisplayListCanvas implements Canvas { _addOp(_maskFilterOps[filter._style.index]); _addDouble(filter._sigma); } - _lastPaintData.maskFilter = paint.maskFilter; + _curMaskFilter = paint.maskFilter; } } void _updateColor(Color color) { - if (_lastPaintData.color != color) { + if (_curColor != color) { + _curColor = color; _addOp(_CanvasOp.setColor); _addInt(color.value); - _lastPaintData.color = color; } } void _updateBlendMode(BlendMode blendMode) { - if (_lastPaintData.blendMode != blendMode) { + if (_curBlendMode != blendMode) { + _curBlendMode = blendMode; _addOp(_CanvasOp.setBlendMode); _addByte(blendMode.index); - _lastPaintData.blendMode = blendMode; } } @@ -5637,7 +5740,7 @@ class _DisplayListCanvas implements Canvas { @override void drawLine(Offset p1, Offset p2, Paint paint) { - _updatePaintData(paint, _drawMask); + _updatePaintData(paint, _paintMask | _strokeStyleNeeded); _addOp(_CanvasOp.drawLine); _addOffset(p1); _addOffset(p2); @@ -5671,7 +5774,7 @@ class _DisplayListCanvas implements Canvas { @override void drawRRect(RRect rrect, Paint paint) { - Rect outerRect = rrect.outerRect; + final Rect outerRect = rrect.outerRect; if (rrect.isRect) { drawRect(outerRect, paint); } else if (rrect.isEllipse) { @@ -5723,7 +5826,7 @@ class _DisplayListCanvas implements Canvas { @override void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) { - _updatePaintData(paint, _drawMask); + _updatePaintData(paint, _paintMask | _strokeStyleNeeded); _addOp(_pointOps[pointMode.index]); _addFloat32List(points); print('adding conservative bounds for drawPoints'); From 8e1bd5e37a9724fda8ad090688fbe22c9d395631 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 26 Mar 2021 22:27:23 -0700 Subject: [PATCH 03/37] move storage of data to native DisplayList and implement toImage() --- flow/BUILD.gn | 4 +- ...ay_list.cc => display_list_interpreter.cc} | 178 ++-------- ...play_list.h => display_list_interpreter.h} | 43 +-- flow/layers/display_list_layer.cc | 51 +-- flow/layers/display_list_layer.h | 9 +- lib/ui/BUILD.gn | 2 + lib/ui/compositing.dart | 6 +- lib/ui/compositing/scene_builder.cc | 6 +- lib/ui/compositing/scene_builder.h | 5 +- lib/ui/dart_ui.cc | 2 + lib/ui/painting.dart | 325 +++++++++--------- lib/ui/painting/display_list.cc | 171 +++++++++ lib/ui/painting/display_list.h | 82 +++++ lib/ui/snapshot_delegate.h | 3 + shell/common/rasterizer.cc | 5 + shell/common/rasterizer.h | 4 + 16 files changed, 507 insertions(+), 389 deletions(-) rename flow/{display_list.cc => display_list_interpreter.cc} (57%) rename flow/{display_list.h => display_list_interpreter.h} (82%) create mode 100644 lib/ui/painting/display_list.cc create mode 100644 lib/ui/painting/display_list.h diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 1c43c29eac32d..af6cfa143ebb3 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -12,8 +12,8 @@ source_set("flow") { "compositor_context.h", "diff_context.cc", "diff_context.h", - "display_list.cc", - "display_list.h", + "display_list_interpreter.cc", + "display_list_interpreter.h", "embedded_views.cc", "embedded_views.h", "frame_timings.cc", diff --git a/flow/display_list.cc b/flow/display_list_interpreter.cc similarity index 57% rename from flow/display_list.cc rename to flow/display_list_interpreter.cc index 730ccf24d2da0..27a97e317009d 100644 --- a/flow/display_list.cc +++ b/flow/display_list_interpreter.cc @@ -2,69 +2,33 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/flow/display_list.h" +#include "flutter/flow/display_list_interpreter.h" #include "flutter/fml/logging.h" -// #include - -// #include "flutter/fml/make_copyable.h" -// #include "flutter/lib/ui/painting/canvas.h" -// #include "flutter/lib/ui/ui_dart_state.h" -// #include "third_party/skia/include/core/SkBlurTypes.h" -// #include "third_party/skia/include/core/SkImage.h" -// #include "third_party/tonic/converter/dart_converter.h" -// #include "third_party/tonic/dart_args.h" -// #include "third_party/tonic/dart_binding_macros.h" -// #include "third_party/tonic/dart_library_natives.h" -// #include "third_party/tonic/dart_persistent_value.h" -// #include "third_party/tonic/logging/dart_invoke.h" - #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" +#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkShader.h" namespace flutter { -// IMPLEMENT_WRAPPERTYPEINFO(ui, DisplayList); - -// #define FOR_EACH_BINDING(V) \ -// V(DisplayList, toImage) \ -// V(DisplayList, dispose) \ -// V(DisplayList, GetAllocationSize) - -// DART_BIND_ALL(DisplayList, FOR_EACH_BINDING) - -// fml::RefPtr DisplayList::Create( -// Dart_Handle dart_handle, -// flutter::SkiaGPUObject picture) { -// auto canvas_picture = fml::MakeRefCounted(std::move(picture)); - -// canvas_picture->AssociateWithDartWrapper(dart_handle); -// return canvas_picture; -// } - -// DisplayList::DisplayList(flutter::SkiaGPUObject picture) -// : picture_(std::move(picture)) {} - -// DisplayList::~DisplayList() = default; - #define CANVAS_OP_MAKE_STRING(name, count, imask) #name #define CANVAS_OP_MAKE_COUNT(name, count, imask) count #define CANVAS_OP_MAKE_IMASK(name, count, imask) imask -const std::vector DisplayListRasterizer::opNames = { +const std::vector DisplayListInterpreter::opNames = { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_STRING), }; -const std::vector DisplayListRasterizer::opArgCounts = { +const std::vector DisplayListInterpreter::opArgCounts = { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_COUNT), }; -const std::vector DisplayListRasterizer::opArgImask = { +const std::vector DisplayListInterpreter::opArgImask = { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_IMASK), }; -DisplayListRasterizer::DisplayListRasterizer(std::vector ops_vector, std::vector data_vector) +DisplayListInterpreter::DisplayListInterpreter(std::vector ops_vector, std::vector data_vector) : ops_it_(ops_vector.begin()), ops_end_(ops_vector.end()), data_it_(data_vector.begin()), @@ -77,7 +41,7 @@ static const std::array filter_qualities = { SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}), }; -void DisplayListRasterizer::Describe() { +void DisplayListInterpreter::Describe() { FML_LOG(ERROR) << "Starting ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); while(HasOp()) { FML_LOG(ERROR) << DescribeNextOp(); @@ -89,9 +53,29 @@ void DisplayListRasterizer::Describe() { FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); } -void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { +constexpr float invert_colors[20] = { + -1.0, 0, 0, 1.0, 0, + 0, -1.0, 0, 1.0, 0, + 0, 0, -1.0, 1.0, 0, + 1.0, 1.0, 1.0, 1.0, 0 +}; + +static sk_sp makeColorFilter(bool invertColors, sk_sp filter) { + if (!invertColors) { + return filter; + } + sk_sp invert_filter = invertColors ? SkColorFilters::Matrix(invert_colors) : nullptr; + if (filter) { + invert_filter = invert_filter->makeComposed(filter); + } + return invert_filter; +} + +void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { + int entrySaveCount = canvas->getSaveCount(); SkPaint paint; - paint.setAntiAlias(true); + bool invertColors = false; + sk_sp colorFilter; FML_LOG(ERROR) << "Starting ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); while (HasOp()) { FML_LOG(INFO) << DescribeNextOp(); @@ -101,8 +85,8 @@ void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { case cops_clearAA: paint.setAntiAlias(false); break; case cops_setDither: paint.setDither(true); break; case cops_clearDither: paint.setDither(false); break; - case cops_setInvertColors: break; // TODO(flar): replaces colorfilter??? - case cops_clearInvertColors: paint.setColorFilter(nullptr); break; + case cops_setInvertColors: invertColors = true; paint.setColorFilter(makeColorFilter(invertColors, colorFilter)); + case cops_clearInvertColors: invertColors = false; paint.setColorFilter(colorFilter); break; case cops_setColor: paint.setColor(GetColor()); break; case cops_setFillStyle: paint.setStyle(SkPaint::Style::kFill_Style); break; case cops_setStrokeStyle: paint.setStyle(SkPaint::Style::kStroke_Style); break; @@ -121,7 +105,7 @@ void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { case cops_setMaskFilterOuter: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kOuter_SkBlurStyle, GetScalar())); break; case cops_setMaskFilterSolid: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kSolid_SkBlurStyle, GetScalar())); break; case cops_setMaskFilterNormal: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, GetScalar())); break; - case cops_clearColorFilter: paint.setColorFilter(nullptr); break; + case cops_clearColorFilter: colorFilter = nullptr; paint.setColorFilter(makeColorFilter(invertColors, colorFilter)); break; case cops_setColorFilter: break; // TODO(flar) deal with Filter object case cops_clearImageFilter: paint.setImageFilter(nullptr); break; case cops_setImageFilter: break; // TODO(flar) deal with Filter object @@ -165,8 +149,8 @@ void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { case cops_drawLine: canvas->drawLine(GetPoint(), GetPoint(), paint); break; case cops_drawPath: break; // TODO(flar) deal with Path object - case cops_drawLines: break; // TODO(flar) deal with List of points case cops_drawPoints: break; // TODO(flar) deal with List of points + case cops_drawLines: break; // TODO(flar) deal with List of points case cops_drawPolygon: break; // TODO(flar) deal with List of points case cops_drawPicture: break; // TODO(flar) deal with Picture object @@ -186,99 +170,9 @@ void DisplayListRasterizer::Rasterize(SkCanvas* canvas) { case cops_drawShadowOccluded: GetScalar(); break; // TODO(flar) deal with Path object } } - FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); + FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) + << ", data: " << (data_end_ - data_it_) + << ", save count delta: " << (canvas->getSaveCount() - entrySaveCount); } -// Dart_Handle DisplayList::toImage(uint32_t width, -// uint32_t height, -// Dart_Handle raw_image_callback) { -// if (!picture_.get()) { -// return tonic::ToDart("Picture is null"); -// } - -// return RasterizeToImage(picture_.get(), width, height, raw_image_callback); -// } - -// void DisplayList::dispose() { -// picture_.reset(); -// ClearDartWrapper();ToSkRoundRect -// } - -// size_t DisplayList::GetAllocationSize() const { -// if (auto picture = picture_.get()) { -// return picture->approximateBytesUsed() + sizeof(Picture); -// } else { -// return sizeof(Picture); -// } -// } - -// Dart_Handle DisplayList::RasterizeToImage(sk_sp picture, -// uint32_t width, -// uint32_t height, -// Dart_Handle raw_image_callback) { -// if (Dart_IsNull(raw_image_callback) || !Dart_IsClosure(raw_image_callback)) { -// return tonic::ToDart("Image callback was invalid"); -// } - -// if (width == 0 || height == 0) { -// return tonic::ToDart("Image dimensions for scene were invalid."); -// } - -// auto* dart_state = UIDartState::Current(); -// auto image_callback = std::make_unique( -// dart_state, raw_image_callback); -// auto unref_queue = dart_state->GetSkiaUnrefQueue(); -// auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); -// auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); -// auto snapshot_delegate = dart_state->GetSnapshotDelegate(); - -// // We can't create an image on this task runner because we don't have a -// // graphics context. Even if we did, it would be slow anyway. Also, this -// // thread owns the sole reference to the layer tree. So we flatten the layer -// // tree into a picture and use that as the thread transport mechanism. - -// auto picture_bounds = SkISize::Make(width, height); - -// auto ui_task = fml::MakeCopyable([image_callback = std::move(image_callback), -// unref_queue]( -// sk_sp raster_image) mutable { -// auto dart_state = image_callback->dart_state().lock(); -// if (!dart_state) { -// // The root isolate could have died in the meantime. -// return; -// } -// tonic::DartState::Scope scope(dart_state); - -// if (!raster_image) { -// tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); -// return; -// } - -// auto dart_image = CanvasImage::Create(); -// dart_image->set_image({std::move(raster_image), std::move(unref_queue)}); -// auto* raw_dart_image = tonic::ToDart(std::move(dart_image)); - -// // All done! -// tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); - -// // image_callback is associated with the Dart isolate and must be deleted -// // on the UI thread. -// image_callback.reset(); -// }); - -// // Kick things off on the raster rask runner. -// fml::TaskRunner::RunNowOrPostTask( -// raster_task_runner, -// [ui_task_runner, snapshot_delegate, picture, picture_bounds, ui_task] { -// sk_sp raster_image = -// snapshot_delegate->MakeRasterSnapshot(picture, picture_bounds); - -// fml::TaskRunner::RunNowOrPostTask( -// ui_task_runner, -// [ui_task, raster_image]() { ui_task(raster_image); }); -// }); - -// return Dart_Null(); -// } - } // namespace flutter diff --git a/flow/display_list.h b/flow/display_list_interpreter.h similarity index 82% rename from flow/display_list.h rename to flow/display_list_interpreter.h index 7b7cfef6dbdd7..fed1087143808 100644 --- a/flow/display_list.h +++ b/flow/display_list_interpreter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_FLOW_DISPLAY_LIST_H_ -#define FLUTTER_FLOW_DISPLAY_LIST_H_ +#ifndef FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_INTERPRETER_H_ +#define FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_INTERPRETER_H_ #include @@ -11,10 +11,6 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRRect.h" -// namespace tonic { -// class DartLibraryNatives; -// } // namespace tonic - namespace flutter { #define FOR_EACH_CANVAS_OP(V) \ @@ -113,9 +109,9 @@ enum CanvasOp { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM), }; -class DisplayListRasterizer { +class DisplayListInterpreter { public: - DisplayListRasterizer(std::vector ops, std::vector data); + DisplayListInterpreter(std::vector ops, std::vector data); void Rasterize(SkCanvas *canvas); @@ -184,35 +180,6 @@ class DisplayListRasterizer { } }; -// class DisplayList : public RefCountedDartWrappable { -// DEFINE_WRAPPERTYPEINFO(); -// FML_FRIEND_MAKE_REF_COUNTED(DisplayList); - -// public: - -// ~DisplayList() override; -// static fml::RefPtr Create(Dart_Handle dart_handle, -// flutter::SkiaGPUObject picture); - -// Dart_Handle toImage(uint32_t width, -// uint32_t height, -// Dart_Handle raw_image_callback); - -// void dispose(); - -// size_t GetAllocationSize() const override; - -// static void RegisterNatives(tonic::DartLibraryNatives* natives); - -// static Dart_Handle RasterizeToImage(sk_sp picture, -// uint32_t width, -// uint32_t height, -// Dart_Handle raw_image_callback); - -// private: -// Picture(flutter::SkiaGPUObject picture); -// }; - } // namespace flutter -#endif // FLUTTER_FLOW_DISPLAY_LIST_H_ +#endif // FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_INTERPRETER_H_ diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 95bffeb5acb07..388ab531a3c5c 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -4,7 +4,7 @@ #include "flutter/flow/layers/display_list_layer.h" -#include "flutter/flow/display_list.h" +#include "flutter/flow/display_list_interpreter.h" #include "third_party/tonic/typed_data/dart_byte_data.h" namespace flutter { @@ -12,30 +12,17 @@ namespace flutter { DisplayListLayer::DisplayListLayer(const SkPoint& offset, const SkRect& cull_rect, const SkRect& draw_rect, - const tonic::Uint8List& ops, - const tonic::DartByteData& data, - Dart_Handle objects, + std::shared_ptr> ops, + std::shared_ptr> data, bool is_complex, bool will_change) : offset_(offset), cull_rect_(cull_rect), draw_rect_(draw_rect), + ops_vector_(ops), + data_vector_(data), is_complex_(is_complex), - will_change_(will_change) { - if (/* Dart_IsNull(data) || */ Dart_IsNull(objects)) { - ops_vector_ = std::vector(0); - data_vector_ = std::vector(0); - FML_LOG(ERROR) << "Dart display list objects released before use"; - return; - } - - // FML_LOG(ERROR) << "Extracting DL data"; - const uint8_t* ops_ptr = ops.data(); - ops_vector_ = std::vector(ops_ptr, ops_ptr + ops.num_elements()); - - const float* data_ptr = static_cast(data.data()); - data_vector_ = std::vector(data_ptr, data_ptr + (data.length_in_bytes() / sizeof(float))); -} + will_change_(will_change) {} #ifdef FLUTTER_ENABLE_DIFF_CONTEXT @@ -152,17 +139,17 @@ void DisplayListLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) } else { bounds.setEmpty(); } - FML_LOG(ERROR) << "display list paint bounds is [" - << bounds.left() << ", " - << bounds.top() << ", " - << bounds.right() << ", " - << bounds.bottom() << "] " - << ops_vector_.size() << " ops"; - if (bounds.isEmpty()) { - FML_LOG(ERROR) << "Contents of empty display list:"; - DisplayListRasterizer rasterizer(ops_vector_, data_vector_); - rasterizer.Describe(); - } + // FML_LOG(ERROR) << "display list paint bounds is [" + // << bounds.left() << ", " + // << bounds.top() << ", " + // << bounds.right() << ", " + // << bounds.bottom() << "] " + // << ops_vector_.size() << " ops"; + // if (bounds.isEmpty()) { + // FML_LOG(ERROR) << "Contents of empty display list:"; + // DisplayListInterpreter interpreter(ops_vector_, data_vector_); + // interpreter.Describe(); + // } set_paint_bounds(bounds); } @@ -189,8 +176,8 @@ void DisplayListLayer::Paint(PaintContext& context) const { // << paint_bounds().right() << ", " // << paint_bounds().bottom() << "] " // << ops_vector_.size() << " ops"; - DisplayListRasterizer rasterizer(ops_vector_, data_vector_); - rasterizer.Rasterize(context.leaf_nodes_canvas); + DisplayListInterpreter interpreter(*ops_vector_, *data_vector_); + interpreter.Rasterize(context.leaf_nodes_canvas); // SkRect bounds = paint_bounds(); SkPaint paint; diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h index 3f67da64b3374..bee8fff0ce335 100644 --- a/flow/layers/display_list_layer.h +++ b/flow/layers/display_list_layer.h @@ -20,9 +20,8 @@ class DisplayListLayer : public Layer { DisplayListLayer(const SkPoint& offset, const SkRect& cull_rect, const SkRect& draw_rect, - const tonic::Uint8List& ops, - const tonic::DartByteData& data, - Dart_Handle objects, + std::shared_ptr> ops, + std::shared_ptr> data, bool is_complex, bool will_change); @@ -40,8 +39,8 @@ class DisplayListLayer : public Layer { SkPoint offset_; SkRect cull_rect_; SkRect draw_rect_; - std::vector ops_vector_; - std::vector data_vector_; + std::shared_ptr> ops_vector_; + std::shared_ptr> data_vector_; bool is_complex_ = false; bool will_change_ = false; diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 1d2ab90df406f..39144d3266a8f 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -28,6 +28,8 @@ source_set("ui") { "painting/codec.h", "painting/color_filter.cc", "painting/color_filter.h", + "painting/display_list.cc", + "painting/display_list.h", "painting/engine_layer.cc", "painting/engine_layer.h", "painting/gradient.cc", diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 8bae1fd8df32a..3ca30bc65e36d 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -714,7 +714,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 { offset.dx, offset.dy, dlPicture._cullRect!.left, dlPicture._cullRect!.top, dlPicture._cullRect!.right, dlPicture._cullRect!.bottom, dlPicture._drawBounds!.left, dlPicture._drawBounds!.top, dlPicture._drawBounds!.right, dlPicture._drawBounds!.bottom, - dlPicture._ops!, dlPicture._data!, dlPicture._objData!, + dlPicture, hints, ); } @@ -734,9 +734,7 @@ class SceneBuilder extends NativeFieldWrapperClass2 { double drawTop, double drawRight, double drawBottom, - Uint8List ops, - ByteData data, - List objects, + _DisplayListPicture dlPicture, int hints, ) native 'SceneBuilder_addDisplayList'; diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 706ea5dee51bf..30b70e913bb47 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -295,15 +295,13 @@ void SceneBuilder::addDisplayList(double dx, double drawTop, double drawRight, double drawBottom, - tonic::Uint8List& ops, - tonic::DartByteData& data, - Dart_Handle objects, + DisplayList* displayList, int hints) { auto layer = std::make_unique( SkPoint::Make(dx, dy), SkRect::MakeLTRB(cullLeft, cullTop, cullRight, cullBottom), SkRect::MakeLTRB(drawLeft, drawTop, drawRight, drawBottom), - ops, data, objects, + displayList->ops_vector(), displayList->data_vector(), !!(hints & 1), !!(hints & 2)); AddLayer(std::move(layer)); } diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h index 455e0ef129056..3e2e366e0c9f2 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -13,6 +13,7 @@ #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/color_filter.h" +#include "flutter/lib/ui/painting/display_list.h" #include "flutter/lib/ui/painting/engine_layer.h" #include "flutter/lib/ui/painting/image_filter.h" #include "flutter/lib/ui/painting/path.h" @@ -114,9 +115,7 @@ class SceneBuilder : public RefCountedDartWrappable { double drawTop, double drawRight, double drawBottom, - tonic::Uint8List& ops, - tonic::DartByteData& data, - Dart_Handle objects, + DisplayList* displayList, int hints); void addTexture(double dx, diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index c22b26b17d3f6..1a70b869758ec 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -12,6 +12,7 @@ #include "flutter/lib/ui/painting/canvas.h" #include "flutter/lib/ui/painting/codec.h" #include "flutter/lib/ui/painting/color_filter.h" +#include "flutter/lib/ui/painting/display_list.h" #include "flutter/lib/ui/painting/engine_layer.h" #include "flutter/lib/ui/painting/gradient.h" #include "flutter/lib/ui/painting/image.h" @@ -67,6 +68,7 @@ void DartUI::InitForGlobal() { Codec::RegisterNatives(g_natives); ColorFilter::RegisterNatives(g_natives); DartRuntimeHooks::RegisterNatives(g_natives); + DisplayList::RegisterNatives(g_natives); EngineLayer::RegisterNatives(g_natives); FontCollection::RegisterNatives(g_natives); ImageDescriptor::RegisterNatives(g_natives); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 96633e19269eb..d50e995089dad 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4606,10 +4606,10 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom); } void _constructor(PictureRecorder recorder, - double left, - double top, - double right, - double bottom) native 'Canvas_constructor'; + double left, + double top, + double right, + double bottom) native 'Canvas_constructor'; _SkiaPictureRecorder? _recorder; @@ -4628,13 +4628,13 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { } } void _saveLayerWithoutBounds(List? paintObjects, ByteData paintData) - native 'Canvas_saveLayerWithoutBounds'; + native 'Canvas_saveLayerWithoutBounds'; void _saveLayer(double left, - double top, - double right, - double bottom, - List? paintObjects, - ByteData paintData) native 'Canvas_saveLayer'; + double top, + double right, + double bottom, + List? paintObjects, + ByteData paintData) native 'Canvas_saveLayer'; @override void restore() native 'Canvas_restore'; @@ -4673,11 +4673,11 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index, doAntiAlias); } void _clipRect(double left, - double top, - double right, - double bottom, - int clipOp, - bool doAntiAlias) native 'Canvas_clipRect'; + double top, + double right, + double bottom, + int clipOp, + bool doAntiAlias) native 'Canvas_clipRect'; @override void clipRRect(RRect rrect, {bool doAntiAlias = true}) { @@ -4711,11 +4711,11 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawLine(p1.dx, p1.dy, p2.dx, p2.dy, paint._objects, paint._data); } void _drawLine(double x1, - double y1, - double x2, - double y2, - List? paintObjects, - ByteData paintData) native 'Canvas_drawLine'; + double y1, + double x2, + double y2, + List? paintObjects, + ByteData paintData) native 'Canvas_drawLine'; @override void drawPaint(Paint paint) { @@ -4732,11 +4732,11 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { paint._objects, paint._data); } void _drawRect(double left, - double top, - double right, - double bottom, - List? paintObjects, - ByteData paintData) native 'Canvas_drawRect'; + double top, + double right, + double bottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawRect'; @override void drawRRect(RRect rrect, Paint paint) { @@ -4745,8 +4745,8 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawRRect(rrect._value32, paint._objects, paint._data); } void _drawRRect(Float32List rrect, - List? paintObjects, - ByteData paintData) native 'Canvas_drawRRect'; + List? paintObjects, + ByteData paintData) native 'Canvas_drawRRect'; @override void drawDRRect(RRect outer, RRect inner, Paint paint) { @@ -4756,9 +4756,9 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawDRRect(outer._value32, inner._value32, paint._objects, paint._data); } void _drawDRRect(Float32List outer, - Float32List inner, - List? paintObjects, - ByteData paintData) native 'Canvas_drawDRRect'; + Float32List inner, + List? paintObjects, + ByteData paintData) native 'Canvas_drawDRRect'; @override void drawOval(Rect rect, Paint paint) { @@ -4768,11 +4768,11 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { paint._objects, paint._data); } void _drawOval(double left, - double top, - double right, - double bottom, - List? paintObjects, - ByteData paintData) native 'Canvas_drawOval'; + double top, + double right, + double bottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawOval'; @override void drawCircle(Offset c, double radius, Paint paint) { @@ -4781,10 +4781,10 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawCircle(c.dx, c.dy, radius, paint._objects, paint._data); } void _drawCircle(double x, - double y, - double radius, - List? paintObjects, - ByteData paintData) native 'Canvas_drawCircle'; + double y, + double radius, + List? paintObjects, + ByteData paintData) native 'Canvas_drawCircle'; @override void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) { @@ -4794,14 +4794,14 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { sweepAngle, useCenter, paint._objects, paint._data); } void _drawArc(double left, - double top, - double right, - double bottom, - double startAngle, - double sweepAngle, - bool useCenter, - List? paintObjects, - ByteData paintData) native 'Canvas_drawArc'; + double top, + double right, + double bottom, + double startAngle, + double sweepAngle, + bool useCenter, + List? paintObjects, + ByteData paintData) native 'Canvas_drawArc'; @override void drawPath(Path path, Paint paint) { @@ -4810,8 +4810,8 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawPath(path, paint._objects, paint._data); } void _drawPath(Path path, - List? paintObjects, - ByteData paintData) native 'Canvas_drawPath'; + List? paintObjects, + ByteData paintData) native 'Canvas_drawPath'; @override void drawImage(Image image, Offset offset, Paint paint) { @@ -4821,10 +4821,10 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawImage(image._image, offset.dx, offset.dy, paint._objects, paint._data); } void _drawImage(_Image image, - double x, - double y, - List? paintObjects, - ByteData paintData) native 'Canvas_drawImage'; + double x, + double y, + List? paintObjects, + ByteData paintData) native 'Canvas_drawImage'; @override void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { @@ -4833,28 +4833,28 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { assert(_rectIsValid(dst)); assert(paint != null); _drawImageRect(image._image, - src.left, - src.top, - src.right, - src.bottom, - dst.left, - dst.top, - dst.right, - dst.bottom, - paint._objects, - paint._data); + src.left, + src.top, + src.right, + src.bottom, + dst.left, + dst.top, + dst.right, + dst.bottom, + paint._objects, + paint._data); } void _drawImageRect(_Image image, - double srcLeft, - double srcTop, - double srcRight, - double srcBottom, - double dstLeft, - double dstTop, - double dstRight, - double dstBottom, - List? paintObjects, - ByteData paintData) native 'Canvas_drawImageRect'; + double srcLeft, + double srcTop, + double srcRight, + double srcBottom, + double dstLeft, + double dstTop, + double dstRight, + double dstBottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawImageRect'; @override void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { @@ -4863,28 +4863,28 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { assert(_rectIsValid(dst)); assert(paint != null); _drawImageNine(image._image, - center.left, - center.top, - center.right, - center.bottom, - dst.left, - dst.top, - dst.right, - dst.bottom, - paint._objects, - paint._data); + center.left, + center.top, + center.right, + center.bottom, + dst.left, + dst.top, + dst.right, + dst.bottom, + paint._objects, + paint._data); } void _drawImageNine(_Image image, - double centerLeft, - double centerTop, - double centerRight, - double centerBottom, - double dstLeft, - double dstTop, - double dstRight, - double dstBottom, - List? paintObjects, - ByteData paintData) native 'Canvas_drawImageNine'; + double centerLeft, + double centerTop, + double centerRight, + double centerBottom, + double dstLeft, + double dstTop, + double dstRight, + double dstBottom, + List? paintObjects, + ByteData paintData) native 'Canvas_drawImageNine'; @override void drawPicture(Picture picture) { @@ -4919,9 +4919,9 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { } void _drawPoints(List? paintObjects, - ByteData paintData, - int pointMode, - Float32List points) native 'Canvas_drawPoints'; + ByteData paintData, + int pointMode, + Float32List points) native 'Canvas_drawPoints'; @override void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) { @@ -4931,18 +4931,18 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawVertices(vertices, blendMode.index, paint._objects, paint._data); } void _drawVertices(Vertices vertices, - int blendMode, - List? paintObjects, - ByteData paintData) native 'Canvas_drawVertices'; + int blendMode, + List? paintObjects, + ByteData paintData) native 'Canvas_drawVertices'; @override void drawAtlas(Image atlas, - List transforms, - List rects, - List? colors, - BlendMode? blendMode, - Rect? cullRect, - Paint paint) { + List transforms, + List rects, + List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { assert(atlas != null); // atlas is checked on the engine side assert(transforms != null); assert(rects != null); @@ -4980,19 +4980,19 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { final Float32List? cullRectBuffer = cullRect?._value32; _drawAtlas( - paint._objects, paint._data, atlas._image, rstTransformBuffer, rectBuffer, - colorBuffer, (blendMode ?? BlendMode.src).index, cullRectBuffer + paint._objects, paint._data, atlas._image, rstTransformBuffer, rectBuffer, + colorBuffer, (blendMode ?? BlendMode.src).index, cullRectBuffer ); } @override void drawRawAtlas(Image atlas, - Float32List rstTransforms, - Float32List rects, - Int32List? colors, - BlendMode? blendMode, - Rect? cullRect, - Paint paint) { + Float32List rstTransforms, + Float32List rects, + Int32List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { assert(atlas != null); // atlas is checked on the engine side assert(rstTransforms != null); assert(rects != null); @@ -5008,19 +5008,19 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".'); _drawAtlas( - paint._objects, paint._data, atlas._image, rstTransforms, rects, - colors, (blendMode ?? BlendMode.src).index, cullRect?._value32 + paint._objects, paint._data, atlas._image, rstTransforms, rects, + colors, (blendMode ?? BlendMode.src).index, cullRect?._value32 ); } void _drawAtlas(List? paintObjects, - ByteData paintData, - _Image atlas, - Float32List rstTransforms, - Float32List rects, - Int32List? colors, - int blendMode, - Float32List? cullRect) native 'Canvas_drawAtlas'; + ByteData paintData, + _Image atlas, + Float32List rstTransforms, + Float32List rects, + Int32List? colors, + int blendMode, + Float32List? cullRect) native 'Canvas_drawAtlas'; @override void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { @@ -5030,9 +5030,9 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { _drawShadow(path, color.value, elevation, transparentOccluder); } void _drawShadow(Path path, - int color, - double elevation, - bool transparentOccluder) native 'Canvas_drawShadow'; + int color, + double elevation, + bool transparentOccluder) native 'Canvas_drawShadow'; } @pragma('vm:entry-point') @@ -5306,24 +5306,6 @@ class _DisplayListCanvas implements Canvas { return dst; } - Uint8List _trimmedOps() { - final Uint8List _trimmed = Uint8List(_numOps); - _trimmed.setRange(0, _numOps, _ops); - return _trimmed; - } - - ByteData _trimmedData() { - final ByteData _trimmed = ByteData(_numDataBytes); - for (int i = 0; i < _numDataBytes; i += 4) { - _trimmed.setInt32(i, _data.getInt32(i)); - } - return _trimmed; - } - - List _trimmedObjects() { - return List.unmodifiable(_objData); - } - void _addByte(int byte) { if (_numOps + 1 > _ops.lengthInBytes) { _ops = _growOps(_ops); @@ -5413,6 +5395,10 @@ class _DisplayListCanvas implements Canvas { _objData.add(vertices); } + void _addParagraph(Paragraph paragraph) { + _objData.add(paragraph); + } + void _addPicture(Picture picture) { _objData.add(picture); } @@ -5515,12 +5501,12 @@ class _DisplayListCanvas implements Canvas { throw ArgumentError('"matrix4" must have 16 entries.'); _addOp(_CanvasOp.transform); _addFloat64List(matrix4); - _ctm.mul(matrix4[0], matrix4[1], matrix4[3], - matrix4[4], matrix4[5], matrix4[7]); - print('transform [${matrix4[ 0]}, ${matrix4[ 1]}, ${matrix4[ 2]}, ${matrix4[ 3]},'); - print(' ${matrix4[ 4]}, ${matrix4[ 5]}, ${matrix4[ 6]}, ${matrix4[ 7]},'); - print(' ${matrix4[ 8]}, ${matrix4[ 9]}, ${matrix4[10]}, ${matrix4[11]},'); - print(' ${matrix4[12]}, ${matrix4[13]}, ${matrix4[14]}, ${matrix4[15]}]'); + _ctm.mul(matrix4[0], matrix4[4], matrix4[12], + matrix4[1], matrix4[5], matrix4[13]); + print('transform [${matrix4[ 0]}, ${matrix4[ 4]}, ${matrix4[ 8]}, ${matrix4[12]},'); + print(' ${matrix4[ 1]}, ${matrix4[ 5]}, ${matrix4[ 9]}, ${matrix4[13]},'); + print(' ${matrix4[ 2]}, ${matrix4[ 6]}, ${matrix4[10]}, ${matrix4[14]},'); + print(' ${matrix4[ 3]}, ${matrix4[ 7]}, ${matrix4[11]}, ${matrix4[15]}]'); } @override @@ -5964,14 +5950,14 @@ class _DisplayListCanvas implements Canvas { void drawParagraph(Paragraph paragraph, Offset offset) { _addOp(_CanvasOp.drawParagraph); _addOffset(offset); + _addParagraph(paragraph); print('not really rendering: $paragraph'); - // TODO(flar): Implement drawParagraph } @override void drawPicture(Picture picture) { _addOp(_CanvasOp.drawPicture); - _addPicture(picture); + _addPicture(picture as _DisplayListPicture); print('adding conservative bounds for drawPicture'); _addBounds(_cullRect, false); } @@ -5988,23 +5974,44 @@ class _DisplayListCanvas implements Canvas { } /// Local storage version of Picture. -class _DisplayListPicture implements Picture { - _DisplayListPicture._(Rect cullRect, Rect drawBounds, Uint8List ops, ByteData data, List objects) +class _DisplayListPicture extends NativeFieldWrapperClass2 implements Picture { + _DisplayListPicture._(Rect cullRect, + Rect drawBounds, + Uint8List ops, int numOps, + ByteData data, int numDataBytes, + List objects) : _cullRect = cullRect, _drawBounds = drawBounds, _ops = ops, _data = data, - _objData = objects; + _objData = objects { + _constructor(ops, numOps, data, numDataBytes); + } + void _constructor(Uint8List ops, int numOps, ByteData data, int dataBytes) native 'DisplayList_constructor'; @override Future toImage(int width, int height) { if (width <= 0 || height <= 0) throw Exception('Invalid image dimensions.'); - if (_cullRect == null || _objData == null) + final Uint8List? ops = _ops; + final ByteData? data = _data; + final List? objects = _objData; + if (ops == null || data == null || objects == null) throw UnimplementedError('toImage called on disposed Picture'); - throw UnimplementedError('toImage not implemented'); + return _futurize( + (_Callback callback) => _toImage(width, height, (_Image? image) { + if (image == null) { + callback(null); + } else { + callback(Image._(image)); + } + }), + ); } + + String? _toImage(int width, int height, _Callback<_Image?> callback) native 'DisplayList_toImage'; + @override void dispose() { _cullRect = null; @@ -6039,9 +6046,9 @@ class _DisplayListPictureRecorder implements PictureRecorder { return _DisplayListPicture._( canvas._cullRect, canvas._drawBounds, - canvas._trimmedOps(), - canvas._trimmedData(), - canvas._trimmedObjects(), + canvas._ops, canvas._numOps, + canvas._data, canvas._numDataBytes, + canvas._objData, ); } diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc new file mode 100644 index 0000000000000..f6039c5794396 --- /dev/null +++ b/lib/ui/painting/display_list.cc @@ -0,0 +1,171 @@ +// 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/display_list.h" + +// #include + +// #include "flutter/fml/make_copyable.h" +// #include "flutter/lib/ui/painting/canvas.h" +// #include "flutter/lib/ui/ui_dart_state.h" +// #include "third_party/skia/include/core/SkBlurTypes.h" +// #include "third_party/skia/include/core/SkImage.h" +// #include "third_party/tonic/converter/dart_converter.h" +// #include "third_party/tonic/dart_args.h" +// #include "third_party/tonic/dart_library_natives.h" +// #include "third_party/tonic/dart_persistent_value.h" +// #include "third_party/tonic/logging/dart_invoke.h" + +#include "flutter/flow/display_list_interpreter.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/make_copyable.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/painting/canvas.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkMaskFilter.h" +#include "third_party/skia/include/core/SkColorFilter.h" +#include "third_party/skia/include/core/SkShader.h" +#include "third_party/tonic/converter/dart_converter.h" +#include "third_party/tonic/dart_binding_macros.h" +#include "third_party/tonic/dart_library_natives.h" + +namespace flutter { + +static void DisplayList_constructor(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + DartCallConstructor(&DisplayList::Create, args); +} + +IMPLEMENT_WRAPPERTYPEINFO(ui, DisplayList); + +#define FOR_EACH_BINDING(V) \ + V(DisplayList, toImage) + +FOR_EACH_BINDING(DART_NATIVE_CALLBACK) + +void DisplayList::RegisterNatives(tonic::DartLibraryNatives* natives) { + natives->Register( + {{"DisplayList_constructor", DisplayList_constructor, 5, true}, + FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); +} + +fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, int numOps, + tonic::DartByteData& data, int dataBytes) { + if (numOps < 0 || + numOps > ops.num_elements() || + dataBytes < 0 || (dataBytes % sizeof(float)) != 0 || + dataBytes > (int) data.length_in_bytes()) { + Dart_ThrowException( + tonic::ToDart("DisplayList constructor called with bad list lengths.")); + return nullptr; + } + const uint8_t* ops_ptr = ops.data(); + std::shared_ptr> ops_vector = + std::make_shared>(ops_ptr, ops_ptr + numOps); + + const float* data_ptr = static_cast(data.data()); + std::shared_ptr> data_vector = + std::make_shared>(data_ptr, data_ptr + (dataBytes / sizeof(float))); + + return fml::MakeRefCounted(ops_vector, data_vector); +} + +DisplayList::DisplayList(std::shared_ptr> ops_vector, + std::shared_ptr> data_vector) + : ops_vector_(ops_vector), + data_vector_(data_vector) {} + +Dart_Handle DisplayList::toImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback) { + return RasterizeToImage(ops_vector_, data_vector_, width, height, raw_image_callback); +} + +Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> ops, + std::shared_ptr> data, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback) { + if (Dart_IsNull(raw_image_callback) || !Dart_IsClosure(raw_image_callback)) { + return tonic::ToDart("Image callback was invalid"); + } + + if (width == 0 || height == 0) { + return tonic::ToDart("Image dimensions for scene were invalid."); + } + + auto* dart_state = UIDartState::Current(); + auto image_callback = std::make_unique( + dart_state, raw_image_callback); + auto unref_queue = dart_state->GetSkiaUnrefQueue(); + auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); + auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); + auto snapshot_delegate = dart_state->GetSnapshotDelegate(); + + // We can't create an image on this task runner because we don't have a + // graphics context. Even if we did, it would be slow anyway. Also, this + // thread owns the sole reference to the layer tree. So we flatten the layer + // tree into a picture and use that as the thread transport mechanism. + + auto picture_bounds = SkISize::Make(width, height); + + auto ui_task = fml::MakeCopyable([image_callback = std::move(image_callback), + unref_queue]( + sk_sp raster_image) mutable { + auto dart_state = image_callback->dart_state().lock(); + if (!dart_state) { + // The root isolate could have died in the meantime. + return; + } + tonic::DartState::Scope scope(dart_state); + + if (!raster_image) { + tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); + return; + } + + auto dart_image = CanvasImage::Create(); + dart_image->set_image({std::move(raster_image), std::move(unref_queue)}); + auto* raw_dart_image = tonic::ToDart(std::move(dart_image)); + + // All done! + tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); + + // image_callback is associated with the Dart isolate and must be deleted + // on the UI thread. + image_callback.reset(); + }); + + // Kick things off on the raster rask runner. + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner, + [ui_task_runner, snapshot_delegate, ops, data, picture_bounds, ui_task] { + sk_sp raster_image = + snapshot_delegate->MakeRasterSnapshot([ops = std::move(ops), data = std::move(data)](SkCanvas* canvas) { + DisplayListInterpreter interpreter(*ops, *data); + interpreter.Rasterize(canvas); + }, picture_bounds); + + fml::TaskRunner::RunNowOrPostTask( + ui_task_runner, + [ui_task, raster_image]() { ui_task(raster_image); }); + }); + + return Dart_Null(); +} + +// void DisplayList::dispose() { +// picture_.reset(); +// ClearDartWrapper();ToSkRoundRect +// } + +// size_t DisplayList::GetAllocationSize() const { +// if (auto picture = picture_.get()) { +// return picture->approximateBytesUsed() + sizeof(Picture); +// } else { +// return sizeof(Picture); +// } +// } + +} // namespace flutter diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h new file mode 100644 index 0000000000000..d378e4761bd73 --- /dev/null +++ b/lib/ui/painting/display_list.h @@ -0,0 +1,82 @@ +// 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_DISPLAY_LIST_H_ +#define FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_H_ + +#include + +#include "flutter/lib/ui/dart_wrapper.h" +#include "third_party/tonic/typed_data/typed_list.h" +#include "third_party/tonic/typed_data/dart_byte_data.h" + +namespace tonic { +class DartLibraryNatives; +} // namespace tonic + +namespace flutter { + +class DisplayList : public RefCountedDartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(DisplayList); + + public: + static fml::RefPtr Create(tonic::Uint8List& ops, int numOps, tonic::DartByteData& data, int dataBytes); + + Dart_Handle toImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback); + + static Dart_Handle RasterizeToImage(std::shared_ptr> ops, + std::shared_ptr> data, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback); + + static void RegisterNatives(tonic::DartLibraryNatives* natives); + + std::shared_ptr> ops_vector() { return ops_vector_; } + std::shared_ptr> data_vector() { return data_vector_; } + + private: + explicit DisplayList(std::shared_ptr> ops_vector, + std::shared_ptr> data_vector); + // explicit DisplayList(); + + std::shared_ptr> ops_vector_; + std::shared_ptr> data_vector_; +}; + +// class DisplayList : public RefCountedDartWrappable { +// DEFINE_WRAPPERTYPEINFO(); +// FML_FRIEND_MAKE_REF_COUNTED(DisplayList); + +// public: + +// ~DisplayList() override; +// static fml::RefPtr Create(Dart_Handle dart_handle, +// flutter::SkiaGPUObject picture); + +// Dart_Handle toImage(uint32_t width, +// uint32_t height, +// Dart_Handle raw_image_callback); + +// void dispose(); + +// size_t GetAllocationSize() const override; + +// static void RegisterNatives(tonic::DartLibraryNatives* natives); + +// static Dart_Handle RasterizeToImage(sk_sp picture, +// uint32_t width, +// uint32_t height, +// Dart_Handle raw_image_callback); + +// private: +// Picture(flutter::SkiaGPUObject picture); +// }; + +} // namespace flutter + +#endif // FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_H_ diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index ad9b8ef1f3612..63bfaac5bb483 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -12,6 +12,9 @@ namespace flutter { class SnapshotDelegate { public: + virtual sk_sp MakeRasterSnapshot(std::function draw_callback, + SkISize picture_size) = 0; + virtual sk_sp MakeRasterSnapshot(sk_sp picture, SkISize picture_size) = 0; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 7281f5f29dddc..761a829af76a6 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -315,6 +315,11 @@ sk_sp Rasterizer::DoMakeRasterSnapshot( return result; } +sk_sp Rasterizer::MakeRasterSnapshot(std::function draw_callback, + SkISize picture_size) { + return DoMakeRasterSnapshot(picture_size, draw_callback); +} + sk_sp Rasterizer::MakeRasterSnapshot(sk_sp picture, SkISize picture_size) { return DoMakeRasterSnapshot(picture_size, diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 1f1559cbb9466..28f65a313906e 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -464,6 +464,10 @@ class Rasterizer final : public SnapshotDelegate { std::shared_ptr external_view_embedder_; bool shared_engine_block_thread_merging_ = false; + // |SnapshotDelegate| + sk_sp MakeRasterSnapshot(std::function draw_callback, + SkISize picture_size) override; + // |SnapshotDelegate| sk_sp MakeRasterSnapshot(sk_sp picture, SkISize picture_size) override; From a33ee18a18667ddfdefb82fd38003ef4ad268bc1 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 28 Mar 2021 00:08:45 -0700 Subject: [PATCH 04/37] Fix a number of inconsistent data vector accesses, memory corruption during shader warmup, pass down object list --- flow/display_list_interpreter.cc | 32 +++-- flow/display_list_interpreter.h | 203 ++++++++++++++++-------------- flow/layers/display_list_layer.cc | 2 +- lib/ui/painting.dart | 26 ++-- lib/ui/painting/display_list.cc | 62 ++++++++- lib/ui/painting/display_list.h | 6 +- 6 files changed, 206 insertions(+), 125 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 27a97e317009d..38b83fe0d865c 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -12,9 +12,10 @@ namespace flutter { -#define CANVAS_OP_MAKE_STRING(name, count, imask) #name -#define CANVAS_OP_MAKE_COUNT(name, count, imask) count -#define CANVAS_OP_MAKE_IMASK(name, count, imask) imask +#define CANVAS_OP_MAKE_STRING(name, count, imask, objcount) #name +#define CANVAS_OP_MAKE_COUNT(name, count, imask, objcount) count +#define CANVAS_OP_MAKE_IMASK(name, count, imask, objcount) imask +#define CANVAS_OP_MAKE_OBJCOUNT(name, count, imask, objcount) objcount const std::vector DisplayListInterpreter::opNames = { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_STRING), @@ -28,11 +29,19 @@ const std::vector DisplayListInterpreter::opArgImask = { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_IMASK), }; -DisplayListInterpreter::DisplayListInterpreter(std::vector ops_vector, std::vector data_vector) - : ops_it_(ops_vector.begin()), - ops_end_(ops_vector.end()), - data_it_(data_vector.begin()), - data_end_(data_vector.end()) {} +const std::vector DisplayListInterpreter::opObjCounts = { + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_OBJCOUNT), +}; + +DisplayListInterpreter::DisplayListInterpreter( + std::shared_ptr> ops_vector, + std::shared_ptr> data_vector) + : ops_vector_(ops_vector), + ops_it_(ops_vector->begin()), + ops_end_(ops_vector->end()), + data_vector_(data_vector), + data_it_(data_vector->begin()), + data_end_(data_vector->end()) {} static const std::array filter_qualities = { SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone), @@ -136,7 +145,7 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { case cops_skew: canvas->skew(GetScalar(), GetScalar()); break; case cops_transform: break; // TODO(flar) deal with Float64List - case cops_drawColor: canvas->drawColor(GetColor(), paint.getBlendMode()); break; + case cops_drawColor: canvas->drawColor(paint.getColor(), paint.getBlendMode()); break; case cops_drawPaint: canvas->drawPaint(paint); break; case cops_drawRect: canvas->drawRect(GetRect(), paint); break; @@ -152,9 +161,9 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { case cops_drawPoints: break; // TODO(flar) deal with List of points case cops_drawLines: break; // TODO(flar) deal with List of points case cops_drawPolygon: break; // TODO(flar) deal with List of points - case cops_drawPicture: break; // TODO(flar) deal with Picture object + case cops_drawVertices: break; // TODO(flar) deal with List of vertices - case cops_drawImage: GetScalar(); GetScalar(); break; // TODO(flar) deal with image object + case cops_drawImage: GetPoint(); break; // TODO(flar) deal with image object case cops_drawImageRect: GetRect(); GetRect(); break; // TODO(flar) deal with image object case cops_drawImageNine: GetRect(); GetRect(); break; // TODO(flar) deal with image object case cops_drawAtlas: @@ -165,6 +174,7 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { GetRect(); break; + case cops_drawPicture: break; // TODO(flar) deal with Picture object case cops_drawParagraph: GetPoint(); break; // TODO(flar) deal with Paragraph object case cops_drawShadow: GetScalar(); break; // TODO(flar) deal with Path object case cops_drawShadowOccluded: GetScalar(); break; // TODO(flar) deal with Path object diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index fed1087143808..6fcb7e035d3b5 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -13,105 +13,108 @@ namespace flutter { +// opName (matches Dart enum name), numDataArgs, intArgMask, numObjArgs #define FOR_EACH_CANVAS_OP(V) \ - V(setAA, 0, 0), \ - V(clearAA, 0, 0), \ - V(setDither, 0, 0), \ - V(clearDither, 0, 0), \ - V(setInvertColors, 0, 0), \ - V(clearInvertColors, 0, 0), \ - V(setFillStyle, 0, 0), \ - V(setStrokeStyle, 0, 0), \ - \ - V(setCapsButt, 0, 0), \ - V(setCapsRound, 0, 0), \ - V(setCapsSquare, 0, 0), \ - V(setJoinsBevel, 0, 0), \ - V(setJoinsMiter, 0, 0), \ - V(setJoinsRound, 0, 0), \ - \ - V(setStrokeWidth, 1, 0), \ - V(setMiterLimit, 1, 0), \ - \ - V(setFilterQualityNearest, 0, 0), \ - V(setFilterQualityLinear, 0, 0), \ - V(setFilterQualityMipmap, 0, 0), \ - V(setFilterQualityCubic, 0, 0), \ - \ - V(setColor, 1, 0x1), \ - V(setBlendMode, 1, 0x1), \ - \ - V(setShader, 0, 0), \ - V(clearShader, 0, 0), \ - V(setColorFilter, 0, 0), \ - V(clearColorFilter, 0, 0), \ - V(setImageFilter, 0, 0), \ - V(clearImageFilter, 0, 0), \ - \ - V(clearMaskFilter, 0, 0), \ - V(setMaskFilterNormal, 1, 0), \ - V(setMaskFilterSolid, 1, 0), \ - V(setMaskFilterOuter, 1, 0), \ - V(setMaskFilterInner, 1, 0), \ - \ - V(save, 0, 0), \ - V(saveLayer, 0, 0), \ - V(saveLayerBounds, 4, 0), \ - V(restore, 0, 0), \ - \ - V(translate, 2, 0), \ - V(scale, 2, 0), \ - V(rotate, 1, 0), \ - V(skew, 2, 0), \ - V(transform, 0, 0), \ - \ - V(clipRect, 4, 0), \ - V(clipRectAA, 4, 0), \ - V(clipRectDiff, 4, 0), \ - V(clipRectAADiff, 4, 0), \ - V(clipRRect, 12, 0), \ - V(clipRRectAA, 12, 0), \ - V(clipPath, 0, 0), \ - V(clipPathAA, 0, 0), \ - \ - V(drawPaint, 0, 0), \ - V(drawColor, 2, 0x3), \ - \ - V(drawLine, 4, 0), \ - V(drawRect, 4, 0), \ - V(drawOval, 4, 0), \ - V(drawCircle, 3, 0), \ - V(drawRRect, 12, 0), \ - V(drawDRRect, 24, 0), \ - V(drawArc, 6, 0), \ - V(drawArcCenter, 6, 0), \ - V(drawPath, 0, 0), \ - \ - V(drawPoints, 0, 0), \ - V(drawLines, 0, 0), \ - V(drawPolygon, 0, 0), \ - \ - V(drawImage, 2, 0), \ - V(drawImageRect, 8, 0), \ - V(drawImageNine, 8, 0), \ - V(drawAtlas, 0, 0), \ - V(drawAtlasColored, 0, 0), \ - V(drawAtlasCulled, 4, 0), \ - V(drawAtlasColoredCulled, 4, 0), \ - \ - V(drawParagraph, 2, 0), \ - V(drawPicture, 0, 0), \ - V(drawShadow, 1, 0), \ - V(drawShadowOccluded, 1, 0) - -#define CANVAS_OP_MAKE_ENUM(name, count, imask) cops_##name + V(setAA, 0, 0, 0), \ + V(clearAA, 0, 0, 0), \ + V(setDither, 0, 0, 0), \ + V(clearDither, 0, 0, 0), \ + V(setInvertColors, 0, 0, 0), \ + V(clearInvertColors, 0, 0, 0), \ + V(setFillStyle, 0, 0, 0), \ + V(setStrokeStyle, 0, 0, 0), \ + \ + V(setCapsButt, 0, 0, 0), \ + V(setCapsRound, 0, 0, 0), \ + V(setCapsSquare, 0, 0, 0), \ + V(setJoinsBevel, 0, 0, 0), \ + V(setJoinsMiter, 0, 0, 0), \ + V(setJoinsRound, 0, 0, 0), \ + \ + V(setStrokeWidth, 1, 0, 0), \ + V(setMiterLimit, 1, 0, 0), \ + \ + V(setFilterQualityNearest, 0, 0, 0), \ + V(setFilterQualityLinear, 0, 0, 0), \ + V(setFilterQualityMipmap, 0, 0, 0), \ + V(setFilterQualityCubic, 0, 0, 0), \ + \ + V(setColor, 1, 0x1, 0), \ + V(setBlendMode, 1, 0x1, 0), \ + \ + V(setShader, 0, 0, 1), \ + V(clearShader, 0, 0, 0), \ + V(setColorFilter, 0, 0, 1), \ + V(clearColorFilter, 0, 0, 0), \ + V(setImageFilter, 0, 0, 1), \ + V(clearImageFilter, 0, 0, 0), \ + \ + V(clearMaskFilter, 0, 0, 0), \ + V(setMaskFilterNormal, 1, 0, 0), \ + V(setMaskFilterSolid, 1, 0, 0), \ + V(setMaskFilterOuter, 1, 0, 0), \ + V(setMaskFilterInner, 1, 0, 0), \ + \ + V(save, 0, 0, 0), \ + V(saveLayer, 0, 0, 0), \ + V(saveLayerBounds, 4, 0, 0), \ + V(restore, 0, 0, 0), \ + \ + V(translate, 2, 0, 0), \ + V(scale, 2, 0, 0), \ + V(rotate, 1, 0, 0), \ + V(skew, 2, 0, 0), \ + V(transform, 0, 0, 1), \ + \ + V(clipRect, 4, 0, 0), \ + V(clipRectAA, 4, 0, 0), \ + V(clipRectDiff, 4, 0, 0), \ + V(clipRectAADiff, 4, 0, 0), \ + V(clipRRect, 12, 0, 0), \ + V(clipRRectAA, 12, 0, 0), \ + V(clipPath, 0, 0, 1), \ + V(clipPathAA, 0, 0, 1), \ + \ + V(drawPaint, 0, 0, 0), \ + V(drawColor, 2, 0x3, 0), \ + \ + V(drawLine, 4, 0, 0), \ + V(drawRect, 4, 0, 0), \ + V(drawOval, 4, 0, 0), \ + V(drawCircle, 3, 0, 0), \ + V(drawRRect, 12, 0, 0), \ + V(drawDRRect, 24, 0, 0), \ + V(drawArc, 6, 0, 0), \ + V(drawArcCenter, 6, 0, 0), \ + V(drawPath, 0, 0, 1), \ + \ + V(drawPoints, 0, 0, 1), \ + V(drawLines, 0, 0, 1), \ + V(drawPolygon, 0, 0, 1), \ + V(drawVertices, 0, 0, 1), \ + \ + V(drawImage, 2, 0, 1), \ + V(drawImageRect, 8, 0, 1), \ + V(drawImageNine, 8, 0, 1), \ + V(drawAtlas, 0, 0, 3), \ + V(drawAtlasColored, 0, 0, 4), \ + V(drawAtlasCulled, 4, 0, 3), \ + V(drawAtlasColoredCulled, 4, 0, 4), \ + \ + V(drawParagraph, 2, 0, 1), \ + V(drawPicture, 0, 0, 1), \ + V(drawShadow, 1, 0, 1), \ + V(drawShadowOccluded, 1, 0, 1) + +#define CANVAS_OP_MAKE_ENUM(name, count, imask, objcount) cops_##name enum CanvasOp { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM), }; class DisplayListInterpreter { public: - DisplayListInterpreter(std::vector ops, std::vector data); + DisplayListInterpreter(std::shared_ptr> ops, + std::shared_ptr> data); void Rasterize(SkCanvas *canvas); @@ -120,10 +123,13 @@ class DisplayListInterpreter { static const std::vector opNames; static const std::vector opArgCounts; static const std::vector opArgImask; + static const std::vector opObjCounts; private: + std::shared_ptr> ops_vector_; std::vector::iterator ops_it_; const std::vector::iterator ops_end_; + std::shared_ptr> data_vector_; std::vector::iterator data_it_; const std::vector::iterator data_end_; @@ -154,6 +160,16 @@ class DisplayListInterpreter { break; } } + if (opObjCounts[op_index] > 0) { + if (opArgCounts[op_index] > 0) { + ss << ", "; + } + if (opObjCounts[op_index] > 1) { + ss << "[" << opObjCounts[op_index] << " objects]"; + } else { + ss << "[object]"; + } + } ss << ")"; return ss.str(); } @@ -163,11 +179,12 @@ class DisplayListInterpreter { SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } - SkColor GetColor() { return GetUint32(); } + SkColor GetColor() { return static_cast(GetUint32()); } SkRect GetRect() { return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), GetScalar()); } SkRRect GetRoundRect() { SkRect rect = GetRect(); SkVector radii[4] = { + // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices { GetScalar(), GetScalar() }, { GetScalar(), GetScalar() }, { GetScalar(), GetScalar() }, diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 388ab531a3c5c..8d5786a2060ea 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -176,7 +176,7 @@ void DisplayListLayer::Paint(PaintContext& context) const { // << paint_bounds().right() << ", " // << paint_bounds().bottom() << "] " // << ops_vector_.size() << " ops"; - DisplayListInterpreter interpreter(*ops_vector_, *data_vector_); + DisplayListInterpreter interpreter(ops_vector_, data_vector_); interpreter.Rasterize(context.leaf_nodes_canvas); // SkRect bounds = paint_bounds(); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index d50e995089dad..3bef93cc439c9 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5165,6 +5165,7 @@ enum _CanvasOp { drawPoints, drawLines, drawPolygon, + drawVertices, drawImage, drawImageRect, @@ -5286,9 +5287,6 @@ class _DisplayListCanvas implements Canvas { dst = Uint8List(src.length + _maxOpsDoubleSize); } dst.setRange(0, _numOps, src); - // for (int i = 0; i < _numOps; i++) { - // dst[i] = src[i]; - // } return dst; } @@ -5306,15 +5304,11 @@ class _DisplayListCanvas implements Canvas { return dst; } - void _addByte(int byte) { - if (_numOps + 1 > _ops.lengthInBytes) { - _ops = _growOps(_ops); - } - _ops[_numOps++] = byte; - } - void _addOp(_CanvasOp op) { - _addByte(op.index); + if (_numOps == _ops.lengthInBytes) { + _ops = _growOps(_ops); + } + _ops[_numOps++] = op.index; } void _addInt(int value) { @@ -5367,8 +5361,9 @@ class _DisplayListCanvas implements Canvas { void _addRRect(RRect rrect) { _addDouble4(rrect.left, rrect.top, rrect.right, rrect.bottom); + // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices _addDouble4(rrect.tlRadiusX, rrect.tlRadiusY, rrect.trRadiusX, rrect.trRadiusY); - _addDouble4(rrect.blRadiusX, rrect.blRadiusY, rrect.brRadiusX, rrect.brRadiusY); + _addDouble4(rrect.brRadiusX, rrect.brRadiusY, rrect.blRadiusX, rrect.blRadiusY); } void _addInt32List(Int32List data) { @@ -5705,7 +5700,7 @@ class _DisplayListCanvas implements Canvas { if (_curBlendMode != blendMode) { _curBlendMode = blendMode; _addOp(_CanvasOp.setBlendMode); - _addByte(blendMode.index); + _addInt(blendMode.index); } } @@ -5823,6 +5818,7 @@ class _DisplayListCanvas implements Canvas { void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) { _updatePaintData(paint, _drawMask); _updateBlendMode(blendMode); + _addOp(_CanvasOp.drawVertices); _addVertices(vertices); print('adding conservative bounds for drawVertices'); _addBounds(_cullRect); @@ -5985,9 +5981,9 @@ class _DisplayListPicture extends NativeFieldWrapperClass2 implements Picture { _ops = ops, _data = data, _objData = objects { - _constructor(ops, numOps, data, numDataBytes); + _constructor(ops, numOps, data, numDataBytes, objects); } - void _constructor(Uint8List ops, int numOps, ByteData data, int dataBytes) native 'DisplayList_constructor'; + void _constructor(Uint8List ops, int numOps, ByteData data, int dataBytes, List objects) native 'DisplayList_constructor'; @override Future toImage(int width, int height) { diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index f6039c5794396..8bf0f7c41f30a 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -22,6 +22,7 @@ #include "flutter/fml/make_copyable.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/painting/canvas.h" +#include "flutter/lib/ui/painting/image_filter.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" #include "third_party/skia/include/core/SkColorFilter.h" @@ -46,12 +47,32 @@ FOR_EACH_BINDING(DART_NATIVE_CALLBACK) void DisplayList::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register( - {{"DisplayList_constructor", DisplayList_constructor, 5, true}, + {{"DisplayList_constructor", DisplayList_constructor, 6, true}, FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } -fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, int numOps, - tonic::DartByteData& data, int dataBytes) { +// static bool checkObjectLength(int index, int numObjects) { +// if (index >= numObjects) { +// Dart_ThrowException( +// tonic::ToDart("DisplayList object array too short.")); +// return false; +// } +// return true; +// } + +// static bool checkImageFilter(Dart_Handle objects[], int numObjects, int index) { +// if (checkObjectLength(index, numObjects)) { +// Dart_Handle image_filter = objects[index]; +// ImageFilter* decoded = +// tonic::DartConverter::FromDart(image_filter); +// } +// } + +fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, + int numOps, + tonic::DartByteData& data, + int dataBytes, + Dart_Handle objList) { if (numOps < 0 || numOps > ops.num_elements() || dataBytes < 0 || (dataBytes % sizeof(float)) != 0 || @@ -60,6 +81,12 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, int numOps, tonic::ToDart("DisplayList constructor called with bad list lengths.")); return nullptr; } + if (Dart_IsNull(objList) || !Dart_IsList(objList)) { + Dart_ThrowException( + tonic::ToDart("DisplayList constructor called with bad object array.")); + return nullptr; + } + const uint8_t* ops_ptr = ops.data(); std::shared_ptr> ops_vector = std::make_shared>(ops_ptr, ops_ptr + numOps); @@ -68,6 +95,33 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, int numOps, std::shared_ptr> data_vector = std::make_shared>(data_ptr, data_ptr + (dataBytes / sizeof(float))); + // int numObjects = 0; + // Dart_ListLength(objList, &numObjects); + // Dart_Handle objects[numObjects]; + // if (Dart_IsError( + // Dart_ListGetRange(objList, 0, numObjects, objects))) { + // return nullptr; + // } + // for (int i = 0; i < numObjects; i++) { + // const char *name; + // Dart_Handle type = Dart_InstanceGetType(objects[i]); + // } + // int obj_index = 0; + // for (int i = 0; i < numOps; i++) { + // uint8_t op = ops_ptr[i]; + // int opObjs = DisplayListInterpreter::opObjCounts[op]; + // if (opObjs > 0) { + // switch (static_cast(op)) { + // case cops_setImageFilter: { + // Dart_Handle image_filter = objects[obj_index++]; + // ImageFilter* decoded = + // tonic::DartConverter::FromDart(image_filter); + // } + // default: break; + // } + // } + // } + return fml::MakeRefCounted(ops_vector, data_vector); } @@ -143,7 +197,7 @@ Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> [ui_task_runner, snapshot_delegate, ops, data, picture_bounds, ui_task] { sk_sp raster_image = snapshot_delegate->MakeRasterSnapshot([ops = std::move(ops), data = std::move(data)](SkCanvas* canvas) { - DisplayListInterpreter interpreter(*ops, *data); + DisplayListInterpreter interpreter(ops, data); interpreter.Rasterize(canvas); }, picture_bounds); diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h index d378e4761bd73..5d17372b03fd4 100644 --- a/lib/ui/painting/display_list.h +++ b/lib/ui/painting/display_list.h @@ -22,7 +22,11 @@ class DisplayList : public RefCountedDartWrappable { FML_FRIEND_MAKE_REF_COUNTED(DisplayList); public: - static fml::RefPtr Create(tonic::Uint8List& ops, int numOps, tonic::DartByteData& data, int dataBytes); + static fml::RefPtr Create(tonic::Uint8List& ops, + int numOps, + tonic::DartByteData& data, + int dataBytes, + Dart_Handle objList); Dart_Handle toImage(uint32_t width, uint32_t height, From bb9f648f20e2564ea475c3cba0a9dd6b562847c8 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 28 Mar 2021 00:47:24 -0700 Subject: [PATCH 05/37] fix angle extraction and missing break statements --- flow/display_list_interpreter.cc | 8 ++++---- flow/display_list_interpreter.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 38b83fe0d865c..3b019e046b478 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -94,7 +94,7 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { case cops_clearAA: paint.setAntiAlias(false); break; case cops_setDither: paint.setDither(true); break; case cops_clearDither: paint.setDither(false); break; - case cops_setInvertColors: invertColors = true; paint.setColorFilter(makeColorFilter(invertColors, colorFilter)); + case cops_setInvertColors: invertColors = true; paint.setColorFilter(makeColorFilter(invertColors, colorFilter)); break; case cops_clearInvertColors: invertColors = false; paint.setColorFilter(colorFilter); break; case cops_setColor: paint.setColor(GetColor()); break; case cops_setFillStyle: paint.setStyle(SkPaint::Style::kFill_Style); break; @@ -141,7 +141,7 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { case cops_translate: canvas->translate(GetScalar(), GetScalar()); break; case cops_scale: canvas->scale(GetScalar(), GetScalar()); break; - case cops_rotate: canvas->rotate(GetScalar() * 180 / M_PI); break; + case cops_rotate: canvas->rotate(GetAngle()); break; case cops_skew: canvas->skew(GetScalar(), GetScalar()); break; case cops_transform: break; // TODO(flar) deal with Float64List @@ -153,8 +153,8 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { case cops_drawRRect: canvas->drawRRect(GetRoundRect(), paint); break; case cops_drawDRRect: canvas->drawDRRect(GetRoundRect(), GetRoundRect(), paint); break; case cops_drawCircle: canvas->drawCircle(GetPoint(), GetScalar(), paint); break; - case cops_drawArc: canvas->drawArc(GetRect(), GetScalar(), GetScalar(), false, paint); - case cops_drawArcCenter: canvas->drawArc(GetRect(), GetScalar(), GetScalar(), true, paint); + case cops_drawArc: canvas->drawArc(GetRect(), GetAngle(), GetAngle(), false, paint); break; + case cops_drawArcCenter: canvas->drawArc(GetRect(), GetAngle(), GetAngle(), true, paint); break; case cops_drawLine: canvas->drawLine(GetPoint(), GetPoint(), paint); break; case cops_drawPath: break; // TODO(flar) deal with Path object diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 6fcb7e035d3b5..8d3d1bd9d3f6c 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -177,6 +177,7 @@ class DisplayListInterpreter { SkScalar GetScalar() { return static_cast(*data_it_++); } uint32_t GetUint32() { union { float f; uint32_t i; } data; data.f = *data_it_++; return data.i; } + SkScalar GetAngle() { return GetScalar() * 180.0 / M_PI; } SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } SkColor GetColor() { return static_cast(GetUint32()); } From 23c5f0f29f3c852d4f0104bdba02be23b76b06fb Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 28 Mar 2021 00:58:07 -0700 Subject: [PATCH 06/37] remove/silence overly verbose debugging prints --- flow/display_list_interpreter.cc | 10 ++++++---- lib/ui/painting.dart | 5 ----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 3b019e046b478..3a160982cb829 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -85,7 +85,6 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { SkPaint paint; bool invertColors = false; sk_sp colorFilter; - FML_LOG(ERROR) << "Starting ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); while (HasOp()) { FML_LOG(INFO) << DescribeNextOp(); CanvasOp op = GetOp(); @@ -180,9 +179,12 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { case cops_drawShadowOccluded: GetScalar(); break; // TODO(flar) deal with Path object } } - FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) - << ", data: " << (data_end_ - data_it_) - << ", save count delta: " << (canvas->getSaveCount() - entrySaveCount); + if (ops_it_ != ops_end_ || data_it_ != data_end_ || canvas->getSaveCount() != entrySaveCount) { + FML_LOG(ERROR) << "Starting ops: " << ops_vector_->size() << ", data: " << data_vector_->size(); + FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) + << ", data: " << (data_end_ - data_it_) + << ", save count delta: " << (canvas->getSaveCount() - entrySaveCount); + } } } // namespace flutter diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 3bef93cc439c9..04cedfc84ba4a 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5498,10 +5498,6 @@ class _DisplayListCanvas implements Canvas { _addFloat64List(matrix4); _ctm.mul(matrix4[0], matrix4[4], matrix4[12], matrix4[1], matrix4[5], matrix4[13]); - print('transform [${matrix4[ 0]}, ${matrix4[ 4]}, ${matrix4[ 8]}, ${matrix4[12]},'); - print(' ${matrix4[ 1]}, ${matrix4[ 5]}, ${matrix4[ 9]}, ${matrix4[13]},'); - print(' ${matrix4[ 2]}, ${matrix4[ 6]}, ${matrix4[10]}, ${matrix4[14]},'); - print(' ${matrix4[ 3]}, ${matrix4[ 7]}, ${matrix4[11]}, ${matrix4[15]}]'); } @override @@ -5947,7 +5943,6 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.drawParagraph); _addOffset(offset); _addParagraph(paragraph); - print('not really rendering: $paragraph'); } @override From e75156d4e45379c1688bed859b315db08d942ab1 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 28 Mar 2021 11:45:33 -0700 Subject: [PATCH 07/37] foreach macro dispatching of canvas ops --- flow/display_list_interpreter.cc | 257 ++++++++++++++++++------------- flow/display_list_interpreter.h | 200 +++++++++++++----------- 2 files changed, 253 insertions(+), 204 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 3a160982cb829..476cb72afe074 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -12,36 +12,36 @@ namespace flutter { -#define CANVAS_OP_MAKE_STRING(name, count, imask, objcount) #name -#define CANVAS_OP_MAKE_COUNT(name, count, imask, objcount) count -#define CANVAS_OP_MAKE_IMASK(name, count, imask, objcount) imask -#define CANVAS_OP_MAKE_OBJCOUNT(name, count, imask, objcount) objcount +#define CANVAS_OP_MAKE_STRING(name, count, imask, objcount) #name, +#define CANVAS_OP_MAKE_COUNT(name, count, imask, objcount) count, +#define CANVAS_OP_MAKE_IMASK(name, count, imask, objcount) imask, +#define CANVAS_OP_MAKE_OBJCOUNT(name, count, imask, objcount) objcount, const std::vector DisplayListInterpreter::opNames = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_STRING), + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_STRING) }; const std::vector DisplayListInterpreter::opArgCounts = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_COUNT), + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_COUNT) }; const std::vector DisplayListInterpreter::opArgImask = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_IMASK), + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_IMASK) }; const std::vector DisplayListInterpreter::opObjCounts = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_OBJCOUNT), + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_OBJCOUNT) }; DisplayListInterpreter::DisplayListInterpreter( std::shared_ptr> ops_vector, std::shared_ptr> data_vector) - : ops_vector_(ops_vector), - ops_it_(ops_vector->begin()), + : ops_it_(ops_vector->begin()), ops_end_(ops_vector->end()), - data_vector_(data_vector), data_it_(data_vector->begin()), - data_end_(data_vector->end()) {} + data_end_(data_vector->end()), + ops_vector_(std::move(ops_vector)), + data_vector_(std::move(data_vector)) {} static const std::array filter_qualities = { SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone), @@ -69,114 +69,28 @@ constexpr float invert_colors[20] = { 1.0, 1.0, 1.0, 1.0, 0 }; -static sk_sp makeColorFilter(bool invertColors, sk_sp filter) { - if (!invertColors) { - return filter; +sk_sp DisplayListInterpreter::makeColorFilter(RasterizeContext& context) { + if (!context.invertColors) { + return context.colorFilter; } - sk_sp invert_filter = invertColors ? SkColorFilters::Matrix(invert_colors) : nullptr; - if (filter) { - invert_filter = invert_filter->makeComposed(filter); + sk_sp invert_filter = SkColorFilters::Matrix(invert_colors); + if (context.colorFilter) { + invert_filter = invert_filter->makeComposed(context.colorFilter); } return invert_filter; } +#define CANVAS_OP_DISPATCH_OP(name, count, imask, objcount) \ + case cops_##name: { execute_##name(context); } break; + void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { int entrySaveCount = canvas->getSaveCount(); - SkPaint paint; - bool invertColors = false; - sk_sp colorFilter; + RasterizeContext context; + context.canvas = canvas; while (HasOp()) { FML_LOG(INFO) << DescribeNextOp(); - CanvasOp op = GetOp(); - switch (op) { - case cops_setAA: paint.setAntiAlias(true); break; - case cops_clearAA: paint.setAntiAlias(false); break; - case cops_setDither: paint.setDither(true); break; - case cops_clearDither: paint.setDither(false); break; - case cops_setInvertColors: invertColors = true; paint.setColorFilter(makeColorFilter(invertColors, colorFilter)); break; - case cops_clearInvertColors: invertColors = false; paint.setColorFilter(colorFilter); break; - case cops_setColor: paint.setColor(GetColor()); break; - case cops_setFillStyle: paint.setStyle(SkPaint::Style::kFill_Style); break; - case cops_setStrokeStyle: paint.setStyle(SkPaint::Style::kStroke_Style); break; - case cops_setStrokeWidth: paint.setStrokeWidth(GetScalar()); break; - case cops_setMiterLimit: paint.setStrokeMiter(GetScalar()); break; - case cops_setCapsButt: paint.setStrokeCap(SkPaint::Cap::kButt_Cap); break; - case cops_setCapsRound: paint.setStrokeCap(SkPaint::Cap::kRound_Cap); break; - case cops_setCapsSquare: paint.setStrokeCap(SkPaint::Cap::kSquare_Cap); break; - case cops_setJoinsMiter: paint.setStrokeJoin(SkPaint::Join::kMiter_Join); break; - case cops_setJoinsRound: paint.setStrokeJoin(SkPaint::Join::kRound_Join); break; - case cops_setJoinsBevel: paint.setStrokeJoin(SkPaint::Join::kBevel_Join); break; - case cops_clearShader: paint.setShader(nullptr); break; - case cops_setShader: break; // TODO(flar) deal with Shader object - case cops_clearMaskFilter: paint.setMaskFilter(nullptr); break; - case cops_setMaskFilterInner: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kInner_SkBlurStyle, GetScalar())); break; - case cops_setMaskFilterOuter: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kOuter_SkBlurStyle, GetScalar())); break; - case cops_setMaskFilterSolid: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kSolid_SkBlurStyle, GetScalar())); break; - case cops_setMaskFilterNormal: paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, GetScalar())); break; - case cops_clearColorFilter: colorFilter = nullptr; paint.setColorFilter(makeColorFilter(invertColors, colorFilter)); break; - case cops_setColorFilter: break; // TODO(flar) deal with Filter object - case cops_clearImageFilter: paint.setImageFilter(nullptr); break; - case cops_setImageFilter: break; // TODO(flar) deal with Filter object - case cops_setFilterQualityNearest: paint.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality); break; - case cops_setFilterQualityLinear: paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality); break; - case cops_setFilterQualityMipmap: paint.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); break; - case cops_setFilterQualityCubic: paint.setFilterQuality(SkFilterQuality::kHigh_SkFilterQuality); break; - case cops_setBlendMode: paint.setBlendMode(GetBlendMode()); break; - - case cops_save: canvas->save(); break; - case cops_saveLayer: canvas->saveLayer(nullptr, &paint); break; - case cops_saveLayerBounds: canvas->saveLayer(GetRect(), &paint); break; - case cops_restore: canvas->restore(); break; - - case cops_clipRect: canvas->clipRect(GetRect()); break; - case cops_clipRectAA: canvas->clipRect(GetRect(), true); break; - case cops_clipRectDiff: canvas->clipRect(GetRect(), SkClipOp::kDifference); break; - case cops_clipRectAADiff: canvas->clipRect(GetRect(), SkClipOp::kDifference, true); break; - - case cops_clipRRect: canvas->clipRRect(GetRoundRect()); break; - case cops_clipRRectAA: canvas->clipRRect(GetRoundRect(), true); break; - case cops_clipPath: break; // TODO(flar) deal with Path object - case cops_clipPathAA: break; // TODO(flar) deal with Path object - - case cops_translate: canvas->translate(GetScalar(), GetScalar()); break; - case cops_scale: canvas->scale(GetScalar(), GetScalar()); break; - case cops_rotate: canvas->rotate(GetAngle()); break; - case cops_skew: canvas->skew(GetScalar(), GetScalar()); break; - case cops_transform: break; // TODO(flar) deal with Float64List - - case cops_drawColor: canvas->drawColor(paint.getColor(), paint.getBlendMode()); break; - case cops_drawPaint: canvas->drawPaint(paint); break; - - case cops_drawRect: canvas->drawRect(GetRect(), paint); break; - case cops_drawOval: canvas->drawOval(GetRect(), paint); break; - case cops_drawRRect: canvas->drawRRect(GetRoundRect(), paint); break; - case cops_drawDRRect: canvas->drawDRRect(GetRoundRect(), GetRoundRect(), paint); break; - case cops_drawCircle: canvas->drawCircle(GetPoint(), GetScalar(), paint); break; - case cops_drawArc: canvas->drawArc(GetRect(), GetAngle(), GetAngle(), false, paint); break; - case cops_drawArcCenter: canvas->drawArc(GetRect(), GetAngle(), GetAngle(), true, paint); break; - case cops_drawLine: canvas->drawLine(GetPoint(), GetPoint(), paint); break; - case cops_drawPath: break; // TODO(flar) deal with Path object - - case cops_drawPoints: break; // TODO(flar) deal with List of points - case cops_drawLines: break; // TODO(flar) deal with List of points - case cops_drawPolygon: break; // TODO(flar) deal with List of points - case cops_drawVertices: break; // TODO(flar) deal with List of vertices - - case cops_drawImage: GetPoint(); break; // TODO(flar) deal with image object - case cops_drawImageRect: GetRect(); GetRect(); break; // TODO(flar) deal with image object - case cops_drawImageNine: GetRect(); GetRect(); break; // TODO(flar) deal with image object - case cops_drawAtlas: - case cops_drawAtlasColored: - break; - case cops_drawAtlasCulled: - case cops_drawAtlasColoredCulled: - GetRect(); - break; - - case cops_drawPicture: break; // TODO(flar) deal with Picture object - case cops_drawParagraph: GetPoint(); break; // TODO(flar) deal with Paragraph object - case cops_drawShadow: GetScalar(); break; // TODO(flar) deal with Path object - case cops_drawShadowOccluded: GetScalar(); break; // TODO(flar) deal with Path object + switch (GetOp()) { + FOR_EACH_CANVAS_OP(CANVAS_OP_DISPATCH_OP) } } if (ops_it_ != ops_end_ || data_it_ != data_end_ || canvas->getSaveCount() != entrySaveCount) { @@ -187,4 +101,125 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { } } +#define CANVAS_OP_DEFINE_OP(name, body) \ +void DisplayListInterpreter::execute_##name(RasterizeContext& context) { \ + body \ +} + +CANVAS_OP_DEFINE_OP(setAA, context.paint.setAntiAlias(true);) +CANVAS_OP_DEFINE_OP(clearAA, context.paint.setAntiAlias(false);) +CANVAS_OP_DEFINE_OP(setDither, context.paint.setDither(true);) +CANVAS_OP_DEFINE_OP(clearDither, context.paint.setDither(false);) + +CANVAS_OP_DEFINE_OP(setInvertColors, + context.invertColors = true; + context.paint.setColorFilter(makeColorFilter(context)); +) +CANVAS_OP_DEFINE_OP(clearInvertColors, + context.invertColors = false; + context.paint.setColorFilter(context.colorFilter); +) +CANVAS_OP_DEFINE_OP(clearColorFilter, + context.colorFilter = nullptr; + context.paint.setColorFilter(makeColorFilter(context)); +) +CANVAS_OP_DEFINE_OP(setColorFilter, /* TODO(flar) deal with Filter objec */) +CANVAS_OP_DEFINE_OP(setColor, context.paint.setColor(GetColor());) +CANVAS_OP_DEFINE_OP(setFillStyle, context.paint.setStyle(SkPaint::Style::kFill_Style);) +CANVAS_OP_DEFINE_OP(setStrokeStyle, context.paint.setStyle(SkPaint::Style::kStroke_Style);) +CANVAS_OP_DEFINE_OP(setStrokeWidth, context.paint.setStrokeWidth(GetScalar());) +CANVAS_OP_DEFINE_OP(setMiterLimit, context.paint.setStrokeMiter(GetScalar());) + +#define CANVAS_CAP_DEFINE_OP(cap) CANVAS_OP_DEFINE_OP(setCaps##cap, \ + context.paint.setStrokeCap(SkPaint::Cap::k##cap##_Cap); \ +) +CANVAS_CAP_DEFINE_OP(Butt) +CANVAS_CAP_DEFINE_OP(Round) +CANVAS_CAP_DEFINE_OP(Square) + +#define CANVAS_JOIN_DEFINE_OP(join) CANVAS_OP_DEFINE_OP(setJoins##join, \ + context.paint.setStrokeJoin(SkPaint::Join::k##join##_Join); \ +) +CANVAS_JOIN_DEFINE_OP(Miter) +CANVAS_JOIN_DEFINE_OP(Round) +CANVAS_JOIN_DEFINE_OP(Bevel) + +CANVAS_OP_DEFINE_OP(clearShader, context.paint.setShader(nullptr);) +CANVAS_OP_DEFINE_OP(setShader, /* TODO(flar) deal with Shader object */) + +CANVAS_OP_DEFINE_OP(clearMaskFilter, context.paint.setMaskFilter(nullptr);) +#define CANVAS_MASK_DEFINE_OP(type) CANVAS_OP_DEFINE_OP(setMaskFilter##type, \ + context.paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::k##type##_SkBlurStyle, GetScalar())); \ +) +CANVAS_MASK_DEFINE_OP(Inner) +CANVAS_MASK_DEFINE_OP(Outer) +CANVAS_MASK_DEFINE_OP(Solid) +CANVAS_MASK_DEFINE_OP(Normal) + +CANVAS_OP_DEFINE_OP(clearImageFilter, context.paint.setImageFilter(nullptr);) +CANVAS_OP_DEFINE_OP(setImageFilter, /* TODO(flar) deal with Filter object */) + +#define CANVAS_FQ_DEFINE_OP(op_type, enum_type) CANVAS_OP_DEFINE_OP(setFilterQuality##op_type, \ + context.paint.setFilterQuality(SkFilterQuality::k##enum_type##_SkFilterQuality); \ +) +CANVAS_FQ_DEFINE_OP(Nearest, None) +CANVAS_FQ_DEFINE_OP(Linear, Low) +CANVAS_FQ_DEFINE_OP(Mipmap, Medium) +CANVAS_FQ_DEFINE_OP(Cubic, High) + +CANVAS_OP_DEFINE_OP(setBlendMode, context.paint.setBlendMode(GetBlendMode());) + +CANVAS_OP_DEFINE_OP(save, context.canvas->save();) +CANVAS_OP_DEFINE_OP(saveLayer, context.canvas->saveLayer(nullptr, &context.paint);) +CANVAS_OP_DEFINE_OP(saveLayerBounds, context.canvas->saveLayer(GetRect(), &context.paint);) +CANVAS_OP_DEFINE_OP(restore, context.canvas->restore();) + +CANVAS_OP_DEFINE_OP(clipRect, context.canvas->clipRect(GetRect());) +CANVAS_OP_DEFINE_OP(clipRectAA, context.canvas->clipRect(GetRect(), true);) +CANVAS_OP_DEFINE_OP(clipRectDiff, context.canvas->clipRect(GetRect(), SkClipOp::kDifference);) +CANVAS_OP_DEFINE_OP(clipRectAADiff, context.canvas->clipRect(GetRect(), SkClipOp::kDifference, true);) + +CANVAS_OP_DEFINE_OP(clipRRect, context.canvas->clipRRect(GetRoundRect());) +CANVAS_OP_DEFINE_OP(clipRRectAA, context.canvas->clipRRect(GetRoundRect(), true);) +CANVAS_OP_DEFINE_OP(clipPath, /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(clipPathAA, /* TODO(flar) deal with Path object */) + +CANVAS_OP_DEFINE_OP(translate, context.canvas->translate(GetScalar(), GetScalar());) +CANVAS_OP_DEFINE_OP(scale, context.canvas->scale(GetScalar(), GetScalar());) +CANVAS_OP_DEFINE_OP(rotate, context.canvas->rotate(GetAngle());) +CANVAS_OP_DEFINE_OP(skew, context.canvas->skew(GetScalar(), GetScalar());) +CANVAS_OP_DEFINE_OP(transform, /* TODO(flar) deal with Float64List */) + +CANVAS_OP_DEFINE_OP(drawColor, context.canvas->drawColor(context.paint.getColor(), context.paint.getBlendMode());) +CANVAS_OP_DEFINE_OP(drawPaint, context.canvas->drawPaint(context.paint);) + +CANVAS_OP_DEFINE_OP(drawRect, context.canvas->drawRect(GetRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawOval, context.canvas->drawOval(GetRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawRRect, context.canvas->drawRRect(GetRoundRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawDRRect, context.canvas->drawDRRect(GetRoundRect(), GetRoundRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawCircle, context.canvas->drawCircle(GetPoint(), GetScalar(), context.paint);) +CANVAS_OP_DEFINE_OP(drawArc, context.canvas->drawArc(GetRect(), GetAngle(), GetAngle(), false, context.paint);) +CANVAS_OP_DEFINE_OP(drawArcCenter, context.canvas->drawArc(GetRect(), GetAngle(), GetAngle(), true, context.paint);) +CANVAS_OP_DEFINE_OP(drawLine, context.canvas->drawLine(GetPoint(), GetPoint(), context.paint);) +CANVAS_OP_DEFINE_OP(drawPath, /* TODO(flar) deal with Path object */) + +CANVAS_OP_DEFINE_OP(drawPoints, /* TODO(flar) deal with List of points */) +CANVAS_OP_DEFINE_OP(drawLines, /* TODO(flar) deal with List of points */) +CANVAS_OP_DEFINE_OP(drawPolygon, /* TODO(flar) deal with List of points */) +CANVAS_OP_DEFINE_OP(drawVertices, /* TODO(flar) deal with List of vertices */) + +CANVAS_OP_DEFINE_OP(drawImage, GetPoint(); /* TODO(flar) deal with image object */) +CANVAS_OP_DEFINE_OP(drawImageRect, GetRect(); GetRect(); /* TODO(flar) deal with image object */) +CANVAS_OP_DEFINE_OP(drawImageNine, GetRect(); GetRect(); /* TODO(flar) deal with image object */) + +CANVAS_OP_DEFINE_OP(drawAtlas, /* TODO(flar) deal with all of the atlas objects */) +CANVAS_OP_DEFINE_OP(drawAtlasColored, /* TODO(flar) deal with all of the atlas objects */) +CANVAS_OP_DEFINE_OP(drawAtlasCulled, GetRect(); /* TODO(flar) deal with all of the atlas objects */) +CANVAS_OP_DEFINE_OP(drawAtlasColoredCulled, GetRect(); /* TODO(flar) deal with all of the atlas objects */) + +CANVAS_OP_DEFINE_OP(drawPicture, /* TODO(flar) deal with Picture object */) +CANVAS_OP_DEFINE_OP(drawParagraph, GetPoint(); /* TODO(flar) deal with Paragraph object */) +CANVAS_OP_DEFINE_OP(drawShadow, GetScalar(); /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(drawShadowOccluded, GetScalar(); /* TODO(flar) deal with Path object */) + } // namespace flutter diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 8d3d1bd9d3f6c..0579717b5e3f7 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -15,102 +15,104 @@ namespace flutter { // opName (matches Dart enum name), numDataArgs, intArgMask, numObjArgs #define FOR_EACH_CANVAS_OP(V) \ - V(setAA, 0, 0, 0), \ - V(clearAA, 0, 0, 0), \ - V(setDither, 0, 0, 0), \ - V(clearDither, 0, 0, 0), \ - V(setInvertColors, 0, 0, 0), \ - V(clearInvertColors, 0, 0, 0), \ - V(setFillStyle, 0, 0, 0), \ - V(setStrokeStyle, 0, 0, 0), \ - \ - V(setCapsButt, 0, 0, 0), \ - V(setCapsRound, 0, 0, 0), \ - V(setCapsSquare, 0, 0, 0), \ - V(setJoinsBevel, 0, 0, 0), \ - V(setJoinsMiter, 0, 0, 0), \ - V(setJoinsRound, 0, 0, 0), \ - \ - V(setStrokeWidth, 1, 0, 0), \ - V(setMiterLimit, 1, 0, 0), \ - \ - V(setFilterQualityNearest, 0, 0, 0), \ - V(setFilterQualityLinear, 0, 0, 0), \ - V(setFilterQualityMipmap, 0, 0, 0), \ - V(setFilterQualityCubic, 0, 0, 0), \ - \ - V(setColor, 1, 0x1, 0), \ - V(setBlendMode, 1, 0x1, 0), \ - \ - V(setShader, 0, 0, 1), \ - V(clearShader, 0, 0, 0), \ - V(setColorFilter, 0, 0, 1), \ - V(clearColorFilter, 0, 0, 0), \ - V(setImageFilter, 0, 0, 1), \ - V(clearImageFilter, 0, 0, 0), \ - \ - V(clearMaskFilter, 0, 0, 0), \ - V(setMaskFilterNormal, 1, 0, 0), \ - V(setMaskFilterSolid, 1, 0, 0), \ - V(setMaskFilterOuter, 1, 0, 0), \ - V(setMaskFilterInner, 1, 0, 0), \ - \ - V(save, 0, 0, 0), \ - V(saveLayer, 0, 0, 0), \ - V(saveLayerBounds, 4, 0, 0), \ - V(restore, 0, 0, 0), \ - \ - V(translate, 2, 0, 0), \ - V(scale, 2, 0, 0), \ - V(rotate, 1, 0, 0), \ - V(skew, 2, 0, 0), \ - V(transform, 0, 0, 1), \ - \ - V(clipRect, 4, 0, 0), \ - V(clipRectAA, 4, 0, 0), \ - V(clipRectDiff, 4, 0, 0), \ - V(clipRectAADiff, 4, 0, 0), \ - V(clipRRect, 12, 0, 0), \ - V(clipRRectAA, 12, 0, 0), \ - V(clipPath, 0, 0, 1), \ - V(clipPathAA, 0, 0, 1), \ - \ - V(drawPaint, 0, 0, 0), \ - V(drawColor, 2, 0x3, 0), \ - \ - V(drawLine, 4, 0, 0), \ - V(drawRect, 4, 0, 0), \ - V(drawOval, 4, 0, 0), \ - V(drawCircle, 3, 0, 0), \ - V(drawRRect, 12, 0, 0), \ - V(drawDRRect, 24, 0, 0), \ - V(drawArc, 6, 0, 0), \ - V(drawArcCenter, 6, 0, 0), \ - V(drawPath, 0, 0, 1), \ - \ - V(drawPoints, 0, 0, 1), \ - V(drawLines, 0, 0, 1), \ - V(drawPolygon, 0, 0, 1), \ - V(drawVertices, 0, 0, 1), \ - \ - V(drawImage, 2, 0, 1), \ - V(drawImageRect, 8, 0, 1), \ - V(drawImageNine, 8, 0, 1), \ - V(drawAtlas, 0, 0, 3), \ - V(drawAtlasColored, 0, 0, 4), \ - V(drawAtlasCulled, 4, 0, 3), \ - V(drawAtlasColoredCulled, 4, 0, 4), \ - \ - V(drawParagraph, 2, 0, 1), \ - V(drawPicture, 0, 0, 1), \ - V(drawShadow, 1, 0, 1), \ + V(setAA, 0, 0, 0) \ + V(clearAA, 0, 0, 0) \ + V(setDither, 0, 0, 0) \ + V(clearDither, 0, 0, 0) \ + V(setInvertColors, 0, 0, 0) \ + V(clearInvertColors, 0, 0, 0) \ + V(setFillStyle, 0, 0, 0) \ + V(setStrokeStyle, 0, 0, 0) \ + \ + V(setCapsButt, 0, 0, 0) \ + V(setCapsRound, 0, 0, 0) \ + V(setCapsSquare, 0, 0, 0) \ + V(setJoinsBevel, 0, 0, 0) \ + V(setJoinsMiter, 0, 0, 0) \ + V(setJoinsRound, 0, 0, 0) \ + \ + V(setStrokeWidth, 1, 0, 0) \ + V(setMiterLimit, 1, 0, 0) \ + \ + V(setFilterQualityNearest, 0, 0, 0) \ + V(setFilterQualityLinear, 0, 0, 0) \ + V(setFilterQualityMipmap, 0, 0, 0) \ + V(setFilterQualityCubic, 0, 0, 0) \ + \ + V(setColor, 1, 0x1, 0) \ + V(setBlendMode, 1, 0x1, 0) \ + \ + V(setShader, 0, 0, 1) \ + V(clearShader, 0, 0, 0) \ + V(setColorFilter, 0, 0, 1) \ + V(clearColorFilter, 0, 0, 0) \ + V(setImageFilter, 0, 0, 1) \ + V(clearImageFilter, 0, 0, 0) \ + \ + V(clearMaskFilter, 0, 0, 0) \ + V(setMaskFilterNormal, 1, 0, 0) \ + V(setMaskFilterSolid, 1, 0, 0) \ + V(setMaskFilterOuter, 1, 0, 0) \ + V(setMaskFilterInner, 1, 0, 0) \ + \ + V(save, 0, 0, 0) \ + V(saveLayer, 0, 0, 0) \ + V(saveLayerBounds, 4, 0, 0) \ + V(restore, 0, 0, 0) \ + \ + V(translate, 2, 0, 0) \ + V(scale, 2, 0, 0) \ + V(rotate, 1, 0, 0) \ + V(skew, 2, 0, 0) \ + V(transform, 0, 0, 1) \ + \ + V(clipRect, 4, 0, 0) \ + V(clipRectAA, 4, 0, 0) \ + V(clipRectDiff, 4, 0, 0) \ + V(clipRectAADiff, 4, 0, 0) \ + V(clipRRect, 12, 0, 0) \ + V(clipRRectAA, 12, 0, 0) \ + V(clipPath, 0, 0, 1) \ + V(clipPathAA, 0, 0, 1) \ + \ + V(drawPaint, 0, 0, 0) \ + V(drawColor, 2, 0x3, 0) \ + \ + V(drawLine, 4, 0, 0) \ + V(drawRect, 4, 0, 0) \ + V(drawOval, 4, 0, 0) \ + V(drawCircle, 3, 0, 0) \ + V(drawRRect, 12, 0, 0) \ + V(drawDRRect, 24, 0, 0) \ + V(drawArc, 6, 0, 0) \ + V(drawArcCenter, 6, 0, 0) \ + V(drawPath, 0, 0, 1) \ + \ + V(drawPoints, 0, 0, 1) \ + V(drawLines, 0, 0, 1) \ + V(drawPolygon, 0, 0, 1) \ + V(drawVertices, 0, 0, 1) \ + \ + V(drawImage, 2, 0, 1) \ + V(drawImageRect, 8, 0, 1) \ + V(drawImageNine, 8, 0, 1) \ + V(drawAtlas, 0, 0, 3) \ + V(drawAtlasColored, 0, 0, 4) \ + V(drawAtlasCulled, 4, 0, 3) \ + V(drawAtlasColoredCulled, 4, 0, 4) \ + \ + V(drawParagraph, 2, 0, 1) \ + V(drawPicture, 0, 0, 1) \ + V(drawShadow, 1, 0, 1) \ V(drawShadowOccluded, 1, 0, 1) -#define CANVAS_OP_MAKE_ENUM(name, count, imask, objcount) cops_##name +#define CANVAS_OP_MAKE_ENUM(name, count, imask, objcount) cops_##name, enum CanvasOp { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM), + FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM) }; +#define CANVAS_OP_DECLARE_OP(name, count, imask, objcount) void execute_##name(RasterizeContext& context); + class DisplayListInterpreter { public: DisplayListInterpreter(std::shared_ptr> ops, @@ -126,13 +128,25 @@ class DisplayListInterpreter { static const std::vector opObjCounts; private: - std::shared_ptr> ops_vector_; std::vector::iterator ops_it_; const std::vector::iterator ops_end_; - std::shared_ptr> data_vector_; std::vector::iterator data_it_; const std::vector::iterator data_end_; + std::shared_ptr> ops_vector_; + std::shared_ptr> data_vector_; + + struct RasterizeContext { + SkCanvas *canvas; + SkPaint paint; + bool invertColors = false; + sk_sp colorFilter; + }; + + static sk_sp makeColorFilter(RasterizeContext& context); + + FOR_EACH_CANVAS_OP(CANVAS_OP_DECLARE_OP) + bool HasOp() { return ops_it_ < ops_end_; } CanvasOp GetOp() { return static_cast(*ops_it_++); } From e79fc243efcc8e173bbbe8b37406e66884bbd73a Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 28 Mar 2021 12:33:10 -0700 Subject: [PATCH 08/37] de-inline description function, fix an ops arg count --- flow/display_list_interpreter.cc | 38 +++++++++++++++++++++++++++++ flow/display_list_interpreter.h | 42 +++----------------------------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 476cb72afe074..5184c53c465e8 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -62,6 +62,44 @@ void DisplayListInterpreter::Describe() { FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); } +std::string DisplayListInterpreter::DescribeNextOp() { + if (!HasOp()) { + return "END-OF-LIST"; + } + std::stringstream ss; + int op_index = *ops_it_; + ss << opNames[op_index] << "(" << std::hex; + for (int i = 0; i < opArgCounts[op_index]; i++) { + if (i > 0) { + ss << ", "; + } + if (data_it_ + i < data_end_) { + union { float f; uint32_t i; } data; + data.f = data_it_[i]; + if ((opArgImask[op_index] & (1 << i)) == 0) { + ss << data.f; + } else { + ss << "0x" << data.i; + } + } else { + ss << "... UNDEFINED ..."; + break; + } + } + if (opObjCounts[op_index] > 0) { + if (opArgCounts[op_index] > 0) { + ss << ", "; + } + if (opObjCounts[op_index] > 1) { + ss << "[" << opObjCounts[op_index] << " objects]"; + } else { + ss << "[object]"; + } + } + ss << ")"; + return ss.str(); +} + constexpr float invert_colors[20] = { -1.0, 0, 0, 1.0, 0, 0, -1.0, 0, 1.0, 0, diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 0579717b5e3f7..557e26f5599b9 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -14,7 +14,7 @@ namespace flutter { // opName (matches Dart enum name), numDataArgs, intArgMask, numObjArgs -#define FOR_EACH_CANVAS_OP(V) \ +#define FOR_EACH_CANVAS_OP(V) \ V(setAA, 0, 0, 0) \ V(clearAA, 0, 0, 0) \ V(setDither, 0, 0, 0) \ @@ -76,7 +76,7 @@ namespace flutter { V(clipPathAA, 0, 0, 1) \ \ V(drawPaint, 0, 0, 0) \ - V(drawColor, 2, 0x3, 0) \ + V(drawColor, 0, 0, 0) \ \ V(drawLine, 4, 0, 0) \ V(drawRect, 4, 0, 0) \ @@ -150,43 +150,7 @@ class DisplayListInterpreter { bool HasOp() { return ops_it_ < ops_end_; } CanvasOp GetOp() { return static_cast(*ops_it_++); } - std::string DescribeNextOp() { - if (!HasOp()) { - return "END-OF-LIST"; - } - std::stringstream ss; - int op_index = *ops_it_; - ss << opNames[op_index] << "(" << std::hex; - for (int i = 0; i < opArgCounts[op_index]; i++) { - if (i > 0) { - ss << ", "; - } - if (data_it_ + i < data_end_) { - union { float f; uint32_t i; } data; - data.f = data_it_[i]; - if ((opArgImask[op_index] & (1 << i)) == 0) { - ss << data.f; - } else { - ss << "0x" << data.i; - } - } else { - ss << "... UNDEFINED ..."; - break; - } - } - if (opObjCounts[op_index] > 0) { - if (opArgCounts[op_index] > 0) { - ss << ", "; - } - if (opObjCounts[op_index] > 1) { - ss << "[" << opObjCounts[op_index] << " objects]"; - } else { - ss << "[object]"; - } - } - ss << ")"; - return ss.str(); - } + std::string DescribeNextOp(); SkScalar GetScalar() { return static_cast(*data_it_++); } uint32_t GetUint32() { union { float f; uint32_t i; } data; data.f = *data_it_++; return data.i; } From 3c367356c7fec987463ce8d929fb1b182f907a14 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 28 Mar 2021 16:13:03 -0700 Subject: [PATCH 09/37] embrace SkSamplingOptions, preparing for SkFilterQuality removal --- flow/display_list_interpreter.cc | 52 ++++++++++++++++++-------------- flow/display_list_interpreter.h | 10 +++++- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 5184c53c465e8..2fbc5568c06d7 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -12,25 +12,25 @@ namespace flutter { -#define CANVAS_OP_MAKE_STRING(name, count, imask, objcount) #name, -#define CANVAS_OP_MAKE_COUNT(name, count, imask, objcount) count, -#define CANVAS_OP_MAKE_IMASK(name, count, imask, objcount) imask, -#define CANVAS_OP_MAKE_OBJCOUNT(name, count, imask, objcount) objcount, +#define CANVAS_OP_TAKE_STRING(name, count, imask, objcount) #name, +#define CANVAS_OP_TAKE_COUNT(name, count, imask, objcount) count, +#define CANVAS_OP_TAKE_IMASK(name, count, imask, objcount) imask, +#define CANVAS_OP_TAKE_OBJCOUNT(name, count, imask, objcount) objcount, const std::vector DisplayListInterpreter::opNames = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_STRING) + FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_STRING) }; const std::vector DisplayListInterpreter::opArgCounts = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_COUNT) + FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_COUNT) }; const std::vector DisplayListInterpreter::opArgImask = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_IMASK) + FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_IMASK) }; const std::vector DisplayListInterpreter::opObjCounts = { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_OBJCOUNT) + FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_OBJCOUNT) }; DisplayListInterpreter::DisplayListInterpreter( @@ -43,13 +43,6 @@ DisplayListInterpreter::DisplayListInterpreter( ops_vector_(std::move(ops_vector)), data_vector_(std::move(data_vector)) {} -static const std::array filter_qualities = { - SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), - SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}), -}; - void DisplayListInterpreter::Describe() { FML_LOG(ERROR) << "Starting ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); while(HasOp()) { @@ -122,9 +115,11 @@ sk_sp DisplayListInterpreter::makeColorFilter(RasterizeContext& c case cops_##name: { execute_##name(context); } break; void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { - int entrySaveCount = canvas->getSaveCount(); RasterizeContext context; context.canvas = canvas; + context.filterMode = LinearSampling.filter; + context.sampling = LinearSampling; + int entrySaveCount = canvas->getSaveCount(); while (HasOp()) { FML_LOG(INFO) << DescribeNextOp(); switch (GetOp()) { @@ -197,13 +192,26 @@ CANVAS_MASK_DEFINE_OP(Normal) CANVAS_OP_DEFINE_OP(clearImageFilter, context.paint.setImageFilter(nullptr);) CANVAS_OP_DEFINE_OP(setImageFilter, /* TODO(flar) deal with Filter object */) -#define CANVAS_FQ_DEFINE_OP(op_type, enum_type) CANVAS_OP_DEFINE_OP(setFilterQuality##op_type, \ - context.paint.setFilterQuality(SkFilterQuality::k##enum_type##_SkFilterQuality); \ +const SkSamplingOptions DisplayListInterpreter::NearestSampling = + SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); +const SkSamplingOptions DisplayListInterpreter::LinearSampling = + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone); +const SkSamplingOptions DisplayListInterpreter::MipmapSampling = + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear); +const SkSamplingOptions DisplayListInterpreter::CubicSampling = + SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}); + +#define CANVAS_FQ_DEFINE_OP(op_type, enum_type, filter_mode) \ +CANVAS_OP_DEFINE_OP(setFilterQuality##op_type, \ + context.filterMode = SkFilterMode::filter_mode; \ + context.sampling = op_type##Sampling; \ + context.paint.setFilterQuality( \ + SkFilterQuality::k##enum_type##_SkFilterQuality); \ ) -CANVAS_FQ_DEFINE_OP(Nearest, None) -CANVAS_FQ_DEFINE_OP(Linear, Low) -CANVAS_FQ_DEFINE_OP(Mipmap, Medium) -CANVAS_FQ_DEFINE_OP(Cubic, High) +CANVAS_FQ_DEFINE_OP(Nearest, None, kNearest) +CANVAS_FQ_DEFINE_OP(Linear, Low, kLinear) +CANVAS_FQ_DEFINE_OP(Mipmap, Medium, kLinear) +CANVAS_FQ_DEFINE_OP(Cubic, High, kLinear) CANVAS_OP_DEFINE_OP(setBlendMode, context.paint.setBlendMode(GetBlendMode());) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 557e26f5599b9..b97c8d0223096 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -127,6 +127,11 @@ class DisplayListInterpreter { static const std::vector opArgImask; static const std::vector opObjCounts; + static const SkSamplingOptions NearestSampling; + static const SkSamplingOptions LinearSampling; + static const SkSamplingOptions MipmapSampling; + static const SkSamplingOptions CubicSampling; + private: std::vector::iterator ops_it_; const std::vector::iterator ops_end_; @@ -141,6 +146,8 @@ class DisplayListInterpreter { SkPaint paint; bool invertColors = false; sk_sp colorFilter; + SkFilterMode filterMode; + SkSamplingOptions sampling; }; static sk_sp makeColorFilter(RasterizeContext& context); @@ -157,8 +164,9 @@ class DisplayListInterpreter { SkScalar GetAngle() { return GetScalar() * 180.0 / M_PI; } SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } - SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } SkColor GetColor() { return static_cast(GetUint32()); } + + SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } SkRect GetRect() { return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), GetScalar()); } SkRRect GetRoundRect() { SkRect rect = GetRect(); From d3f2ea215f27a6ce06bf245bfc0912a1ce8f0d93 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 28 Mar 2021 22:55:50 -0700 Subject: [PATCH 10/37] Formalize parameter descriptions of display list ops, remove some dead code --- flow/display_list_interpreter.cc | 204 ++++++++++-------- flow/display_list_interpreter.h | 347 ++++++++++++++++++------------ flow/layers/display_list_layer.cc | 17 -- lib/ui/painting.dart | 79 ++++--- lib/ui/painting/display_list.cc | 25 ++- lib/ui/painting/display_list.h | 36 +--- 6 files changed, 391 insertions(+), 317 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 2fbc5568c06d7..659cb8bf5a2ed 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -12,81 +12,81 @@ namespace flutter { -#define CANVAS_OP_TAKE_STRING(name, count, imask, objcount) #name, -#define CANVAS_OP_TAKE_COUNT(name, count, imask, objcount) count, -#define CANVAS_OP_TAKE_IMASK(name, count, imask, objcount) imask, -#define CANVAS_OP_TAKE_OBJCOUNT(name, count, imask, objcount) objcount, +#define CANVAS_OP_TAKE_STRING(name, arg) #name, +#define CANVAS_OP_TAKE_ARGS(name, args) CANVAS_OP_ARGS_##args, const std::vector DisplayListInterpreter::opNames = { FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_STRING) }; -const std::vector DisplayListInterpreter::opArgCounts = { - FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_COUNT) -}; - -const std::vector DisplayListInterpreter::opArgImask = { - FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_IMASK) -}; - -const std::vector DisplayListInterpreter::opObjCounts = { - FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_OBJCOUNT) +const std::vector DisplayListInterpreter::opArguments = { + FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_ARGS) }; DisplayListInterpreter::DisplayListInterpreter( std::shared_ptr> ops_vector, std::shared_ptr> data_vector) - : ops_it_(ops_vector->begin()), - ops_end_(ops_vector->end()), - data_it_(data_vector->begin()), - data_end_(data_vector->end()), - ops_vector_(std::move(ops_vector)), + : ops_vector_(std::move(ops_vector)), data_vector_(std::move(data_vector)) {} void DisplayListInterpreter::Describe() { - FML_LOG(ERROR) << "Starting ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); - while(HasOp()) { - FML_LOG(ERROR) << DescribeNextOp(); - CanvasOp op = GetOp(); - for (int i = 0; i < opArgCounts[op]; i++) { - GetScalar(); - } + Iterator it(this); + FML_LOG(ERROR) << "Starting ops: " << (it.ops_end - it.ops) + << ", data: " << (it.data_end - it.data); + while(it.HasOp()) { + FML_LOG(ERROR) << DescribeOneOp(it); } - FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) << ", data: " << (data_end_ - data_it_); + FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) + << ", data: " << (it.data_end - it.data); +} + +std::string DisplayListInterpreter::DescribeNextOp(const Iterator& it) { + Iterator it_copy(it); + return DescribeOneOp(it_copy); } -std::string DisplayListInterpreter::DescribeNextOp() { - if (!HasOp()) { +std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { + if (!it.HasOp()) { return "END-OF-LIST"; } std::stringstream ss; - int op_index = *ops_it_; - ss << opNames[op_index] << "(" << std::hex; - for (int i = 0; i < opArgCounts[op_index]; i++) { - if (i > 0) { - ss << ", "; - } - if (data_it_ + i < data_end_) { - union { float f; uint32_t i; } data; - data.f = data_it_[i]; - if ((opArgImask[op_index] & (1 << i)) == 0) { - ss << data.f; - } else { - ss << "0x" << data.i; - } + CanvasOp op = it.GetOp(); + ss << opNames[op] << "("; + bool first = true; + for (uint32_t arg_types = opArguments[op]; arg_types != 0; arg_types >>= CANVAS_OP_ARG_SHIFT) { + if (first) { + first = false; } else { - ss << "... UNDEFINED ..."; - break; - } - } - if (opObjCounts[op_index] > 0) { - if (opArgCounts[op_index] > 0) { ss << ", "; } - if (opObjCounts[op_index] > 1) { - ss << "[" << opObjCounts[op_index] << " objects]"; - } else { - ss << "[object]"; + CanvasOpArg arg_type = static_cast(arg_types & CANVAS_OP_ARG_MASK); + switch (arg_type) { + case empty: ss << "?none?"; break; // This should never happen + case scalar: ss << it.GetScalar(); break; + case color: ss << "Color(" << std::hex << "0x" << it.GetUint32() << ")"; break; + case blend_mode: ss << "BlendMode(" << std::dec << it.GetUint32() << ")"; break; + case angle: ss << it.GetAngle(); break; + case point: ss << "Point(x: " << it.GetScalar() << ", y: " << it.GetScalar() << ")"; break; + case rect: ss << "Rect(l: " << it.GetScalar() << ", t: " << it.GetScalar() + << ", r: " << it.GetScalar() << ", b: " << it.GetScalar() << ")"; break; + case round_rect: ss << "RoundRect(" + << "Rect(l: " << it.GetScalar() << ", t: " << it.GetScalar() << ", r: " + << it.GetScalar() << ", b: " << it.GetScalar() << "), " + << "ul: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " + << "ur: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " + << "lr: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " + << "ll: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "))"; break; + case int32_list: ss << "[Int32List]"; break; + case float32_list: ss << "[Float32List]"; break; + case matrix_row3: ss << "[" << it.GetScalar() << ", " << it.GetScalar() << ", " << it.GetScalar() << "]"; break; + case image: ss << "[Image]"; break; + case path: ss << "[Path]"; break; + case vertices: ss << "[Vertices]"; break; + case paragraph: ss << "[Paragraph]"; break; + case picture: ss << "[Picture]"; break; + case shader: ss << "[Shader]"; break; + case color_filter: ss << "[ColorFilter]"; break; + case image_filter: ss << "[ImageFilter]"; break; } } ss << ")"; @@ -111,8 +111,8 @@ sk_sp DisplayListInterpreter::makeColorFilter(RasterizeContext& c return invert_filter; } -#define CANVAS_OP_DISPATCH_OP(name, count, imask, objcount) \ - case cops_##name: { execute_##name(context); } break; +#define CANVAS_OP_DISPATCH_OP(name, args) \ + case cops_##name: { execute_##name(context, it); } break; void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { RasterizeContext context; @@ -120,22 +120,23 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { context.filterMode = LinearSampling.filter; context.sampling = LinearSampling; int entrySaveCount = canvas->getSaveCount(); - while (HasOp()) { - FML_LOG(INFO) << DescribeNextOp(); - switch (GetOp()) { + Iterator it(this); + while (it.HasOp()) { + FML_LOG(INFO) << DescribeNextOp(it); + switch (it.GetOp()) { FOR_EACH_CANVAS_OP(CANVAS_OP_DISPATCH_OP) } } - if (ops_it_ != ops_end_ || data_it_ != data_end_ || canvas->getSaveCount() != entrySaveCount) { + if (it.ops != it.ops_end || it.data != it.data_end || canvas->getSaveCount() != entrySaveCount) { FML_LOG(ERROR) << "Starting ops: " << ops_vector_->size() << ", data: " << data_vector_->size(); - FML_LOG(ERROR) << "Remaining ops: " << (ops_end_ - ops_it_) - << ", data: " << (data_end_ - data_it_) + FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) + << ", data: " << (it.data_end - it.data) << ", save count delta: " << (canvas->getSaveCount() - entrySaveCount); } } #define CANVAS_OP_DEFINE_OP(name, body) \ -void DisplayListInterpreter::execute_##name(RasterizeContext& context) { \ +void DisplayListInterpreter::execute_##name(RasterizeContext& context, Iterator& it) { \ body \ } @@ -157,11 +158,11 @@ CANVAS_OP_DEFINE_OP(clearColorFilter, context.paint.setColorFilter(makeColorFilter(context)); ) CANVAS_OP_DEFINE_OP(setColorFilter, /* TODO(flar) deal with Filter objec */) -CANVAS_OP_DEFINE_OP(setColor, context.paint.setColor(GetColor());) +CANVAS_OP_DEFINE_OP(setColor, context.paint.setColor(it.GetColor());) CANVAS_OP_DEFINE_OP(setFillStyle, context.paint.setStyle(SkPaint::Style::kFill_Style);) CANVAS_OP_DEFINE_OP(setStrokeStyle, context.paint.setStyle(SkPaint::Style::kStroke_Style);) -CANVAS_OP_DEFINE_OP(setStrokeWidth, context.paint.setStrokeWidth(GetScalar());) -CANVAS_OP_DEFINE_OP(setMiterLimit, context.paint.setStrokeMiter(GetScalar());) +CANVAS_OP_DEFINE_OP(setStrokeWidth, context.paint.setStrokeWidth(it.GetScalar());) +CANVAS_OP_DEFINE_OP(setMiterLimit, context.paint.setStrokeMiter(it.GetScalar());) #define CANVAS_CAP_DEFINE_OP(cap) CANVAS_OP_DEFINE_OP(setCaps##cap, \ context.paint.setStrokeCap(SkPaint::Cap::k##cap##_Cap); \ @@ -182,7 +183,7 @@ CANVAS_OP_DEFINE_OP(setShader, /* TODO(flar) deal with Shader object */) CANVAS_OP_DEFINE_OP(clearMaskFilter, context.paint.setMaskFilter(nullptr);) #define CANVAS_MASK_DEFINE_OP(type) CANVAS_OP_DEFINE_OP(setMaskFilter##type, \ - context.paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::k##type##_SkBlurStyle, GetScalar())); \ + context.paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::k##type##_SkBlurStyle, it.GetScalar())); \ ) CANVAS_MASK_DEFINE_OP(Inner) CANVAS_MASK_DEFINE_OP(Outer) @@ -213,40 +214,53 @@ CANVAS_FQ_DEFINE_OP(Linear, Low, kLinear) CANVAS_FQ_DEFINE_OP(Mipmap, Medium, kLinear) CANVAS_FQ_DEFINE_OP(Cubic, High, kLinear) -CANVAS_OP_DEFINE_OP(setBlendMode, context.paint.setBlendMode(GetBlendMode());) +CANVAS_OP_DEFINE_OP(setBlendMode, context.paint.setBlendMode(it.GetBlendMode());) CANVAS_OP_DEFINE_OP(save, context.canvas->save();) CANVAS_OP_DEFINE_OP(saveLayer, context.canvas->saveLayer(nullptr, &context.paint);) -CANVAS_OP_DEFINE_OP(saveLayerBounds, context.canvas->saveLayer(GetRect(), &context.paint);) +CANVAS_OP_DEFINE_OP(saveLayerBounds, context.canvas->saveLayer(it.GetRect(), &context.paint);) CANVAS_OP_DEFINE_OP(restore, context.canvas->restore();) -CANVAS_OP_DEFINE_OP(clipRect, context.canvas->clipRect(GetRect());) -CANVAS_OP_DEFINE_OP(clipRectAA, context.canvas->clipRect(GetRect(), true);) -CANVAS_OP_DEFINE_OP(clipRectDiff, context.canvas->clipRect(GetRect(), SkClipOp::kDifference);) -CANVAS_OP_DEFINE_OP(clipRectAADiff, context.canvas->clipRect(GetRect(), SkClipOp::kDifference, true);) +CANVAS_OP_DEFINE_OP(clipRect, context.canvas->clipRect(it.GetRect());) +CANVAS_OP_DEFINE_OP(clipRectAA, context.canvas->clipRect(it.GetRect(), true);) +CANVAS_OP_DEFINE_OP(clipRectDiff, context.canvas->clipRect(it.GetRect(), SkClipOp::kDifference);) +CANVAS_OP_DEFINE_OP(clipRectAADiff, context.canvas->clipRect(it.GetRect(), SkClipOp::kDifference, true);) -CANVAS_OP_DEFINE_OP(clipRRect, context.canvas->clipRRect(GetRoundRect());) -CANVAS_OP_DEFINE_OP(clipRRectAA, context.canvas->clipRRect(GetRoundRect(), true);) +CANVAS_OP_DEFINE_OP(clipRRect, context.canvas->clipRRect(it.GetRoundRect());) +CANVAS_OP_DEFINE_OP(clipRRectAA, context.canvas->clipRRect(it.GetRoundRect(), true);) CANVAS_OP_DEFINE_OP(clipPath, /* TODO(flar) deal with Path object */) CANVAS_OP_DEFINE_OP(clipPathAA, /* TODO(flar) deal with Path object */) -CANVAS_OP_DEFINE_OP(translate, context.canvas->translate(GetScalar(), GetScalar());) -CANVAS_OP_DEFINE_OP(scale, context.canvas->scale(GetScalar(), GetScalar());) -CANVAS_OP_DEFINE_OP(rotate, context.canvas->rotate(GetAngle());) -CANVAS_OP_DEFINE_OP(skew, context.canvas->skew(GetScalar(), GetScalar());) -CANVAS_OP_DEFINE_OP(transform, /* TODO(flar) deal with Float64List */) +CANVAS_OP_DEFINE_OP(translate, context.canvas->translate(it.GetScalar(), it.GetScalar());) +CANVAS_OP_DEFINE_OP(scale, context.canvas->scale(it.GetScalar(), it.GetScalar());) +CANVAS_OP_DEFINE_OP(rotate, context.canvas->rotate(it.GetAngle());) +CANVAS_OP_DEFINE_OP(skew, context.canvas->skew(it.GetScalar(), it.GetScalar());) +CANVAS_OP_DEFINE_OP(transform2x3, + context.canvas->concat(SkMatrix::MakeAll( + it.GetScalar(), it.GetScalar(), it.GetScalar(), + it.GetScalar(), it.GetScalar(), it.GetScalar(), + 0.0, 0.0, 0.1 + )); +) +CANVAS_OP_DEFINE_OP(transform3x3, + context.canvas->concat(SkMatrix::MakeAll( + it.GetScalar(), it.GetScalar(), it.GetScalar(), + it.GetScalar(), it.GetScalar(), it.GetScalar(), + it.GetScalar(), it.GetScalar(), it.GetScalar() + )); +) CANVAS_OP_DEFINE_OP(drawColor, context.canvas->drawColor(context.paint.getColor(), context.paint.getBlendMode());) CANVAS_OP_DEFINE_OP(drawPaint, context.canvas->drawPaint(context.paint);) -CANVAS_OP_DEFINE_OP(drawRect, context.canvas->drawRect(GetRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawOval, context.canvas->drawOval(GetRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawRRect, context.canvas->drawRRect(GetRoundRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawDRRect, context.canvas->drawDRRect(GetRoundRect(), GetRoundRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawCircle, context.canvas->drawCircle(GetPoint(), GetScalar(), context.paint);) -CANVAS_OP_DEFINE_OP(drawArc, context.canvas->drawArc(GetRect(), GetAngle(), GetAngle(), false, context.paint);) -CANVAS_OP_DEFINE_OP(drawArcCenter, context.canvas->drawArc(GetRect(), GetAngle(), GetAngle(), true, context.paint);) -CANVAS_OP_DEFINE_OP(drawLine, context.canvas->drawLine(GetPoint(), GetPoint(), context.paint);) +CANVAS_OP_DEFINE_OP(drawRect, context.canvas->drawRect(it.GetRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawOval, context.canvas->drawOval(it.GetRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawRRect, context.canvas->drawRRect(it.GetRoundRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawDRRect, context.canvas->drawDRRect(it.GetRoundRect(), it.GetRoundRect(), context.paint);) +CANVAS_OP_DEFINE_OP(drawCircle, context.canvas->drawCircle(it.GetPoint(), it.GetScalar(), context.paint);) +CANVAS_OP_DEFINE_OP(drawArc, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), false, context.paint);) +CANVAS_OP_DEFINE_OP(drawArcCenter, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), true, context.paint);) +CANVAS_OP_DEFINE_OP(drawLine, context.canvas->drawLine(it.GetPoint(), it.GetPoint(), context.paint);) CANVAS_OP_DEFINE_OP(drawPath, /* TODO(flar) deal with Path object */) CANVAS_OP_DEFINE_OP(drawPoints, /* TODO(flar) deal with List of points */) @@ -254,18 +268,18 @@ CANVAS_OP_DEFINE_OP(drawLines, /* TODO(flar) deal with List of points */) CANVAS_OP_DEFINE_OP(drawPolygon, /* TODO(flar) deal with List of points */) CANVAS_OP_DEFINE_OP(drawVertices, /* TODO(flar) deal with List of vertices */) -CANVAS_OP_DEFINE_OP(drawImage, GetPoint(); /* TODO(flar) deal with image object */) -CANVAS_OP_DEFINE_OP(drawImageRect, GetRect(); GetRect(); /* TODO(flar) deal with image object */) -CANVAS_OP_DEFINE_OP(drawImageNine, GetRect(); GetRect(); /* TODO(flar) deal with image object */) +CANVAS_OP_DEFINE_OP(drawImage, it.GetPoint(); /* TODO(flar) deal with image object */) +CANVAS_OP_DEFINE_OP(drawImageRect, it.GetRect(); it.GetRect(); /* TODO(flar) deal with image object */) +CANVAS_OP_DEFINE_OP(drawImageNine, it.GetRect(); it.GetRect(); /* TODO(flar) deal with image object */) CANVAS_OP_DEFINE_OP(drawAtlas, /* TODO(flar) deal with all of the atlas objects */) CANVAS_OP_DEFINE_OP(drawAtlasColored, /* TODO(flar) deal with all of the atlas objects */) -CANVAS_OP_DEFINE_OP(drawAtlasCulled, GetRect(); /* TODO(flar) deal with all of the atlas objects */) -CANVAS_OP_DEFINE_OP(drawAtlasColoredCulled, GetRect(); /* TODO(flar) deal with all of the atlas objects */) +CANVAS_OP_DEFINE_OP(drawAtlasCulled, it.GetRect(); /* TODO(flar) deal with all of the atlas objects */) +CANVAS_OP_DEFINE_OP(drawAtlasColoredCulled, it.GetRect(); /* TODO(flar) deal with all of the atlas objects */) CANVAS_OP_DEFINE_OP(drawPicture, /* TODO(flar) deal with Picture object */) -CANVAS_OP_DEFINE_OP(drawParagraph, GetPoint(); /* TODO(flar) deal with Paragraph object */) -CANVAS_OP_DEFINE_OP(drawShadow, GetScalar(); /* TODO(flar) deal with Path object */) -CANVAS_OP_DEFINE_OP(drawShadowOccluded, GetScalar(); /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(drawParagraph, it.GetPoint(); /* TODO(flar) deal with Paragraph object */) +CANVAS_OP_DEFINE_OP(drawShadow, it.GetScalar(); /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(drawShadowOccluded, it.GetScalar(); /* TODO(flar) deal with Path object */) } // namespace flutter diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index b97c8d0223096..6ef92cdc0e7e9 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -13,106 +13,172 @@ namespace flutter { -// opName (matches Dart enum name), numDataArgs, intArgMask, numObjArgs -#define FOR_EACH_CANVAS_OP(V) \ - V(setAA, 0, 0, 0) \ - V(clearAA, 0, 0, 0) \ - V(setDither, 0, 0, 0) \ - V(clearDither, 0, 0, 0) \ - V(setInvertColors, 0, 0, 0) \ - V(clearInvertColors, 0, 0, 0) \ - V(setFillStyle, 0, 0, 0) \ - V(setStrokeStyle, 0, 0, 0) \ - \ - V(setCapsButt, 0, 0, 0) \ - V(setCapsRound, 0, 0, 0) \ - V(setCapsSquare, 0, 0, 0) \ - V(setJoinsBevel, 0, 0, 0) \ - V(setJoinsMiter, 0, 0, 0) \ - V(setJoinsRound, 0, 0, 0) \ - \ - V(setStrokeWidth, 1, 0, 0) \ - V(setMiterLimit, 1, 0, 0) \ - \ - V(setFilterQualityNearest, 0, 0, 0) \ - V(setFilterQualityLinear, 0, 0, 0) \ - V(setFilterQualityMipmap, 0, 0, 0) \ - V(setFilterQualityCubic, 0, 0, 0) \ - \ - V(setColor, 1, 0x1, 0) \ - V(setBlendMode, 1, 0x1, 0) \ - \ - V(setShader, 0, 0, 1) \ - V(clearShader, 0, 0, 0) \ - V(setColorFilter, 0, 0, 1) \ - V(clearColorFilter, 0, 0, 0) \ - V(setImageFilter, 0, 0, 1) \ - V(clearImageFilter, 0, 0, 0) \ - \ - V(clearMaskFilter, 0, 0, 0) \ - V(setMaskFilterNormal, 1, 0, 0) \ - V(setMaskFilterSolid, 1, 0, 0) \ - V(setMaskFilterOuter, 1, 0, 0) \ - V(setMaskFilterInner, 1, 0, 0) \ - \ - V(save, 0, 0, 0) \ - V(saveLayer, 0, 0, 0) \ - V(saveLayerBounds, 4, 0, 0) \ - V(restore, 0, 0, 0) \ - \ - V(translate, 2, 0, 0) \ - V(scale, 2, 0, 0) \ - V(rotate, 1, 0, 0) \ - V(skew, 2, 0, 0) \ - V(transform, 0, 0, 1) \ - \ - V(clipRect, 4, 0, 0) \ - V(clipRectAA, 4, 0, 0) \ - V(clipRectDiff, 4, 0, 0) \ - V(clipRectAADiff, 4, 0, 0) \ - V(clipRRect, 12, 0, 0) \ - V(clipRRectAA, 12, 0, 0) \ - V(clipPath, 0, 0, 1) \ - V(clipPathAA, 0, 0, 1) \ - \ - V(drawPaint, 0, 0, 0) \ - V(drawColor, 0, 0, 0) \ - \ - V(drawLine, 4, 0, 0) \ - V(drawRect, 4, 0, 0) \ - V(drawOval, 4, 0, 0) \ - V(drawCircle, 3, 0, 0) \ - V(drawRRect, 12, 0, 0) \ - V(drawDRRect, 24, 0, 0) \ - V(drawArc, 6, 0, 0) \ - V(drawArcCenter, 6, 0, 0) \ - V(drawPath, 0, 0, 1) \ - \ - V(drawPoints, 0, 0, 1) \ - V(drawLines, 0, 0, 1) \ - V(drawPolygon, 0, 0, 1) \ - V(drawVertices, 0, 0, 1) \ - \ - V(drawImage, 2, 0, 1) \ - V(drawImageRect, 8, 0, 1) \ - V(drawImageNine, 8, 0, 1) \ - V(drawAtlas, 0, 0, 3) \ - V(drawAtlasColored, 0, 0, 4) \ - V(drawAtlasCulled, 4, 0, 3) \ - V(drawAtlasColoredCulled, 4, 0, 4) \ - \ - V(drawParagraph, 2, 0, 1) \ - V(drawPicture, 0, 0, 1) \ - V(drawShadow, 1, 0, 1) \ - V(drawShadowOccluded, 1, 0, 1) - -#define CANVAS_OP_MAKE_ENUM(name, count, imask, objcount) cops_##name, +enum CanvasOpArg { + empty, // Forces all following enum values to be non-zero + scalar, + color, + blend_mode, + angle, + point, + rect, + round_rect, + int32_list, + float32_list, + matrix_row3, + image, + path, + vertices, + paragraph, + picture, + shader, + color_filter, + image_filter, +}; +#define CANVAS_OP_ARG_SHIFT 5 +#define CANVAS_OP_ARG_MASK ((1 << CANVAS_OP_ARG_SHIFT) - 1) + +#define CANVAS_OP_APPEND_ARG(arg_list, arg) \ + (((arg_list) << CANVAS_OP_ARG_SHIFT) | CanvasOpArg::arg) +#define CANVAS_OP_ARGS1(arg) \ + (CanvasOpArg::arg) +#define CANVAS_OP_ARGS2(arg1, arg2) \ + CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS1(arg2), arg1) +#define CANVAS_OP_ARGS3(arg1, arg2, arg3) \ + CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS2(arg2, arg3), arg1) +#define CANVAS_OP_ARGS4(arg1, arg2, arg3, arg4) \ + CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS3(arg2, arg3, arg4), arg1) +#define CANVAS_OP_ARGS5(arg1, arg2, arg3, arg4, arg5) \ + CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS4(arg2, arg3, arg4, arg5), arg1) + +#define CANVAS_OP_ARGS__ 0 +#define CANVAS_OP_ARGS_Scalar CANVAS_OP_ARGS1(scalar) +#define CANVAS_OP_ARGS_2Scalars CANVAS_OP_ARGS2(scalar, scalar) +#define CANVAS_OP_ARGS_Angle CANVAS_OP_ARGS1(angle) +#define CANVAS_OP_ARGS_Color CANVAS_OP_ARGS1(color) +#define CANVAS_OP_ARGS_BlendMode CANVAS_OP_ARGS1(blend_mode) +#define CANVAS_OP_ARGS_Point_Scalar CANVAS_OP_ARGS2(point, scalar) +#define CANVAS_OP_ARGS_2Points CANVAS_OP_ARGS2(point, point) +#define CANVAS_OP_ARGS_Rect CANVAS_OP_ARGS1(rect) +#define CANVAS_OP_ARGS_Rect_2Angles CANVAS_OP_ARGS3(rect, angle, angle) +#define CANVAS_OP_ARGS_RoundRect CANVAS_OP_ARGS1(round_rect) +#define CANVAS_OP_ARGS_2RoundRects CANVAS_OP_ARGS2(round_rect, round_rect) +#define CANVAS_OP_ARGS_F32List CANVAS_OP_ARGS1(float32_list) +#define CANVAS_OP_ARGS_Matrix2x3 CANVAS_OP_ARGS2(matrix_row3, matrix_row3) +#define CANVAS_OP_ARGS_Matrix3x3 CANVAS_OP_ARGS3(matrix_row3, matrix_row3, matrix_row3) +#define CANVAS_OP_ARGS_Path CANVAS_OP_ARGS1(path) +#define CANVAS_OP_ARGS_Path_Scalar CANVAS_OP_ARGS2(path, scalar) +#define CANVAS_OP_ARGS_Vertices CANVAS_OP_ARGS1(vertices) +#define CANVAS_OP_ARGS_Image_Point CANVAS_OP_ARGS2(image, point) +#define CANVAS_OP_ARGS_Image_2Rects CANVAS_OP_ARGS3(image, rect, rect) +#define CANVAS_OP_ARGS_Atlas CANVAS_OP_ARGS3(image, float32_list, float32_list) +#define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS4(image, float32_list, float32_list, int32_list) +#define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS4(image, float32_list, float32_list, rect) +#define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS5(image, float32_list, float32_list, int32_list, rect) +#define CANVAS_OP_ARGS_Paragraph_Point CANVAS_OP_ARGS2(paragraph, point) +#define CANVAS_OP_ARGS_Picture CANVAS_OP_ARGS1(picture) +#define CANVAS_OP_ARGS_Shader CANVAS_OP_ARGS1(shader) +#define CANVAS_OP_ARGS_ColorFilter CANVAS_OP_ARGS1(color_filter) +#define CANVAS_OP_ARGS_ImageFilter CANVAS_OP_ARGS1(image_filter) + +// opName (matches Dart enum name), argListDescriptor +#define FOR_EACH_CANVAS_OP(V) \ + V(setAA, _) \ + V(clearAA, _) \ + V(setDither, _) \ + V(clearDither, _) \ + V(setInvertColors, _) \ + V(clearInvertColors, _) \ + V(setFillStyle, _) \ + V(setStrokeStyle, _) \ + \ + V(setCapsButt, _) \ + V(setCapsRound, _) \ + V(setCapsSquare, _) \ + V(setJoinsBevel, _) \ + V(setJoinsMiter, _) \ + V(setJoinsRound, _) \ + \ + V(setStrokeWidth, Scalar) \ + V(setMiterLimit, Scalar) \ + \ + V(setFilterQualityNearest, _) \ + V(setFilterQualityLinear, _) \ + V(setFilterQualityMipmap, _) \ + V(setFilterQualityCubic, _) \ + \ + V(setColor, Color) \ + V(setBlendMode, BlendMode) \ + \ + V(setShader, Shader) \ + V(clearShader, _) \ + V(setColorFilter, ColorFilter) \ + V(clearColorFilter, _) \ + V(setImageFilter, ImageFilter) \ + V(clearImageFilter, _) \ + \ + V(clearMaskFilter, _) \ + V(setMaskFilterNormal, Scalar) \ + V(setMaskFilterSolid, Scalar) \ + V(setMaskFilterOuter, Scalar) \ + V(setMaskFilterInner, Scalar) \ + \ + V(save, _) \ + V(saveLayer, _) \ + V(saveLayerBounds, Rect) \ + V(restore, _) \ + \ + V(translate, 2Scalars) \ + V(scale, 2Scalars) \ + V(rotate, Angle) \ + V(skew, 2Scalars) \ + V(transform2x3, Matrix2x3) \ + V(transform3x3, Matrix3x3) \ + \ + V(clipRect, Rect) \ + V(clipRectAA, Rect) \ + V(clipRectDiff, Rect) \ + V(clipRectAADiff, Rect) \ + V(clipRRect, RoundRect) \ + V(clipRRectAA, RoundRect) \ + V(clipPath, Path) \ + V(clipPathAA, Path) \ + \ + V(drawPaint, _) \ + V(drawColor, _) \ + \ + V(drawLine, 2Points) \ + V(drawRect, Rect) \ + V(drawOval, Rect) \ + V(drawCircle, Point_Scalar) \ + V(drawRRect, RoundRect) \ + V(drawDRRect, 2RoundRects) \ + V(drawArc, Rect_2Angles) \ + V(drawArcCenter, Rect_2Angles) \ + V(drawPath, Path) \ + \ + V(drawPoints, F32List) \ + V(drawLines, F32List) \ + V(drawPolygon, F32List) \ + V(drawVertices, Vertices) \ + \ + V(drawImage, Image_Point) \ + V(drawImageRect, Image_2Rects) \ + V(drawImageNine, Image_2Rects) \ + V(drawAtlas, Atlas) \ + V(drawAtlasColored, Atlas_Colors) \ + V(drawAtlasCulled, Atlas_Rect) \ + V(drawAtlasColoredCulled, Atlas_Colors_Rect) \ + \ + V(drawParagraph, Paragraph_Point) \ + V(drawPicture, Picture) \ + V(drawShadow, Path_Scalar) \ + V(drawShadowOccluded, Path_Scalar) + +#define CANVAS_OP_MAKE_ENUM(name, args) cops_##name, enum CanvasOp { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM) }; -#define CANVAS_OP_DECLARE_OP(name, count, imask, objcount) void execute_##name(RasterizeContext& context); - class DisplayListInterpreter { public: DisplayListInterpreter(std::shared_ptr> ops, @@ -123,9 +189,7 @@ class DisplayListInterpreter { void Describe(); static const std::vector opNames; - static const std::vector opArgCounts; - static const std::vector opArgImask; - static const std::vector opObjCounts; + static const std::vector opArguments; static const SkSamplingOptions NearestSampling; static const SkSamplingOptions LinearSampling; @@ -133,14 +197,56 @@ class DisplayListInterpreter { static const SkSamplingOptions CubicSampling; private: - std::vector::iterator ops_it_; - const std::vector::iterator ops_end_; - std::vector::iterator data_it_; - const std::vector::iterator data_end_; - std::shared_ptr> ops_vector_; std::shared_ptr> data_vector_; + class Iterator { + public: + Iterator(const DisplayListInterpreter* interpreter) + : ops(interpreter->ops_vector_->begin()), + ops_end(interpreter->ops_vector_->end()), + data(interpreter->data_vector_->begin()), + data_end(interpreter->data_vector_->end()) {} + + Iterator(const Iterator& iterator) + : ops(iterator.ops), + ops_end(iterator.ops_end), + data(iterator.data), + data_end(iterator.data_end) {} + + bool HasOp() { return ops < ops_end; } + + CanvasOp GetOp() { return static_cast(*ops++); } + SkScalar GetScalar() { return static_cast(*data++); } + uint32_t GetUint32() { union { float f; uint32_t i; } u; u.f = *data++; return u.i; } + + SkScalar GetAngle() { return GetScalar() * 180.0 / M_PI; } + SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } + SkColor GetColor() { return static_cast(GetUint32()); } + + SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } + SkRect GetRect() { return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), GetScalar()); } + SkRRect GetRoundRect() { + SkRect rect = GetRect(); + SkVector radii[4] = { + // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices + { GetScalar(), GetScalar() }, + { GetScalar(), GetScalar() }, + { GetScalar(), GetScalar() }, + { GetScalar(), GetScalar() }, + }; + + SkRRect rrect; + rrect.setRectRadii(rect, radii); + return rrect; + } + + std::vector::iterator ops; + const std::vector::iterator ops_end; + std::vector::iterator data; + const std::vector::iterator data_end; + }; + struct RasterizeContext { SkCanvas *canvas; SkPaint paint; @@ -152,36 +258,13 @@ class DisplayListInterpreter { static sk_sp makeColorFilter(RasterizeContext& context); +#define CANVAS_OP_DECLARE_OP(name, args) \ + void execute_##name(RasterizeContext& context, Iterator& it); + FOR_EACH_CANVAS_OP(CANVAS_OP_DECLARE_OP) - bool HasOp() { return ops_it_ < ops_end_; } - CanvasOp GetOp() { return static_cast(*ops_it_++); } - - std::string DescribeNextOp(); - - SkScalar GetScalar() { return static_cast(*data_it_++); } - uint32_t GetUint32() { union { float f; uint32_t i; } data; data.f = *data_it_++; return data.i; } - - SkScalar GetAngle() { return GetScalar() * 180.0 / M_PI; } - SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } - SkColor GetColor() { return static_cast(GetUint32()); } - - SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } - SkRect GetRect() { return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), GetScalar()); } - SkRRect GetRoundRect() { - SkRect rect = GetRect(); - SkVector radii[4] = { - // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices - { GetScalar(), GetScalar() }, - { GetScalar(), GetScalar() }, - { GetScalar(), GetScalar() }, - { GetScalar(), GetScalar() }, - }; - - SkRRect rrect; - rrect.setRectRadii(rect, radii); - return rrect; - } + std::string DescribeNextOp(const Iterator& it); + std::string DescribeOneOp(Iterator& it); }; } // namespace flutter diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 8d5786a2060ea..83c0a78798e42 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -179,27 +179,10 @@ void DisplayListLayer::Paint(PaintContext& context) const { DisplayListInterpreter interpreter(ops_vector_, data_vector_); interpreter.Rasterize(context.leaf_nodes_canvas); - // SkRect bounds = paint_bounds(); SkPaint paint; paint.setColor(is_complex_ ? (will_change_ ? SkColors::kRed : SkColors::kYellow) : (will_change_ ? SkColors::kBlue : SkColors::kGreen)); -// paint.setAlphaf(0.125f); -// context.leaf_nodes_canvas->drawRect(bounds, paint); -// paint.setStyle(SkPaint::Style::kStroke_Style); -// // paint.setAlphaf(1.0f); -// paint.setAntiAlias(true); -// paint.setColor(SkColors::kBlack); -// // paint.setStrokeWidth(5.0f); -// context.leaf_nodes_canvas->drawRect(bounds, paint); -// context.leaf_nodes_canvas->drawLine( -// SkPoint::Make(bounds.left(), bounds.top()), -// SkPoint::Make(bounds.right(), bounds.bottom()), -// paint); -// context.leaf_nodes_canvas->drawLine( -// SkPoint::Make(bounds.right(), bounds.top()), -// SkPoint::Make(bounds.left(), bounds.bottom()), -// paint); } } // namespace flutter diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 04cedfc84ba4a..12ea8edcb38c3 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5138,7 +5138,8 @@ enum _CanvasOp { scale, rotate, skew, - transform, + transform2x3, + transform3x3, clipRect, clipRectAA, @@ -5319,7 +5320,7 @@ class _DisplayListCanvas implements Canvas { _numDataBytes += 4; } - void _addDouble(double value) { + void _addScalar(double value) { if (_numDataBytes + 4 > _data.lengthInBytes) { _data = _growData(_data); } @@ -5327,7 +5328,7 @@ class _DisplayListCanvas implements Canvas { _numDataBytes += 4; } - void _addDouble2(double v1, double v2) { + void _addScalar2(double v1, double v2) { if (_numDataBytes + 8 > _data.lengthInBytes) { _data = _growData(_data); } @@ -5337,7 +5338,19 @@ class _DisplayListCanvas implements Canvas { _numDataBytes += 4; } - void _addDouble4(double v1, double v2, double v3, double v4) { + void _addScalar3(double v1, double v2, double v3) { + if (_numDataBytes + 12 > _data.lengthInBytes) { + _data = _growData(_data); + } + _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); + _numDataBytes += 4; + _data.setFloat32(_numDataBytes, v2, _kFakeHostEndian); + _numDataBytes += 4; + _data.setFloat32(_numDataBytes, v3, _kFakeHostEndian); + _numDataBytes += 4; + } + + void _addScalar4(double v1, double v2, double v3, double v4) { if (_numDataBytes + 16 > _data.lengthInBytes) { _data = _growData(_data); } @@ -5352,18 +5365,18 @@ class _DisplayListCanvas implements Canvas { } void _addOffset(Offset offset) { - _addDouble2(offset.dx, offset.dy); + _addScalar2(offset.dx, offset.dy); } void _addRect(Rect r) { - _addDouble4(r.left, r.top, r.right, r.bottom); + _addScalar4(r.left, r.top, r.right, r.bottom); } void _addRRect(RRect rrect) { - _addDouble4(rrect.left, rrect.top, rrect.right, rrect.bottom); + _addScalar4(rrect.left, rrect.top, rrect.right, rrect.bottom); // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices - _addDouble4(rrect.tlRadiusX, rrect.tlRadiusY, rrect.trRadiusX, rrect.trRadiusY); - _addDouble4(rrect.brRadiusX, rrect.brRadiusY, rrect.blRadiusX, rrect.blRadiusY); + _addScalar4(rrect.tlRadiusX, rrect.tlRadiusY, rrect.trRadiusX, rrect.trRadiusY); + _addScalar4(rrect.brRadiusX, rrect.brRadiusY, rrect.blRadiusX, rrect.blRadiusY); } void _addInt32List(Int32List data) { @@ -5374,10 +5387,6 @@ class _DisplayListCanvas implements Canvas { _objData.add(data); } - void _addFloat64List(Float64List data) { - _objData.add(data); - } - void _addImageData(Image image) { _objData.add(image._image); } @@ -5465,28 +5474,28 @@ class _DisplayListCanvas implements Canvas { @override void translate(double dx, double dy) { _addOp(_CanvasOp.translate); - _addDouble2(dx, dy); + _addScalar2(dx, dy); _ctm.translate(dx, dy); } @override void scale(double sx, [ double? sy ]) { _addOp(_CanvasOp.scale); - _addDouble2(sx, sy ?? sx); + _addScalar2(sx, sy ?? sx); _ctm.scale(sx, sy ?? sx); } @override void rotate(double radians) { _addOp(_CanvasOp.rotate); - _addDouble(radians); + _addScalar(radians); _ctm.rotate(radians); } @override void skew(double sx, double sy) { _addOp(_CanvasOp.skew); - _addDouble2(sx, sy); + _addScalar2(sx, sy); _ctm.skew(sx, sy); } @@ -5494,8 +5503,16 @@ class _DisplayListCanvas implements Canvas { void transform(Float64List matrix4) { if (matrix4.length != 16) throw ArgumentError('"matrix4" must have 16 entries.'); - _addOp(_CanvasOp.transform); - _addFloat64List(matrix4); + if (matrix4[3] == 0.0 && matrix4[7] == 0.0 && matrix4[15] == 1.0) { + _addOp(_CanvasOp.transform2x3); + _addScalar3(matrix4[0], matrix4[4], matrix4[12]); + _addScalar3(matrix4[1], matrix4[5], matrix4[13]); + } else { + _addOp(_CanvasOp.transform3x3); + _addScalar3(matrix4[0], matrix4[4], matrix4[12]); + _addScalar3(matrix4[1], matrix4[5], matrix4[13]); + _addScalar3(matrix4[3], matrix4[7], matrix4[15]); + } _ctm.mul(matrix4[0], matrix4[4], matrix4[12], matrix4[1], matrix4[5], matrix4[13]); } @@ -5622,7 +5639,7 @@ class _DisplayListCanvas implements Canvas { if (_curStrokeWidth != paint.strokeWidth) { _curStrokeWidth = paint.strokeWidth; _addOp(_CanvasOp.setStrokeWidth); - _addDouble(_curStrokeWidth); + _addScalar(_curStrokeWidth); } if (_curStrokeCap != paint.strokeCap) { _curStrokeCap = paint.strokeCap; @@ -5635,7 +5652,7 @@ class _DisplayListCanvas implements Canvas { if (_curMiterLimit != paint.strokeMiterLimit) { _curMiterLimit = paint.strokeMiterLimit; _addOp(_CanvasOp.setMiterLimit); - _addDouble(_curMiterLimit); + _addScalar(_curMiterLimit); } } if ((dataNeeded & _filterQualityNeeded) != 0 && _curFilterQuality != paint.filterQuality) { @@ -5678,7 +5695,7 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.clearMaskFilter); } else { _addOp(_maskFilterOps[filter._style.index]); - _addDouble(filter._sigma); + _addScalar(filter._sigma); } _curMaskFilter = paint.maskFilter; } @@ -5745,7 +5762,7 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _drawMask); _addOp(_CanvasOp.drawCircle); _addOffset(center); - _addDouble(radius); + _addScalar(radius); _addBounds(Rect.fromCenter(center: center, width: radius, height: radius)); } @@ -5778,7 +5795,7 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _drawMask); _addOp(useCenter ? _CanvasOp.drawArcCenter : _CanvasOp.drawArc); _addRect(rect); - _addDouble2(startAngle, sweepAngle); + _addScalar2(startAngle, sweepAngle); _addBounds(rect); } @@ -5824,8 +5841,8 @@ class _DisplayListCanvas implements Canvas { void drawImage(Image image, Offset offset, Paint paint) { _updatePaintData(paint, _imageMask); _addOp(_CanvasOp.drawImage); - _addOffset(offset); _addImageData(image); + _addOffset(offset); _addBounds(Rect.fromLTWH(offset.dx, offset.dy, image.width.toDouble(), image.height.toDouble()), false); } @@ -5833,9 +5850,9 @@ class _DisplayListCanvas implements Canvas { void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { _updatePaintData(paint, _imageMask); _addOp(_CanvasOp.drawImageRect); + _addImageData(image); _addRect(src); _addRect(dst); - _addImageData(image); _addBounds(dst, false); } @@ -5843,9 +5860,9 @@ class _DisplayListCanvas implements Canvas { void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { _updatePaintData(paint, _imageMask); _addOp(_CanvasOp.drawImageNine); + _addImageData(image); _addRect(center); _addRect(dst); - _addImageData(image); _addBounds(dst, false); } @@ -5893,13 +5910,13 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _imageMask); _updateBlendMode(blendMode ?? BlendMode.src); _addOp(op); + _addImageData(atlas); _addFloat32List(rstTransformBuffer); _addFloat32List(rectBuffer); if (colorBuffer != null) _addInt32List(colorBuffer); if (cullRect != null) _addRect(cullRect); - _addImageData(atlas); print('adding conservative bounds for drawAtlas'); _addBounds(_cullRect, false); } @@ -5927,13 +5944,13 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _imageMask); _updateBlendMode(blendMode ?? BlendMode.src); _addOp(op); + _addImageData(atlas); _addFloat32List(rstTransforms); _addFloat32List(rects); if (colors != null) _addInt32List(colors); if (cullRect != null) _addRect(cullRect); - _addImageData(atlas); print('adding conservative bounds for drawAtlas'); _addBounds(_cullRect, false); } @@ -5941,8 +5958,8 @@ class _DisplayListCanvas implements Canvas { @override void drawParagraph(Paragraph paragraph, Offset offset) { _addOp(_CanvasOp.drawParagraph); - _addOffset(offset); _addParagraph(paragraph); + _addOffset(offset); } @override @@ -5957,8 +5974,8 @@ class _DisplayListCanvas implements Canvas { void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { _updateColor(color); _addOp(transparentOccluder ? _CanvasOp.drawShadowOccluded : _CanvasOp.drawShadow); - _addDouble(elevation); _addPathData(path); + _addScalar(elevation); print('adding conservative bounds for drawShadow'); _addBounds(_cullRect, false); } diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index 8bf0f7c41f30a..bd585a60a71ca 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -130,12 +130,24 @@ DisplayList::DisplayList(std::shared_ptr> ops_vector, : ops_vector_(ops_vector), data_vector_(data_vector) {} +DisplayList::~DisplayList() = default; + Dart_Handle DisplayList::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { return RasterizeToImage(ops_vector_, data_vector_, width, height, raw_image_callback); } +void DisplayList::dispose() { + ops_vector_.reset(); + data_vector_.reset(); + ClearDartWrapper(); +} + +size_t DisplayList::GetAllocationSize() const { + return ops_vector_->size() + (data_vector_->size() * sizeof(float)); +} + Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> ops, std::shared_ptr> data, uint32_t width, @@ -209,17 +221,4 @@ Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> return Dart_Null(); } -// void DisplayList::dispose() { -// picture_.reset(); -// ClearDartWrapper();ToSkRoundRect -// } - -// size_t DisplayList::GetAllocationSize() const { -// if (auto picture = picture_.get()) { -// return picture->approximateBytesUsed() + sizeof(Picture); -// } else { -// return sizeof(Picture); -// } -// } - } // namespace flutter diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h index 5d17372b03fd4..3ed3c085c6316 100644 --- a/lib/ui/painting/display_list.h +++ b/lib/ui/painting/display_list.h @@ -22,6 +22,9 @@ class DisplayList : public RefCountedDartWrappable { FML_FRIEND_MAKE_REF_COUNTED(DisplayList); public: + + ~DisplayList() override; + static fml::RefPtr Create(tonic::Uint8List& ops, int numOps, tonic::DartByteData& data, @@ -32,6 +35,10 @@ class DisplayList : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + void dispose(); + + size_t GetAllocationSize() const override; + static Dart_Handle RasterizeToImage(std::shared_ptr> ops, std::shared_ptr> data, uint32_t width, @@ -52,35 +59,6 @@ class DisplayList : public RefCountedDartWrappable { std::shared_ptr> data_vector_; }; -// class DisplayList : public RefCountedDartWrappable { -// DEFINE_WRAPPERTYPEINFO(); -// FML_FRIEND_MAKE_REF_COUNTED(DisplayList); - -// public: - -// ~DisplayList() override; -// static fml::RefPtr Create(Dart_Handle dart_handle, -// flutter::SkiaGPUObject picture); - -// Dart_Handle toImage(uint32_t width, -// uint32_t height, -// Dart_Handle raw_image_callback); - -// void dispose(); - -// size_t GetAllocationSize() const override; - -// static void RegisterNatives(tonic::DartLibraryNatives* natives); - -// static Dart_Handle RasterizeToImage(sk_sp picture, -// uint32_t width, -// uint32_t height, -// Dart_Handle raw_image_callback); - -// private: -// Picture(flutter::SkiaGPUObject picture); -// }; - } // namespace flutter #endif // FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_H_ From f299605b12ec938281e797a793aba00a8978967e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 29 Mar 2021 14:08:27 -0700 Subject: [PATCH 11/37] move Int/Float lists to data array and implement drawPoints --- flow/display_list_interpreter.cc | 70 +++++++++++++++++++++++++------- flow/display_list_interpreter.h | 39 ++++++++++++------ lib/ui/painting.dart | 48 ++++++++++++++++------ lib/ui/painting/display_list.cc | 3 +- 4 files changed, 119 insertions(+), 41 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 659cb8bf5a2ed..510652a4f250e 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -19,7 +19,7 @@ const std::vector DisplayListInterpreter::opNames = { FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_STRING) }; -const std::vector DisplayListInterpreter::opArguments = { +const std::vector DisplayListInterpreter::opArguments = { FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_ARGS) }; @@ -76,8 +76,28 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { << "ur: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " << "lr: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " << "ll: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "))"; break; - case int32_list: ss << "[Int32List]"; break; - case float32_list: ss << "[Float32List]"; break; + case uint32_list: + case scalar_list: { + uint32_t len = it.GetUint32(); + ss << std::dec << "(len=" << len << ")[" << std::hex; + for (uint32_t i = 0; i < len; i++) { + if (i > 0) { + ss << ", "; + if (len > 8 && i == 4) { + it.skipData(len - 8); + i += (len - 8); + ss << "..., "; + } + } + if (arg_type == scalar_list) { + ss << it.GetScalar(); + } else { + ss << it.GetUint32(); + } + } + ss << "]"; + break; + } case matrix_row3: ss << "[" << it.GetScalar() << ", " << it.GetScalar() << ", " << it.GetScalar() << "]"; break; case image: ss << "[Image]"; break; case path: ss << "[Path]"; break; @@ -202,17 +222,17 @@ const SkSamplingOptions DisplayListInterpreter::MipmapSampling = const SkSamplingOptions DisplayListInterpreter::CubicSampling = SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}); -#define CANVAS_FQ_DEFINE_OP(op_type, enum_type, filter_mode) \ +#define CANVAS_OP_DEFINE_FQ(op_type, enum_type, filter_mode) \ CANVAS_OP_DEFINE_OP(setFilterQuality##op_type, \ context.filterMode = SkFilterMode::filter_mode; \ context.sampling = op_type##Sampling; \ context.paint.setFilterQuality( \ SkFilterQuality::k##enum_type##_SkFilterQuality); \ ) -CANVAS_FQ_DEFINE_OP(Nearest, None, kNearest) -CANVAS_FQ_DEFINE_OP(Linear, Low, kLinear) -CANVAS_FQ_DEFINE_OP(Mipmap, Medium, kLinear) -CANVAS_FQ_DEFINE_OP(Cubic, High, kLinear) +CANVAS_OP_DEFINE_FQ(Nearest, None, kNearest) +CANVAS_OP_DEFINE_FQ(Linear, Low, kLinear) +CANVAS_OP_DEFINE_FQ(Mipmap, Medium, kLinear) +CANVAS_OP_DEFINE_FQ(Cubic, High, kLinear) CANVAS_OP_DEFINE_OP(setBlendMode, context.paint.setBlendMode(it.GetBlendMode());) @@ -263,19 +283,39 @@ CANVAS_OP_DEFINE_OP(drawArcCenter, context.canvas->drawArc(it.GetRect(), it.GetA CANVAS_OP_DEFINE_OP(drawLine, context.canvas->drawLine(it.GetPoint(), it.GetPoint(), context.paint);) CANVAS_OP_DEFINE_OP(drawPath, /* TODO(flar) deal with Path object */) -CANVAS_OP_DEFINE_OP(drawPoints, /* TODO(flar) deal with List of points */) -CANVAS_OP_DEFINE_OP(drawLines, /* TODO(flar) deal with List of points */) -CANVAS_OP_DEFINE_OP(drawPolygon, /* TODO(flar) deal with List of points */) +#define CANVAS_OP_DEFINE_POINT_OP(mode) \ +CANVAS_OP_DEFINE_OP(draw##mode, \ + SkScalar *flt_ptr; \ + uint32_t len = it.GetFloatList(&flt_ptr); \ + const SkPoint *pt_ptr = reinterpret_cast(flt_ptr); \ + context.canvas->drawPoints(SkCanvas::PointMode::k##mode##_PointMode, len / 2, pt_ptr, context.paint); \ +) +CANVAS_OP_DEFINE_POINT_OP(Points) +CANVAS_OP_DEFINE_POINT_OP(Lines) +CANVAS_OP_DEFINE_POINT_OP(Polygon) CANVAS_OP_DEFINE_OP(drawVertices, /* TODO(flar) deal with List of vertices */) CANVAS_OP_DEFINE_OP(drawImage, it.GetPoint(); /* TODO(flar) deal with image object */) CANVAS_OP_DEFINE_OP(drawImageRect, it.GetRect(); it.GetRect(); /* TODO(flar) deal with image object */) CANVAS_OP_DEFINE_OP(drawImageNine, it.GetRect(); it.GetRect(); /* TODO(flar) deal with image object */) -CANVAS_OP_DEFINE_OP(drawAtlas, /* TODO(flar) deal with all of the atlas objects */) -CANVAS_OP_DEFINE_OP(drawAtlasColored, /* TODO(flar) deal with all of the atlas objects */) -CANVAS_OP_DEFINE_OP(drawAtlasCulled, it.GetRect(); /* TODO(flar) deal with all of the atlas objects */) -CANVAS_OP_DEFINE_OP(drawAtlasColoredCulled, it.GetRect(); /* TODO(flar) deal with all of the atlas objects */) +#define CANVAS_OP_DEFINE_ATLAS(op_type, has_colors, has_rect) \ +CANVAS_OP_DEFINE_OP(op_type, \ + SkScalar *ptr; \ + it.GetFloatList(&ptr); \ + it.GetFloatList(&ptr); \ + if (has_colors) { \ + uint32_t *ptr2; \ + it.GetIntList(&ptr2); \ + } \ + if (has_rect) { \ + it.GetRect(); \ + } \ +) +CANVAS_OP_DEFINE_ATLAS(drawAtlas, false, false) +CANVAS_OP_DEFINE_ATLAS(drawAtlasColored, true, false) +CANVAS_OP_DEFINE_ATLAS(drawAtlasCulled, false, true) +CANVAS_OP_DEFINE_ATLAS(drawAtlasColoredCulled, true, true) CANVAS_OP_DEFINE_OP(drawPicture, /* TODO(flar) deal with Picture object */) CANVAS_OP_DEFINE_OP(drawParagraph, it.GetPoint(); /* TODO(flar) deal with Paragraph object */) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 6ef92cdc0e7e9..2c8a24839cd4f 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -22,8 +22,8 @@ enum CanvasOpArg { point, rect, round_rect, - int32_list, - float32_list, + uint32_list, + scalar_list, matrix_row3, image, path, @@ -62,7 +62,7 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS_Rect_2Angles CANVAS_OP_ARGS3(rect, angle, angle) #define CANVAS_OP_ARGS_RoundRect CANVAS_OP_ARGS1(round_rect) #define CANVAS_OP_ARGS_2RoundRects CANVAS_OP_ARGS2(round_rect, round_rect) -#define CANVAS_OP_ARGS_F32List CANVAS_OP_ARGS1(float32_list) +#define CANVAS_OP_ARGS_ScalarList CANVAS_OP_ARGS1(scalar_list) #define CANVAS_OP_ARGS_Matrix2x3 CANVAS_OP_ARGS2(matrix_row3, matrix_row3) #define CANVAS_OP_ARGS_Matrix3x3 CANVAS_OP_ARGS3(matrix_row3, matrix_row3, matrix_row3) #define CANVAS_OP_ARGS_Path CANVAS_OP_ARGS1(path) @@ -70,10 +70,10 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS_Vertices CANVAS_OP_ARGS1(vertices) #define CANVAS_OP_ARGS_Image_Point CANVAS_OP_ARGS2(image, point) #define CANVAS_OP_ARGS_Image_2Rects CANVAS_OP_ARGS3(image, rect, rect) -#define CANVAS_OP_ARGS_Atlas CANVAS_OP_ARGS3(image, float32_list, float32_list) -#define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS4(image, float32_list, float32_list, int32_list) -#define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS4(image, float32_list, float32_list, rect) -#define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS5(image, float32_list, float32_list, int32_list, rect) +#define CANVAS_OP_ARGS_Atlas CANVAS_OP_ARGS3(image, scalar_list, scalar_list) +#define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS4(image, scalar_list, scalar_list, uint32_list) +#define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS4(image, scalar_list, scalar_list, rect) +#define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS5(image, scalar_list, scalar_list, uint32_list, rect) #define CANVAS_OP_ARGS_Paragraph_Point CANVAS_OP_ARGS2(paragraph, point) #define CANVAS_OP_ARGS_Picture CANVAS_OP_ARGS1(picture) #define CANVAS_OP_ARGS_Shader CANVAS_OP_ARGS1(shader) @@ -156,9 +156,9 @@ enum CanvasOpArg { V(drawArcCenter, Rect_2Angles) \ V(drawPath, Path) \ \ - V(drawPoints, F32List) \ - V(drawLines, F32List) \ - V(drawPolygon, F32List) \ + V(drawPoints, ScalarList) \ + V(drawLines, ScalarList) \ + V(drawPolygon, ScalarList) \ V(drawVertices, Vertices) \ \ V(drawImage, Image_Point) \ @@ -189,7 +189,7 @@ class DisplayListInterpreter { void Describe(); static const std::vector opNames; - static const std::vector opArguments; + static const std::vector opArguments; static const SkSamplingOptions NearestSampling; static const SkSamplingOptions LinearSampling; @@ -215,8 +215,9 @@ class DisplayListInterpreter { data_end(iterator.data_end) {} bool HasOp() { return ops < ops_end; } - CanvasOp GetOp() { return static_cast(*ops++); } + + void skipData(int n) { data += n; } SkScalar GetScalar() { return static_cast(*data++); } uint32_t GetUint32() { union { float f; uint32_t i; } u; u.f = *data++; return u.i; } @@ -241,6 +242,20 @@ class DisplayListInterpreter { return rrect; } + uint32_t GetIntList(uint32_t **int_ptr) { + uint32_t len = GetUint32(); + *int_ptr = (uint32_t *) &*data; + skipData(len); + return len; + } + + uint32_t GetFloatList(SkScalar **flt_ptr) { + uint32_t len = GetUint32(); + *flt_ptr = &*data; + skipData(len); + return len; + } + std::vector::iterator ops; const std::vector::iterator ops_end; std::vector::iterator data; diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 12ea8edcb38c3..de114a34e8c05 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5292,13 +5292,18 @@ class _DisplayListCanvas implements Canvas { } static const int _maxDataDoubleSize = 1 << 24; - ByteData _growData(ByteData src) { - ByteData dst; + ByteData _growData(ByteData src, int neededBytes) { + int growLength; if (src.lengthInBytes <= _maxDataDoubleSize) { - dst = ByteData(src.lengthInBytes * 2); + growLength = src.lengthInBytes; } else { - dst = ByteData(src.lengthInBytes + _maxDataDoubleSize); + growLength = _maxDataDoubleSize; } + if (growLength < neededBytes) { + growLength = (neededBytes + _maxDataDoubleSize) ~/ _maxDataDoubleSize; + growLength *= _maxDataDoubleSize; + } + final ByteData dst = ByteData(src.lengthInBytes + growLength); for (int i = 0; i < _numDataBytes; i += 4) { dst.setInt32(i, src.getInt32(i, _kFakeHostEndian), _kFakeHostEndian); } @@ -5314,7 +5319,7 @@ class _DisplayListCanvas implements Canvas { void _addInt(int value) { if (_numDataBytes + 4 > _data.lengthInBytes) { - _data = _growData(_data); + _data = _growData(_data, 4); } _data.setInt32(_numDataBytes, value, _kFakeHostEndian); _numDataBytes += 4; @@ -5322,7 +5327,7 @@ class _DisplayListCanvas implements Canvas { void _addScalar(double value) { if (_numDataBytes + 4 > _data.lengthInBytes) { - _data = _growData(_data); + _data = _growData(_data, 4); } _data.setFloat32(_numDataBytes, value, _kFakeHostEndian); _numDataBytes += 4; @@ -5330,7 +5335,7 @@ class _DisplayListCanvas implements Canvas { void _addScalar2(double v1, double v2) { if (_numDataBytes + 8 > _data.lengthInBytes) { - _data = _growData(_data); + _data = _growData(_data, 8); } _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); _numDataBytes += 4; @@ -5340,7 +5345,7 @@ class _DisplayListCanvas implements Canvas { void _addScalar3(double v1, double v2, double v3) { if (_numDataBytes + 12 > _data.lengthInBytes) { - _data = _growData(_data); + _data = _growData(_data, 12); } _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); _numDataBytes += 4; @@ -5352,7 +5357,7 @@ class _DisplayListCanvas implements Canvas { void _addScalar4(double v1, double v2, double v3, double v4) { if (_numDataBytes + 16 > _data.lengthInBytes) { - _data = _growData(_data); + _data = _growData(_data, 16); } _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); _numDataBytes += 4; @@ -5380,11 +5385,27 @@ class _DisplayListCanvas implements Canvas { } void _addInt32List(Int32List data) { - _objData.add(data); + final int len = data.length; + _addInt(len); + if (_numDataBytes + len * 4 > _data.lengthInBytes) { + _data = _growData(_data, len * 4); + } + for (int i = 0; i < len; i++) { + _data.setInt32(_numDataBytes, data[i], _kFakeHostEndian); + _numDataBytes += 4; + } } void _addFloat32List(Float32List data) { - _objData.add(data); + final int len = data.length; + _addInt(len); + if (_numDataBytes + len * 4 > _data.lengthInBytes) { + _data = _growData(_data, len * 4); + } + for (int i = 0; i < len; i++) { + _data.setFloat32(_numDataBytes, data[i], _kFakeHostEndian); + _numDataBytes += 4; + } } void _addImageData(Image image) { @@ -5823,8 +5844,9 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _paintMask | _strokeStyleNeeded); _addOp(_pointOps[pointMode.index]); _addFloat32List(points); - print('adding conservative bounds for drawPoints'); - _addBounds(_cullRect); + for (int i = 0; i + 1 < points.length; i += 2) { + _addPointToBounds(points[i], points[i + 1]); + } } @override diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index bd585a60a71ca..2e63585a8ea8e 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -122,7 +122,8 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, // } // } - return fml::MakeRefCounted(ops_vector, data_vector); + return fml::MakeRefCounted(std::move(ops_vector), + std::move(data_vector)); } DisplayList::DisplayList(std::shared_ptr> ops_vector, From d2d62847314cbcce0511d3f5ca0f505e8c3c563e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 29 Mar 2021 20:47:37 -0700 Subject: [PATCH 12/37] implement drawImage calls and setColor/ImageFilter --- flow/display_list_interpreter.cc | 131 +++++++++++++++++++--------- flow/display_list_interpreter.h | 29 +++++- flow/layers/display_list_layer.cc | 4 +- flow/layers/display_list_layer.h | 3 + lib/ui/compositing/scene_builder.cc | 2 +- lib/ui/painting/display_list.cc | 120 ++++++++++++++++++------- lib/ui/painting/display_list.h | 11 ++- 7 files changed, 220 insertions(+), 80 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 510652a4f250e..eb558b3ba76c3 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -25,19 +25,23 @@ const std::vector DisplayListInterpreter::opArguments = { DisplayListInterpreter::DisplayListInterpreter( std::shared_ptr> ops_vector, - std::shared_ptr> data_vector) + std::shared_ptr> data_vector, + std::shared_ptr> ref_vector) : ops_vector_(std::move(ops_vector)), - data_vector_(std::move(data_vector)) {} + data_vector_(std::move(data_vector)), + ref_vector_(ref_vector) {} void DisplayListInterpreter::Describe() { Iterator it(this); FML_LOG(ERROR) << "Starting ops: " << (it.ops_end - it.ops) - << ", data: " << (it.data_end - it.data); + << ", data: " << (it.data_end - it.data) + << ", refs: " << (it.refs_end - it.refs); while(it.HasOp()) { FML_LOG(ERROR) << DescribeOneOp(it); } FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) - << ", data: " << (it.data_end - it.data); + << ", data: " << (it.data_end - it.data) + << ", refs: " << (it.refs_end - it.refs); } std::string DisplayListInterpreter::DescribeNextOp(const Iterator& it) { @@ -147,10 +151,16 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { FOR_EACH_CANVAS_OP(CANVAS_OP_DISPATCH_OP) } } - if (it.ops != it.ops_end || it.data != it.data_end || canvas->getSaveCount() != entrySaveCount) { - FML_LOG(ERROR) << "Starting ops: " << ops_vector_->size() << ", data: " << data_vector_->size(); + if (it.ops != it.ops_end || + it.data != it.data_end || + it.refs != it.refs_end || + canvas->getSaveCount() != entrySaveCount) { + FML_LOG(ERROR) << "Starting ops: " << ops_vector_->size() + << ", data: " << data_vector_->size() + << ", refs: " << ref_vector_->size(); FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) << ", data: " << (it.data_end - it.data) + << ", refs: " << (it.refs_end - it.refs) << ", save count delta: " << (canvas->getSaveCount() - entrySaveCount); } } @@ -177,7 +187,10 @@ CANVAS_OP_DEFINE_OP(clearColorFilter, context.colorFilter = nullptr; context.paint.setColorFilter(makeColorFilter(context)); ) -CANVAS_OP_DEFINE_OP(setColorFilter, /* TODO(flar) deal with Filter objec */) +CANVAS_OP_DEFINE_OP(setColorFilter, + context.colorFilter = it.GetColorFilter(); + context.paint.setColorFilter(makeColorFilter(context)); +) CANVAS_OP_DEFINE_OP(setColor, context.paint.setColor(it.GetColor());) CANVAS_OP_DEFINE_OP(setFillStyle, context.paint.setStyle(SkPaint::Style::kFill_Style);) CANVAS_OP_DEFINE_OP(setStrokeStyle, context.paint.setStyle(SkPaint::Style::kStroke_Style);) @@ -199,7 +212,7 @@ CANVAS_JOIN_DEFINE_OP(Round) CANVAS_JOIN_DEFINE_OP(Bevel) CANVAS_OP_DEFINE_OP(clearShader, context.paint.setShader(nullptr);) -CANVAS_OP_DEFINE_OP(setShader, /* TODO(flar) deal with Shader object */) +CANVAS_OP_DEFINE_OP(setShader, it.skipSkRef();) CANVAS_OP_DEFINE_OP(clearMaskFilter, context.paint.setMaskFilter(nullptr);) #define CANVAS_MASK_DEFINE_OP(type) CANVAS_OP_DEFINE_OP(setMaskFilter##type, \ @@ -211,7 +224,7 @@ CANVAS_MASK_DEFINE_OP(Solid) CANVAS_MASK_DEFINE_OP(Normal) CANVAS_OP_DEFINE_OP(clearImageFilter, context.paint.setImageFilter(nullptr);) -CANVAS_OP_DEFINE_OP(setImageFilter, /* TODO(flar) deal with Filter object */) +CANVAS_OP_DEFINE_OP(setImageFilter, context.paint.setImageFilter(it.GetImageFilter());) const SkSamplingOptions DisplayListInterpreter::NearestSampling = SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); @@ -248,8 +261,8 @@ CANVAS_OP_DEFINE_OP(clipRectAADiff, context.canvas->clipRect(it.GetRect(), SkCli CANVAS_OP_DEFINE_OP(clipRRect, context.canvas->clipRRect(it.GetRoundRect());) CANVAS_OP_DEFINE_OP(clipRRectAA, context.canvas->clipRRect(it.GetRoundRect(), true);) -CANVAS_OP_DEFINE_OP(clipPath, /* TODO(flar) deal with Path object */) -CANVAS_OP_DEFINE_OP(clipPathAA, /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(clipPath, it.skipSkRef(); /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(clipPathAA, it.skipSkRef(); /* TODO(flar) deal with Path object */) CANVAS_OP_DEFINE_OP(translate, context.canvas->translate(it.GetScalar(), it.GetScalar());) CANVAS_OP_DEFINE_OP(scale, context.canvas->scale(it.GetScalar(), it.GetScalar());) @@ -281,45 +294,81 @@ CANVAS_OP_DEFINE_OP(drawCircle, context.canvas->drawCircle(it.GetPoint(), it.Get CANVAS_OP_DEFINE_OP(drawArc, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), false, context.paint);) CANVAS_OP_DEFINE_OP(drawArcCenter, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), true, context.paint);) CANVAS_OP_DEFINE_OP(drawLine, context.canvas->drawLine(it.GetPoint(), it.GetPoint(), context.paint);) -CANVAS_OP_DEFINE_OP(drawPath, /* TODO(flar) deal with Path object */) - -#define CANVAS_OP_DEFINE_POINT_OP(mode) \ -CANVAS_OP_DEFINE_OP(draw##mode, \ - SkScalar *flt_ptr; \ - uint32_t len = it.GetFloatList(&flt_ptr); \ - const SkPoint *pt_ptr = reinterpret_cast(flt_ptr); \ - context.canvas->drawPoints(SkCanvas::PointMode::k##mode##_PointMode, len / 2, pt_ptr, context.paint); \ +CANVAS_OP_DEFINE_OP(drawPath, it.skipSkRef(); /* TODO(flar) deal with Path object */) + +#define CANVAS_OP_DEFINE_POINT_OP(mode) \ +CANVAS_OP_DEFINE_OP(draw##mode, \ + SkScalar *flt_ptr; \ + uint32_t len = it.GetFloatList(&flt_ptr); \ + const SkPoint *pt_ptr = reinterpret_cast(flt_ptr); \ + context.canvas->drawPoints(SkCanvas::PointMode::k##mode##_PointMode, \ + len / 2, pt_ptr, context.paint); \ ) CANVAS_OP_DEFINE_POINT_OP(Points) CANVAS_OP_DEFINE_POINT_OP(Lines) CANVAS_OP_DEFINE_POINT_OP(Polygon) -CANVAS_OP_DEFINE_OP(drawVertices, /* TODO(flar) deal with List of vertices */) - -CANVAS_OP_DEFINE_OP(drawImage, it.GetPoint(); /* TODO(flar) deal with image object */) -CANVAS_OP_DEFINE_OP(drawImageRect, it.GetRect(); it.GetRect(); /* TODO(flar) deal with image object */) -CANVAS_OP_DEFINE_OP(drawImageNine, it.GetRect(); it.GetRect(); /* TODO(flar) deal with image object */) - -#define CANVAS_OP_DEFINE_ATLAS(op_type, has_colors, has_rect) \ -CANVAS_OP_DEFINE_OP(op_type, \ - SkScalar *ptr; \ - it.GetFloatList(&ptr); \ - it.GetFloatList(&ptr); \ - if (has_colors) { \ - uint32_t *ptr2; \ - it.GetIntList(&ptr2); \ - } \ - if (has_rect) { \ - it.GetRect(); \ - } \ +CANVAS_OP_DEFINE_OP(drawVertices, it.skipSkRef(); /* TODO(flar) deal with List of vertices */) + +CANVAS_OP_DEFINE_OP(drawImage, + sk_sp image = it.GetImage(); + SkPoint point = it.GetPoint(); + context.canvas->drawImage(image, point.fX, point.fY, context.sampling, &context.paint); +) +CANVAS_OP_DEFINE_OP(drawImageRect, + sk_sp image = it.GetImage(); + SkRect src = it.GetRect(); + SkRect dst = it.GetRect(); + context.canvas->drawImageRect(image, src, dst, context.sampling, &context.paint, SkCanvas::kFast_SrcRectConstraint); +) +CANVAS_OP_DEFINE_OP(drawImageNine, + sk_sp image = it.GetImage(); + SkRect center = it.GetRect(); + SkRect dst = it.GetRect(); + context.canvas->drawImageNine(image.get(), center.round(), dst, context.filterMode); +) + +#define CANVAS_OP_DEFINE_ATLAS(op_type, has_colors, has_rect) \ +CANVAS_OP_DEFINE_OP(op_type, \ + sk_sp image = it.GetImage(); \ + SkScalar *rst_ptr; \ + int nrstscalars = it.GetFloatList(&rst_ptr); \ + SkScalar *rect_ptr; \ + int nrectscalars = it.GetFloatList(&rect_ptr); \ + int numrects = nrectscalars / 4; \ + uint32_t *clr_ptr = nullptr; \ + int ncolorints = numrects; \ + if (has_colors) { \ + ncolorints = it.GetIntList(&clr_ptr); \ + } \ + SkRect* pCullRect = nullptr; \ + SkRect cull_rect; \ + if (has_rect) { \ + cull_rect = it.GetRect(); \ + pCullRect = &cull_rect; \ + } \ + if (nrectscalars != numrects * 4 || \ + nrstscalars != numrects * 4 || \ + ncolorints != numrects) { \ + FML_LOG(ERROR) << "Mismatched Atlas array lengths"; \ + return; \ + } \ + context.canvas->drawAtlas( \ + image.get(), \ + reinterpret_cast(rst_ptr), \ + reinterpret_cast(rect_ptr), \ + reinterpret_cast(clr_ptr), \ + numrects, \ + context.paint.getBlendMode(), context.sampling, pCullRect, \ + &context.paint); \ ) CANVAS_OP_DEFINE_ATLAS(drawAtlas, false, false) CANVAS_OP_DEFINE_ATLAS(drawAtlasColored, true, false) CANVAS_OP_DEFINE_ATLAS(drawAtlasCulled, false, true) CANVAS_OP_DEFINE_ATLAS(drawAtlasColoredCulled, true, true) -CANVAS_OP_DEFINE_OP(drawPicture, /* TODO(flar) deal with Picture object */) -CANVAS_OP_DEFINE_OP(drawParagraph, it.GetPoint(); /* TODO(flar) deal with Paragraph object */) -CANVAS_OP_DEFINE_OP(drawShadow, it.GetScalar(); /* TODO(flar) deal with Path object */) -CANVAS_OP_DEFINE_OP(drawShadowOccluded, it.GetScalar(); /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(drawPicture, it.skipSkRef(); /* TODO(flar) deal with Picture object */) +CANVAS_OP_DEFINE_OP(drawParagraph, it.skipSkRef(); it.GetPoint(); /* TODO(flar) deal with Paragraph object */) +CANVAS_OP_DEFINE_OP(drawShadow, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(drawShadowOccluded, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) } // namespace flutter diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 2c8a24839cd4f..ce1bb88d264a6 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -8,6 +8,9 @@ #include #include "third_party/skia/include/core/SkColorFilter.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRRect.h" @@ -179,10 +182,18 @@ enum CanvasOp { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM) }; +class DisplayListRefHolder { + public: + sk_sp colorFilter; + sk_sp imageFilter; + sk_sp image; +}; + class DisplayListInterpreter { public: DisplayListInterpreter(std::shared_ptr> ops, - std::shared_ptr> data); + std::shared_ptr> data, + std::shared_ptr> refs); void Rasterize(SkCanvas *canvas); @@ -199,6 +210,7 @@ class DisplayListInterpreter { private: std::shared_ptr> ops_vector_; std::shared_ptr> data_vector_; + std::shared_ptr> ref_vector_; class Iterator { public: @@ -206,13 +218,17 @@ class DisplayListInterpreter { : ops(interpreter->ops_vector_->begin()), ops_end(interpreter->ops_vector_->end()), data(interpreter->data_vector_->begin()), - data_end(interpreter->data_vector_->end()) {} + data_end(interpreter->data_vector_->end()), + refs(interpreter->ref_vector_->begin()), + refs_end(interpreter->ref_vector_->end()) {} Iterator(const Iterator& iterator) : ops(iterator.ops), ops_end(iterator.ops_end), data(iterator.data), - data_end(iterator.data_end) {} + data_end(iterator.data_end), + refs(iterator.refs), + refs_end(iterator.refs_end) {} bool HasOp() { return ops < ops_end; } CanvasOp GetOp() { return static_cast(*ops++); } @@ -256,10 +272,17 @@ class DisplayListInterpreter { return len; } + void skipSkRef() { refs++; } + const sk_sp GetColorFilter() { return (refs++)->colorFilter; } + const sk_sp GetImageFilter() { return (refs++)->imageFilter; } + const sk_sp GetImage() { return (refs++)->image; } + std::vector::iterator ops; const std::vector::iterator ops_end; std::vector::iterator data; const std::vector::iterator data_end; + std::vector::iterator refs; + const std::vector::iterator refs_end; }; struct RasterizeContext { diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 83c0a78798e42..11c3c9a9e3a20 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -14,6 +14,7 @@ DisplayListLayer::DisplayListLayer(const SkPoint& offset, const SkRect& draw_rect, std::shared_ptr> ops, std::shared_ptr> data, + std::shared_ptr> refs, bool is_complex, bool will_change) : offset_(offset), @@ -21,6 +22,7 @@ DisplayListLayer::DisplayListLayer(const SkPoint& offset, draw_rect_(draw_rect), ops_vector_(ops), data_vector_(data), + ref_vector_(refs), is_complex_(is_complex), will_change_(will_change) {} @@ -176,7 +178,7 @@ void DisplayListLayer::Paint(PaintContext& context) const { // << paint_bounds().right() << ", " // << paint_bounds().bottom() << "] " // << ops_vector_.size() << " ops"; - DisplayListInterpreter interpreter(ops_vector_, data_vector_); + DisplayListInterpreter interpreter(ops_vector_, data_vector_, ref_vector_); interpreter.Rasterize(context.leaf_nodes_canvas); SkPaint paint; diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h index bee8fff0ce335..556ef7faacbe2 100644 --- a/flow/layers/display_list_layer.h +++ b/flow/layers/display_list_layer.h @@ -7,6 +7,7 @@ #include +#include "flutter/flow/display_list_interpreter.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/skia_gpu_object.h" @@ -22,6 +23,7 @@ class DisplayListLayer : public Layer { const SkRect& draw_rect, std::shared_ptr> ops, std::shared_ptr> data, + std::shared_ptr> refs, bool is_complex, bool will_change); @@ -41,6 +43,7 @@ class DisplayListLayer : public Layer { SkRect draw_rect_; std::shared_ptr> ops_vector_; std::shared_ptr> data_vector_; + std::shared_ptr> ref_vector_; bool is_complex_ = false; bool will_change_ = false; diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 30b70e913bb47..928e76224cc31 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -301,7 +301,7 @@ void SceneBuilder::addDisplayList(double dx, SkPoint::Make(dx, dy), SkRect::MakeLTRB(cullLeft, cullTop, cullRight, cullBottom), SkRect::MakeLTRB(drawLeft, drawTop, drawRight, drawBottom), - displayList->ops_vector(), displayList->data_vector(), + displayList->ops_vector(), displayList->data_vector(), displayList->ref_vector(), !!(hints & 1), !!(hints & 2)); AddLayer(std::move(layer)); } diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index 2e63585a8ea8e..532f202d8b70e 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -95,48 +95,101 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, std::shared_ptr> data_vector = std::make_shared>(data_ptr, data_ptr + (dataBytes / sizeof(float))); - // int numObjects = 0; - // Dart_ListLength(objList, &numObjects); - // Dart_Handle objects[numObjects]; - // if (Dart_IsError( - // Dart_ListGetRange(objList, 0, numObjects, objects))) { - // return nullptr; - // } - // for (int i = 0; i < numObjects; i++) { - // const char *name; - // Dart_Handle type = Dart_InstanceGetType(objects[i]); - // } - // int obj_index = 0; - // for (int i = 0; i < numOps; i++) { - // uint8_t op = ops_ptr[i]; - // int opObjs = DisplayListInterpreter::opObjCounts[op]; - // if (opObjs > 0) { - // switch (static_cast(op)) { - // case cops_setImageFilter: { - // Dart_Handle image_filter = objects[obj_index++]; - // ImageFilter* decoded = - // tonic::DartConverter::FromDart(image_filter); - // } - // default: break; - // } - // } - // } + intptr_t numObjects = 0; + Dart_ListLength(objList, &numObjects); + Dart_Handle objects[numObjects]; + if (Dart_IsError( + Dart_ListGetRange(objList, 0, numObjects, objects))) { + return nullptr; + } + + std::shared_ptr> ref_vector = + std::make_shared>(); + int obj_index = 0; + const DisplayListRefHolder empty_holder; + for (uint8_t op : *ops_vector) { + for (uint32_t args = DisplayListInterpreter::opArguments[op]; + args != 0; + args >>= CANVAS_OP_ARG_SHIFT) { + switch (static_cast(args & CANVAS_OP_ARG_MASK)) { + case color_filter: { + DisplayListRefHolder holder; + holder.colorFilter = tonic::DartConverter::FromDart(objects[obj_index++])->filter(); + ref_vector->emplace_back(holder); + break; + } + case image_filter: { + DisplayListRefHolder holder; + holder.imageFilter = tonic::DartConverter::FromDart(objects[obj_index++])->filter(); + ref_vector->emplace_back(holder); + break; + } + case picture: + ref_vector->emplace_back(empty_holder); + obj_index++; + break; + case path: + ref_vector->emplace_back(empty_holder); + obj_index++; + // ref_vector->emplace_back(static_cast>(tonic::DartConverter::FromDart(objects[obj_index++])->path())); + break; + case shader: + ref_vector->emplace_back(empty_holder); + obj_index++; + // ref_vector->emplace_back(static_cast>(tonic::DartConverter::FromDart(objects[obj_index++])->picture())); + break; + case image: { + DisplayListRefHolder holder; + holder.image = tonic::DartConverter::FromDart(objects[obj_index++])->image(); + ref_vector->emplace_back(holder); + break; + } + case paragraph: + ref_vector->emplace_back(empty_holder); + obj_index++; + break; + case vertices: + ref_vector->emplace_back(empty_holder); + obj_index++; + break; + case empty: + case angle: + case color: + case blend_mode: + case matrix_row3: + case point: + case rect: + case round_rect: + case scalar: + case scalar_list: + case uint32_list: + break; + } + } + } + if (obj_index != numObjects) { + FML_LOG(ERROR) << "Bad number of objects: " << obj_index << " != " << numObjects; + return nullptr; + } return fml::MakeRefCounted(std::move(ops_vector), - std::move(data_vector)); + std::move(data_vector), + std::move(ref_vector)); } DisplayList::DisplayList(std::shared_ptr> ops_vector, - std::shared_ptr> data_vector) + std::shared_ptr> data_vector, + std::shared_ptr> ref_vector) : ops_vector_(ops_vector), - data_vector_(data_vector) {} + data_vector_(data_vector), + ref_vector_(ref_vector) {} DisplayList::~DisplayList() = default; Dart_Handle DisplayList::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { - return RasterizeToImage(ops_vector_, data_vector_, width, height, raw_image_callback); + return RasterizeToImage(ops_vector_, data_vector_, ref_vector_, width, height, raw_image_callback); } void DisplayList::dispose() { @@ -151,6 +204,7 @@ size_t DisplayList::GetAllocationSize() const { Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> ops, std::shared_ptr> data, + std::shared_ptr> refs, uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -207,10 +261,10 @@ Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> // Kick things off on the raster rask runner. fml::TaskRunner::RunNowOrPostTask( raster_task_runner, - [ui_task_runner, snapshot_delegate, ops, data, picture_bounds, ui_task] { + [ui_task_runner, snapshot_delegate, ops, data, refs, picture_bounds, ui_task] { sk_sp raster_image = - snapshot_delegate->MakeRasterSnapshot([ops = std::move(ops), data = std::move(data)](SkCanvas* canvas) { - DisplayListInterpreter interpreter(ops, data); + snapshot_delegate->MakeRasterSnapshot([ops = std::move(ops), data = std::move(data), refs = std::move(refs)](SkCanvas* canvas) { + DisplayListInterpreter interpreter(ops, data, refs); interpreter.Rasterize(canvas); }, picture_bounds); diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h index 3ed3c085c6316..38ec8fa9444c9 100644 --- a/lib/ui/painting/display_list.h +++ b/lib/ui/painting/display_list.h @@ -7,9 +7,14 @@ #include +#include "flutter/flow/display_list_interpreter.h" #include "flutter/lib/ui/dart_wrapper.h" #include "third_party/tonic/typed_data/typed_list.h" #include "third_party/tonic/typed_data/dart_byte_data.h" +#include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/include/core/SkColorFilter.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkImage.h" namespace tonic { class DartLibraryNatives; @@ -41,6 +46,7 @@ class DisplayList : public RefCountedDartWrappable { static Dart_Handle RasterizeToImage(std::shared_ptr> ops, std::shared_ptr> data, + std::shared_ptr> refs, uint32_t width, uint32_t height, Dart_Handle raw_image_callback); @@ -49,14 +55,17 @@ class DisplayList : public RefCountedDartWrappable { std::shared_ptr> ops_vector() { return ops_vector_; } std::shared_ptr> data_vector() { return data_vector_; } + std::shared_ptr> ref_vector() { return ref_vector_; } private: explicit DisplayList(std::shared_ptr> ops_vector, - std::shared_ptr> data_vector); + std::shared_ptr> data_vector, + std::shared_ptr> ref_vector); // explicit DisplayList(); std::shared_ptr> ops_vector_; std::shared_ptr> data_vector_; + std::shared_ptr> ref_vector_; }; } // namespace flutter From 7f18ebf2f9e8f2ef1b7e8fdad0934432f0344950 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 29 Mar 2021 21:49:47 -0700 Subject: [PATCH 13/37] add support for shaders and vertices --- flow/display_list_interpreter.cc | 4 +-- flow/display_list_interpreter.h | 5 ++++ lib/ui/painting/display_list.cc | 45 +++++++++++++++----------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index eb558b3ba76c3..ed58f41d06834 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -212,7 +212,7 @@ CANVAS_JOIN_DEFINE_OP(Round) CANVAS_JOIN_DEFINE_OP(Bevel) CANVAS_OP_DEFINE_OP(clearShader, context.paint.setShader(nullptr);) -CANVAS_OP_DEFINE_OP(setShader, it.skipSkRef();) +CANVAS_OP_DEFINE_OP(setShader, context.paint.setShader(it.GetShader());) CANVAS_OP_DEFINE_OP(clearMaskFilter, context.paint.setMaskFilter(nullptr);) #define CANVAS_MASK_DEFINE_OP(type) CANVAS_OP_DEFINE_OP(setMaskFilter##type, \ @@ -307,7 +307,7 @@ CANVAS_OP_DEFINE_OP(draw##mode, \ CANVAS_OP_DEFINE_POINT_OP(Points) CANVAS_OP_DEFINE_POINT_OP(Lines) CANVAS_OP_DEFINE_POINT_OP(Polygon) -CANVAS_OP_DEFINE_OP(drawVertices, it.skipSkRef(); /* TODO(flar) deal with List of vertices */) +CANVAS_OP_DEFINE_OP(drawVertices, context.canvas->drawVertices(it.GetVertices(), context.paint.getBlendMode(), context.paint);) CANVAS_OP_DEFINE_OP(drawImage, sk_sp image = it.GetImage(); diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index ce1bb88d264a6..5e04910fcf5b2 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -13,6 +13,7 @@ #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRRect.h" +#include "third_party/skia/include/core/SkVertices.h" namespace flutter { @@ -187,6 +188,8 @@ class DisplayListRefHolder { sk_sp colorFilter; sk_sp imageFilter; sk_sp image; + sk_sp vertices; + sk_sp shader; }; class DisplayListInterpreter { @@ -276,6 +279,8 @@ class DisplayListInterpreter { const sk_sp GetColorFilter() { return (refs++)->colorFilter; } const sk_sp GetImageFilter() { return (refs++)->imageFilter; } const sk_sp GetImage() { return (refs++)->image; } + const sk_sp GetVertices() { return (refs++)->vertices; } + const sk_sp GetShader() { return (refs++)-> shader; } std::vector::iterator ops; const std::vector::iterator ops_end; diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index 532f202d8b70e..ae41dec40f6cb 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -22,6 +22,7 @@ #include "flutter/fml/make_copyable.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/painting/canvas.h" +#include "flutter/lib/ui/painting/shader.h" #include "flutter/lib/ui/painting/image_filter.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" @@ -51,23 +52,6 @@ void DisplayList::RegisterNatives(tonic::DartLibraryNatives* natives) { FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } -// static bool checkObjectLength(int index, int numObjects) { -// if (index >= numObjects) { -// Dart_ThrowException( -// tonic::ToDart("DisplayList object array too short.")); -// return false; -// } -// return true; -// } - -// static bool checkImageFilter(Dart_Handle objects[], int numObjects, int index) { -// if (checkObjectLength(index, numObjects)) { -// Dart_Handle image_filter = objects[index]; -// ImageFilter* decoded = -// tonic::DartConverter::FromDart(image_filter); -// } -// } - fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, int numOps, tonic::DartByteData& data, @@ -125,19 +109,29 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, break; } case picture: + // TODO(flar): find a way to bake a picture into the refs vector. ref_vector->emplace_back(empty_holder); obj_index++; break; case path: + // TODO(flar): find a way to bake a path into the refs vector. ref_vector->emplace_back(empty_holder); obj_index++; // ref_vector->emplace_back(static_cast>(tonic::DartConverter::FromDart(objects[obj_index++])->path())); break; - case shader: - ref_vector->emplace_back(empty_holder); - obj_index++; - // ref_vector->emplace_back(static_cast>(tonic::DartConverter::FromDart(objects[obj_index++])->picture())); + case shader: { + DisplayListRefHolder holder; + // TODO(flar) we should eventually be baking the filterquality into the Shader + // The existing Shader::shader(FQ) API is meant to be called in context from + // the SkiaCanvas. We could be parsing the stream to determine the filter quality + // that would be in effect when we reach this op, but that is overhead to consider + // another time. (The dart DisplayListCanvas code could also encode the current + // FQ into the op code - but soon we should be able to encode it into the shader + // itself and this will be moot...) + holder.shader = tonic::DartConverter::FromDart(objects[obj_index++])->shader(SkFilterQuality::kLow_SkFilterQuality); + ref_vector->emplace_back(holder); break; + } case image: { DisplayListRefHolder holder; holder.image = tonic::DartConverter::FromDart(objects[obj_index++])->image(); @@ -145,13 +139,16 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, break; } case paragraph: + // TODO(flar): find a way to bake a shader into the refs vector. ref_vector->emplace_back(empty_holder); obj_index++; break; - case vertices: - ref_vector->emplace_back(empty_holder); - obj_index++; + case vertices: { + DisplayListRefHolder holder; + holder.vertices = tonic::DartConverter::FromDart(objects[obj_index++])->vertices(); + ref_vector->emplace_back(holder); break; + } case empty: case angle: case color: From 9ba2de0e2339cca9706b1fab6cf16efd405ef353 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 30 Mar 2021 00:08:22 -0700 Subject: [PATCH 14/37] implement drawParagraph via SkPicture --- flow/display_list_interpreter.cc | 4 ++-- flow/display_list_interpreter.h | 11 +++++++---- lib/ui/painting.dart | 32 ++++++++++++++++++++++++-------- lib/ui/painting/display_list.cc | 9 +++++---- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index ed58f41d06834..6117a830da08d 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -106,7 +106,7 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { case image: ss << "[Image]"; break; case path: ss << "[Path]"; break; case vertices: ss << "[Vertices]"; break; - case paragraph: ss << "[Paragraph]"; break; + case skpicture: ss << "[SkPicture]"; break; case picture: ss << "[Picture]"; break; case shader: ss << "[Shader]"; break; case color_filter: ss << "[ColorFilter]"; break; @@ -367,7 +367,7 @@ CANVAS_OP_DEFINE_ATLAS(drawAtlasCulled, false, true) CANVAS_OP_DEFINE_ATLAS(drawAtlasColoredCulled, true, true) CANVAS_OP_DEFINE_OP(drawPicture, it.skipSkRef(); /* TODO(flar) deal with Picture object */) -CANVAS_OP_DEFINE_OP(drawParagraph, it.skipSkRef(); it.GetPoint(); /* TODO(flar) deal with Paragraph object */) +CANVAS_OP_DEFINE_OP(drawSkPicture, context.canvas->drawPicture(it.GetSkPicture());) CANVAS_OP_DEFINE_OP(drawShadow, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) CANVAS_OP_DEFINE_OP(drawShadowOccluded, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 5e04910fcf5b2..e22481d17fc7c 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -12,6 +12,7 @@ #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkVertices.h" @@ -32,7 +33,7 @@ enum CanvasOpArg { image, path, vertices, - paragraph, + skpicture, picture, shader, color_filter, @@ -78,7 +79,7 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS4(image, scalar_list, scalar_list, uint32_list) #define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS4(image, scalar_list, scalar_list, rect) #define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS5(image, scalar_list, scalar_list, uint32_list, rect) -#define CANVAS_OP_ARGS_Paragraph_Point CANVAS_OP_ARGS2(paragraph, point) +#define CANVAS_OP_ARGS_SkPicture CANVAS_OP_ARGS1(skpicture) #define CANVAS_OP_ARGS_Picture CANVAS_OP_ARGS1(picture) #define CANVAS_OP_ARGS_Shader CANVAS_OP_ARGS1(shader) #define CANVAS_OP_ARGS_ColorFilter CANVAS_OP_ARGS1(color_filter) @@ -173,7 +174,7 @@ enum CanvasOpArg { V(drawAtlasCulled, Atlas_Rect) \ V(drawAtlasColoredCulled, Atlas_Colors_Rect) \ \ - V(drawParagraph, Paragraph_Point) \ + V(drawSkPicture, SkPicture) \ V(drawPicture, Picture) \ V(drawShadow, Path_Scalar) \ V(drawShadowOccluded, Path_Scalar) @@ -190,6 +191,7 @@ class DisplayListRefHolder { sk_sp image; sk_sp vertices; sk_sp shader; + sk_sp picture; }; class DisplayListInterpreter { @@ -280,7 +282,8 @@ class DisplayListInterpreter { const sk_sp GetImageFilter() { return (refs++)->imageFilter; } const sk_sp GetImage() { return (refs++)->image; } const sk_sp GetVertices() { return (refs++)->vertices; } - const sk_sp GetShader() { return (refs++)-> shader; } + const sk_sp GetShader() { return (refs++)->shader; } + const sk_sp GetSkPicture() { return (refs++)->picture; } std::vector::iterator ops; const std::vector::iterator ops_end; diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index de114a34e8c05..05df5d17f7c70 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5176,7 +5176,7 @@ enum _CanvasOp { drawAtlasCulled, drawAtlasColoredCulled, - drawParagraph, + drawSkPicture, drawPicture, drawShadow, drawShadowOccluded, @@ -5424,6 +5424,10 @@ class _DisplayListCanvas implements Canvas { _objData.add(paragraph); } + void _addSkPicture(_SkiaPicture picture) { + _objData.add(picture); + } + void _addPicture(Picture picture) { _objData.add(picture); } @@ -5979,17 +5983,29 @@ class _DisplayListCanvas implements Canvas { @override void drawParagraph(Paragraph paragraph, Offset offset) { - _addOp(_CanvasOp.drawParagraph); - _addParagraph(paragraph); - _addOffset(offset); + final _SkiaPictureRecorder recorder = _SkiaPictureRecorder(); + final _SkiaCanvas canvas = _SkiaCanvas(recorder); + paragraph._paint(canvas, offset.dx, offset.dy); + _drawSkiaPicture(recorder.endRecording() as _SkiaPicture); + print('adding conservative bounds for drawParagaph'); + } + + void _drawSkiaPicture(_SkiaPicture picture) { + _addOp(_CanvasOp.drawSkPicture); + _addSkPicture(picture); + _addBounds(_cullRect, false); } @override void drawPicture(Picture picture) { - _addOp(_CanvasOp.drawPicture); - _addPicture(picture as _DisplayListPicture); - print('adding conservative bounds for drawPicture'); - _addBounds(_cullRect, false); + if (picture is _SkiaPicture) { + _drawSkiaPicture(picture); + } else { + _addOp(_CanvasOp.drawPicture); + _addPicture(picture as _DisplayListPicture); + print('adding conservative bounds for drawPicture'); + _addBounds(_cullRect, false); + } } @override diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index ae41dec40f6cb..cfa5ae255c8ea 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -138,11 +138,12 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, ref_vector->emplace_back(holder); break; } - case paragraph: - // TODO(flar): find a way to bake a shader into the refs vector. - ref_vector->emplace_back(empty_holder); - obj_index++; + case skpicture: { + DisplayListRefHolder holder; + holder.picture = tonic::DartConverter::FromDart(objects[obj_index++])->picture(); + ref_vector->emplace_back(holder); break; + } case vertices: { DisplayListRefHolder holder; holder.vertices = tonic::DartConverter::FromDart(objects[obj_index++])->vertices(); From 90a37ce055a59a2598490691cca70a355e6092b8 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 30 Mar 2021 00:43:48 -0700 Subject: [PATCH 15/37] adjust some paint attribute defaults and masks --- flow/display_list_interpreter.cc | 4 ++-- lib/ui/painting.dart | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 6117a830da08d..f0a39856e3dc5 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -141,8 +141,8 @@ sk_sp DisplayListInterpreter::makeColorFilter(RasterizeContext& c void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { RasterizeContext context; context.canvas = canvas; - context.filterMode = LinearSampling.filter; - context.sampling = LinearSampling; + context.filterMode = NearestSampling.filter; + context.sampling = NearestSampling; int entrySaveCount = canvas->getSaveCount(); Iterator it(this); while (it.HasOp()) { diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 05df5d17f7c70..70028d1447e80 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5420,9 +5420,9 @@ class _DisplayListCanvas implements Canvas { _objData.add(vertices); } - void _addParagraph(Paragraph paragraph) { - _objData.add(paragraph); - } + // void _addParagraph(Paragraph paragraph) { + // _objData.add(paragraph); + // } void _addSkPicture(_SkiaPicture picture) { _objData.add(picture); @@ -5601,9 +5601,11 @@ class _DisplayListCanvas implements Canvas { static const int _maskFilterNeeded = 11; static const int _ditherNeeded = 12; - static const int _paintMask = _aaNeeded | _colorNeeded | _blendNeeded; - static const int _drawMask = _paintMask | _paintStyleNeeded; - static const int _imageMask = _blendNeeded | _filterQualityNeeded; + static const int _paintMask = _aaNeeded | _colorNeeded | _blendNeeded | _invertColorsNeeded + | _colorFilterNeeded | _shaderNeeded; + static const int _drawMask = _paintMask | _paintStyleNeeded | _maskFilterNeeded; + static const int _strokeMask = _paintMask | _strokeStyleNeeded | _maskFilterNeeded; + static const int _imageMask = _blendNeeded | _filterQualityNeeded | _imageFilterNeeded | _ditherNeeded; static const int _saveLayerMask = _blendNeeded; static const List<_CanvasOp> _filterQualityOps = <_CanvasOp>[ @@ -5744,7 +5746,7 @@ class _DisplayListCanvas implements Canvas { @override void drawPaint(Paint paint) { - _updatePaintData(paint, _drawMask); + _updatePaintData(paint, _paintMask); _addOp(_CanvasOp.drawPaint); _addBounds(_cullRect, false); } @@ -5759,7 +5761,7 @@ class _DisplayListCanvas implements Canvas { @override void drawLine(Offset p1, Offset p2, Paint paint) { - _updatePaintData(paint, _paintMask | _strokeStyleNeeded); + _updatePaintData(paint, _strokeMask); _addOp(_CanvasOp.drawLine); _addOffset(p1); _addOffset(p2); @@ -5845,7 +5847,7 @@ class _DisplayListCanvas implements Canvas { @override void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) { - _updatePaintData(paint, _paintMask | _strokeStyleNeeded); + _updatePaintData(paint, _strokeMask); _addOp(_pointOps[pointMode.index]); _addFloat32List(points); for (int i = 0; i + 1 < points.length; i += 2) { From e4c52bd1aa0f664bc058ce33846720867399d92b Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 30 Mar 2021 15:40:26 -0700 Subject: [PATCH 16/37] add ability to render new _DisplayListPicture objects --- flow/display_list_interpreter.cc | 11 ++++++++--- flow/display_list_interpreter.h | 20 ++++++++++++++++---- lib/ui/painting.dart | 7 ++++--- lib/ui/painting/display_list.cc | 20 +++++++++++--------- lib/ui/painting/display_list.h | 2 ++ 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index f0a39856e3dc5..c231eed7b9222 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -23,13 +23,18 @@ const std::vector DisplayListInterpreter::opArguments = { FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_ARGS) }; +DisplayListInterpreter::DisplayListInterpreter(DisplayListData data) + : ops_vector_(data.ops_vector), + data_vector_(data.data_vector), + ref_vector_(data.ref_vector) {} + DisplayListInterpreter::DisplayListInterpreter( std::shared_ptr> ops_vector, std::shared_ptr> data_vector, std::shared_ptr> ref_vector) : ops_vector_(std::move(ops_vector)), data_vector_(std::move(data_vector)), - ref_vector_(ref_vector) {} + ref_vector_(std::move(ref_vector)) {} void DisplayListInterpreter::Describe() { Iterator it(this); @@ -107,7 +112,7 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { case path: ss << "[Path]"; break; case vertices: ss << "[Vertices]"; break; case skpicture: ss << "[SkPicture]"; break; - case picture: ss << "[Picture]"; break; + case display_list: ss << "[DisplayList]"; break; case shader: ss << "[Shader]"; break; case color_filter: ss << "[ColorFilter]"; break; case image_filter: ss << "[ImageFilter]"; break; @@ -366,7 +371,7 @@ CANVAS_OP_DEFINE_ATLAS(drawAtlasColored, true, false) CANVAS_OP_DEFINE_ATLAS(drawAtlasCulled, false, true) CANVAS_OP_DEFINE_ATLAS(drawAtlasColoredCulled, true, true) -CANVAS_OP_DEFINE_OP(drawPicture, it.skipSkRef(); /* TODO(flar) deal with Picture object */) +CANVAS_OP_DEFINE_OP(drawDisplayList, DisplayListInterpreter(it.GetDisplayList()).Rasterize(context.canvas);) CANVAS_OP_DEFINE_OP(drawSkPicture, context.canvas->drawPicture(it.GetSkPicture());) CANVAS_OP_DEFINE_OP(drawShadow, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) CANVAS_OP_DEFINE_OP(drawShadowOccluded, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index e22481d17fc7c..72fadf3ff039b 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -34,7 +34,7 @@ enum CanvasOpArg { path, vertices, skpicture, - picture, + display_list, shader, color_filter, image_filter, @@ -80,7 +80,7 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS4(image, scalar_list, scalar_list, rect) #define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS5(image, scalar_list, scalar_list, uint32_list, rect) #define CANVAS_OP_ARGS_SkPicture CANVAS_OP_ARGS1(skpicture) -#define CANVAS_OP_ARGS_Picture CANVAS_OP_ARGS1(picture) +#define CANVAS_OP_ARGS_DisplayList CANVAS_OP_ARGS1(display_list) #define CANVAS_OP_ARGS_Shader CANVAS_OP_ARGS1(shader) #define CANVAS_OP_ARGS_ColorFilter CANVAS_OP_ARGS1(color_filter) #define CANVAS_OP_ARGS_ImageFilter CANVAS_OP_ARGS1(image_filter) @@ -175,7 +175,7 @@ enum CanvasOpArg { V(drawAtlasColoredCulled, Atlas_Colors_Rect) \ \ V(drawSkPicture, SkPicture) \ - V(drawPicture, Picture) \ + V(drawDisplayList, DisplayList) \ V(drawShadow, Path_Scalar) \ V(drawShadowOccluded, Path_Scalar) @@ -184,18 +184,29 @@ enum CanvasOp { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM) }; +class DisplayListRefHolder; + +struct DisplayListData { + std::shared_ptr> ops_vector; + std::shared_ptr> data_vector; + std::shared_ptr> ref_vector; +}; + class DisplayListRefHolder { - public: + public: sk_sp colorFilter; sk_sp imageFilter; sk_sp image; sk_sp vertices; sk_sp shader; sk_sp picture; + DisplayListData displayList; }; class DisplayListInterpreter { public: + DisplayListInterpreter(DisplayListData data); + DisplayListInterpreter(std::shared_ptr> ops, std::shared_ptr> data, std::shared_ptr> refs); @@ -284,6 +295,7 @@ class DisplayListInterpreter { const sk_sp GetVertices() { return (refs++)->vertices; } const sk_sp GetShader() { return (refs++)->shader; } const sk_sp GetSkPicture() { return (refs++)->picture; } + const DisplayListData GetDisplayList() { return (refs++)->displayList; } std::vector::iterator ops; const std::vector::iterator ops_end; diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 70028d1447e80..eae0e925ae33d 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5177,7 +5177,7 @@ enum _CanvasOp { drawAtlasColoredCulled, drawSkPicture, - drawPicture, + drawDisplayList, drawShadow, drawShadowOccluded, } @@ -6002,10 +6002,11 @@ class _DisplayListCanvas implements Canvas { void drawPicture(Picture picture) { if (picture is _SkiaPicture) { _drawSkiaPicture(picture); + print('adding conservative bounds for drawPicture(Skia)'); } else { - _addOp(_CanvasOp.drawPicture); + _addOp(_CanvasOp.drawDisplayList); _addPicture(picture as _DisplayListPicture); - print('adding conservative bounds for drawPicture'); + print('adding conservative bounds for drawPicture(DisplayList)'); _addBounds(_cullRect, false); } } diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index cfa5ae255c8ea..c04894612fa8a 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -108,11 +108,12 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, ref_vector->emplace_back(holder); break; } - case picture: - // TODO(flar): find a way to bake a picture into the refs vector. - ref_vector->emplace_back(empty_holder); - obj_index++; + case display_list: { + DisplayListRefHolder holder; + holder.displayList = tonic::DartConverter::FromDart(objects[obj_index++])->data(); + ref_vector->emplace_back(holder); break; + } case path: // TODO(flar): find a way to bake a path into the refs vector. ref_vector->emplace_back(empty_holder); @@ -123,11 +124,12 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, DisplayListRefHolder holder; // TODO(flar) we should eventually be baking the filterquality into the Shader // The existing Shader::shader(FQ) API is meant to be called in context from - // the SkiaCanvas. We could be parsing the stream to determine the filter quality - // that would be in effect when we reach this op, but that is overhead to consider - // another time. (The dart DisplayListCanvas code could also encode the current - // FQ into the op code - but soon we should be able to encode it into the shader - // itself and this will be moot...) + // the SkiaCanvas paint method. We could parse the stream to determine the + // filter quality that would be in effect when we reach this op, but that is + // overhead to consider another time. + // (The dart DisplayListCanvas code could also encode the current FQ into the + // op code - but soon we should be able to encode it into the shader itself + // and this issue will be moot...) holder.shader = tonic::DartConverter::FromDart(objects[obj_index++])->shader(SkFilterQuality::kLow_SkFilterQuality); ref_vector->emplace_back(holder); break; diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h index 38ec8fa9444c9..23d9660650bc1 100644 --- a/lib/ui/painting/display_list.h +++ b/lib/ui/painting/display_list.h @@ -40,6 +40,8 @@ class DisplayList : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + DisplayListData data() { return { ops_vector_, data_vector_, ref_vector_ }; } + void dispose(); size_t GetAllocationSize() const override; From e6c51c5d323dc97f1da3f6b7b27e65acf619553d Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 30 Mar 2021 23:36:33 -0700 Subject: [PATCH 17/37] implement drawPath/Shadow and a few bounds improvements --- flow/display_list_interpreter.cc | 22 +++++- flow/display_list_interpreter.h | 6 ++ lib/ui/painting.dart | 129 ++++++++++++++++++++----------- lib/ui/painting/display_list.cc | 11 +-- lib/ui/painting/picture.cc | 13 ++++ lib/ui/painting/picture.h | 3 + 6 files changed, 133 insertions(+), 51 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index c231eed7b9222..d9b90fa2a81da 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -5,6 +5,7 @@ #include "flutter/flow/display_list_interpreter.h" #include "flutter/fml/logging.h" +#include "flutter/flow/layers/physical_shape_layer.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" #include "third_party/skia/include/core/SkColorFilter.h" @@ -299,7 +300,11 @@ CANVAS_OP_DEFINE_OP(drawCircle, context.canvas->drawCircle(it.GetPoint(), it.Get CANVAS_OP_DEFINE_OP(drawArc, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), false, context.paint);) CANVAS_OP_DEFINE_OP(drawArcCenter, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), true, context.paint);) CANVAS_OP_DEFINE_OP(drawLine, context.canvas->drawLine(it.GetPoint(), it.GetPoint(), context.paint);) -CANVAS_OP_DEFINE_OP(drawPath, it.skipSkRef(); /* TODO(flar) deal with Path object */) +CANVAS_OP_DEFINE_OP(drawPath, + SkPath path; + it.GetPath(path); + context.canvas->drawPath(path, context.paint); +) #define CANVAS_OP_DEFINE_POINT_OP(mode) \ CANVAS_OP_DEFINE_OP(draw##mode, \ @@ -373,7 +378,18 @@ CANVAS_OP_DEFINE_ATLAS(drawAtlasColoredCulled, true, true) CANVAS_OP_DEFINE_OP(drawDisplayList, DisplayListInterpreter(it.GetDisplayList()).Rasterize(context.canvas);) CANVAS_OP_DEFINE_OP(drawSkPicture, context.canvas->drawPicture(it.GetSkPicture());) -CANVAS_OP_DEFINE_OP(drawShadow, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) -CANVAS_OP_DEFINE_OP(drawShadowOccluded, it.skipSkRef(); it.GetScalar(); /* TODO(flar) deal with Path object */) + +#define CANVAS_OP_DEFINE_SHADOW_OP(optype, occludes) \ +CANVAS_OP_DEFINE_OP(optype, \ + SkPath path; \ + it.GetPath(path); \ + SkColor color = context.paint.getColor(); \ + /* TODO(flar): How to deal with dpr */ \ + SkScalar dpr = 1.0; \ + flutter::PhysicalShapeLayer::DrawShadow(context.canvas, path, color, \ + it.GetScalar(), occludes, dpr); \ +) +CANVAS_OP_DEFINE_SHADOW_OP(drawShadow, false) +CANVAS_OP_DEFINE_SHADOW_OP(drawShadowOccluded, true) } // namespace flutter diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 72fadf3ff039b..94b4ac80c5385 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -13,6 +13,7 @@ #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkVertices.h" @@ -200,6 +201,7 @@ class DisplayListRefHolder { sk_sp vertices; sk_sp shader; sk_sp picture; + sk_sp pathData; DisplayListData displayList; }; @@ -296,6 +298,10 @@ class DisplayListInterpreter { const sk_sp GetShader() { return (refs++)->shader; } const sk_sp GetSkPicture() { return (refs++)->picture; } const DisplayListData GetDisplayList() { return (refs++)->displayList; } + void GetPath(SkPath& path) { + SkData* data = (refs++)->pathData.get(); + path.readFromMemory(data->data(), data->size()); + } std::vector::iterator ops; const std::vector::iterator ops_end; diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index eae0e925ae33d..cceee252f5d44 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5057,6 +5057,12 @@ class _SkiaPicture extends NativeFieldWrapperClass2 implements Picture { String? _toImage(int width, int height, _Callback<_Image?> callback) native 'Picture_toImage'; + Rect _getBounds() { + final Float32List rect = _getBoundsF32(); + return Rect.fromLTRB(rect[0], rect[1], rect[2], rect[3]); + } + Float32List _getBoundsF32() native 'Picture_getBounds'; + @override void dispose() native 'Picture_dispose'; @@ -5201,6 +5207,9 @@ class _MatrixTransform { double mxx; double mxy; double mxt; double myx; double myy; double myt; + bool get isRectilinear => (mxy == 0.0 && myx == 0.0) || (mxx == 0.0 && myy == 0.0); + bool get isNotRectilinear => (mxy != 0.0 || myx != 0.0) && (mxx != 0.0 || myy != 0.0); + double transformX(double x, double y) { return x * mxx + y * mxy + mxt; } @@ -5245,16 +5254,55 @@ class _MatrixTransform { } } +class _BoundsAccumulator { + double _minX = Rect._giantScalar; + double _minY = Rect._giantScalar; + double _maxX = -Rect._giantScalar; + double _maxY = -Rect._giantScalar; + + void accumulate(double x, double y) { + if (_minX > x) + _minX = x; + if (_minY > y) + _minY = y; + if (_maxX < x) + _maxX = x; + if (_maxY < y) + _maxY = y; + } + + void accumulateBounds(Rect r, RSTransform rst) { + accumulateRstBounds(r.left, r.top, r.right, r.bottom, rst.scos, rst.ssin, rst.tx, rst.ty); + } + + void accumulateRstBounds(double left, double top, double right, double bottom, + double scos, double ssin, double tx, double ty) { + if (ssin == 0) { + accumulate(scos * left + tx, scos * top + ty); + accumulate(scos * right + tx, scos * bottom + ty); + return; + } else if (scos == 0) { + accumulate(-ssin * top + tx, ssin * left + ty); + accumulate(-ssin * bottom + tx, ssin * right + ty); + return; + } else { + accumulate(scos * left - ssin * top + tx, ssin * left + scos * top + ty); + accumulate(scos * right - ssin * top + tx, ssin * right + scos * top + ty); + accumulate(scos * left - ssin * bottom + tx, ssin * left + scos * bottom + ty); + accumulate(scos * right - ssin * bottom + tx, ssin * right + scos * bottom + ty); + } + } + + Rect get bounds => Rect.fromLTRB(_minX, _minY, _maxX, _maxY); +} + /// Local storage version of Canvas class _DisplayListCanvas implements Canvas { /// Make a Canvas2 _DisplayListCanvas(PictureRecorder recorder, [Rect? cullRect]) : _recorder = recorder as _DisplayListPictureRecorder, _cullRect = cullRect ?? Rect.largest, - _minX = Rect._giantScalar, - _minY = Rect._giantScalar, - _maxX = -Rect._giantScalar, - _maxY = -Rect._giantScalar, + _accumulator = _BoundsAccumulator(), _ops = Uint8List(128), _numOps = 0, _data = ByteData(128 * 4), _numDataBytes = 0, _objData = [], @@ -5265,10 +5313,7 @@ class _DisplayListCanvas implements Canvas { _DisplayListPictureRecorder? _recorder; Rect _cullRect; - double _minX; - double _minY; - double _maxX; - double _maxY; + _BoundsAccumulator _accumulator; int _numOps; Uint8List _ops; int _numDataBytes; @@ -5277,7 +5322,7 @@ class _DisplayListCanvas implements Canvas { _MatrixTransform _ctm; List<_MatrixTransform> _ctmStack; - Rect get _drawBounds => Rect.fromLTRB(_minX, _minY, _maxX, _maxY); + Rect get _drawBounds => _accumulator.bounds; static const int _maxOpsDoubleSize = 1 << 20; Uint8List _growOps(Uint8List src) { @@ -5420,15 +5465,11 @@ class _DisplayListCanvas implements Canvas { _objData.add(vertices); } - // void _addParagraph(Paragraph paragraph) { - // _objData.add(paragraph); - // } - void _addSkPicture(_SkiaPicture picture) { _objData.add(picture); } - void _addPicture(Picture picture) { + void _addPicture(_DisplayListPicture picture) { _objData.add(picture); } @@ -5445,16 +5486,7 @@ class _DisplayListCanvas implements Canvas { } void _addPointToBounds(double ux, double uy) { - final double dx = _ctm.transformX(ux, uy); - final double dy = _ctm.transformY(ux, uy); - if (_minX > dx) - _minX = dx; - if (_minY > dy) - _minY = dy; - if (_maxX < dx) - _maxX = dx; - if (_maxY < dy) - _maxY = dy; + _accumulator.accumulate(_ctm.transformX(ux, uy), _ctm.transformY(ux, uy)); } void _addLTRBToBounds(double l, double t, double r, double b, [ bool? isStroke ]) { @@ -5462,6 +5494,10 @@ class _DisplayListCanvas implements Canvas { final double pad = isStroke ? _curStrokeWidth : 0; _addPointToBounds(l - pad, t - pad); _addPointToBounds(r + pad, b + pad); + if (_ctm.isNotRectilinear) { + _addPointToBounds(r + pad, t - pad); + _addPointToBounds(l - pad, b + pad); + } } void _addBounds(Rect r, [ bool? isStroke ]) { @@ -5748,7 +5784,6 @@ class _DisplayListCanvas implements Canvas { void drawPaint(Paint paint) { _updatePaintData(paint, _paintMask); _addOp(_CanvasOp.drawPaint); - _addBounds(_cullRect, false); } @override @@ -5756,7 +5791,6 @@ class _DisplayListCanvas implements Canvas { _updateColor(color); _updateBlendMode(blendMode); _addOp(_CanvasOp.drawColor); - _addBounds(_cullRect, false); } @override @@ -5850,9 +5884,11 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _strokeMask); _addOp(_pointOps[pointMode.index]); _addFloat32List(points); + final _BoundsAccumulator ptBounds = _BoundsAccumulator(); for (int i = 0; i + 1 < points.length; i += 2) { - _addPointToBounds(points[i], points[i + 1]); + ptBounds.accumulate(points[i], points[i + 1]); } + _addBounds(ptBounds.bounds, true); } @override @@ -5911,6 +5947,7 @@ class _DisplayListCanvas implements Canvas { final Float32List rstTransformBuffer = Float32List(rectCount * 4); final Float32List rectBuffer = Float32List(rectCount * 4); + final _BoundsAccumulator rstBounds = _BoundsAccumulator(); for (int i = 0; i < rectCount; ++i) { final int index0 = i * 4; final int index1 = index0 + 1; @@ -5927,6 +5964,7 @@ class _DisplayListCanvas implements Canvas { rectBuffer[index1] = rect.top; rectBuffer[index2] = rect.right; rectBuffer[index3] = rect.bottom; + rstBounds.accumulateBounds(rect, rstTransform); } final Int32List? colorBuffer = (colors == null || colors.isEmpty) ? null : _encodeColorList(colors); @@ -5945,8 +5983,7 @@ class _DisplayListCanvas implements Canvas { _addInt32List(colorBuffer); if (cullRect != null) _addRect(cullRect); - print('adding conservative bounds for drawAtlas'); - _addBounds(_cullRect, false); + _addBounds(rstBounds.bounds, false); } @override @@ -5965,6 +6002,12 @@ class _DisplayListCanvas implements Canvas { if (colors != null && colors.length * 4 != rectCount) throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".'); + final _BoundsAccumulator rstBounds = _BoundsAccumulator(); + for (int i = 0; i < rects.length; i += 4) { + rstBounds.accumulateRstBounds( + rects[i], rects[i+1], rects[i+2], rects[i+3], + rstTransforms[i], rstTransforms[i+1], rstTransforms[i+2], rstTransforms[i+3]); + } final _CanvasOp op = (cullRect == null) ? (colors == null) ? _CanvasOp.drawAtlas : _CanvasOp.drawAtlasColored : (colors == null) ? _CanvasOp.drawAtlasCulled : _CanvasOp.drawAtlasColoredCulled; @@ -5979,8 +6022,19 @@ class _DisplayListCanvas implements Canvas { _addInt32List(colors); if (cullRect != null) _addRect(cullRect); - print('adding conservative bounds for drawAtlas'); - _addBounds(_cullRect, false); + _addBounds(rstBounds.bounds, false); + } + + void _drawSkiaPicture(_SkiaPicture picture) { + _addOp(_CanvasOp.drawSkPicture); + _addSkPicture(picture); + _addBounds(picture._getBounds(), false); + } + + void _drawDisplayListPicture(_DisplayListPicture picture) { + _addOp(_CanvasOp.drawDisplayList); + _addPicture(picture); + _addBounds(picture._drawBounds ?? Rect.zero, false); } @override @@ -5989,25 +6043,14 @@ class _DisplayListCanvas implements Canvas { final _SkiaCanvas canvas = _SkiaCanvas(recorder); paragraph._paint(canvas, offset.dx, offset.dy); _drawSkiaPicture(recorder.endRecording() as _SkiaPicture); - print('adding conservative bounds for drawParagaph'); - } - - void _drawSkiaPicture(_SkiaPicture picture) { - _addOp(_CanvasOp.drawSkPicture); - _addSkPicture(picture); - _addBounds(_cullRect, false); } @override void drawPicture(Picture picture) { if (picture is _SkiaPicture) { _drawSkiaPicture(picture); - print('adding conservative bounds for drawPicture(Skia)'); } else { - _addOp(_CanvasOp.drawDisplayList); - _addPicture(picture as _DisplayListPicture); - print('adding conservative bounds for drawPicture(DisplayList)'); - _addBounds(_cullRect, false); + _drawDisplayListPicture(picture as _DisplayListPicture); } } diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index c04894612fa8a..40b951f305cb8 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -22,6 +22,7 @@ #include "flutter/fml/make_copyable.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/painting/canvas.h" +#include "flutter/lib/ui/painting/path.h" #include "flutter/lib/ui/painting/shader.h" #include "flutter/lib/ui/painting/image_filter.h" #include "third_party/skia/include/core/SkImageFilter.h" @@ -114,12 +115,12 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, ref_vector->emplace_back(holder); break; } - case path: - // TODO(flar): find a way to bake a path into the refs vector. - ref_vector->emplace_back(empty_holder); - obj_index++; - // ref_vector->emplace_back(static_cast>(tonic::DartConverter::FromDart(objects[obj_index++])->path())); + case path: { + DisplayListRefHolder holder; + holder.pathData = tonic::DartConverter::FromDart(objects[obj_index++])->path().serialize(); + ref_vector->emplace_back(holder); break; + } case shader: { DisplayListRefHolder holder; // TODO(flar) we should eventually be baking the filterquality into the Shader diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 5225d993ba4fb..91d39c1812042 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -23,6 +23,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); #define FOR_EACH_BINDING(V) \ V(Picture, toImage) \ + V(Picture, getBounds) \ V(Picture, dispose) \ V(Picture, GetAllocationSize) @@ -42,6 +43,18 @@ Picture::Picture(flutter::SkiaGPUObject picture) Picture::~Picture() = default; +tonic::Float32List Picture::getBounds() { + tonic::Float32List rect(Dart_NewTypedData(Dart_TypedData_kFloat32, 4)); + if (auto picture = picture_.get()) { + const SkRect& bounds = picture->cullRect(); + rect[0] = bounds.left(); + rect[1] = bounds.top(); + rect[2] = bounds.right(); + rect[3] = bounds.bottom(); + } + return rect; +} + Dart_Handle Picture::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index e0158d400ff5e..78ef8b9f138b5 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ +#include "third_party/tonic/typed_data/typed_list.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" @@ -33,6 +34,8 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + tonic::Float32List getBounds(); + void dispose(); size_t GetAllocationSize() const override; From 1702fa3ea6f7cf904f71814add879ad000ecc19f Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Wed, 31 Mar 2021 12:30:04 -0700 Subject: [PATCH 18/37] implement bounds updates for last few canvas ops --- lib/ui/painting.dart | 23 +++++++++++++++++++---- lib/ui/painting/vertices.cc | 14 +++++++++++++- lib/ui/painting/vertices.h | 2 ++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index cceee252f5d44..98d9f3128f47c 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3811,6 +3811,12 @@ class Vertices extends NativeFieldWrapperClass2 { Float32List? textureCoordinates, Int32List? colors, Uint16List? indices) native 'Vertices_init'; + + Rect _getBounds() { + final Float32List rect = _getBoundsF32(); + return Rect.fromLTRB(rect[0], rect[1], rect[2], rect[3]); + } + Float32List _getBoundsF32() native 'Vertices_getBounds'; } /// Defines how a list of points is interpreted when drawing a set of points. @@ -5897,8 +5903,7 @@ class _DisplayListCanvas implements Canvas { _updateBlendMode(blendMode); _addOp(_CanvasOp.drawVertices); _addVertices(vertices); - print('adding conservative bounds for drawVertices'); - _addBounds(_cullRect); + _addBounds(vertices._getBounds()); } @override @@ -6054,14 +6059,24 @@ class _DisplayListCanvas implements Canvas { } } + // Constants from physical_shape_layer.cc + static const double _kLightHeight = 600; + static const double _kLightRadius = 800; + Rect _shadowBounds(Rect pathBounds, double elevation) { + final double lightRelativeHeight = _kLightHeight - elevation; + final double tx = elevation * (_kLightRadius + pathBounds.width * 0.5) / lightRelativeHeight; + final double ty = elevation * (_kLightRadius + 600 + pathBounds.height) / lightRelativeHeight; + return Rect.fromLTRB(pathBounds.left - tx, pathBounds.top, + pathBounds.right + tx, pathBounds.bottom + ty); + } + @override void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { _updateColor(color); _addOp(transparentOccluder ? _CanvasOp.drawShadowOccluded : _CanvasOp.drawShadow); _addPathData(path); _addScalar(elevation); - print('adding conservative bounds for drawShadow'); - _addBounds(_cullRect, false); + _addBounds(_shadowBounds(path.getBounds(), elevation), false); } } diff --git a/lib/ui/painting/vertices.cc b/lib/ui/painting/vertices.cc index 8617aee51f554..fc8ea3dfc221c 100644 --- a/lib/ui/painting/vertices.cc +++ b/lib/ui/painting/vertices.cc @@ -31,7 +31,9 @@ void DecodeInts(const tonic::Int32List& ints, T* out) { IMPLEMENT_WRAPPERTYPEINFO(ui, Vertices); -#define FOR_EACH_BINDING(V) V(Vertices, init) +#define FOR_EACH_BINDING(V) \ + V(Vertices, init) \ + V(Vertices, getBounds) FOR_EACH_BINDING(DART_NATIVE_CALLBACK) @@ -94,6 +96,16 @@ bool Vertices::init(Dart_Handle vertices_handle, return true; } +tonic::Float32List Vertices::getBounds() { + tonic::Float32List rect(Dart_NewTypedData(Dart_TypedData_kFloat32, 4)); + const SkRect& bounds = vertices_->bounds(); + rect[0] = bounds.left(); + rect[1] = bounds.top(); + rect[2] = bounds.right(); + rect[3] = bounds.bottom(); + return rect; +} + size_t Vertices::GetAllocationSize() const { return sizeof(Vertices) + vertices_->approximateSize(); } diff --git a/lib/ui/painting/vertices.h b/lib/ui/painting/vertices.h index 1b4c8601df806..c34a4057955e7 100644 --- a/lib/ui/painting/vertices.h +++ b/lib/ui/painting/vertices.h @@ -33,6 +33,8 @@ class Vertices : public RefCountedDartWrappable { const sk_sp& vertices() const { return vertices_; } + tonic::Float32List getBounds(); + size_t GetAllocationSize() const override; private: From fe786573293920da8cba42aab590088c00b0affc Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 1 Apr 2021 14:11:55 -0700 Subject: [PATCH 19/37] fix paint attribute bit constants --- lib/ui/painting.dart | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 98d9f3128f47c..42e028aff6fd8 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5630,18 +5630,18 @@ class _DisplayListCanvas implements Canvas { MaskFilter? _curMaskFilter; ImageFilter? _curImageFilter; - static const int _aaNeeded = 1; - static const int _colorNeeded = 2; - static const int _blendNeeded = 3; - static const int _invertColorsNeeded = 4; - static const int _filterQualityNeeded = 5; - static const int _paintStyleNeeded = 6; - static const int _strokeStyleNeeded = 7; - static const int _shaderNeeded = 8; - static const int _colorFilterNeeded = 9; - static const int _imageFilterNeeded = 10; - static const int _maskFilterNeeded = 11; - static const int _ditherNeeded = 12; + static const int _aaNeeded = 1 << 0; + static const int _colorNeeded = 1 << 1; + static const int _blendNeeded = 1 << 2; + static const int _invertColorsNeeded = 1 << 3; + static const int _filterQualityNeeded = 1 << 4; + static const int _paintStyleNeeded = 1 << 5; + static const int _strokeStyleNeeded = 1 << 6; + static const int _shaderNeeded = 1 << 7; + static const int _colorFilterNeeded = 1 << 8; + static const int _imageFilterNeeded = 1 << 9; + static const int _maskFilterNeeded = 1 << 10; + static const int _ditherNeeded = 1 << 11; static const int _paintMask = _aaNeeded | _colorNeeded | _blendNeeded | _invertColorsNeeded | _colorFilterNeeded | _shaderNeeded; From 2328f87559e67868ba5c6f8ebd43d8ea28a68a97 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 1 Apr 2021 17:20:20 -0700 Subject: [PATCH 20/37] fix drawAtlas blend mode --- flow/display_list_interpreter.cc | 3 ++- flow/display_list_interpreter.h | 10 ++++++---- lib/ui/painting.dart | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index d9b90fa2a81da..ff362722fa5e9 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -344,6 +344,7 @@ CANVAS_OP_DEFINE_OP(op_type, \ int nrstscalars = it.GetFloatList(&rst_ptr); \ SkScalar *rect_ptr; \ int nrectscalars = it.GetFloatList(&rect_ptr); \ + SkBlendMode blendMode = it.GetBlendMode(); \ int numrects = nrectscalars / 4; \ uint32_t *clr_ptr = nullptr; \ int ncolorints = numrects; \ @@ -368,7 +369,7 @@ CANVAS_OP_DEFINE_OP(op_type, \ reinterpret_cast(rect_ptr), \ reinterpret_cast(clr_ptr), \ numrects, \ - context.paint.getBlendMode(), context.sampling, pCullRect, \ + blendMode, context.sampling, pCullRect, \ &context.paint); \ ) CANVAS_OP_DEFINE_ATLAS(drawAtlas, false, false) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 94b4ac80c5385..92017a5cc8e1c 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -55,6 +55,8 @@ enum CanvasOpArg { CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS3(arg2, arg3, arg4), arg1) #define CANVAS_OP_ARGS5(arg1, arg2, arg3, arg4, arg5) \ CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS4(arg2, arg3, arg4, arg5), arg1) +#define CANVAS_OP_ARGS6(arg1, arg2, arg3, arg4, arg5, arg6) \ + CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS5(arg2, arg3, arg4, arg5, arg6), arg1) #define CANVAS_OP_ARGS__ 0 #define CANVAS_OP_ARGS_Scalar CANVAS_OP_ARGS1(scalar) @@ -76,10 +78,10 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS_Vertices CANVAS_OP_ARGS1(vertices) #define CANVAS_OP_ARGS_Image_Point CANVAS_OP_ARGS2(image, point) #define CANVAS_OP_ARGS_Image_2Rects CANVAS_OP_ARGS3(image, rect, rect) -#define CANVAS_OP_ARGS_Atlas CANVAS_OP_ARGS3(image, scalar_list, scalar_list) -#define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS4(image, scalar_list, scalar_list, uint32_list) -#define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS4(image, scalar_list, scalar_list, rect) -#define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS5(image, scalar_list, scalar_list, uint32_list, rect) +#define CANVAS_OP_ARGS_Atlas CANVAS_OP_ARGS4(image, scalar_list, scalar_list, blend_mode) +#define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS5(image, scalar_list, scalar_list, blend_mode, uint32_list) +#define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS5(image, scalar_list, scalar_list, blend_mode, rect) +#define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS6(image, scalar_list, scalar_list, blend_mode, uint32_list, rect) #define CANVAS_OP_ARGS_SkPicture CANVAS_OP_ARGS1(skpicture) #define CANVAS_OP_ARGS_DisplayList CANVAS_OP_ARGS1(display_list) #define CANVAS_OP_ARGS_Shader CANVAS_OP_ARGS1(shader) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 42e028aff6fd8..9699a1ad78246 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5979,11 +5979,11 @@ class _DisplayListCanvas implements Canvas { : (colorBuffer == null) ? _CanvasOp.drawAtlasCulled : _CanvasOp.drawAtlasColoredCulled; _updatePaintData(paint, _imageMask); - _updateBlendMode(blendMode ?? BlendMode.src); _addOp(op); _addImageData(atlas); _addFloat32List(rstTransformBuffer); _addFloat32List(rectBuffer); + _addInt((blendMode ?? BlendMode.src).index); if (colorBuffer != null) _addInt32List(colorBuffer); if (cullRect != null) @@ -6018,11 +6018,11 @@ class _DisplayListCanvas implements Canvas { : (colors == null) ? _CanvasOp.drawAtlasCulled : _CanvasOp.drawAtlasColoredCulled; _updatePaintData(paint, _imageMask); - _updateBlendMode(blendMode ?? BlendMode.src); _addOp(op); _addImageData(atlas); _addFloat32List(rstTransforms); _addFloat32List(rects); + _addInt((blendMode ?? BlendMode.src).index); if (colors != null) _addInt32List(colors); if (cullRect != null) From b5ace2f63943264c9ac1306ce5c8abaebb82560a Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 2 Apr 2021 01:10:48 -0700 Subject: [PATCH 21/37] streamline buffer operations and cache longest buffer --- flow/display_list_interpreter.cc | 13 +- flow/display_list_interpreter.h | 21 +- lib/ui/painting.dart | 464 +++++++++++++++++-------------- lib/ui/painting/display_list.cc | 8 +- lib/ui/painting/display_list.h | 2 +- 5 files changed, 274 insertions(+), 234 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index ff362722fa5e9..841f52bd223a0 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -289,7 +289,7 @@ CANVAS_OP_DEFINE_OP(transform3x3, )); ) -CANVAS_OP_DEFINE_OP(drawColor, context.canvas->drawColor(context.paint.getColor(), context.paint.getBlendMode());) +CANVAS_OP_DEFINE_OP(drawColor, context.canvas->drawColor(it.GetColor(), it.GetBlendMode());) CANVAS_OP_DEFINE_OP(drawPaint, context.canvas->drawPaint(context.paint);) CANVAS_OP_DEFINE_OP(drawRect, context.canvas->drawRect(it.GetRect(), context.paint);) @@ -317,7 +317,7 @@ CANVAS_OP_DEFINE_OP(draw##mode, \ CANVAS_OP_DEFINE_POINT_OP(Points) CANVAS_OP_DEFINE_POINT_OP(Lines) CANVAS_OP_DEFINE_POINT_OP(Polygon) -CANVAS_OP_DEFINE_OP(drawVertices, context.canvas->drawVertices(it.GetVertices(), context.paint.getBlendMode(), context.paint);) +CANVAS_OP_DEFINE_OP(drawVertices, context.canvas->drawVertices(it.GetVertices(), it.GetBlendMode(), context.paint);) CANVAS_OP_DEFINE_OP(drawImage, sk_sp image = it.GetImage(); @@ -340,11 +340,11 @@ CANVAS_OP_DEFINE_OP(drawImageNine, #define CANVAS_OP_DEFINE_ATLAS(op_type, has_colors, has_rect) \ CANVAS_OP_DEFINE_OP(op_type, \ sk_sp image = it.GetImage(); \ + SkBlendMode blendMode = it.GetBlendMode(); \ SkScalar *rst_ptr; \ int nrstscalars = it.GetFloatList(&rst_ptr); \ SkScalar *rect_ptr; \ int nrectscalars = it.GetFloatList(&rect_ptr); \ - SkBlendMode blendMode = it.GetBlendMode(); \ int numrects = nrectscalars / 4; \ uint32_t *clr_ptr = nullptr; \ int ncolorints = numrects; \ @@ -369,7 +369,7 @@ CANVAS_OP_DEFINE_OP(op_type, \ reinterpret_cast(rect_ptr), \ reinterpret_cast(clr_ptr), \ numrects, \ - blendMode, context.sampling, pCullRect, \ + blendMode, context.sampling, pCullRect, \ &context.paint); \ ) CANVAS_OP_DEFINE_ATLAS(drawAtlas, false, false) @@ -384,11 +384,12 @@ CANVAS_OP_DEFINE_OP(drawSkPicture, context.canvas->drawPicture(it.GetSkPicture() CANVAS_OP_DEFINE_OP(optype, \ SkPath path; \ it.GetPath(path); \ - SkColor color = context.paint.getColor(); \ + SkColor color = it.GetColor(); \ + SkScalar elevation = it.GetScalar(); \ /* TODO(flar): How to deal with dpr */ \ SkScalar dpr = 1.0; \ flutter::PhysicalShapeLayer::DrawShadow(context.canvas, path, color, \ - it.GetScalar(), occludes, dpr); \ + elevation, occludes, dpr); \ ) CANVAS_OP_DEFINE_SHADOW_OP(drawShadow, false) CANVAS_OP_DEFINE_SHADOW_OP(drawShadowOccluded, true) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 92017a5cc8e1c..e29560b2aa8e8 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -64,6 +64,7 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS_Angle CANVAS_OP_ARGS1(angle) #define CANVAS_OP_ARGS_Color CANVAS_OP_ARGS1(color) #define CANVAS_OP_ARGS_BlendMode CANVAS_OP_ARGS1(blend_mode) +#define CANVAS_OP_ARGS_Color_BlendMode CANVAS_OP_ARGS2(color, blend_mode) #define CANVAS_OP_ARGS_Point_Scalar CANVAS_OP_ARGS2(point, scalar) #define CANVAS_OP_ARGS_2Points CANVAS_OP_ARGS2(point, point) #define CANVAS_OP_ARGS_Rect CANVAS_OP_ARGS1(rect) @@ -74,14 +75,14 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS_Matrix2x3 CANVAS_OP_ARGS2(matrix_row3, matrix_row3) #define CANVAS_OP_ARGS_Matrix3x3 CANVAS_OP_ARGS3(matrix_row3, matrix_row3, matrix_row3) #define CANVAS_OP_ARGS_Path CANVAS_OP_ARGS1(path) -#define CANVAS_OP_ARGS_Path_Scalar CANVAS_OP_ARGS2(path, scalar) -#define CANVAS_OP_ARGS_Vertices CANVAS_OP_ARGS1(vertices) +#define CANVAS_OP_ARGS_Path_Scalar_Scalar CANVAS_OP_ARGS3(path, scalar, scalar) +#define CANVAS_OP_ARGS_Vertices_BlendMode CANVAS_OP_ARGS2(vertices, blend_mode) #define CANVAS_OP_ARGS_Image_Point CANVAS_OP_ARGS2(image, point) #define CANVAS_OP_ARGS_Image_2Rects CANVAS_OP_ARGS3(image, rect, rect) -#define CANVAS_OP_ARGS_Atlas CANVAS_OP_ARGS4(image, scalar_list, scalar_list, blend_mode) -#define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS5(image, scalar_list, scalar_list, blend_mode, uint32_list) -#define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS5(image, scalar_list, scalar_list, blend_mode, rect) -#define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS6(image, scalar_list, scalar_list, blend_mode, uint32_list, rect) +#define CANVAS_OP_ARGS_Atlas CANVAS_OP_ARGS4(image, blend_mode, scalar_list, scalar_list) +#define CANVAS_OP_ARGS_Atlas_Colors CANVAS_OP_ARGS5(image, blend_mode, scalar_list, scalar_list, uint32_list) +#define CANVAS_OP_ARGS_Atlas_Rect CANVAS_OP_ARGS5(image, blend_mode, scalar_list, scalar_list, rect) +#define CANVAS_OP_ARGS_Atlas_Colors_Rect CANVAS_OP_ARGS6(image, blend_mode, scalar_list, scalar_list, uint32_list, rect) #define CANVAS_OP_ARGS_SkPicture CANVAS_OP_ARGS1(skpicture) #define CANVAS_OP_ARGS_DisplayList CANVAS_OP_ARGS1(display_list) #define CANVAS_OP_ARGS_Shader CANVAS_OP_ARGS1(shader) @@ -152,7 +153,7 @@ enum CanvasOpArg { V(clipPathAA, Path) \ \ V(drawPaint, _) \ - V(drawColor, _) \ + V(drawColor, Color_BlendMode) \ \ V(drawLine, 2Points) \ V(drawRect, Rect) \ @@ -167,7 +168,7 @@ enum CanvasOpArg { V(drawPoints, ScalarList) \ V(drawLines, ScalarList) \ V(drawPolygon, ScalarList) \ - V(drawVertices, Vertices) \ + V(drawVertices, Vertices_BlendMode) \ \ V(drawImage, Image_Point) \ V(drawImageRect, Image_2Rects) \ @@ -179,8 +180,8 @@ enum CanvasOpArg { \ V(drawSkPicture, SkPicture) \ V(drawDisplayList, DisplayList) \ - V(drawShadow, Path_Scalar) \ - V(drawShadowOccluded, Path_Scalar) + V(drawShadow, Path_Scalar_Scalar) \ + V(drawShadowOccluded, Path_Scalar_Scalar) #define CANVAS_OP_MAKE_ENUM(name, args) cops_##name, enum CanvasOp { diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 9699a1ad78246..097064c2a5b78 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5309,154 +5309,180 @@ class _DisplayListCanvas implements Canvas { : _recorder = recorder as _DisplayListPictureRecorder, _cullRect = cullRect ?? Rect.largest, _accumulator = _BoundsAccumulator(), - _ops = Uint8List(128), _numOps = 0, - _data = ByteData(128 * 4), _numDataBytes = 0, + _ops = _emptyOps, _numOps = 0, + _data = _emptyData, _numData = 0, + _dataInts = _emptyInts, _dataFloats = _emptyFloats, _objData = [], _ctm = _MatrixTransform._identity(), _ctmStack = <_MatrixTransform>[] { _recorder!._canvas = this; } + static Uint8List _emptyOps = Uint8List(0); + static Uint8List _cachedOps = _emptyOps; + static ByteData _emptyData = ByteData(0); + static ByteData _cachedData = _emptyData; + static Uint32List _emptyInts = _emptyData.buffer.asUint32List(); + static Float32List _emptyFloats = _emptyData.buffer.asFloat32List(); + static List _deadObjects = List.empty(growable: false); + _DisplayListPictureRecorder? _recorder; Rect _cullRect; _BoundsAccumulator _accumulator; int _numOps; Uint8List _ops; - int _numDataBytes; + int _numData; ByteData _data; + late Uint32List _dataInts; + late Float32List _dataFloats; List _objData; _MatrixTransform _ctm; List<_MatrixTransform> _ctmStack; - Rect get _drawBounds => _accumulator.bounds; - - static const int _maxOpsDoubleSize = 1 << 20; - Uint8List _growOps(Uint8List src) { - Uint8List dst; - if (src.length <= _maxOpsDoubleSize) { - dst = Uint8List(src.length * 2); - } else { - dst = Uint8List(src.length + _maxOpsDoubleSize); + void _dispose() { + if (_cachedOps.length < _ops.length) { + _cachedOps = _ops; + } + if (_cachedData.lengthInBytes < _data.lengthInBytes) { + _cachedData = _data; } - dst.setRange(0, _numOps, src); - return dst; + _recorder = null; + _ops = _emptyOps; + _data = _emptyData; + _dataInts = _emptyInts; + _dataFloats = _emptyFloats; + _numOps = _numData = 0; + _objData = _deadObjects; } - static const int _maxDataDoubleSize = 1 << 24; - ByteData _growData(ByteData src, int neededBytes) { - int growLength; - if (src.lengthInBytes <= _maxDataDoubleSize) { - growLength = src.lengthInBytes; + Rect get _drawBounds => _accumulator.bounds; + + static const int _minOpsSize = 1 << 8; + static const int _maxOpsGrow = 1 << 20; + static const int _minDataSize = 1 << 10; + static const int _maxDataGrow = 1 << 24; + + int _newSize(int curSize, int minSize, int maxGrow, int needed) { + int newSize; + if (curSize < minSize) { + newSize = minSize; + } else if (curSize < maxGrow) { + newSize = curSize * 2; } else { - growLength = _maxDataDoubleSize; + newSize = curSize + maxGrow; } - if (growLength < neededBytes) { - growLength = (neededBytes + _maxDataDoubleSize) ~/ _maxDataDoubleSize; - growLength *= _maxDataDoubleSize; + if (newSize < curSize + needed) { + newSize = curSize + needed + maxGrow; + newSize -= newSize % maxGrow; } - final ByteData dst = ByteData(src.lengthInBytes + growLength); - for (int i = 0; i < _numDataBytes; i += 4) { - dst.setInt32(i, src.getInt32(i, _kFakeHostEndian), _kFakeHostEndian); + return newSize; + } + + void _addOp(_CanvasOp op, int dataNeeded) { + if (_numOps >= _ops.length) { + if (_recorder == null) + throw StateError('Attempting to render to disposed Canvas'); + final int newSize = _newSize(_ops.length, _minOpsSize, _maxOpsGrow, 1); + final Uint8List newOps; + if (newSize <= _cachedOps.length) { + newOps = _cachedOps; + _cachedOps = _emptyOps; + } else { + newOps = Uint8List(_newSize(_ops.length, _minOpsSize, _maxOpsGrow, 1)); + } + newOps.setRange(0, _numOps, _ops); + _ops = newOps; } - return dst; - } - - void _addOp(_CanvasOp op) { - if (_numOps == _ops.lengthInBytes) { - _ops = _growOps(_ops); + if (_numData + dataNeeded >= _dataInts.length) { + final int newSize = 4 * _newSize(_dataInts.length, _minDataSize, _maxDataGrow, dataNeeded); + final ByteData newData; + if (newSize <= _cachedData.lengthInBytes / 4) { + newData = _cachedData; + _cachedData = _emptyData; + } else { + newData = ByteData(4 * _newSize(_dataInts.length, _minDataSize, _maxDataGrow, dataNeeded)); } - _ops[_numOps++] = op.index; + final Uint32List newInts = newData.buffer.asUint32List(); + newInts.setRange(0, _numData, _dataInts); + _data = newData; + _dataInts = newInts; + _dataFloats = newData.buffer.asFloat32List(); + } + assert(_numOps < _ops.length); + _ops[_numOps++] = op.index; } void _addInt(int value) { - if (_numDataBytes + 4 > _data.lengthInBytes) { - _data = _growData(_data, 4); - } - _data.setInt32(_numDataBytes, value, _kFakeHostEndian); - _numDataBytes += 4; + assert(_numData < _dataInts.length); + _dataInts[_numData++] = value; } void _addScalar(double value) { - if (_numDataBytes + 4 > _data.lengthInBytes) { - _data = _growData(_data, 4); - } - _data.setFloat32(_numDataBytes, value, _kFakeHostEndian); - _numDataBytes += 4; + assert(_numData < _dataFloats.length); + _dataFloats[_numData++] = value; } void _addScalar2(double v1, double v2) { - if (_numDataBytes + 8 > _data.lengthInBytes) { - _data = _growData(_data, 8); - } - _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); - _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v2, _kFakeHostEndian); - _numDataBytes += 4; + assert(_numData + 2 <= _dataFloats.length); + _dataFloats[_numData++] = v1; + _dataFloats[_numData++] = v2; } void _addScalar3(double v1, double v2, double v3) { - if (_numDataBytes + 12 > _data.lengthInBytes) { - _data = _growData(_data, 12); - } - _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); - _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v2, _kFakeHostEndian); - _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v3, _kFakeHostEndian); - _numDataBytes += 4; - } - - void _addScalar4(double v1, double v2, double v3, double v4) { - if (_numDataBytes + 16 > _data.lengthInBytes) { - _data = _growData(_data, 16); - } - _data.setFloat32(_numDataBytes, v1, _kFakeHostEndian); - _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v2, _kFakeHostEndian); - _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v3, _kFakeHostEndian); - _numDataBytes += 4; - _data.setFloat32(_numDataBytes, v4, _kFakeHostEndian); - _numDataBytes += 4; + assert(_numData + 3 <= _dataFloats.length); + _dataFloats[_numData++] = v1; + _dataFloats[_numData++] = v2; + _dataFloats[_numData++] = v3; } + static const int _nOffsetData = 2; void _addOffset(Offset offset) { - _addScalar2(offset.dx, offset.dy); + assert(_numData + _nOffsetData <= _dataFloats.length); + _dataFloats[_numData++] = offset.dx; + _dataFloats[_numData++] = offset.dy; } + static const int _nRectData = 4; void _addRect(Rect r) { - _addScalar4(r.left, r.top, r.right, r.bottom); + assert(_numData + _nRectData <= _dataFloats.length); + _dataFloats[_numData++] = r.left; + _dataFloats[_numData++] = r.top; + _dataFloats[_numData++] = r.right; + _dataFloats[_numData++] = r.bottom; } + static const int _nRoundRectData = 12; void _addRRect(RRect rrect) { - _addScalar4(rrect.left, rrect.top, rrect.right, rrect.bottom); + assert(_numData + _nRoundRectData <= _dataFloats.length); + _dataFloats[_numData++] = rrect.left; + _dataFloats[_numData++] = rrect.top; + _dataFloats[_numData++] = rrect.right; + _dataFloats[_numData++] = rrect.bottom; // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices - _addScalar4(rrect.tlRadiusX, rrect.tlRadiusY, rrect.trRadiusX, rrect.trRadiusY); - _addScalar4(rrect.brRadiusX, rrect.brRadiusY, rrect.blRadiusX, rrect.blRadiusY); + _dataFloats[_numData++] = rrect.tlRadiusX; + _dataFloats[_numData++] = rrect.tlRadiusY; + _dataFloats[_numData++] = rrect.trRadiusX; + _dataFloats[_numData++] = rrect.trRadiusY; + _dataFloats[_numData++] = rrect.brRadiusX; + _dataFloats[_numData++] = rrect.brRadiusY; + _dataFloats[_numData++] = rrect.blRadiusX; + _dataFloats[_numData++] = rrect.blRadiusY; } void _addInt32List(Int32List data) { final int len = data.length; - _addInt(len); - if (_numDataBytes + len * 4 > _data.lengthInBytes) { - _data = _growData(_data, len * 4); - } - for (int i = 0; i < len; i++) { - _data.setInt32(_numDataBytes, data[i], _kFakeHostEndian); - _numDataBytes += 4; - } + assert(_numData + len + 1 <= _dataInts.length); + _dataInts[_numData++] = len; + _dataInts.setRange(_numData, _numData + len, data); + _numData += len; } void _addFloat32List(Float32List data) { final int len = data.length; - _addInt(len); - if (_numDataBytes + len * 4 > _data.lengthInBytes) { - _data = _growData(_data, len * 4); - } - for (int i = 0; i < len; i++) { - _data.setFloat32(_numDataBytes, data[i], _kFakeHostEndian); - _numDataBytes += 4; - } + assert(_numData + len + 1 <= _dataFloats.length); + _dataInts[_numData++] = len; + _dataFloats.setRange(_numData, _numData + len, data); + _numData += len; } void _addImageData(Image image) { @@ -5512,7 +5538,7 @@ class _DisplayListCanvas implements Canvas { @override void save() { - _addOp(_CanvasOp.save); + _addOp(_CanvasOp.save, 0); _ctmStack.add(_MatrixTransform._copy(_ctm)); } @@ -5520,9 +5546,9 @@ class _DisplayListCanvas implements Canvas { void saveLayer(Rect? bounds, Paint paint) { _updatePaintData(paint, _saveLayerMask); if (bounds == null) { - _addOp(_CanvasOp.saveLayer); + _addOp(_CanvasOp.saveLayer, 0); } else { - _addOp(_CanvasOp.saveLayerBounds); + _addOp(_CanvasOp.saveLayerBounds, _nRectData); _addRect(bounds); } _ctmStack.add(_MatrixTransform._copy(_ctm)); @@ -5535,33 +5561,33 @@ class _DisplayListCanvas implements Canvas { void restore() { if (_ctmStack.isNotEmpty) { _ctm = _ctmStack.removeLast(); - _addOp(_CanvasOp.restore); + _addOp(_CanvasOp.restore, 0); } } @override void translate(double dx, double dy) { - _addOp(_CanvasOp.translate); + _addOp(_CanvasOp.translate, 2); _addScalar2(dx, dy); _ctm.translate(dx, dy); } @override void scale(double sx, [ double? sy ]) { - _addOp(_CanvasOp.scale); + _addOp(_CanvasOp.scale, 2); _addScalar2(sx, sy ?? sx); _ctm.scale(sx, sy ?? sx); } @override void rotate(double radians) { - _addOp(_CanvasOp.rotate); + _addOp(_CanvasOp.rotate, 1); _addScalar(radians); _ctm.rotate(radians); } @override void skew(double sx, double sy) { - _addOp(_CanvasOp.skew); + _addOp(_CanvasOp.skew, 2); _addScalar2(sx, sy); _ctm.skew(sx, sy); } @@ -5571,11 +5597,11 @@ class _DisplayListCanvas implements Canvas { if (matrix4.length != 16) throw ArgumentError('"matrix4" must have 16 entries.'); if (matrix4[3] == 0.0 && matrix4[7] == 0.0 && matrix4[15] == 1.0) { - _addOp(_CanvasOp.transform2x3); + _addOp(_CanvasOp.transform2x3, 6); _addScalar3(matrix4[0], matrix4[4], matrix4[12]); _addScalar3(matrix4[1], matrix4[5], matrix4[13]); } else { - _addOp(_CanvasOp.transform3x3); + _addOp(_CanvasOp.transform3x3, 9); _addScalar3(matrix4[0], matrix4[4], matrix4[12]); _addScalar3(matrix4[1], matrix4[5], matrix4[13]); _addScalar3(matrix4[3], matrix4[7], matrix4[15]); @@ -5588,10 +5614,10 @@ class _DisplayListCanvas implements Canvas { void clipRect(Rect rect, {ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = false}) { switch (clipOp) { case ClipOp.intersect: - _addOp(doAntiAlias ? _CanvasOp.clipRectAA : _CanvasOp.clipRect); + _addOp(doAntiAlias ? _CanvasOp.clipRectAA : _CanvasOp.clipRect, _nRectData); break; case ClipOp.difference: - _addOp(doAntiAlias ? _CanvasOp.clipRectAADiff : _CanvasOp.clipRectDiff); + _addOp(doAntiAlias ? _CanvasOp.clipRectAADiff : _CanvasOp.clipRectDiff, _nRectData); break; } _addRect(rect); @@ -5602,14 +5628,14 @@ class _DisplayListCanvas implements Canvas { if (rrect.isRect) { clipRect(rrect.outerRect, doAntiAlias: doAntiAlias); } else { - _addOp(doAntiAlias ? _CanvasOp.clipRRectAA : _CanvasOp.clipRRect); + _addOp(doAntiAlias ? _CanvasOp.clipRRectAA : _CanvasOp.clipRRect, _nRoundRectData); _addRRect(rrect); } } @override void clipPath(Path path, {bool doAntiAlias = false}) { - _addOp(doAntiAlias ? _CanvasOp.clipPathAA : _CanvasOp.clipPath); + _addOp(doAntiAlias ? _CanvasOp.clipPathAA : _CanvasOp.clipPath, 0); _addPathData(path); } @@ -5679,26 +5705,30 @@ class _DisplayListCanvas implements Canvas { void _updatePaintData(Paint paint, int dataNeeded) { if ((dataNeeded & _aaNeeded) != 0 && _curAA != paint.isAntiAlias) { _curAA = paint.isAntiAlias; - _addOp(_curAA ? _CanvasOp.setAA : _CanvasOp.clearAA); + _addOp(_curAA ? _CanvasOp.setAA : _CanvasOp.clearAA, 0); } if ((dataNeeded & _ditherNeeded) != 0 && _curDither != paint._dither) { _curDither = paint._dither; - _addOp(_curDither ? _CanvasOp.setDither : _CanvasOp.clearDither); + _addOp(_curDither ? _CanvasOp.setDither : _CanvasOp.clearDither, 0); } - if ((dataNeeded & _colorNeeded) != 0) { - _updateColor(paint.color); + if ((dataNeeded & _colorNeeded) != 0 && _curColor != paint.color) { + _curColor = paint.color; + _addOp(_CanvasOp.setColor, 1); + _addInt(_curColor.value); } - if ((dataNeeded & _blendNeeded) != 0) { - _updateBlendMode(paint.blendMode); + if ((dataNeeded & _blendNeeded) != 0 && _curBlendMode != paint.blendMode) { + _curBlendMode = paint.blendMode; + _addOp(_CanvasOp.setBlendMode, 1); + _addInt(_curBlendMode.index); } if ((dataNeeded & _invertColorsNeeded) != 0 && _curInvertColors != paint.invertColors) { _curInvertColors = paint.invertColors; - _addOp(_curInvertColors ? _CanvasOp.setInvertColors : _CanvasOp.clearInvertColors); + _addOp(_curInvertColors ? _CanvasOp.setInvertColors : _CanvasOp.clearInvertColors, 0); } if ((dataNeeded & _paintStyleNeeded) != 0) { if (_curPaintStyle != paint.style) { _curPaintStyle = paint.style; - _addOp(_curPaintStyle == PaintingStyle.fill ? _CanvasOp.setFillStyle : _CanvasOp.setStrokeStyle); + _addOp(_curPaintStyle == PaintingStyle.fill ? _CanvasOp.setFillStyle : _CanvasOp.setStrokeStyle, 0); } if (_curPaintStyle == PaintingStyle.stroke) { dataNeeded |= _strokeStyleNeeded; @@ -5707,33 +5737,33 @@ class _DisplayListCanvas implements Canvas { if ((dataNeeded & _strokeStyleNeeded) != 0) { if (_curStrokeWidth != paint.strokeWidth) { _curStrokeWidth = paint.strokeWidth; - _addOp(_CanvasOp.setStrokeWidth); + _addOp(_CanvasOp.setStrokeWidth, 1); _addScalar(_curStrokeWidth); } if (_curStrokeCap != paint.strokeCap) { _curStrokeCap = paint.strokeCap; - _addOp(_strokeCapOps[_curStrokeCap.index]); + _addOp(_strokeCapOps[_curStrokeCap.index], 0); } if (_curStrokeJoin != paint.strokeJoin) { _curStrokeJoin = paint.strokeJoin; - _addOp(_strokeJoinOps[_curStrokeJoin.index]); + _addOp(_strokeJoinOps[_curStrokeJoin.index], 0); } if (_curMiterLimit != paint.strokeMiterLimit) { _curMiterLimit = paint.strokeMiterLimit; - _addOp(_CanvasOp.setMiterLimit); + _addOp(_CanvasOp.setMiterLimit, 1); _addScalar(_curMiterLimit); } } if ((dataNeeded & _filterQualityNeeded) != 0 && _curFilterQuality != paint.filterQuality) { _curFilterQuality = paint.filterQuality; - _addOp(_filterQualityOps[_curFilterQuality.index]); + _addOp(_filterQualityOps[_curFilterQuality.index], 0); } if ((dataNeeded & _shaderNeeded) != 0 && _curShader != paint.shader) { final Shader? shader = paint.shader; if (shader == null) { - _addOp(_CanvasOp.clearShader); + _addOp(_CanvasOp.clearShader, 0); } else { - _addOp(_CanvasOp.setShader); + _addOp(_CanvasOp.setShader, 0); _addShader(shader); } _curShader = paint.shader; @@ -5741,9 +5771,9 @@ class _DisplayListCanvas implements Canvas { if ((dataNeeded & _colorFilterNeeded) != 0 && _curColorFilter != paint.colorFilter) { final _ColorFilter? filter = paint.colorFilter?._toNativeColorFilter(); if (filter == null) { - _addOp(_CanvasOp.clearColorFilter); + _addOp(_CanvasOp.clearColorFilter, 0); } else { - _addOp(_CanvasOp.setColorFilter); + _addOp(_CanvasOp.setColorFilter, 0); _addColorFilter(filter); } _curColorFilter = paint.colorFilter; @@ -5751,9 +5781,9 @@ class _DisplayListCanvas implements Canvas { if ((dataNeeded & _imageFilterNeeded) != 0 && _curImageFilter != paint.imageFilter) { final _ImageFilter? filter = paint.imageFilter?._toNativeImageFilter(); if (filter == null) { - _addOp(_CanvasOp.clearImageFilter); + _addOp(_CanvasOp.clearImageFilter, 0); } else { - _addOp(_CanvasOp.setImageFilter); + _addOp(_CanvasOp.setImageFilter, 0); _addImageFilter(filter); } _curImageFilter = paint.imageFilter; @@ -5761,48 +5791,32 @@ class _DisplayListCanvas implements Canvas { if ((dataNeeded & _maskFilterNeeded) != 0 && _curMaskFilter != paint.maskFilter) { final MaskFilter? filter = paint.maskFilter; if (filter == null) { - _addOp(_CanvasOp.clearMaskFilter); + _addOp(_CanvasOp.clearMaskFilter, 0); } else { - _addOp(_maskFilterOps[filter._style.index]); + _addOp(_maskFilterOps[filter._style.index], 1); _addScalar(filter._sigma); } _curMaskFilter = paint.maskFilter; } } - void _updateColor(Color color) { - if (_curColor != color) { - _curColor = color; - _addOp(_CanvasOp.setColor); - _addInt(color.value); - } - } - - void _updateBlendMode(BlendMode blendMode) { - if (_curBlendMode != blendMode) { - _curBlendMode = blendMode; - _addOp(_CanvasOp.setBlendMode); - _addInt(blendMode.index); - } - } - @override void drawPaint(Paint paint) { _updatePaintData(paint, _paintMask); - _addOp(_CanvasOp.drawPaint); + _addOp(_CanvasOp.drawPaint, 0); } @override void drawColor(Color color, BlendMode blendMode) { - _updateColor(color); - _updateBlendMode(blendMode); - _addOp(_CanvasOp.drawColor); + _addOp(_CanvasOp.drawColor, 2); + _addInt(color.value); + _addInt(blendMode.index); } @override void drawLine(Offset p1, Offset p2, Paint paint) { _updatePaintData(paint, _strokeMask); - _addOp(_CanvasOp.drawLine); + _addOp(_CanvasOp.drawLine, 2 * _nOffsetData); _addOffset(p1); _addOffset(p2); _addBounds(Rect.fromPoints(p1, p2), true); @@ -5811,7 +5825,7 @@ class _DisplayListCanvas implements Canvas { @override void drawRect(Rect rect, Paint paint) { _updatePaintData(paint, _drawMask); - _addOp(_CanvasOp.drawRect); + _addOp(_CanvasOp.drawRect, _nRectData); _addRect(rect); _addBounds(rect); } @@ -5819,7 +5833,7 @@ class _DisplayListCanvas implements Canvas { @override void drawOval(Rect rect, Paint paint) { _updatePaintData(paint, _drawMask); - _addOp(_CanvasOp.drawOval); + _addOp(_CanvasOp.drawOval, _nRectData); _addRect(rect); _addBounds(rect); } @@ -5827,7 +5841,7 @@ class _DisplayListCanvas implements Canvas { @override void drawCircle(Offset center, double radius, Paint paint) { _updatePaintData(paint, _drawMask); - _addOp(_CanvasOp.drawCircle); + _addOp(_CanvasOp.drawCircle, _nOffsetData + 1); _addOffset(center); _addScalar(radius); _addBounds(Rect.fromCenter(center: center, width: radius, height: radius)); @@ -5842,7 +5856,7 @@ class _DisplayListCanvas implements Canvas { drawOval(outerRect, paint); } else { _updatePaintData(paint, _drawMask); - _addOp(_CanvasOp.drawRRect); + _addOp(_CanvasOp.drawRRect, _nRoundRectData); _addRRect(rrect); } _addBounds(outerRect); @@ -5851,7 +5865,7 @@ class _DisplayListCanvas implements Canvas { @override void drawDRRect(RRect outer, RRect inner, Paint paint) { _updatePaintData(paint, _drawMask); - _addOp(_CanvasOp.drawDRRect); + _addOp(_CanvasOp.drawDRRect, 2 * _nRoundRectData); _addRRect(outer); _addRRect(inner); _addBounds(outer.outerRect); @@ -5860,7 +5874,7 @@ class _DisplayListCanvas implements Canvas { @override void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) { _updatePaintData(paint, _drawMask); - _addOp(useCenter ? _CanvasOp.drawArcCenter : _CanvasOp.drawArc); + _addOp(useCenter ? _CanvasOp.drawArcCenter : _CanvasOp.drawArc, _nRectData + 2); _addRect(rect); _addScalar2(startAngle, sweepAngle); _addBounds(rect); @@ -5869,14 +5883,23 @@ class _DisplayListCanvas implements Canvas { @override void drawPath(Path path, Paint paint) { _updatePaintData(paint, _drawMask); - _addOp(_CanvasOp.drawPath); + _addOp(_CanvasOp.drawPath, 0); _addPathData(path); _addBounds(path.getBounds()); } @override void drawPoints(PointMode pointMode, List points, Paint paint) { - drawRawPoints(pointMode, _encodePointList(points), paint); + _updatePaintData(paint, _strokeMask); + _addOp(_pointOps[pointMode.index], points.length * 2 + 1); + _dataInts[_numData++] = points.length * 2; + final _BoundsAccumulator ptBounds = _BoundsAccumulator(); + for (Offset pt in points) { + _dataFloats[_numData++] = pt.dx; + _dataFloats[_numData++] = pt.dy; + ptBounds.accumulate(pt.dx, pt.dy); + } + _addBounds(ptBounds.bounds, true); } static const List<_CanvasOp> _pointOps = <_CanvasOp>[ @@ -5888,7 +5911,7 @@ class _DisplayListCanvas implements Canvas { @override void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) { _updatePaintData(paint, _strokeMask); - _addOp(_pointOps[pointMode.index]); + _addOp(_pointOps[pointMode.index], points.length + 1); _addFloat32List(points); final _BoundsAccumulator ptBounds = _BoundsAccumulator(); for (int i = 0; i + 1 < points.length; i += 2) { @@ -5900,16 +5923,16 @@ class _DisplayListCanvas implements Canvas { @override void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) { _updatePaintData(paint, _drawMask); - _updateBlendMode(blendMode); - _addOp(_CanvasOp.drawVertices); + _addOp(_CanvasOp.drawVertices, 1); _addVertices(vertices); + _addInt(blendMode.index); _addBounds(vertices._getBounds()); } @override void drawImage(Image image, Offset offset, Paint paint) { _updatePaintData(paint, _imageMask); - _addOp(_CanvasOp.drawImage); + _addOp(_CanvasOp.drawImage, _nOffsetData); _addImageData(image); _addOffset(offset); _addBounds(Rect.fromLTWH(offset.dx, offset.dy, image.width.toDouble(), image.height.toDouble()), false); @@ -5918,7 +5941,7 @@ class _DisplayListCanvas implements Canvas { @override void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { _updatePaintData(paint, _imageMask); - _addOp(_CanvasOp.drawImageRect); + _addOp(_CanvasOp.drawImageRect, 2 * _nRectData); _addImageData(image); _addRect(src); _addRect(dst); @@ -5928,13 +5951,33 @@ class _DisplayListCanvas implements Canvas { @override void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { _updatePaintData(paint, _imageMask); - _addOp(_CanvasOp.drawImageNine); + _addOp(_CanvasOp.drawImageNine, 2 * _nRectData); _addImageData(image); _addRect(center); _addRect(dst); _addBounds(dst, false); } + void _addAtlasOp(int rectCount, bool hasColors, bool hasCullRect) { + if (hasColors) { + if (hasCullRect) { + // 3 list counts + 2 lists of 4 values per rect + 1 list of 1 value per rect + rect + blend mode + _addOp(_CanvasOp.drawAtlasColoredCulled, 3 + rectCount * 9 + _nRectData + 1); + } else { + // 3 list counts + 2 lists of 4 values per rect + 1 list of 1 value per rect + blend mode + _addOp(_CanvasOp.drawAtlasColored, 3 + rectCount * 9 + 1); + } + } else { + if (hasCullRect) { + // 2 list counts + 2 lists of 4 values per rect + rect + blend mode + _addOp(_CanvasOp.drawAtlasCulled, 2 + rectCount * 8 + _nRectData + 1); + } else { + // 2 list counts + 2 lists of 4 values per rect + blend mode + _addOp(_CanvasOp.drawAtlas, 2 + rectCount * 8 + 1); + } + } + } + @override void drawAtlas(Image atlas, List transforms, @@ -5949,45 +5992,41 @@ class _DisplayListCanvas implements Canvas { if (colors != null && colors.isNotEmpty && colors.length != rectCount) throw ArgumentError('If non-null, "colors" length must match that of "transforms" and "rects".'); - final Float32List rstTransformBuffer = Float32List(rectCount * 4); - final Float32List rectBuffer = Float32List(rectCount * 4); + _updatePaintData(paint, _imageMask); + _addAtlasOp(rectCount, colors?.isNotEmpty ?? false, cullRect != null); + _addImageData(atlas); + _addInt((blendMode ?? BlendMode.src).index); + _dataInts[_numData++] = rectCount * 4; + int rstBase = _numData; + _numData += rectCount * 4; + _dataInts[_numData++] = rectCount * 4; + int rectBase = _numData; + _numData += rectCount * 4; final _BoundsAccumulator rstBounds = _BoundsAccumulator(); - for (int i = 0; i < rectCount; ++i) { - final int index0 = i * 4; - final int index1 = index0 + 1; - final int index2 = index0 + 2; - final int index3 = index0 + 3; + for (int i = 0; i < rectCount; i++) { final RSTransform rstTransform = transforms[i]; final Rect rect = rects[i]; assert(_rectIsValid(rect)); - rstTransformBuffer[index0] = rstTransform.scos; - rstTransformBuffer[index1] = rstTransform.ssin; - rstTransformBuffer[index2] = rstTransform.tx; - rstTransformBuffer[index3] = rstTransform.ty; - rectBuffer[index0] = rect.left; - rectBuffer[index1] = rect.top; - rectBuffer[index2] = rect.right; - rectBuffer[index3] = rect.bottom; + _dataFloats[rstBase++] = rstTransform.scos; + _dataFloats[rstBase++] = rstTransform.ssin; + _dataFloats[rstBase++] = rstTransform.tx; + _dataFloats[rstBase++] = rstTransform.ty; + _dataFloats[rectBase++] = rect.left; + _dataFloats[rectBase++] = rect.top; + _dataFloats[rectBase++] = rect.right; + _dataFloats[rectBase++] = rect.bottom; rstBounds.accumulateBounds(rect, rstTransform); } - - final Int32List? colorBuffer = (colors == null || colors.isEmpty) ? null : _encodeColorList(colors); - - final _CanvasOp op = (cullRect == null) - ? (colorBuffer == null) ? _CanvasOp.drawAtlas : _CanvasOp.drawAtlasColored - : (colorBuffer == null) ? _CanvasOp.drawAtlasCulled : _CanvasOp.drawAtlasColoredCulled; - - _updatePaintData(paint, _imageMask); - _addOp(op); - _addImageData(atlas); - _addFloat32List(rstTransformBuffer); - _addFloat32List(rectBuffer); - _addInt((blendMode ?? BlendMode.src).index); - if (colorBuffer != null) - _addInt32List(colorBuffer); + if (colors != null && colors.isNotEmpty) { + _dataInts[_numData++] = rectCount; + for (int i = 0; i < rectCount; i++) { + _dataInts[_numData++] = colors[i].value; + } + } if (cullRect != null) _addRect(cullRect); + _addBounds(rstBounds.bounds, false); } @@ -6007,37 +6046,35 @@ class _DisplayListCanvas implements Canvas { if (colors != null && colors.length * 4 != rectCount) throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".'); - final _BoundsAccumulator rstBounds = _BoundsAccumulator(); - for (int i = 0; i < rects.length; i += 4) { - rstBounds.accumulateRstBounds( - rects[i], rects[i+1], rects[i+2], rects[i+3], - rstTransforms[i], rstTransforms[i+1], rstTransforms[i+2], rstTransforms[i+3]); - } - final _CanvasOp op = (cullRect == null) - ? (colors == null) ? _CanvasOp.drawAtlas : _CanvasOp.drawAtlasColored - : (colors == null) ? _CanvasOp.drawAtlasCulled : _CanvasOp.drawAtlasColoredCulled; - _updatePaintData(paint, _imageMask); - _addOp(op); + _addAtlasOp(rectCount, colors?.isNotEmpty ?? false, cullRect != null); _addImageData(atlas); + _addInt((blendMode ?? BlendMode.src).index); + _addFloat32List(rstTransforms); _addFloat32List(rects); - _addInt((blendMode ?? BlendMode.src).index); if (colors != null) _addInt32List(colors); if (cullRect != null) _addRect(cullRect); + + final _BoundsAccumulator rstBounds = _BoundsAccumulator(); + for (int i = 0; i < rects.length; i += 4) { + rstBounds.accumulateRstBounds( + rects[i], rects[i+1], rects[i+2], rects[i+3], + rstTransforms[i], rstTransforms[i+1], rstTransforms[i+2], rstTransforms[i+3]); + } _addBounds(rstBounds.bounds, false); } void _drawSkiaPicture(_SkiaPicture picture) { - _addOp(_CanvasOp.drawSkPicture); + _addOp(_CanvasOp.drawSkPicture, 0); _addSkPicture(picture); _addBounds(picture._getBounds(), false); } void _drawDisplayListPicture(_DisplayListPicture picture) { - _addOp(_CanvasOp.drawDisplayList); + _addOp(_CanvasOp.drawDisplayList, 0); _addPicture(picture); _addBounds(picture._drawBounds ?? Rect.zero, false); } @@ -6072,9 +6109,9 @@ class _DisplayListCanvas implements Canvas { @override void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) { - _updateColor(color); - _addOp(transparentOccluder ? _CanvasOp.drawShadowOccluded : _CanvasOp.drawShadow); + _addOp(transparentOccluder ? _CanvasOp.drawShadowOccluded : _CanvasOp.drawShadow, 2); _addPathData(path); + _addInt(color.value); _addScalar(elevation); _addBounds(_shadowBounds(path.getBounds(), elevation), false); } @@ -6148,15 +6185,16 @@ class _DisplayListPictureRecorder implements PictureRecorder { final _DisplayListCanvas? canvas = _canvas; if (canvas == null) throw StateError('PictureRecorder did not start recording.'); - canvas._recorder = null; _canvas = null; - return _DisplayListPicture._( + final Picture picture = _DisplayListPicture._( canvas._cullRect, canvas._drawBounds, canvas._ops, canvas._numOps, - canvas._data, canvas._numDataBytes, + canvas._data, canvas._numData, canvas._objData, ); + canvas._dispose(); + return picture; } _DisplayListCanvas? _canvas; diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index 40b951f305cb8..606b1da08c3ba 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -56,12 +56,12 @@ void DisplayList::RegisterNatives(tonic::DartLibraryNatives* natives) { fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, int numOps, tonic::DartByteData& data, - int dataBytes, + int numData, Dart_Handle objList) { if (numOps < 0 || numOps > ops.num_elements() || - dataBytes < 0 || (dataBytes % sizeof(float)) != 0 || - dataBytes > (int) data.length_in_bytes()) { + numData < 0 || (data.length_in_bytes() % sizeof(float)) != 0 || + numData > (int) (data.length_in_bytes() / sizeof(float))) { Dart_ThrowException( tonic::ToDart("DisplayList constructor called with bad list lengths.")); return nullptr; @@ -78,7 +78,7 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, const float* data_ptr = static_cast(data.data()); std::shared_ptr> data_vector = - std::make_shared>(data_ptr, data_ptr + (dataBytes / sizeof(float))); + std::make_shared>(data_ptr, data_ptr + numData); intptr_t numObjects = 0; Dart_ListLength(objList, &numObjects); diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h index 23d9660650bc1..17ee3b46a46de 100644 --- a/lib/ui/painting/display_list.h +++ b/lib/ui/painting/display_list.h @@ -33,7 +33,7 @@ class DisplayList : public RefCountedDartWrappable { static fml::RefPtr Create(tonic::Uint8List& ops, int numOps, tonic::DartByteData& data, - int dataBytes, + int numData, Dart_Handle objList); Dart_Handle toImage(uint32_t width, From 7a8789f23e21ef64677e806e8c6a2bb9045b3607 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 6 May 2021 19:41:34 -0700 Subject: [PATCH 22/37] minor fixes: transform2x3 constants, indentation, paint shader sampling --- flow/display_list_interpreter.cc | 2 +- lib/ui/painting.dart | 24 ++++++++++++------------ lib/ui/painting/display_list.cc | 28 ++++++++++++++++++---------- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index 841f52bd223a0..f113145e36c35 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -278,7 +278,7 @@ CANVAS_OP_DEFINE_OP(transform2x3, context.canvas->concat(SkMatrix::MakeAll( it.GetScalar(), it.GetScalar(), it.GetScalar(), it.GetScalar(), it.GetScalar(), it.GetScalar(), - 0.0, 0.0, 0.1 + 0.0, 0.0, 1.0 )); ) CANVAS_OP_DEFINE_OP(transform3x3, diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 097064c2a5b78..e4c32a6eca991 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5980,12 +5980,12 @@ class _DisplayListCanvas implements Canvas { @override void drawAtlas(Image atlas, - List transforms, - List rects, - List? colors, - BlendMode? blendMode, - Rect? cullRect, - Paint paint) { + List transforms, + List rects, + List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { final int rectCount = rects.length; if (transforms.length != rectCount) throw ArgumentError('"transforms" and "rects" lengths must match.'); @@ -6032,12 +6032,12 @@ class _DisplayListCanvas implements Canvas { @override void drawRawAtlas(Image atlas, - Float32List rstTransforms, - Float32List rects, - Int32List? colors, - BlendMode? blendMode, - Rect? cullRect, - Paint paint) { + Float32List rstTransforms, + Float32List rects, + Int32List? colors, + BlendMode? blendMode, + Rect? cullRect, + Paint paint) { final int rectCount = rects.length; if (rstTransforms.length != rectCount) throw ArgumentError('"rstTransforms" and "rects" lengths must match.'); diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index 606b1da08c3ba..93ac58fbd0427 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -91,8 +91,24 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, std::shared_ptr> ref_vector = std::make_shared>(); int obj_index = 0; - const DisplayListRefHolder empty_holder; + SkSamplingOptions sampling = DisplayListInterpreter::NearestSampling; for (uint8_t op : *ops_vector) { + switch (op) { + // All of the following op types have no arguments so they can + // use continue instead of break for efficiency. + case CanvasOp::cops_setFilterQualityNearest: + sampling = DisplayListInterpreter::NearestSampling; + continue; + case CanvasOp::cops_setFilterQualityLinear: + sampling = DisplayListInterpreter::LinearSampling; + continue; + case CanvasOp::cops_setFilterQualityMipmap: + sampling = DisplayListInterpreter::MipmapSampling; + continue; + case CanvasOp::cops_setFilterQualityCubic: + sampling = DisplayListInterpreter::CubicSampling; + continue; + } for (uint32_t args = DisplayListInterpreter::opArguments[op]; args != 0; args >>= CANVAS_OP_ARG_SHIFT) { @@ -123,15 +139,7 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, } case shader: { DisplayListRefHolder holder; - // TODO(flar) we should eventually be baking the filterquality into the Shader - // The existing Shader::shader(FQ) API is meant to be called in context from - // the SkiaCanvas paint method. We could parse the stream to determine the - // filter quality that would be in effect when we reach this op, but that is - // overhead to consider another time. - // (The dart DisplayListCanvas code could also encode the current FQ into the - // op code - but soon we should be able to encode it into the shader itself - // and this issue will be moot...) - holder.shader = tonic::DartConverter::FromDart(objects[obj_index++])->shader(SkFilterQuality::kLow_SkFilterQuality); + holder.shader = tonic::DartConverter::FromDart(objects[obj_index++])->shader(sampling); ref_vector->emplace_back(holder); break; } From 13b41afceed762d9516173edf97d31784aa7a976 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 7 May 2021 18:00:28 -0700 Subject: [PATCH 23/37] fix ci/format.sh complaints --- flow/display_list_interpreter.cc | 553 +++++++++++++++++----------- flow/display_list_interpreter.h | 91 +++-- flow/layers/display_list_layer.cc | 54 +-- flow/layers/display_list_layer.h | 2 +- lib/ui/compositing/scene_builder.cc | 4 +- lib/ui/compositing/scene_builder.h | 2 +- lib/ui/painting/display_list.cc | 117 +++--- lib/ui/painting/display_list.h | 35 +- lib/ui/painting/picture.h | 2 +- lib/ui/snapshot_delegate.h | 5 +- shell/common/rasterizer.cc | 5 +- shell/common/rasterizer.h | 5 +- 12 files changed, 520 insertions(+), 355 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index f113145e36c35..fe56a5ad44ae5 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -6,22 +6,21 @@ #include "flutter/fml/logging.h" #include "flutter/flow/layers/physical_shape_layer.h" +#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" -#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkShader.h" namespace flutter { #define CANVAS_OP_TAKE_STRING(name, arg) #name, -#define CANVAS_OP_TAKE_ARGS(name, args) CANVAS_OP_ARGS_##args, - const std::vector DisplayListInterpreter::opNames = { - FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_STRING) + FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_STRING) // }; +#define CANVAS_OP_TAKE_ARGS(name, args) CANVAS_OP_ARGS_##args, const std::vector DisplayListInterpreter::opArguments = { - FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_ARGS) + FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_ARGS) // }; DisplayListInterpreter::DisplayListInterpreter(DisplayListData data) @@ -42,7 +41,7 @@ void DisplayListInterpreter::Describe() { FML_LOG(ERROR) << "Starting ops: " << (it.ops_end - it.ops) << ", data: " << (it.data_end - it.data) << ", refs: " << (it.refs_end - it.refs); - while(it.HasOp()) { + while (it.HasOp()) { FML_LOG(ERROR) << DescribeOneOp(it); } FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) @@ -63,29 +62,48 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { CanvasOp op = it.GetOp(); ss << opNames[op] << "("; bool first = true; - for (uint32_t arg_types = opArguments[op]; arg_types != 0; arg_types >>= CANVAS_OP_ARG_SHIFT) { + for (uint32_t arg_types = opArguments[op]; arg_types != 0; + arg_types >>= CANVAS_OP_ARG_SHIFT) { if (first) { first = false; } else { ss << ", "; } - CanvasOpArg arg_type = static_cast(arg_types & CANVAS_OP_ARG_MASK); + CanvasOpArg arg_type = + static_cast(arg_types & CANVAS_OP_ARG_MASK); switch (arg_type) { - case empty: ss << "?none?"; break; // This should never happen - case scalar: ss << it.GetScalar(); break; - case color: ss << "Color(" << std::hex << "0x" << it.GetUint32() << ")"; break; - case blend_mode: ss << "BlendMode(" << std::dec << it.GetUint32() << ")"; break; - case angle: ss << it.GetAngle(); break; - case point: ss << "Point(x: " << it.GetScalar() << ", y: " << it.GetScalar() << ")"; break; - case rect: ss << "Rect(l: " << it.GetScalar() << ", t: " << it.GetScalar() - << ", r: " << it.GetScalar() << ", b: " << it.GetScalar() << ")"; break; - case round_rect: ss << "RoundRect(" - << "Rect(l: " << it.GetScalar() << ", t: " << it.GetScalar() << ", r: " - << it.GetScalar() << ", b: " << it.GetScalar() << "), " - << "ul: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " - << "ur: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " - << "lr: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " - << "ll: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "))"; break; + case empty: + // This should never happen + ss << "?none?"; + break; + case scalar: + ss << it.GetScalar(); + break; + case color: + ss << "Color(" << std::hex << "0x" << it.GetUint32() << ")"; + break; + case blend_mode: + ss << "BlendMode(" << std::dec << it.GetUint32() << ")"; + break; + case angle: + ss << it.GetAngle(); + break; + case point: + ss << "Point(x: " << it.GetScalar() << ", y: " << it.GetScalar() << ")"; + break; + case rect: + ss << "Rect(l: " << it.GetScalar() << ", t: " << it.GetScalar() + << ", r: " << it.GetScalar() << ", b: " << it.GetScalar() << ")"; + break; + case round_rect: + ss << "RoundRect(" + << "Rect(l: " << it.GetScalar() << ", t: " << it.GetScalar() + << ", r: " << it.GetScalar() << ", b: " << it.GetScalar() << "), " + << "ul: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " + << "ur: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " + << "lr: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "), " + << "ll: (h: " << it.GetScalar() << ", v: " << it.GetScalar() << "))"; + break; case uint32_list: case scalar_list: { uint32_t len = it.GetUint32(); @@ -108,29 +126,51 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { ss << "]"; break; } - case matrix_row3: ss << "[" << it.GetScalar() << ", " << it.GetScalar() << ", " << it.GetScalar() << "]"; break; - case image: ss << "[Image]"; break; - case path: ss << "[Path]"; break; - case vertices: ss << "[Vertices]"; break; - case skpicture: ss << "[SkPicture]"; break; - case display_list: ss << "[DisplayList]"; break; - case shader: ss << "[Shader]"; break; - case color_filter: ss << "[ColorFilter]"; break; - case image_filter: ss << "[ImageFilter]"; break; + case matrix_row3: + ss << "[" << it.GetScalar() << ", " << it.GetScalar() << ", " + << it.GetScalar() << "]"; + break; + case image: + ss << "[Image]"; + break; + case path: + ss << "[Path]"; + break; + case vertices: + ss << "[Vertices]"; + break; + case skpicture: + ss << "[SkPicture]"; + break; + case display_list: + ss << "[DisplayList]"; + break; + case shader: + ss << "[Shader]"; + break; + case color_filter: + ss << "[ColorFilter]"; + break; + case image_filter: + ss << "[ImageFilter]"; + break; } } ss << ")"; return ss.str(); } +// clang-format off constexpr float invert_colors[20] = { -1.0, 0, 0, 1.0, 0, 0, -1.0, 0, 1.0, 0, 0, 0, -1.0, 1.0, 0, 1.0, 1.0, 1.0, 1.0, 0 }; +// clang-format on -sk_sp DisplayListInterpreter::makeColorFilter(RasterizeContext& context) { +sk_sp DisplayListInterpreter::makeColorFilter( + RasterizeContext& context) { if (!context.invertColors) { return context.colorFilter; } @@ -142,7 +182,9 @@ sk_sp DisplayListInterpreter::makeColorFilter(RasterizeContext& c } #define CANVAS_OP_DISPATCH_OP(name, args) \ - case cops_##name: { execute_##name(context, it); } break; + case cops_##name: \ + execute_##name(context, it); \ + break; void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { RasterizeContext context; @@ -153,244 +195,339 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { Iterator it(this); while (it.HasOp()) { FML_LOG(INFO) << DescribeNextOp(it); - switch (it.GetOp()) { - FOR_EACH_CANVAS_OP(CANVAS_OP_DISPATCH_OP) - } + switch (it.GetOp()) { FOR_EACH_CANVAS_OP(CANVAS_OP_DISPATCH_OP) } } - if (it.ops != it.ops_end || - it.data != it.data_end || - it.refs != it.refs_end || - canvas->getSaveCount() != entrySaveCount) { + if (it.ops != it.ops_end || it.data != it.data_end || + it.refs != it.refs_end || canvas->getSaveCount() != entrySaveCount) { FML_LOG(ERROR) << "Starting ops: " << ops_vector_->size() << ", data: " << data_vector_->size() << ", refs: " << ref_vector_->size(); FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) - << ", data: " << (it.data_end - it.data) - << ", refs: " << (it.refs_end - it.refs) - << ", save count delta: " << (canvas->getSaveCount() - entrySaveCount); + << ", data: " << (it.data_end - it.data) + << ", refs: " << (it.refs_end - it.refs) + << ", save count delta: " + << (canvas->getSaveCount() - entrySaveCount); } } -#define CANVAS_OP_DEFINE_OP(name, body) \ -void DisplayListInterpreter::execute_##name(RasterizeContext& context, Iterator& it) { \ - body \ -} +#define CANVAS_OP_DEFINE_OP(name) \ + void DisplayListInterpreter::execute_##name(RasterizeContext& context, \ + Iterator& it) -CANVAS_OP_DEFINE_OP(setAA, context.paint.setAntiAlias(true);) -CANVAS_OP_DEFINE_OP(clearAA, context.paint.setAntiAlias(false);) -CANVAS_OP_DEFINE_OP(setDither, context.paint.setDither(true);) -CANVAS_OP_DEFINE_OP(clearDither, context.paint.setDither(false);) +CANVAS_OP_DEFINE_OP(setAA) { + context.paint.setAntiAlias(true); +} +CANVAS_OP_DEFINE_OP(clearAA) { + context.paint.setAntiAlias(false); +} +CANVAS_OP_DEFINE_OP(setDither) { + context.paint.setDither(true); +} +CANVAS_OP_DEFINE_OP(clearDither) { + context.paint.setDither(false); +} -CANVAS_OP_DEFINE_OP(setInvertColors, +CANVAS_OP_DEFINE_OP(setInvertColors) { context.invertColors = true; context.paint.setColorFilter(makeColorFilter(context)); -) -CANVAS_OP_DEFINE_OP(clearInvertColors, +} +CANVAS_OP_DEFINE_OP(clearInvertColors) { context.invertColors = false; context.paint.setColorFilter(context.colorFilter); -) -CANVAS_OP_DEFINE_OP(clearColorFilter, +} +CANVAS_OP_DEFINE_OP(clearColorFilter) { context.colorFilter = nullptr; context.paint.setColorFilter(makeColorFilter(context)); -) -CANVAS_OP_DEFINE_OP(setColorFilter, +} +CANVAS_OP_DEFINE_OP(setColorFilter) { context.colorFilter = it.GetColorFilter(); context.paint.setColorFilter(makeColorFilter(context)); -) -CANVAS_OP_DEFINE_OP(setColor, context.paint.setColor(it.GetColor());) -CANVAS_OP_DEFINE_OP(setFillStyle, context.paint.setStyle(SkPaint::Style::kFill_Style);) -CANVAS_OP_DEFINE_OP(setStrokeStyle, context.paint.setStyle(SkPaint::Style::kStroke_Style);) -CANVAS_OP_DEFINE_OP(setStrokeWidth, context.paint.setStrokeWidth(it.GetScalar());) -CANVAS_OP_DEFINE_OP(setMiterLimit, context.paint.setStrokeMiter(it.GetScalar());) - -#define CANVAS_CAP_DEFINE_OP(cap) CANVAS_OP_DEFINE_OP(setCaps##cap, \ - context.paint.setStrokeCap(SkPaint::Cap::k##cap##_Cap); \ -) +} + +CANVAS_OP_DEFINE_OP(setColor) { + context.paint.setColor(it.GetColor()); +} +CANVAS_OP_DEFINE_OP(setFillStyle) { + context.paint.setStyle(SkPaint::Style::kFill_Style); +} +CANVAS_OP_DEFINE_OP(setStrokeStyle) { + context.paint.setStyle(SkPaint::Style::kStroke_Style); +} +CANVAS_OP_DEFINE_OP(setStrokeWidth) { + context.paint.setStrokeWidth(it.GetScalar()); +} +CANVAS_OP_DEFINE_OP(setMiterLimit) { + context.paint.setStrokeMiter(it.GetScalar()); +} + +#define CANVAS_CAP_DEFINE_OP(cap) \ + CANVAS_OP_DEFINE_OP(setCaps##cap) { \ + context.paint.setStrokeCap(SkPaint::Cap::k##cap##_Cap); \ + } CANVAS_CAP_DEFINE_OP(Butt) CANVAS_CAP_DEFINE_OP(Round) CANVAS_CAP_DEFINE_OP(Square) -#define CANVAS_JOIN_DEFINE_OP(join) CANVAS_OP_DEFINE_OP(setJoins##join, \ - context.paint.setStrokeJoin(SkPaint::Join::k##join##_Join); \ -) +#define CANVAS_JOIN_DEFINE_OP(join) \ + CANVAS_OP_DEFINE_OP(setJoins##join) { \ + context.paint.setStrokeJoin(SkPaint::Join::k##join##_Join); \ + } CANVAS_JOIN_DEFINE_OP(Miter) CANVAS_JOIN_DEFINE_OP(Round) CANVAS_JOIN_DEFINE_OP(Bevel) -CANVAS_OP_DEFINE_OP(clearShader, context.paint.setShader(nullptr);) -CANVAS_OP_DEFINE_OP(setShader, context.paint.setShader(it.GetShader());) +CANVAS_OP_DEFINE_OP(clearShader) { + context.paint.setShader(nullptr); +} +CANVAS_OP_DEFINE_OP(setShader) { + context.paint.setShader(it.GetShader()); +} -CANVAS_OP_DEFINE_OP(clearMaskFilter, context.paint.setMaskFilter(nullptr);) -#define CANVAS_MASK_DEFINE_OP(type) CANVAS_OP_DEFINE_OP(setMaskFilter##type, \ - context.paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::k##type##_SkBlurStyle, it.GetScalar())); \ -) +#define CANVAS_MASK_DEFINE_OP(type) \ + CANVAS_OP_DEFINE_OP(setMaskFilter##type) { \ + SkBlurStyle style = SkBlurStyle::k##type##_SkBlurStyle; \ + SkScalar sigma = it.GetScalar(); \ + context.paint.setMaskFilter(SkMaskFilter::MakeBlur(style, sigma)); \ + } +CANVAS_OP_DEFINE_OP(clearMaskFilter) { + context.paint.setMaskFilter(nullptr); +} CANVAS_MASK_DEFINE_OP(Inner) CANVAS_MASK_DEFINE_OP(Outer) CANVAS_MASK_DEFINE_OP(Solid) CANVAS_MASK_DEFINE_OP(Normal) -CANVAS_OP_DEFINE_OP(clearImageFilter, context.paint.setImageFilter(nullptr);) -CANVAS_OP_DEFINE_OP(setImageFilter, context.paint.setImageFilter(it.GetImageFilter());) +CANVAS_OP_DEFINE_OP(clearImageFilter) { + context.paint.setImageFilter(nullptr); +} +CANVAS_OP_DEFINE_OP(setImageFilter) { + context.paint.setImageFilter(it.GetImageFilter()); +} const SkSamplingOptions DisplayListInterpreter::NearestSampling = - SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); + SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); const SkSamplingOptions DisplayListInterpreter::LinearSampling = - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone); + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone); const SkSamplingOptions DisplayListInterpreter::MipmapSampling = - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear); + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear); const SkSamplingOptions DisplayListInterpreter::CubicSampling = - SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}); + SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f}); #define CANVAS_OP_DEFINE_FQ(op_type, enum_type, filter_mode) \ -CANVAS_OP_DEFINE_OP(setFilterQuality##op_type, \ - context.filterMode = SkFilterMode::filter_mode; \ - context.sampling = op_type##Sampling; \ - context.paint.setFilterQuality( \ - SkFilterQuality::k##enum_type##_SkFilterQuality); \ -) + CANVAS_OP_DEFINE_OP(setFilterQuality##op_type) { \ + context.filterMode = SkFilterMode::filter_mode; \ + context.sampling = op_type##Sampling; \ + context.paint.setFilterQuality( \ + SkFilterQuality::k##enum_type##_SkFilterQuality); \ + } CANVAS_OP_DEFINE_FQ(Nearest, None, kNearest) CANVAS_OP_DEFINE_FQ(Linear, Low, kLinear) CANVAS_OP_DEFINE_FQ(Mipmap, Medium, kLinear) CANVAS_OP_DEFINE_FQ(Cubic, High, kLinear) -CANVAS_OP_DEFINE_OP(setBlendMode, context.paint.setBlendMode(it.GetBlendMode());) - -CANVAS_OP_DEFINE_OP(save, context.canvas->save();) -CANVAS_OP_DEFINE_OP(saveLayer, context.canvas->saveLayer(nullptr, &context.paint);) -CANVAS_OP_DEFINE_OP(saveLayerBounds, context.canvas->saveLayer(it.GetRect(), &context.paint);) -CANVAS_OP_DEFINE_OP(restore, context.canvas->restore();) - -CANVAS_OP_DEFINE_OP(clipRect, context.canvas->clipRect(it.GetRect());) -CANVAS_OP_DEFINE_OP(clipRectAA, context.canvas->clipRect(it.GetRect(), true);) -CANVAS_OP_DEFINE_OP(clipRectDiff, context.canvas->clipRect(it.GetRect(), SkClipOp::kDifference);) -CANVAS_OP_DEFINE_OP(clipRectAADiff, context.canvas->clipRect(it.GetRect(), SkClipOp::kDifference, true);) - -CANVAS_OP_DEFINE_OP(clipRRect, context.canvas->clipRRect(it.GetRoundRect());) -CANVAS_OP_DEFINE_OP(clipRRectAA, context.canvas->clipRRect(it.GetRoundRect(), true);) -CANVAS_OP_DEFINE_OP(clipPath, it.skipSkRef(); /* TODO(flar) deal with Path object */) -CANVAS_OP_DEFINE_OP(clipPathAA, it.skipSkRef(); /* TODO(flar) deal with Path object */) - -CANVAS_OP_DEFINE_OP(translate, context.canvas->translate(it.GetScalar(), it.GetScalar());) -CANVAS_OP_DEFINE_OP(scale, context.canvas->scale(it.GetScalar(), it.GetScalar());) -CANVAS_OP_DEFINE_OP(rotate, context.canvas->rotate(it.GetAngle());) -CANVAS_OP_DEFINE_OP(skew, context.canvas->skew(it.GetScalar(), it.GetScalar());) -CANVAS_OP_DEFINE_OP(transform2x3, - context.canvas->concat(SkMatrix::MakeAll( - it.GetScalar(), it.GetScalar(), it.GetScalar(), - it.GetScalar(), it.GetScalar(), it.GetScalar(), - 0.0, 0.0, 1.0 - )); -) -CANVAS_OP_DEFINE_OP(transform3x3, - context.canvas->concat(SkMatrix::MakeAll( - it.GetScalar(), it.GetScalar(), it.GetScalar(), - it.GetScalar(), it.GetScalar(), it.GetScalar(), - it.GetScalar(), it.GetScalar(), it.GetScalar() - )); -) - -CANVAS_OP_DEFINE_OP(drawColor, context.canvas->drawColor(it.GetColor(), it.GetBlendMode());) -CANVAS_OP_DEFINE_OP(drawPaint, context.canvas->drawPaint(context.paint);) - -CANVAS_OP_DEFINE_OP(drawRect, context.canvas->drawRect(it.GetRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawOval, context.canvas->drawOval(it.GetRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawRRect, context.canvas->drawRRect(it.GetRoundRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawDRRect, context.canvas->drawDRRect(it.GetRoundRect(), it.GetRoundRect(), context.paint);) -CANVAS_OP_DEFINE_OP(drawCircle, context.canvas->drawCircle(it.GetPoint(), it.GetScalar(), context.paint);) -CANVAS_OP_DEFINE_OP(drawArc, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), false, context.paint);) -CANVAS_OP_DEFINE_OP(drawArcCenter, context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), true, context.paint);) -CANVAS_OP_DEFINE_OP(drawLine, context.canvas->drawLine(it.GetPoint(), it.GetPoint(), context.paint);) -CANVAS_OP_DEFINE_OP(drawPath, +CANVAS_OP_DEFINE_OP(setBlendMode) { + context.paint.setBlendMode(it.GetBlendMode()); +} + +CANVAS_OP_DEFINE_OP(save) { + context.canvas->save(); +} +CANVAS_OP_DEFINE_OP(saveLayer) { + context.canvas->saveLayer(nullptr, &context.paint); +} +CANVAS_OP_DEFINE_OP(saveLayerBounds) { + context.canvas->saveLayer(it.GetRect(), &context.paint); +} +CANVAS_OP_DEFINE_OP(restore) { + context.canvas->restore(); +} + +CANVAS_OP_DEFINE_OP(clipRect) { + context.canvas->clipRect(it.GetRect()); +} +CANVAS_OP_DEFINE_OP(clipRectAA) { + context.canvas->clipRect(it.GetRect(), true); +} +CANVAS_OP_DEFINE_OP(clipRectDiff) { + context.canvas->clipRect(it.GetRect(), SkClipOp::kDifference); +} +CANVAS_OP_DEFINE_OP(clipRectAADiff) { + context.canvas->clipRect(it.GetRect(), SkClipOp::kDifference, true); +} + +CANVAS_OP_DEFINE_OP(clipRRect) { + context.canvas->clipRRect(it.GetRoundRect()); +} +CANVAS_OP_DEFINE_OP(clipRRectAA) { + context.canvas->clipRRect(it.GetRoundRect(), true); +} +CANVAS_OP_DEFINE_OP(clipPath) { + it.skipSkRef(); /* TODO(flar) deal with Path object */ +} +CANVAS_OP_DEFINE_OP(clipPathAA) { + it.skipSkRef(); /* TODO(flar) deal with Path object */ +} + +CANVAS_OP_DEFINE_OP(translate) { + context.canvas->translate(it.GetScalar(), it.GetScalar()); +} +CANVAS_OP_DEFINE_OP(scale) { + context.canvas->scale(it.GetScalar(), it.GetScalar()); +} +CANVAS_OP_DEFINE_OP(rotate) { + context.canvas->rotate(it.GetAngle()); +} +CANVAS_OP_DEFINE_OP(skew) { + context.canvas->skew(it.GetScalar(), it.GetScalar()); +} +CANVAS_OP_DEFINE_OP(transform2x3) { + // clang-format off + context.canvas->concat( + SkMatrix::MakeAll(it.GetScalar(), it.GetScalar(), it.GetScalar(), + it.GetScalar(), it.GetScalar(), it.GetScalar(), + 0.0, 0.0, 1.0)); + // clang-format on +} +CANVAS_OP_DEFINE_OP(transform3x3) { + context.canvas->concat( + SkMatrix::MakeAll(it.GetScalar(), it.GetScalar(), it.GetScalar(), + it.GetScalar(), it.GetScalar(), it.GetScalar(), + it.GetScalar(), it.GetScalar(), it.GetScalar())); +} + +CANVAS_OP_DEFINE_OP(drawColor) { + context.canvas->drawColor(it.GetColor(), it.GetBlendMode()); +} +CANVAS_OP_DEFINE_OP(drawPaint) { + context.canvas->drawPaint(context.paint); +} + +CANVAS_OP_DEFINE_OP(drawRect) { + context.canvas->drawRect(it.GetRect(), context.paint); +} +CANVAS_OP_DEFINE_OP(drawOval) { + context.canvas->drawOval(it.GetRect(), context.paint); +} +CANVAS_OP_DEFINE_OP(drawRRect) { + context.canvas->drawRRect(it.GetRoundRect(), context.paint); +} +CANVAS_OP_DEFINE_OP(drawDRRect) { + context.canvas->drawDRRect(it.GetRoundRect(), it.GetRoundRect(), + context.paint); +} +CANVAS_OP_DEFINE_OP(drawCircle) { + context.canvas->drawCircle(it.GetPoint(), it.GetScalar(), context.paint); +} +CANVAS_OP_DEFINE_OP(drawArc) { + context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), false, + context.paint); +} +CANVAS_OP_DEFINE_OP(drawArcCenter) { + context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), true, + context.paint); +} +CANVAS_OP_DEFINE_OP(drawLine) { + context.canvas->drawLine(it.GetPoint(), it.GetPoint(), context.paint); +} +CANVAS_OP_DEFINE_OP(drawPath) { SkPath path; it.GetPath(path); context.canvas->drawPath(path, context.paint); -) - -#define CANVAS_OP_DEFINE_POINT_OP(mode) \ -CANVAS_OP_DEFINE_OP(draw##mode, \ - SkScalar *flt_ptr; \ - uint32_t len = it.GetFloatList(&flt_ptr); \ - const SkPoint *pt_ptr = reinterpret_cast(flt_ptr); \ - context.canvas->drawPoints(SkCanvas::PointMode::k##mode##_PointMode, \ - len / 2, pt_ptr, context.paint); \ -) +} + +#define CANVAS_OP_DEFINE_POINT_OP(mode) \ + CANVAS_OP_DEFINE_OP(draw##mode) { \ + SkScalar* flt_ptr; \ + uint32_t len = it.GetFloatList(&flt_ptr); \ + const SkPoint* pt_ptr = reinterpret_cast(flt_ptr); \ + context.canvas->drawPoints(SkCanvas::PointMode::k##mode##_PointMode, \ + len / 2, pt_ptr, context.paint); \ + } CANVAS_OP_DEFINE_POINT_OP(Points) CANVAS_OP_DEFINE_POINT_OP(Lines) CANVAS_OP_DEFINE_POINT_OP(Polygon) -CANVAS_OP_DEFINE_OP(drawVertices, context.canvas->drawVertices(it.GetVertices(), it.GetBlendMode(), context.paint);) -CANVAS_OP_DEFINE_OP(drawImage, +CANVAS_OP_DEFINE_OP(drawVertices) { + context.canvas->drawVertices(it.GetVertices(), it.GetBlendMode(), + context.paint); +} + +CANVAS_OP_DEFINE_OP(drawImage) { sk_sp image = it.GetImage(); SkPoint point = it.GetPoint(); - context.canvas->drawImage(image, point.fX, point.fY, context.sampling, &context.paint); -) -CANVAS_OP_DEFINE_OP(drawImageRect, + context.canvas->drawImage(image, point.fX, point.fY, context.sampling, + &context.paint); +} +CANVAS_OP_DEFINE_OP(drawImageRect) { sk_sp image = it.GetImage(); SkRect src = it.GetRect(); SkRect dst = it.GetRect(); - context.canvas->drawImageRect(image, src, dst, context.sampling, &context.paint, SkCanvas::kFast_SrcRectConstraint); -) -CANVAS_OP_DEFINE_OP(drawImageNine, + context.canvas->drawImageRect(image, src, dst, context.sampling, + &context.paint, + SkCanvas::kFast_SrcRectConstraint); +} +CANVAS_OP_DEFINE_OP(drawImageNine) { sk_sp image = it.GetImage(); SkRect center = it.GetRect(); SkRect dst = it.GetRect(); - context.canvas->drawImageNine(image.get(), center.round(), dst, context.filterMode); -) - -#define CANVAS_OP_DEFINE_ATLAS(op_type, has_colors, has_rect) \ -CANVAS_OP_DEFINE_OP(op_type, \ - sk_sp image = it.GetImage(); \ - SkBlendMode blendMode = it.GetBlendMode(); \ - SkScalar *rst_ptr; \ - int nrstscalars = it.GetFloatList(&rst_ptr); \ - SkScalar *rect_ptr; \ - int nrectscalars = it.GetFloatList(&rect_ptr); \ - int numrects = nrectscalars / 4; \ - uint32_t *clr_ptr = nullptr; \ - int ncolorints = numrects; \ - if (has_colors) { \ - ncolorints = it.GetIntList(&clr_ptr); \ - } \ - SkRect* pCullRect = nullptr; \ - SkRect cull_rect; \ - if (has_rect) { \ - cull_rect = it.GetRect(); \ - pCullRect = &cull_rect; \ - } \ - if (nrectscalars != numrects * 4 || \ - nrstscalars != numrects * 4 || \ - ncolorints != numrects) { \ - FML_LOG(ERROR) << "Mismatched Atlas array lengths"; \ - return; \ - } \ - context.canvas->drawAtlas( \ - image.get(), \ - reinterpret_cast(rst_ptr), \ - reinterpret_cast(rect_ptr), \ - reinterpret_cast(clr_ptr), \ - numrects, \ - blendMode, context.sampling, pCullRect, \ - &context.paint); \ -) + context.canvas->drawImageNine(image.get(), center.round(), dst, + context.filterMode); +} + +#define CANVAS_OP_DEFINE_ATLAS(op_type, has_colors, has_rect) \ + CANVAS_OP_DEFINE_OP(op_type) { \ + sk_sp image = it.GetImage(); \ + SkBlendMode blendMode = it.GetBlendMode(); \ + SkScalar* rst_ptr; \ + int nrstscalars = it.GetFloatList(&rst_ptr); \ + SkScalar* rect_ptr; \ + int nrectscalars = it.GetFloatList(&rect_ptr); \ + int numrects = nrectscalars / 4; \ + uint32_t* clr_ptr = nullptr; \ + int ncolorints = numrects; \ + if (has_colors) { \ + ncolorints = it.GetIntList(&clr_ptr); \ + } \ + SkRect* pCullRect = nullptr; \ + SkRect cull_rect; \ + if (has_rect) { \ + cull_rect = it.GetRect(); \ + pCullRect = &cull_rect; \ + } \ + if (nrectscalars != numrects * 4 || nrstscalars != numrects * 4 || \ + ncolorints != numrects) { \ + FML_LOG(ERROR) << "Mismatched Atlas array lengths"; \ + return; \ + } \ + context.canvas->drawAtlas( \ + image.get(), reinterpret_cast(rst_ptr), \ + reinterpret_cast(rect_ptr), \ + reinterpret_cast(clr_ptr), numrects, blendMode, \ + context.sampling, pCullRect, &context.paint); \ + } CANVAS_OP_DEFINE_ATLAS(drawAtlas, false, false) CANVAS_OP_DEFINE_ATLAS(drawAtlasColored, true, false) CANVAS_OP_DEFINE_ATLAS(drawAtlasCulled, false, true) CANVAS_OP_DEFINE_ATLAS(drawAtlasColoredCulled, true, true) -CANVAS_OP_DEFINE_OP(drawDisplayList, DisplayListInterpreter(it.GetDisplayList()).Rasterize(context.canvas);) -CANVAS_OP_DEFINE_OP(drawSkPicture, context.canvas->drawPicture(it.GetSkPicture());) - -#define CANVAS_OP_DEFINE_SHADOW_OP(optype, occludes) \ -CANVAS_OP_DEFINE_OP(optype, \ - SkPath path; \ - it.GetPath(path); \ - SkColor color = it.GetColor(); \ - SkScalar elevation = it.GetScalar(); \ - /* TODO(flar): How to deal with dpr */ \ - SkScalar dpr = 1.0; \ - flutter::PhysicalShapeLayer::DrawShadow(context.canvas, path, color, \ - elevation, occludes, dpr); \ -) +CANVAS_OP_DEFINE_OP(drawDisplayList) { + DisplayListInterpreter(it.GetDisplayList()).Rasterize(context.canvas); +} +CANVAS_OP_DEFINE_OP(drawSkPicture) { + context.canvas->drawPicture(it.GetSkPicture()); +} + +#define CANVAS_OP_DEFINE_SHADOW_OP(optype, occludes) \ + CANVAS_OP_DEFINE_OP(optype) { \ + SkPath path; \ + it.GetPath(path); \ + SkColor color = it.GetColor(); \ + SkScalar elevation = it.GetScalar(); \ + /* TODO(flar): How to deal with dpr */ \ + SkScalar dpr = 1.0; \ + flutter::PhysicalShapeLayer::DrawShadow(context.canvas, path, color, \ + elevation, occludes, dpr); \ + } CANVAS_OP_DEFINE_SHADOW_OP(drawShadow, false) CANVAS_OP_DEFINE_SHADOW_OP(drawShadowOccluded, true) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index e29560b2aa8e8..76a82f41fd74d 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -7,14 +7,14 @@ #include +#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImageFilter.h" -#include "third_party/skia/include/core/SkShader.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkRRect.h" +#include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkVertices.h" namespace flutter { @@ -41,12 +41,11 @@ enum CanvasOpArg { image_filter, }; #define CANVAS_OP_ARG_SHIFT 5 -#define CANVAS_OP_ARG_MASK ((1 << CANVAS_OP_ARG_SHIFT) - 1) +#define CANVAS_OP_ARG_MASK ((1 << CANVAS_OP_ARG_SHIFT) - 1) #define CANVAS_OP_APPEND_ARG(arg_list, arg) \ (((arg_list) << CANVAS_OP_ARG_SHIFT) | CanvasOpArg::arg) -#define CANVAS_OP_ARGS1(arg) \ - (CanvasOpArg::arg) +#define CANVAS_OP_ARGS1(arg) (CanvasOpArg::arg) #define CANVAS_OP_ARGS2(arg1, arg2) \ CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS1(arg2), arg1) #define CANVAS_OP_ARGS3(arg1, arg2, arg3) \ @@ -58,6 +57,7 @@ enum CanvasOpArg { #define CANVAS_OP_ARGS6(arg1, arg2, arg3, arg4, arg5, arg6) \ CANVAS_OP_APPEND_ARG(CANVAS_OP_ARGS5(arg2, arg3, arg4, arg5, arg6), arg1) +// clang-format off #define CANVAS_OP_ARGS__ 0 #define CANVAS_OP_ARGS_Scalar CANVAS_OP_ARGS1(scalar) #define CANVAS_OP_ARGS_2Scalars CANVAS_OP_ARGS2(scalar, scalar) @@ -182,11 +182,10 @@ enum CanvasOpArg { V(drawDisplayList, DisplayList) \ V(drawShadow, Path_Scalar_Scalar) \ V(drawShadowOccluded, Path_Scalar_Scalar) +// clang-format on #define CANVAS_OP_MAKE_ENUM(name, args) cops_##name, -enum CanvasOp { - FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM) -}; +enum CanvasOp { FOR_EACH_CANVAS_OP(CANVAS_OP_MAKE_ENUM) }; class DisplayListRefHolder; @@ -212,11 +211,12 @@ class DisplayListInterpreter { public: DisplayListInterpreter(DisplayListData data); - DisplayListInterpreter(std::shared_ptr> ops, - std::shared_ptr> data, - std::shared_ptr> refs); + DisplayListInterpreter( + std::shared_ptr> ops, + std::shared_ptr> data, + std::shared_ptr> refs); - void Rasterize(SkCanvas *canvas); + void Rasterize(SkCanvas* canvas); void Describe(); @@ -236,42 +236,53 @@ class DisplayListInterpreter { class Iterator { public: Iterator(const DisplayListInterpreter* interpreter) - : ops(interpreter->ops_vector_->begin()), - ops_end(interpreter->ops_vector_->end()), - data(interpreter->data_vector_->begin()), - data_end(interpreter->data_vector_->end()), - refs(interpreter->ref_vector_->begin()), - refs_end(interpreter->ref_vector_->end()) {} + : ops(interpreter->ops_vector_->begin()), + ops_end(interpreter->ops_vector_->end()), + data(interpreter->data_vector_->begin()), + data_end(interpreter->data_vector_->end()), + refs(interpreter->ref_vector_->begin()), + refs_end(interpreter->ref_vector_->end()) {} Iterator(const Iterator& iterator) - : ops(iterator.ops), - ops_end(iterator.ops_end), - data(iterator.data), - data_end(iterator.data_end), - refs(iterator.refs), - refs_end(iterator.refs_end) {} + : ops(iterator.ops), + ops_end(iterator.ops_end), + data(iterator.data), + data_end(iterator.data_end), + refs(iterator.refs), + refs_end(iterator.refs_end) {} bool HasOp() { return ops < ops_end; } CanvasOp GetOp() { return static_cast(*ops++); } void skipData(int n) { data += n; } SkScalar GetScalar() { return static_cast(*data++); } - uint32_t GetUint32() { union { float f; uint32_t i; } u; u.f = *data++; return u.i; } + uint32_t GetUint32() { + union { + float f; + uint32_t i; + } u; + u.f = *data++; + return u.i; + } SkScalar GetAngle() { return GetScalar() * 180.0 / M_PI; } SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } SkColor GetColor() { return static_cast(GetUint32()); } SkPoint GetPoint() { return SkPoint::Make(GetScalar(), GetScalar()); } - SkRect GetRect() { return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), GetScalar()); } + SkRect GetRect() { + return SkRect::MakeLTRB(GetScalar(), GetScalar(), GetScalar(), + GetScalar()); + } SkRRect GetRoundRect() { SkRect rect = GetRect(); SkVector radii[4] = { - // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices - { GetScalar(), GetScalar() }, - { GetScalar(), GetScalar() }, - { GetScalar(), GetScalar() }, - { GetScalar(), GetScalar() }, + // SkRRect Radii order is UL, UR, LR, LL + // as per SkRRect::Corner indices + {GetScalar(), GetScalar()}, + {GetScalar(), GetScalar()}, + {GetScalar(), GetScalar()}, + {GetScalar(), GetScalar()}, }; SkRRect rrect; @@ -279,14 +290,14 @@ class DisplayListInterpreter { return rrect; } - uint32_t GetIntList(uint32_t **int_ptr) { + uint32_t GetIntList(uint32_t** int_ptr) { uint32_t len = GetUint32(); - *int_ptr = (uint32_t *) &*data; + *int_ptr = (uint32_t*)&*data; skipData(len); return len; } - uint32_t GetFloatList(SkScalar **flt_ptr) { + uint32_t GetFloatList(SkScalar** flt_ptr) { uint32_t len = GetUint32(); *flt_ptr = &*data; skipData(len); @@ -294,8 +305,12 @@ class DisplayListInterpreter { } void skipSkRef() { refs++; } - const sk_sp GetColorFilter() { return (refs++)->colorFilter; } - const sk_sp GetImageFilter() { return (refs++)->imageFilter; } + const sk_sp GetColorFilter() { + return (refs++)->colorFilter; + } + const sk_sp GetImageFilter() { + return (refs++)->imageFilter; + } const sk_sp GetImage() { return (refs++)->image; } const sk_sp GetVertices() { return (refs++)->vertices; } const sk_sp GetShader() { return (refs++)->shader; } @@ -315,7 +330,7 @@ class DisplayListInterpreter { }; struct RasterizeContext { - SkCanvas *canvas; + SkCanvas* canvas; SkPaint paint; bool invertColors = false; sk_sp colorFilter; diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 11c3c9a9e3a20..6bf7ec9e9558e 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -9,14 +9,15 @@ namespace flutter { -DisplayListLayer::DisplayListLayer(const SkPoint& offset, - const SkRect& cull_rect, - const SkRect& draw_rect, - std::shared_ptr> ops, - std::shared_ptr> data, - std::shared_ptr> refs, - bool is_complex, - bool will_change) +DisplayListLayer::DisplayListLayer( + const SkPoint& offset, + const SkRect& cull_rect, + const SkRect& draw_rect, + std::shared_ptr> ops, + std::shared_ptr> data, + std::shared_ptr> refs, + bool is_complex, + bool will_change) : offset_(offset), cull_rect_(cull_rect), draw_rect_(draw_rect), @@ -106,24 +107,25 @@ void DisplayListLayer::Diff(DiffContext* context, const Layer* old_layer) { #endif // FLUTTER_ENABLE_DIFF_CONTEXT -void DisplayListLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { +void DisplayListLayer::Preroll(PrerollContext* context, + const SkMatrix& matrix) { TRACE_EVENT0("flutter", "DisplayListLayer::Preroll"); #if defined(LEGACY_FUCHSIA_EMBEDDER) CheckForChildLayerBelow(context); #endif -// if (auto* cache = context->raster_cache) { -// TRACE_EVENT0("flutter", "DisplayListLayer::RasterCache (Preroll)"); + // if (auto* cache = context->raster_cache) { + // TRACE_EVENT0("flutter", "DisplayListLayer::RasterCache (Preroll)"); -// SkMatrix ctm = matrix; -// ctm.preTranslate(offset_.x(), offset_.y()); -// #ifndef SUPPORT_FRACTIONAL_TRANSLATION -// ctm = RasterCache::GetIntegralTransCTM(ctm); -// #endif -// cache->Prepare(context->gr_context, sk_picture, ctm, -// context->dst_color_space, is_complex_, will_change_); -// } + // SkMatrix ctm = matrix; + // ctm.preTranslate(offset_.x(), offset_.y()); + // #ifndef SUPPORT_FRACTIONAL_TRANSLATION + // ctm = RasterCache::GetIntegralTransCTM(ctm); + // #endif + // cache->Prepare(context->gr_context, sk_picture, ctm, + // context->dst_color_space, is_complex_, will_change_); + // } // FML_LOG(ERROR) << "display list cull rect is [" // << cull_rect_.left() << ", " @@ -166,11 +168,11 @@ void DisplayListLayer::Paint(PaintContext& context) const { context.leaf_nodes_canvas->getTotalMatrix())); #endif -// if (context.raster_cache && -// context.raster_cache->Draw(*picture(), *context.leaf_nodes_canvas)) { -// TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); -// return; -// } + // if (context.raster_cache && + // context.raster_cache->Draw(*picture(), *context.leaf_nodes_canvas)) { + // TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); + // return; + // } // FML_LOG(ERROR) << "painting [" // << paint_bounds().left() << ", " @@ -183,8 +185,8 @@ void DisplayListLayer::Paint(PaintContext& context) const { SkPaint paint; paint.setColor(is_complex_ - ? (will_change_ ? SkColors::kRed : SkColors::kYellow) - : (will_change_ ? SkColors::kBlue : SkColors::kGreen)); + ? (will_change_ ? SkColors::kRed : SkColors::kYellow) + : (will_change_ ? SkColors::kBlue : SkColors::kGreen)); } } // namespace flutter diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h index 556ef7faacbe2..24ad236874d68 100644 --- a/flow/layers/display_list_layer.h +++ b/flow/layers/display_list_layer.h @@ -11,8 +11,8 @@ #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/skia_gpu_object.h" -#include "third_party/tonic/typed_data/typed_list.h" #include "third_party/tonic/typed_data/dart_byte_data.h" +#include "third_party/tonic/typed_data/typed_list.h" namespace flutter { diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 928e76224cc31..6c18890fb2285 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -301,8 +301,8 @@ void SceneBuilder::addDisplayList(double dx, SkPoint::Make(dx, dy), SkRect::MakeLTRB(cullLeft, cullTop, cullRight, cullBottom), SkRect::MakeLTRB(drawLeft, drawTop, drawRight, drawBottom), - displayList->ops_vector(), displayList->data_vector(), displayList->ref_vector(), - !!(hints & 1), !!(hints & 2)); + displayList->ops_vector(), displayList->data_vector(), + displayList->ref_vector(), !!(hints & 1), !!(hints & 2)); AddLayer(std::move(layer)); } diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h index 3e2e366e0c9f2..0ed1fdee03778 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -20,8 +20,8 @@ #include "flutter/lib/ui/painting/picture.h" #include "flutter/lib/ui/painting/rrect.h" #include "flutter/lib/ui/painting/shader.h" -#include "third_party/tonic/typed_data/typed_list.h" #include "third_party/tonic/typed_data/dart_byte_data.h" +#include "third_party/tonic/typed_data/typed_list.h" #if defined(LEGACY_FUCHSIA_EMBEDDER) #include "flutter/lib/ui/compositing/scene_host.h" // nogncheck diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index 93ac58fbd0427..a173021fc8c97 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -4,30 +4,17 @@ #include "flutter/lib/ui/painting/display_list.h" -// #include - -// #include "flutter/fml/make_copyable.h" -// #include "flutter/lib/ui/painting/canvas.h" -// #include "flutter/lib/ui/ui_dart_state.h" -// #include "third_party/skia/include/core/SkBlurTypes.h" -// #include "third_party/skia/include/core/SkImage.h" -// #include "third_party/tonic/converter/dart_converter.h" -// #include "third_party/tonic/dart_args.h" -// #include "third_party/tonic/dart_library_natives.h" -// #include "third_party/tonic/dart_persistent_value.h" -// #include "third_party/tonic/logging/dart_invoke.h" - #include "flutter/flow/display_list_interpreter.h" #include "flutter/fml/logging.h" #include "flutter/fml/make_copyable.h" -#include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/painting/canvas.h" +#include "flutter/lib/ui/painting/image_filter.h" #include "flutter/lib/ui/painting/path.h" #include "flutter/lib/ui/painting/shader.h" -#include "flutter/lib/ui/painting/image_filter.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMaskFilter.h" -#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_binding_macros.h" @@ -42,8 +29,7 @@ static void DisplayList_constructor(Dart_NativeArguments args) { IMPLEMENT_WRAPPERTYPEINFO(ui, DisplayList); -#define FOR_EACH_BINDING(V) \ - V(DisplayList, toImage) +#define FOR_EACH_BINDING(V) V(DisplayList, toImage) FOR_EACH_BINDING(DART_NATIVE_CALLBACK) @@ -58,10 +44,9 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, tonic::DartByteData& data, int numData, Dart_Handle objList) { - if (numOps < 0 || - numOps > ops.num_elements() || - numData < 0 || (data.length_in_bytes() % sizeof(float)) != 0 || - numData > (int) (data.length_in_bytes() / sizeof(float))) { + if (numOps < 0 || numOps > ops.num_elements() || numData < 0 || + (data.length_in_bytes() % sizeof(float)) != 0 || + numData > (int)(data.length_in_bytes() / sizeof(float))) { Dart_ThrowException( tonic::ToDart("DisplayList constructor called with bad list lengths.")); return nullptr; @@ -74,22 +59,21 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, const uint8_t* ops_ptr = ops.data(); std::shared_ptr> ops_vector = - std::make_shared>(ops_ptr, ops_ptr + numOps); + std::make_shared>(ops_ptr, ops_ptr + numOps); const float* data_ptr = static_cast(data.data()); std::shared_ptr> data_vector = - std::make_shared>(data_ptr, data_ptr + numData); + std::make_shared>(data_ptr, data_ptr + numData); intptr_t numObjects = 0; Dart_ListLength(objList, &numObjects); Dart_Handle objects[numObjects]; - if (Dart_IsError( - Dart_ListGetRange(objList, 0, numObjects, objects))) { + if (Dart_IsError(Dart_ListGetRange(objList, 0, numObjects, objects))) { return nullptr; } std::shared_ptr> ref_vector = - std::make_shared>(); + std::make_shared>(); int obj_index = 0; SkSamplingOptions sampling = DisplayListInterpreter::NearestSampling; for (uint8_t op : *ops_vector) { @@ -109,55 +93,71 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, sampling = DisplayListInterpreter::CubicSampling; continue; } - for (uint32_t args = DisplayListInterpreter::opArguments[op]; - args != 0; + for (uint32_t args = DisplayListInterpreter::opArguments[op]; args != 0; args >>= CANVAS_OP_ARG_SHIFT) { switch (static_cast(args & CANVAS_OP_ARG_MASK)) { case color_filter: { DisplayListRefHolder holder; - holder.colorFilter = tonic::DartConverter::FromDart(objects[obj_index++])->filter(); + holder.colorFilter = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->filter(); ref_vector->emplace_back(holder); break; } case image_filter: { DisplayListRefHolder holder; - holder.imageFilter = tonic::DartConverter::FromDart(objects[obj_index++])->filter(); + holder.imageFilter = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->filter(); ref_vector->emplace_back(holder); break; } case display_list: { DisplayListRefHolder holder; - holder.displayList = tonic::DartConverter::FromDart(objects[obj_index++])->data(); + holder.displayList = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->data(); ref_vector->emplace_back(holder); break; } case path: { DisplayListRefHolder holder; - holder.pathData = tonic::DartConverter::FromDart(objects[obj_index++])->path().serialize(); + holder.pathData = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->path() + .serialize(); ref_vector->emplace_back(holder); break; } case shader: { DisplayListRefHolder holder; - holder.shader = tonic::DartConverter::FromDart(objects[obj_index++])->shader(sampling); + holder.shader = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->shader(sampling); ref_vector->emplace_back(holder); break; } case image: { DisplayListRefHolder holder; - holder.image = tonic::DartConverter::FromDart(objects[obj_index++])->image(); + holder.image = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->image(); ref_vector->emplace_back(holder); break; } case skpicture: { DisplayListRefHolder holder; - holder.picture = tonic::DartConverter::FromDart(objects[obj_index++])->picture(); + holder.picture = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->picture(); ref_vector->emplace_back(holder); break; } case vertices: { DisplayListRefHolder holder; - holder.vertices = tonic::DartConverter::FromDart(objects[obj_index++])->vertices(); + holder.vertices = + tonic::DartConverter::FromDart(objects[obj_index++]) + ->vertices(); ref_vector->emplace_back(holder); break; } @@ -177,18 +177,19 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, } } if (obj_index != numObjects) { - FML_LOG(ERROR) << "Bad number of objects: " << obj_index << " != " << numObjects; + FML_LOG(ERROR) << "Bad number of objects: " << obj_index + << " != " << numObjects; return nullptr; } - return fml::MakeRefCounted(std::move(ops_vector), - std::move(data_vector), - std::move(ref_vector)); + return fml::MakeRefCounted( + std::move(ops_vector), std::move(data_vector), std::move(ref_vector)); } -DisplayList::DisplayList(std::shared_ptr> ops_vector, - std::shared_ptr> data_vector, - std::shared_ptr> ref_vector) +DisplayList::DisplayList( + std::shared_ptr> ops_vector, + std::shared_ptr> data_vector, + std::shared_ptr> ref_vector) : ops_vector_(ops_vector), data_vector_(data_vector), ref_vector_(ref_vector) {} @@ -198,7 +199,8 @@ DisplayList::~DisplayList() = default; Dart_Handle DisplayList::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { - return RasterizeToImage(ops_vector_, data_vector_, ref_vector_, width, height, raw_image_callback); + return RasterizeToImage(ops_vector_, data_vector_, ref_vector_, width, height, + raw_image_callback); } void DisplayList::dispose() { @@ -211,12 +213,13 @@ size_t DisplayList::GetAllocationSize() const { return ops_vector_->size() + (data_vector_->size() * sizeof(float)); } -Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> ops, - std::shared_ptr> data, - std::shared_ptr> refs, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_callback) { +Dart_Handle DisplayList::RasterizeToImage( + std::shared_ptr> ops, + std::shared_ptr> data, + std::shared_ptr> refs, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback) { if (Dart_IsNull(raw_image_callback) || !Dart_IsClosure(raw_image_callback)) { return tonic::ToDart("Image callback was invalid"); } @@ -269,13 +272,15 @@ Dart_Handle DisplayList::RasterizeToImage(std::shared_ptr> // Kick things off on the raster rask runner. fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, - [ui_task_runner, snapshot_delegate, ops, data, refs, picture_bounds, ui_task] { - sk_sp raster_image = - snapshot_delegate->MakeRasterSnapshot([ops = std::move(ops), data = std::move(data), refs = std::move(refs)](SkCanvas* canvas) { + raster_task_runner, [ui_task_runner, snapshot_delegate, ops, data, refs, + picture_bounds, ui_task] { + sk_sp raster_image = snapshot_delegate->MakeRasterSnapshot( + [ops = std::move(ops), data = std::move(data), + refs = std::move(refs)](SkCanvas* canvas) { DisplayListInterpreter interpreter(ops, data, refs); interpreter.Rasterize(canvas); - }, picture_bounds); + }, + picture_bounds); fml::TaskRunner::RunNowOrPostTask( ui_task_runner, diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h index 17ee3b46a46de..dc97c86b4730e 100644 --- a/lib/ui/painting/display_list.h +++ b/lib/ui/painting/display_list.h @@ -9,12 +9,12 @@ #include "flutter/flow/display_list_interpreter.h" #include "flutter/lib/ui/dart_wrapper.h" -#include "third_party/tonic/typed_data/typed_list.h" -#include "third_party/tonic/typed_data/dart_byte_data.h" -#include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkColorFilter.h" -#include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/tonic/typed_data/dart_byte_data.h" +#include "third_party/tonic/typed_data/typed_list.h" namespace tonic { class DartLibraryNatives; @@ -27,7 +27,6 @@ class DisplayList : public RefCountedDartWrappable { FML_FRIEND_MAKE_REF_COUNTED(DisplayList); public: - ~DisplayList() override; static fml::RefPtr Create(tonic::Uint8List& ops, @@ -40,29 +39,33 @@ class DisplayList : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); - DisplayListData data() { return { ops_vector_, data_vector_, ref_vector_ }; } + DisplayListData data() { return {ops_vector_, data_vector_, ref_vector_}; } void dispose(); size_t GetAllocationSize() const override; - static Dart_Handle RasterizeToImage(std::shared_ptr> ops, - std::shared_ptr> data, - std::shared_ptr> refs, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_callback); + static Dart_Handle RasterizeToImage( + std::shared_ptr> ops, + std::shared_ptr> data, + std::shared_ptr> refs, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback); static void RegisterNatives(tonic::DartLibraryNatives* natives); std::shared_ptr> ops_vector() { return ops_vector_; } std::shared_ptr> data_vector() { return data_vector_; } - std::shared_ptr> ref_vector() { return ref_vector_; } + std::shared_ptr> ref_vector() { + return ref_vector_; + } private: - explicit DisplayList(std::shared_ptr> ops_vector, - std::shared_ptr> data_vector, - std::shared_ptr> ref_vector); + explicit DisplayList( + std::shared_ptr> ops_vector, + std::shared_ptr> data_vector, + std::shared_ptr> ref_vector); // explicit DisplayList(); std::shared_ptr> ops_vector_; diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 78ef8b9f138b5..b660772fe737a 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -5,12 +5,12 @@ #ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ -#include "third_party/tonic/typed_data/typed_list.h" #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/ui_dart_state.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/tonic/typed_data/typed_list.h" namespace tonic { class DartLibraryNatives; diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 63bfaac5bb483..a1f7c618b0653 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -12,8 +12,9 @@ namespace flutter { class SnapshotDelegate { public: - virtual sk_sp MakeRasterSnapshot(std::function draw_callback, - SkISize picture_size) = 0; + virtual sk_sp MakeRasterSnapshot( + std::function draw_callback, + SkISize picture_size) = 0; virtual sk_sp MakeRasterSnapshot(sk_sp picture, SkISize picture_size) = 0; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 761a829af76a6..da488be80a3e6 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -315,8 +315,9 @@ sk_sp Rasterizer::DoMakeRasterSnapshot( return result; } -sk_sp Rasterizer::MakeRasterSnapshot(std::function draw_callback, - SkISize picture_size) { +sk_sp Rasterizer::MakeRasterSnapshot( + std::function draw_callback, + SkISize picture_size) { return DoMakeRasterSnapshot(picture_size, draw_callback); } diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 28f65a313906e..8abd3f2b56b4e 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -465,8 +465,9 @@ class Rasterizer final : public SnapshotDelegate { bool shared_engine_block_thread_merging_ = false; // |SnapshotDelegate| - sk_sp MakeRasterSnapshot(std::function draw_callback, - SkISize picture_size) override; + sk_sp MakeRasterSnapshot( + std::function draw_callback, + SkISize picture_size) override; // |SnapshotDelegate| sk_sp MakeRasterSnapshot(sk_sp picture, From ce83fc3030260b42dce713506479b8747374b3e1 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 7 May 2021 18:06:23 -0700 Subject: [PATCH 24/37] add licenses --- ci/licenses_golden/licenses_flutter | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d8405fe3ba39d..2cd98cbbf7ff4 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -36,6 +36,8 @@ FILE: ../../../flutter/flow/compositor_context.cc FILE: ../../../flutter/flow/compositor_context.h FILE: ../../../flutter/flow/diff_context.cc FILE: ../../../flutter/flow/diff_context.h +FILE: ../../../flutter/flow/display_list_interpreter.cc +FILE: ../../../flutter/flow/display_list_interpreter.h FILE: ../../../flutter/flow/embedded_view_params_unittests.cc FILE: ../../../flutter/flow/embedded_views.cc FILE: ../../../flutter/flow/embedded_views.h @@ -69,6 +71,8 @@ FILE: ../../../flutter/flow/layers/color_filter_layer_unittests.cc FILE: ../../../flutter/flow/layers/container_layer.cc FILE: ../../../flutter/flow/layers/container_layer.h FILE: ../../../flutter/flow/layers/container_layer_unittests.cc +FILE: ../../../flutter/flow/layers/display_list_layer.cc +FILE: ../../../flutter/flow/layers/display_list_layer.h FILE: ../../../flutter/flow/layers/fuchsia_layer_unittests.cc FILE: ../../../flutter/flow/layers/image_filter_layer.cc FILE: ../../../flutter/flow/layers/image_filter_layer.h @@ -341,6 +345,8 @@ FILE: ../../../flutter/lib/ui/painting/codec.cc FILE: ../../../flutter/lib/ui/painting/codec.h FILE: ../../../flutter/lib/ui/painting/color_filter.cc FILE: ../../../flutter/lib/ui/painting/color_filter.h +FILE: ../../../flutter/lib/ui/painting/display_list.cc +FILE: ../../../flutter/lib/ui/painting/display_list.h FILE: ../../../flutter/lib/ui/painting/engine_layer.cc FILE: ../../../flutter/lib/ui/painting/engine_layer.h FILE: ../../../flutter/lib/ui/painting/gradient.cc From 0482ea7e45e198e3c46c34a49ea9695218a71b98 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 7 May 2021 18:43:33 -0700 Subject: [PATCH 25/37] fix test depending on SkiaPicture and missing drawImage native args for SkiaCanvas --- lib/ui/fixtures/ui_test.dart | 3 +++ lib/ui/painting.dart | 17 +++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index 9e274e94eb70e..b7ac814a68aac 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -100,6 +100,9 @@ Future pumpImage() async { ); final Image image = await completer.future; + // This test assumes the old Skia Picture/Canvas implementation + useDisplayListPictures = false; + final FrameCallback renderBlank = (Duration duration) { image.dispose(); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index e4c32a6eca991..489647cc750e3 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4824,13 +4824,14 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { assert(image != null); // image is checked on the engine side assert(_offsetIsValid(offset)); assert(paint != null); - _drawImage(image._image, offset.dx, offset.dy, paint._objects, paint._data); + _drawImage(image._image, offset.dx, offset.dy, paint._objects, paint._data, paint.filterQuality.index); } void _drawImage(_Image image, double x, double y, List? paintObjects, - ByteData paintData) native 'Canvas_drawImage'; + ByteData paintData, + int filterQualityIndex) native 'Canvas_drawImage'; @override void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { @@ -4848,7 +4849,8 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { dst.right, dst.bottom, paint._objects, - paint._data); + paint._data, + paint.filterQuality.index); } void _drawImageRect(_Image image, double srcLeft, @@ -4860,7 +4862,8 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { double dstRight, double dstBottom, List? paintObjects, - ByteData paintData) native 'Canvas_drawImageRect'; + ByteData paintData, + int filterQualityIndex) native 'Canvas_drawImageRect'; @override void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { @@ -4878,7 +4881,8 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { dst.right, dst.bottom, paint._objects, - paint._data); + paint._data, + paint.filterQuality.index); } void _drawImageNine(_Image image, double centerLeft, @@ -4890,7 +4894,8 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { double dstRight, double dstBottom, List? paintObjects, - ByteData paintData) native 'Canvas_drawImageNine'; + ByteData paintData, + int filterQualityIndex) native 'Canvas_drawImageNine'; @override void drawPicture(Picture picture) { From db9220268959987e37302867f84193034e1c998a Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 9 May 2021 18:54:38 -0700 Subject: [PATCH 26/37] minor fixes to pass tests, 2 bugs found --- lib/ui/painting.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 489647cc750e3..aee08f7b8232f 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5675,7 +5675,7 @@ class _DisplayListCanvas implements Canvas { static const int _ditherNeeded = 1 << 11; static const int _paintMask = _aaNeeded | _colorNeeded | _blendNeeded | _invertColorsNeeded - | _colorFilterNeeded | _shaderNeeded; + | _colorFilterNeeded | _shaderNeeded | _imageFilterNeeded; static const int _drawMask = _paintMask | _paintStyleNeeded | _maskFilterNeeded; static const int _strokeMask = _paintMask | _strokeStyleNeeded | _maskFilterNeeded; static const int _imageMask = _blendNeeded | _filterQualityNeeded | _imageFilterNeeded | _ditherNeeded; @@ -5899,7 +5899,7 @@ class _DisplayListCanvas implements Canvas { _addOp(_pointOps[pointMode.index], points.length * 2 + 1); _dataInts[_numData++] = points.length * 2; final _BoundsAccumulator ptBounds = _BoundsAccumulator(); - for (Offset pt in points) { + for (final Offset pt in points) { _dataFloats[_numData++] = pt.dx; _dataFloats[_numData++] = pt.dy; ptBounds.accumulate(pt.dx, pt.dy); @@ -5991,6 +5991,12 @@ class _DisplayListCanvas implements Canvas { BlendMode? blendMode, Rect? cullRect, Paint paint) { + assert(atlas != null); // atlas is checked on the engine side + assert(transforms != null); + assert(rects != null); + assert(colors == null || colors.isEmpty || blendMode != null); + assert(paint != null); + final int rectCount = rects.length; if (transforms.length != rectCount) throw ArgumentError('"transforms" and "rects" lengths must match.'); @@ -6058,7 +6064,7 @@ class _DisplayListCanvas implements Canvas { _addFloat32List(rstTransforms); _addFloat32List(rects); - if (colors != null) + if (colors != null && colors.isNotEmpty) _addInt32List(colors); if (cullRect != null) _addRect(cullRect); From 7bb0ac04303ab4de6c8d6531875f15eab6e9285f Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 9 May 2021 21:45:39 -0700 Subject: [PATCH 27/37] pass dither flag for paint ops that use shaders --- lib/ui/painting.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index aee08f7b8232f..cc6b4baa0b8fe 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5675,7 +5675,7 @@ class _DisplayListCanvas implements Canvas { static const int _ditherNeeded = 1 << 11; static const int _paintMask = _aaNeeded | _colorNeeded | _blendNeeded | _invertColorsNeeded - | _colorFilterNeeded | _shaderNeeded | _imageFilterNeeded; + | _colorFilterNeeded | _shaderNeeded | _ditherNeeded | _imageFilterNeeded; static const int _drawMask = _paintMask | _paintStyleNeeded | _maskFilterNeeded; static const int _strokeMask = _paintMask | _strokeStyleNeeded | _maskFilterNeeded; static const int _imageMask = _blendNeeded | _filterQualityNeeded | _imageFilterNeeded | _ditherNeeded; From 7d92a081af3b40b669d7e6dda62fd7ad8c44c933 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 9 May 2021 21:57:27 -0700 Subject: [PATCH 28/37] implement clipPath --- flow/display_list_interpreter.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index fe56a5ad44ae5..f12c33a51ffe9 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -362,10 +362,14 @@ CANVAS_OP_DEFINE_OP(clipRRectAA) { context.canvas->clipRRect(it.GetRoundRect(), true); } CANVAS_OP_DEFINE_OP(clipPath) { - it.skipSkRef(); /* TODO(flar) deal with Path object */ + SkPath path; + it.GetPath(path); + context.canvas->clipPath(path); } CANVAS_OP_DEFINE_OP(clipPathAA) { - it.skipSkRef(); /* TODO(flar) deal with Path object */ + SkPath path; + it.GetPath(path); + context.canvas->clipPath(path, true); } CANVAS_OP_DEFINE_OP(translate) { From ea82498509eb9595b77733e5c87c2179a976e37f Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 9 May 2021 22:05:45 -0700 Subject: [PATCH 29/37] import cmath for M_PI on Windows --- flow/display_list_interpreter.h | 1 + 1 file changed, 1 insertion(+) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 76a82f41fd74d..62469d99b3470 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_INTERPRETER_H_ #define FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_INTERPRETER_H_ +#include #include #include "third_party/skia/include/core/SkCanvas.h" From 8a747f0a0ba5f160da962a296e96895e70bc1730 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 10 May 2021 11:59:34 -0700 Subject: [PATCH 30/37] remove dead code --- flow/display_list_interpreter.h | 1 - 1 file changed, 1 deletion(-) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 62469d99b3470..4bbadd69452d2 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -305,7 +305,6 @@ class DisplayListInterpreter { return len; } - void skipSkRef() { refs++; } const sk_sp GetColorFilter() { return (refs++)->colorFilter; } From c13700e954001bae0a1dd0ad6ebaba6c85203ae2 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 10 May 2021 13:55:27 -0700 Subject: [PATCH 31/37] remove use of problematic M_PI constant --- flow/display_list_interpreter.cc | 8 ++++---- flow/display_list_interpreter.h | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index f12c33a51ffe9..b93ff2ed5d5b0 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -86,7 +86,7 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { ss << "BlendMode(" << std::dec << it.GetUint32() << ")"; break; case angle: - ss << it.GetAngle(); + ss << it.GetDegrees(); break; case point: ss << "Point(x: " << it.GetScalar() << ", y: " << it.GetScalar() << ")"; @@ -379,7 +379,7 @@ CANVAS_OP_DEFINE_OP(scale) { context.canvas->scale(it.GetScalar(), it.GetScalar()); } CANVAS_OP_DEFINE_OP(rotate) { - context.canvas->rotate(it.GetAngle()); + context.canvas->rotate(it.GetDegrees()); } CANVAS_OP_DEFINE_OP(skew) { context.canvas->skew(it.GetScalar(), it.GetScalar()); @@ -423,11 +423,11 @@ CANVAS_OP_DEFINE_OP(drawCircle) { context.canvas->drawCircle(it.GetPoint(), it.GetScalar(), context.paint); } CANVAS_OP_DEFINE_OP(drawArc) { - context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), false, + context.canvas->drawArc(it.GetRect(), it.GetDegrees(), it.GetDegrees(), false, context.paint); } CANVAS_OP_DEFINE_OP(drawArcCenter) { - context.canvas->drawArc(it.GetRect(), it.GetAngle(), it.GetAngle(), true, + context.canvas->drawArc(it.GetRect(), it.GetDegrees(), it.GetDegrees(), true, context.paint); } CANVAS_OP_DEFINE_OP(drawLine) { diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 4bbadd69452d2..0182d1e5ee663 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_INTERPRETER_H_ #define FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_INTERPRETER_H_ -#include #include #include "third_party/skia/include/core/SkCanvas.h" @@ -266,7 +265,7 @@ class DisplayListInterpreter { return u.i; } - SkScalar GetAngle() { return GetScalar() * 180.0 / M_PI; } + SkScalar GetDegrees() { return SkRadiansToDegrees(GetScalar()); } SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } SkColor GetColor() { return static_cast(GetUint32()); } From 87aeac5e614d8cae950865fe99c109479a26f0e7 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 10 May 2021 14:46:14 -0700 Subject: [PATCH 32/37] more accurate radian conversion --- flow/display_list_interpreter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 0182d1e5ee663..6c8cd899d8dd6 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -265,7 +265,7 @@ class DisplayListInterpreter { return u.i; } - SkScalar GetDegrees() { return SkRadiansToDegrees(GetScalar()); } + SkScalar GetDegrees() { return GetScalar() * 180 / SK_DoublePI; } SkBlendMode GetBlendMode() { return static_cast(GetUint32()); } SkColor GetColor() { return static_cast(GetUint32()); } From dc51f7a0356ee756122dd0f09fa3d28c8ebbefcd Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 10 May 2021 16:30:55 -0700 Subject: [PATCH 33/37] reverted default back to Skia pictures for compatibility --- lib/ui/fixtures/ui_test.dart | 3 --- lib/ui/painting.dart | 32 ++++++++++++++++++-------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index b7ac814a68aac..9e274e94eb70e 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -100,9 +100,6 @@ Future pumpImage() async { ); final Image image = await completer.future; - // This test assumes the old Skia Picture/Canvas implementation - useDisplayListPictures = false; - final FrameCallback renderBlank = (Duration duration) { image.dispose(); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index cc6b4baa0b8fe..99360e2219ee8 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3863,7 +3863,7 @@ enum ClipOp { } /// A flag to enable use of the new DisplayList format for Picture objects. -bool useDisplayListPictures = true; +bool _useDisplayListPictures = false; /// An interface for recording graphical operations. /// @@ -3895,11 +3895,8 @@ abstract class Canvas { /// /// To end the recording, call [PictureRecorder.endRecording] on the /// given recorder. - factory Canvas(PictureRecorder recorder, [ Rect? cullRect ]) { - return useDisplayListPictures - ? _DisplayListCanvas(recorder, cullRect) - : _SkiaCanvas(recorder, cullRect); - } + factory Canvas(PictureRecorder recorder, [ Rect? cullRect ]) => + recorder._makeCanvas(cullRect); /// Saves a copy of the current transform and clip on the save stack. /// @@ -4579,11 +4576,14 @@ abstract class PictureRecorder { /// [Canvas] and begin recording, pass this [PictureRecorder] to the /// [Canvas] constructor. factory PictureRecorder() { - return useDisplayListPictures + return _useDisplayListPictures ? _DisplayListPictureRecorder() : _SkiaPictureRecorder(); } + // Return a canvas appropriate for this PictureRecorder type + Canvas _makeCanvas(Rect? cullRect); + /// Whether this object is currently recording commands. /// /// Specifically, this returns true if a [Canvas] object has been @@ -4603,10 +4603,10 @@ abstract class PictureRecorder { class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { @pragma('vm:entry-point') - _SkiaCanvas(PictureRecorder recorder, [ Rect? cullRect ]) : assert(recorder != null) { + _SkiaCanvas(_SkiaPictureRecorder recorder, [ Rect? cullRect ]) : assert(recorder != null) { if (recorder.isRecording) throw ArgumentError('"recorder" must not already be associated with another Canvas.'); - _recorder = recorder as _SkiaPictureRecorder; + _recorder = recorder; _recorder!._canvas = this; cullRect ??= Rect.largest; _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom); @@ -5086,6 +5086,9 @@ class _SkiaPictureRecorder extends NativeFieldWrapperClass2 implements PictureRe _SkiaPictureRecorder() { _constructor(); } void _constructor() native 'PictureRecorder_constructor'; + @override + Canvas _makeCanvas(Rect? cullRect) => _SkiaCanvas(this, cullRect); + @override bool get isRecording => _canvas != null; @@ -5307,11 +5310,9 @@ class _BoundsAccumulator { Rect get bounds => Rect.fromLTRB(_minX, _minY, _maxX, _maxY); } -/// Local storage version of Canvas class _DisplayListCanvas implements Canvas { - /// Make a Canvas2 - _DisplayListCanvas(PictureRecorder recorder, [Rect? cullRect]) - : _recorder = recorder as _DisplayListPictureRecorder, + _DisplayListCanvas(_DisplayListPictureRecorder recorder, [Rect? cullRect]) + : _recorder = recorder, _cullRect = cullRect ?? Rect.largest, _accumulator = _BoundsAccumulator(), _ops = _emptyOps, _numOps = 0, @@ -5320,7 +5321,7 @@ class _DisplayListCanvas implements Canvas { _objData = [], _ctm = _MatrixTransform._identity(), _ctmStack = <_MatrixTransform>[] { - _recorder!._canvas = this; + recorder._canvas = this; } static Uint8List _emptyOps = Uint8List(0); @@ -6188,6 +6189,9 @@ class _DisplayListPicture extends NativeFieldWrapperClass2 implements Picture { /// Local storage version of PictureRecorder class _DisplayListPictureRecorder implements PictureRecorder { + @override + Canvas _makeCanvas(Rect? cullRect) => _DisplayListCanvas(this, cullRect); + @override bool get isRecording => _canvas != null; From b37b35043d102075e6f3ca4f739dbf04f4ddaf49 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 10 May 2021 18:50:06 -0700 Subject: [PATCH 34/37] missing filterQuality args on SkiaCanvas drawAtlas native calls --- lib/ui/painting.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 99360e2219ee8..e8690868f4e41 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4989,9 +4989,10 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { final Int32List? colorBuffer = (colors == null || colors.isEmpty) ? null : _encodeColorList(colors); final Float32List? cullRectBuffer = cullRect?._value32; + final int qualityIndex = paint.filterQuality.index; _drawAtlas( - paint._objects, paint._data, atlas._image, rstTransformBuffer, rectBuffer, + paint._objects, paint._data, qualityIndex, atlas._image, rstTransformBuffer, rectBuffer, colorBuffer, (blendMode ?? BlendMode.src).index, cullRectBuffer ); } @@ -5018,14 +5019,17 @@ class _SkiaCanvas extends NativeFieldWrapperClass2 implements Canvas { if (colors != null && colors.length * 4 != rectCount) throw ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".'); + final int qualityIndex = paint.filterQuality.index; + _drawAtlas( - paint._objects, paint._data, atlas._image, rstTransforms, rects, + paint._objects, paint._data, qualityIndex, atlas._image, rstTransforms, rects, colors, (blendMode ?? BlendMode.src).index, cullRect?._value32 ); } void _drawAtlas(List? paintObjects, ByteData paintData, + int filterQualityIndex, _Image atlas, Float32List rstTransforms, Float32List rects, From 2d8711b4a45c594014b4a756e4f9ae0903040890 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 14 May 2021 16:24:16 -0700 Subject: [PATCH 35/37] review feedback --- flow/display_list_interpreter.cc | 61 +++--- flow/display_list_interpreter.h | 30 +-- flow/layers/display_list_layer.cc | 108 +--------- lib/ui/painting.dart | 320 ++++++++++++++++-------------- 4 files changed, 223 insertions(+), 296 deletions(-) diff --git a/flow/display_list_interpreter.cc b/flow/display_list_interpreter.cc index b93ff2ed5d5b0..dfdb7bbe3fa86 100644 --- a/flow/display_list_interpreter.cc +++ b/flow/display_list_interpreter.cc @@ -13,17 +13,21 @@ namespace flutter { +#ifndef NDEBUG + #define CANVAS_OP_TAKE_STRING(name, arg) #name, const std::vector DisplayListInterpreter::opNames = { FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_STRING) // }; +#endif // NDEBUG + #define CANVAS_OP_TAKE_ARGS(name, args) CANVAS_OP_ARGS_##args, const std::vector DisplayListInterpreter::opArguments = { FOR_EACH_CANVAS_OP(CANVAS_OP_TAKE_ARGS) // }; -DisplayListInterpreter::DisplayListInterpreter(DisplayListData data) +DisplayListInterpreter::DisplayListInterpreter(const DisplayListData& data) : ops_vector_(data.ops_vector), data_vector_(data.data_vector), ref_vector_(data.ref_vector) {} @@ -36,17 +40,19 @@ DisplayListInterpreter::DisplayListInterpreter( data_vector_(std::move(data_vector)), ref_vector_(std::move(ref_vector)) {} +#ifndef NDEBUG + void DisplayListInterpreter::Describe() { Iterator it(this); - FML_LOG(ERROR) << "Starting ops: " << (it.ops_end - it.ops) - << ", data: " << (it.data_end - it.data) - << ", refs: " << (it.refs_end - it.refs); + FML_LOG(INFO) << "Starting ops: " << (it.ops_end - it.ops) + << ", data: " << (it.data_end - it.data) + << ", refs: " << (it.refs_end - it.refs); while (it.HasOp()) { - FML_LOG(ERROR) << DescribeOneOp(it); + FML_LOG(INFO) << DescribeOneOp(it); } - FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) - << ", data: " << (it.data_end - it.data) - << ", refs: " << (it.refs_end - it.refs); + FML_LOG(INFO) << "Remaining ops: " << (it.ops_end - it.ops) + << ", data: " << (it.data_end - it.data) + << ", refs: " << (it.refs_end - it.refs); } std::string DisplayListInterpreter::DescribeNextOp(const Iterator& it) { @@ -73,7 +79,7 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { static_cast(arg_types & CANVAS_OP_ARG_MASK); switch (arg_type) { case empty: - // This should never happen + FML_DCHECK(false); ss << "?none?"; break; case scalar: @@ -160,6 +166,8 @@ std::string DisplayListInterpreter::DescribeOneOp(Iterator& it) { return ss.str(); } +#endif // NDEBUG + // clang-format off constexpr float invert_colors[20] = { -1.0, 0, 0, 1.0, 0, @@ -194,20 +202,12 @@ void DisplayListInterpreter::Rasterize(SkCanvas* canvas) { int entrySaveCount = canvas->getSaveCount(); Iterator it(this); while (it.HasOp()) { - FML_LOG(INFO) << DescribeNextOp(it); switch (it.GetOp()) { FOR_EACH_CANVAS_OP(CANVAS_OP_DISPATCH_OP) } } - if (it.ops != it.ops_end || it.data != it.data_end || - it.refs != it.refs_end || canvas->getSaveCount() != entrySaveCount) { - FML_LOG(ERROR) << "Starting ops: " << ops_vector_->size() - << ", data: " << data_vector_->size() - << ", refs: " << ref_vector_->size(); - FML_LOG(ERROR) << "Remaining ops: " << (it.ops_end - it.ops) - << ", data: " << (it.data_end - it.data) - << ", refs: " << (it.refs_end - it.refs) - << ", save count delta: " - << (canvas->getSaveCount() - entrySaveCount); - } + FML_DCHECK(it.ops == it.ops_end); + FML_DCHECK(it.data == it.data_end); + FML_DCHECK(it.refs == it.refs_end); + FML_DCHECK(canvas->getSaveCount() == entrySaveCount); } #define CANVAS_OP_DEFINE_OP(name) \ @@ -240,7 +240,7 @@ CANVAS_OP_DEFINE_OP(clearColorFilter) { context.paint.setColorFilter(makeColorFilter(context)); } CANVAS_OP_DEFINE_OP(setColorFilter) { - context.colorFilter = it.GetColorFilter(); + context.colorFilter = it.GetColorFilterRef(); context.paint.setColorFilter(makeColorFilter(context)); } @@ -280,7 +280,7 @@ CANVAS_OP_DEFINE_OP(clearShader) { context.paint.setShader(nullptr); } CANVAS_OP_DEFINE_OP(setShader) { - context.paint.setShader(it.GetShader()); + context.paint.setShader(it.GetShaderRef()); } #define CANVAS_MASK_DEFINE_OP(type) \ @@ -301,7 +301,7 @@ CANVAS_OP_DEFINE_OP(clearImageFilter) { context.paint.setImageFilter(nullptr); } CANVAS_OP_DEFINE_OP(setImageFilter) { - context.paint.setImageFilter(it.GetImageFilter()); + context.paint.setImageFilter(it.GetImageFilterRef()); } const SkSamplingOptions DisplayListInterpreter::NearestSampling = @@ -457,13 +457,13 @@ CANVAS_OP_DEFINE_OP(drawVertices) { } CANVAS_OP_DEFINE_OP(drawImage) { - sk_sp image = it.GetImage(); + const SkImage* image = it.GetImage(); SkPoint point = it.GetPoint(); context.canvas->drawImage(image, point.fX, point.fY, context.sampling, &context.paint); } CANVAS_OP_DEFINE_OP(drawImageRect) { - sk_sp image = it.GetImage(); + const SkImage* image = it.GetImage(); SkRect src = it.GetRect(); SkRect dst = it.GetRect(); context.canvas->drawImageRect(image, src, dst, context.sampling, @@ -471,16 +471,15 @@ CANVAS_OP_DEFINE_OP(drawImageRect) { SkCanvas::kFast_SrcRectConstraint); } CANVAS_OP_DEFINE_OP(drawImageNine) { - sk_sp image = it.GetImage(); + const SkImage* image = it.GetImage(); SkRect center = it.GetRect(); SkRect dst = it.GetRect(); - context.canvas->drawImageNine(image.get(), center.round(), dst, - context.filterMode); + context.canvas->drawImageNine(image, center.round(), dst, context.filterMode); } #define CANVAS_OP_DEFINE_ATLAS(op_type, has_colors, has_rect) \ CANVAS_OP_DEFINE_OP(op_type) { \ - sk_sp image = it.GetImage(); \ + const SkImage* image = it.GetImage(); \ SkBlendMode blendMode = it.GetBlendMode(); \ SkScalar* rst_ptr; \ int nrstscalars = it.GetFloatList(&rst_ptr); \ @@ -504,7 +503,7 @@ CANVAS_OP_DEFINE_OP(drawImageNine) { return; \ } \ context.canvas->drawAtlas( \ - image.get(), reinterpret_cast(rst_ptr), \ + image, reinterpret_cast(rst_ptr), \ reinterpret_cast(rect_ptr), \ reinterpret_cast(clr_ptr), numrects, blendMode, \ context.sampling, pCullRect, &context.paint); \ diff --git a/flow/display_list_interpreter.h b/flow/display_list_interpreter.h index 6c8cd899d8dd6..ee57dd80ddb76 100644 --- a/flow/display_list_interpreter.h +++ b/flow/display_list_interpreter.h @@ -209,7 +209,7 @@ class DisplayListRefHolder { class DisplayListInterpreter { public: - DisplayListInterpreter(DisplayListData data); + DisplayListInterpreter(const DisplayListData& data); DisplayListInterpreter( std::shared_ptr> ops, @@ -218,9 +218,12 @@ class DisplayListInterpreter { void Rasterize(SkCanvas* canvas); +#ifndef NDEBUG void Describe(); static const std::vector opNames; +#endif + static const std::vector opArguments; static const SkSamplingOptions NearestSampling; @@ -290,31 +293,32 @@ class DisplayListInterpreter { return rrect; } - uint32_t GetIntList(uint32_t** int_ptr) { + uint32_t GetIntList(uint32_t** uint32_list_ptr) { uint32_t len = GetUint32(); - *int_ptr = (uint32_t*)&*data; + *uint32_list_ptr = reinterpret_cast(&*data); skipData(len); return len; } - uint32_t GetFloatList(SkScalar** flt_ptr) { + uint32_t GetFloatList(SkScalar** scalar_list_ptr) { uint32_t len = GetUint32(); - *flt_ptr = &*data; + *scalar_list_ptr = reinterpret_cast(&*data); skipData(len); return len; } - const sk_sp GetColorFilter() { + const sk_sp GetColorFilterRef() { return (refs++)->colorFilter; } - const sk_sp GetImageFilter() { + const sk_sp GetImageFilterRef() { return (refs++)->imageFilter; } - const sk_sp GetImage() { return (refs++)->image; } - const sk_sp GetVertices() { return (refs++)->vertices; } - const sk_sp GetShader() { return (refs++)->shader; } - const sk_sp GetSkPicture() { return (refs++)->picture; } - const DisplayListData GetDisplayList() { return (refs++)->displayList; } + const sk_sp GetShaderRef() { return (refs++)->shader; } + + const SkImage* GetImage() { return (refs++)->image.get(); } + const SkVertices* GetVertices() { return (refs++)->vertices.get(); } + const SkPicture* GetSkPicture() { return (refs++)->picture.get(); } + const DisplayListData& GetDisplayList() { return (refs++)->displayList; } void GetPath(SkPath& path) { SkData* data = (refs++)->pathData.get(); path.readFromMemory(data->data(), data->size()); @@ -344,8 +348,10 @@ class DisplayListInterpreter { FOR_EACH_CANVAS_OP(CANVAS_OP_DECLARE_OP) +#ifndef NDEBUG std::string DescribeNextOp(const Iterator& it); std::string DescribeOneOp(Iterator& it); +#endif }; } // namespace flutter diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 6bf7ec9e9558e..883ebbd494964 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -29,6 +29,7 @@ DisplayListLayer::DisplayListLayer( #ifdef FLUTTER_ENABLE_DIFF_CONTEXT +// TODO(flar) Implement display list comparisons and ::IsReplacing method void DisplayListLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); auto* prev = static_cast(old_layer); @@ -47,64 +48,6 @@ void DisplayListLayer::Diff(DiffContext* context, const Layer* old_layer) { context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); } -// bool DisplayListLayer::Compare(DiffContext::Statistics& statistics, -// const PictureLayer* l1, -// const PictureLayer* l2) { -// const auto& pic1 = l1->picture_.get(); -// const auto& pic2 = l2->picture_.get(); -// if (pic1.get() == pic2.get()) { -// statistics.AddSameInstancePicture(); -// return true; -// } -// auto op_cnt_1 = pic1->approximateOpCount(); -// auto op_cnt_2 = pic2->approximateOpCount(); -// if (op_cnt_1 != op_cnt_2 || pic1->cullRect() != pic2->cullRect()) { -// statistics.AddNewPicture(); -// return false; -// } - -// if (op_cnt_1 > 10) { -// statistics.AddPictureTooComplexToCompare(); -// return false; -// } - -// statistics.AddDeepComparePicture(); - -// // TODO(knopp) we don't actually need the data; this could be done without -// // allocations by implementing stream that calculates SHA hash and -// // comparing those hashes -// auto d1 = l1->SerializedPicture(); -// auto d2 = l2->SerializedPicture(); -// auto res = d1->equals(d2.get()); -// if (res) { -// statistics.AddDifferentInstanceButEqualPicture(); -// } else { -// statistics.AddNewPicture(); -// } -// return res; -// } - -// sk_sp PictureLayer::SerializedPicture() const { -// if (!cached_serialized_picture_) { -// SkSerialProcs procs = { -// nullptr, -// nullptr, -// [](SkImage* i, void* ctx) { -// auto id = i->uniqueID(); -// return SkData::MakeWithCopy(&id, sizeof(id)); -// }, -// nullptr, -// [](SkTypeface* tf, void* ctx) { -// auto id = tf->uniqueID(); -// return SkData::MakeWithCopy(&id, sizeof(id)); -// }, -// nullptr, -// }; -// cached_serialized_picture_ = picture_.get()->serialize(&procs); -// } -// return cached_serialized_picture_; -// } - #endif // FLUTTER_ENABLE_DIFF_CONTEXT void DisplayListLayer::Preroll(PrerollContext* context, @@ -115,45 +58,14 @@ void DisplayListLayer::Preroll(PrerollContext* context, CheckForChildLayerBelow(context); #endif - // if (auto* cache = context->raster_cache) { - // TRACE_EVENT0("flutter", "DisplayListLayer::RasterCache (Preroll)"); - - // SkMatrix ctm = matrix; - // ctm.preTranslate(offset_.x(), offset_.y()); - // #ifndef SUPPORT_FRACTIONAL_TRANSLATION - // ctm = RasterCache::GetIntegralTransCTM(ctm); - // #endif - // cache->Prepare(context->gr_context, sk_picture, ctm, - // context->dst_color_space, is_complex_, will_change_); - // } - - // FML_LOG(ERROR) << "display list cull rect is [" - // << cull_rect_.left() << ", " - // << cull_rect_.top() << ", " - // << cull_rect_.right() << ", " - // << cull_rect_.bottom() << "]"; - // FML_LOG(ERROR) << "display list draw rect is [" - // << draw_rect_.left() << ", " - // << draw_rect_.top() << ", " - // << draw_rect_.right() << ", " - // << draw_rect_.bottom() << "]"; + // TODO(flar): implement DisplayList raster caching + SkRect bounds = draw_rect_; if (true || bounds.intersect(cull_rect_)) { bounds.offset(offset_.x(), offset_.y()); } else { bounds.setEmpty(); } - // FML_LOG(ERROR) << "display list paint bounds is [" - // << bounds.left() << ", " - // << bounds.top() << ", " - // << bounds.right() << ", " - // << bounds.bottom() << "] " - // << ops_vector_.size() << " ops"; - // if (bounds.isEmpty()) { - // FML_LOG(ERROR) << "Contents of empty display list:"; - // DisplayListInterpreter interpreter(ops_vector_, data_vector_); - // interpreter.Describe(); - // } set_paint_bounds(bounds); } @@ -168,18 +80,8 @@ void DisplayListLayer::Paint(PaintContext& context) const { context.leaf_nodes_canvas->getTotalMatrix())); #endif - // if (context.raster_cache && - // context.raster_cache->Draw(*picture(), *context.leaf_nodes_canvas)) { - // TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); - // return; - // } - - // FML_LOG(ERROR) << "painting [" - // << paint_bounds().left() << ", " - // << paint_bounds().top() << ", " - // << paint_bounds().right() << ", " - // << paint_bounds().bottom() << "] " - // << ops_vector_.size() << " ops"; + // TODO(flar): implement DisplayList raster caching + DisplayListInterpreter interpreter(ops_vector_, data_vector_, ref_vector_); interpreter.Rasterize(context.leaf_nodes_canvas); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index e8690868f4e41..5319edc520cbd 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5236,7 +5236,7 @@ class _MatrixTransform { return x * myx + y * myy + myt; } - void mul(double mxx, double mxy, double mxt, double myx, double myy, double myt) { + void multiply(double mxx, double mxy, double mxt, double myx, double myy, double myt) { final double mxxNew = this.mxx * mxx + this.mxy * myx; final double mxyNew = this.mxx * mxy + this.mxy * myy; final double mxtNew = this.mxx * mxt + this.mxy * myt + this.mxt; @@ -5252,23 +5252,23 @@ class _MatrixTransform { } void translate(double tx, double ty) { - mul(1.0, 0.0, tx, - 0.0, 1.0, ty); + multiply(1.0, 0.0, tx, + 0.0, 1.0, ty); } void scale(double sx, double sy) { - mul(sx, 0.0, 0.0, - 0.0, sy, 0.0); + multiply(sx, 0.0, 0.0, + 0.0, sy, 0.0); } void rotate(double radians) { - mul(math.cos(radians), -math.sin(radians), 0.0, - math.sin(radians), math.cos(radians), 0.0); + multiply(math.cos(radians), -math.sin(radians), 0.0, + math.sin(radians), math.cos(radians), 0.0); } void skew(double sx, double sy) { - mul(1.0, sx, 0.0, - sy, 1.0, 0.0); + multiply(1.0, sx, 0.0, + sy, 1.0, 0.0); } } @@ -5319,10 +5319,10 @@ class _DisplayListCanvas implements Canvas { : _recorder = recorder, _cullRect = cullRect ?? Rect.largest, _accumulator = _BoundsAccumulator(), - _ops = _emptyOps, _numOps = 0, - _data = _emptyData, _numData = 0, + _ops = _emptyOps, _opCount = 0, + _data = _emptyData, _dataCount = 0, _dataInts = _emptyInts, _dataFloats = _emptyFloats, - _objData = [], + _nativeRefs = [], _ctm = _MatrixTransform._identity(), _ctmStack = <_MatrixTransform>[] { recorder._canvas = this; @@ -5334,18 +5334,18 @@ class _DisplayListCanvas implements Canvas { static ByteData _cachedData = _emptyData; static Uint32List _emptyInts = _emptyData.buffer.asUint32List(); static Float32List _emptyFloats = _emptyData.buffer.asFloat32List(); - static List _deadObjects = List.empty(growable: false); + static List _deadObjects = List.empty(growable: false); _DisplayListPictureRecorder? _recorder; Rect _cullRect; _BoundsAccumulator _accumulator; - int _numOps; + int _opCount; Uint8List _ops; - int _numData; + int _dataCount; ByteData _data; late Uint32List _dataInts; late Float32List _dataFloats; - List _objData; + List _nativeRefs; _MatrixTransform _ctm; List<_MatrixTransform> _ctmStack; @@ -5361,8 +5361,8 @@ class _DisplayListCanvas implements Canvas { _data = _emptyData; _dataInts = _emptyInts; _dataFloats = _emptyFloats; - _numOps = _numData = 0; - _objData = _deadObjects; + _opCount = _dataCount = 0; + _nativeRefs = _deadObjects; } Rect get _drawBounds => _accumulator.bounds; @@ -5389,7 +5389,7 @@ class _DisplayListCanvas implements Canvas { } void _addOp(_CanvasOp op, int dataNeeded) { - if (_numOps >= _ops.length) { + if (_opCount >= _ops.length) { if (_recorder == null) throw StateError('Attempting to render to disposed Canvas'); final int newSize = _newSize(_ops.length, _minOpsSize, _maxOpsGrow, 1); @@ -5400,10 +5400,10 @@ class _DisplayListCanvas implements Canvas { } else { newOps = Uint8List(_newSize(_ops.length, _minOpsSize, _maxOpsGrow, 1)); } - newOps.setRange(0, _numOps, _ops); + newOps.setRange(0, _opCount, _ops); _ops = newOps; } - if (_numData + dataNeeded >= _dataInts.length) { + if (_dataCount + dataNeeded >= _dataInts.length) { final int newSize = 4 * _newSize(_dataInts.length, _minDataSize, _maxDataGrow, dataNeeded); final ByteData newData; if (newSize <= _cachedData.lengthInBytes / 4) { @@ -5413,127 +5413,133 @@ class _DisplayListCanvas implements Canvas { newData = ByteData(4 * _newSize(_dataInts.length, _minDataSize, _maxDataGrow, dataNeeded)); } final Uint32List newInts = newData.buffer.asUint32List(); - newInts.setRange(0, _numData, _dataInts); + newInts.setRange(0, _dataCount, _dataInts); _data = newData; _dataInts = newInts; _dataFloats = newData.buffer.asFloat32List(); } - assert(_numOps < _ops.length); - _ops[_numOps++] = op.index; + assert(_opCount < _ops.length); + _ops[_opCount++] = op.index; } void _addInt(int value) { - assert(_numData < _dataInts.length); - _dataInts[_numData++] = value; + assert(_dataCount < _dataInts.length); + _dataInts[_dataCount++] = value; } void _addScalar(double value) { - assert(_numData < _dataFloats.length); - _dataFloats[_numData++] = value; + assert(_dataCount < _dataFloats.length); + _dataFloats[_dataCount++] = value; } void _addScalar2(double v1, double v2) { - assert(_numData + 2 <= _dataFloats.length); - _dataFloats[_numData++] = v1; - _dataFloats[_numData++] = v2; + assert(_dataCount + 2 <= _dataFloats.length); + _dataFloats[_dataCount++] = v1; + _dataFloats[_dataCount++] = v2; } void _addScalar3(double v1, double v2, double v3) { - assert(_numData + 3 <= _dataFloats.length); - _dataFloats[_numData++] = v1; - _dataFloats[_numData++] = v2; - _dataFloats[_numData++] = v3; + assert(_dataCount + 3 <= _dataFloats.length); + _dataFloats[_dataCount++] = v1; + _dataFloats[_dataCount++] = v2; + _dataFloats[_dataCount++] = v3; } static const int _nOffsetData = 2; void _addOffset(Offset offset) { - assert(_numData + _nOffsetData <= _dataFloats.length); - _dataFloats[_numData++] = offset.dx; - _dataFloats[_numData++] = offset.dy; + assert(_dataCount + _nOffsetData <= _dataFloats.length); + _dataFloats[_dataCount++] = offset.dx; + _dataFloats[_dataCount++] = offset.dy; } static const int _nRectData = 4; void _addRect(Rect r) { - assert(_numData + _nRectData <= _dataFloats.length); - _dataFloats[_numData++] = r.left; - _dataFloats[_numData++] = r.top; - _dataFloats[_numData++] = r.right; - _dataFloats[_numData++] = r.bottom; + assert(_dataCount + _nRectData <= _dataFloats.length); + _dataFloats[_dataCount++] = r.left; + _dataFloats[_dataCount++] = r.top; + _dataFloats[_dataCount++] = r.right; + _dataFloats[_dataCount++] = r.bottom; } static const int _nRoundRectData = 12; void _addRRect(RRect rrect) { - assert(_numData + _nRoundRectData <= _dataFloats.length); - _dataFloats[_numData++] = rrect.left; - _dataFloats[_numData++] = rrect.top; - _dataFloats[_numData++] = rrect.right; - _dataFloats[_numData++] = rrect.bottom; + assert(_dataCount + _nRoundRectData <= _dataFloats.length); + _dataFloats[_dataCount++] = rrect.left; + _dataFloats[_dataCount++] = rrect.top; + _dataFloats[_dataCount++] = rrect.right; + _dataFloats[_dataCount++] = rrect.bottom; // SkRRect Radii order is UL, UR, LR, LL as per SkRRect::Corner indices - _dataFloats[_numData++] = rrect.tlRadiusX; - _dataFloats[_numData++] = rrect.tlRadiusY; - _dataFloats[_numData++] = rrect.trRadiusX; - _dataFloats[_numData++] = rrect.trRadiusY; - _dataFloats[_numData++] = rrect.brRadiusX; - _dataFloats[_numData++] = rrect.brRadiusY; - _dataFloats[_numData++] = rrect.blRadiusX; - _dataFloats[_numData++] = rrect.blRadiusY; + _dataFloats[_dataCount++] = rrect.tlRadiusX; + _dataFloats[_dataCount++] = rrect.tlRadiusY; + _dataFloats[_dataCount++] = rrect.trRadiusX; + _dataFloats[_dataCount++] = rrect.trRadiusY; + _dataFloats[_dataCount++] = rrect.brRadiusX; + _dataFloats[_dataCount++] = rrect.brRadiusY; + _dataFloats[_dataCount++] = rrect.blRadiusX; + _dataFloats[_dataCount++] = rrect.blRadiusY; } void _addInt32List(Int32List data) { final int len = data.length; - assert(_numData + len + 1 <= _dataInts.length); - _dataInts[_numData++] = len; - _dataInts.setRange(_numData, _numData + len, data); - _numData += len; + assert(_dataCount + len + 1 <= _dataInts.length); + _dataInts[_dataCount++] = len; + _dataInts.setRange(_dataCount, _dataCount + len, data); + _dataCount += len; } void _addFloat32List(Float32List data) { final int len = data.length; - assert(_numData + len + 1 <= _dataFloats.length); - _dataInts[_numData++] = len; - _dataFloats.setRange(_numData, _numData + len, data); - _numData += len; + assert(_dataCount + len + 1 <= _dataFloats.length); + _dataInts[_dataCount++] = len; + _dataFloats.setRange(_dataCount, _dataCount + len, data); + _dataCount += len; } void _addImageData(Image image) { - _objData.add(image._image); + _nativeRefs.add(image._image); } void _addPathData(Path path) { - _objData.add(path); + _nativeRefs.add(path); } void _addVertices(Vertices vertices) { - _objData.add(vertices); + _nativeRefs.add(vertices); } void _addSkPicture(_SkiaPicture picture) { - _objData.add(picture); + _nativeRefs.add(picture); } void _addPicture(_DisplayListPicture picture) { - _objData.add(picture); + _nativeRefs.add(picture); } void _addShader(Shader shader) { - _objData.add(shader); + _nativeRefs.add(shader); } void _addColorFilter(_ColorFilter filter) { - _objData.add(filter); + _nativeRefs.add(filter); } void _addImageFilter(_ImageFilter filter) { - _objData.add(filter); + _nativeRefs.add(filter); } void _addPointToBounds(double ux, double uy) { _accumulator.accumulate(_ctm.transformX(ux, uy), _ctm.transformY(ux, uy)); } + void _addStrokedPointToBounds(double ux, double uy) { + final double pad = _currentStrokeWidth * 0.5; + _addPointToBounds(ux - pad, uy - pad); + _addPointToBounds(ux + pad, uy + pad); + } + void _addLTRBToBounds(double l, double t, double r, double b, [ bool? isStroke ]) { - isStroke ??= _curPaintStyle == PaintingStyle.stroke; - final double pad = isStroke ? _curStrokeWidth : 0; + isStroke ??= _currentPaintStyle == PaintingStyle.stroke; + final double pad = isStroke ? _currentStrokeWidth * 0.5 : 0; _addPointToBounds(l - pad, t - pad); _addPointToBounds(r + pad, b + pad); if (_ctm.isNotRectilinear) { @@ -5616,8 +5622,8 @@ class _DisplayListCanvas implements Canvas { _addScalar3(matrix4[1], matrix4[5], matrix4[13]); _addScalar3(matrix4[3], matrix4[7], matrix4[15]); } - _ctm.mul(matrix4[0], matrix4[4], matrix4[12], - matrix4[1], matrix4[5], matrix4[13]); + _ctm.multiply(matrix4[0], matrix4[4], matrix4[12], + matrix4[1], matrix4[5], matrix4[13]); } @override @@ -5649,23 +5655,32 @@ class _DisplayListCanvas implements Canvas { _addPathData(path); } - // These fields track the SkPaint defaults in SkPaint::SkPaint() - Color _curColor = const Color(0xFF000000); - double _curStrokeWidth = 0.0; - double _curMiterLimit = 4.0; - bool _curAA = false; - bool _curDither = false; - bool _curInvertColors = false; - StrokeCap _curStrokeCap = StrokeCap.butt; - StrokeJoin _curStrokeJoin = StrokeJoin.miter; - PaintingStyle _curPaintStyle = PaintingStyle.fill; - FilterQuality _curFilterQuality = FilterQuality.none; - BlendMode _curBlendMode = BlendMode.srcOver; - Shader? _curShader; - ColorFilter? _curColorFilter; - MaskFilter? _curMaskFilter; - ImageFilter? _curImageFilter; - + // These values were originally derived from the SkPaint constructor defaults + // but now are their own spec for backwards compatibility. + // + // Rather than pass down a Paint object with each call, or repeating all relevant + // Paint attributes with each call, we instead maintain a concept of "the most + // recent attributes synchronized through the byte stream (referred to here as + // the "current" value of the attribute). If any operation depends on an attribute + // value that is not the same as the most recent value that was synchronized + // through the byte stream, we send along the new value and record it in these fields. + Color _currentColor = const Color(0xFF000000); + double _currentStrokeWidth = 0.0; + double _currentMiterLimit = 4.0; + bool _currentAA = false; + bool _currentDither = false; + bool _currentInvertColors = false; + StrokeCap _currentStrokeCap = StrokeCap.butt; + StrokeJoin _currentStrokeJoin = StrokeJoin.miter; + PaintingStyle _currentPaintStyle = PaintingStyle.fill; + FilterQuality _currentFilterQuality = FilterQuality.none; + BlendMode _currentBlendMode = BlendMode.srcOver; + Shader? _currentShader; + ColorFilter? _currentColorFilter; + MaskFilter? _currentMaskFilter; + ImageFilter? _currentImageFilter; + + // Mask bits for the various attributes that might be needed for a given operation. static const int _aaNeeded = 1 << 0; static const int _colorNeeded = 1 << 1; static const int _blendNeeded = 1 << 2; @@ -5679,6 +5694,10 @@ class _DisplayListCanvas implements Canvas { static const int _maskFilterNeeded = 1 << 10; static const int _ditherNeeded = 1 << 11; + // Combinations of the above mask bits that are common to typical "draw" calls. + // Note that the _strokeStyle is handled conditionally during synchronization + // if the _paintStyle attribute value is synchronized. It can also be manually + // specified for operations that will be always stroking, like [drawLine]. static const int _paintMask = _aaNeeded | _colorNeeded | _blendNeeded | _invertColorsNeeded | _colorFilterNeeded | _shaderNeeded | _ditherNeeded | _imageFilterNeeded; static const int _drawMask = _paintMask | _paintStyleNeeded | _maskFilterNeeded; @@ -5713,62 +5732,62 @@ class _DisplayListCanvas implements Canvas { ]; void _updatePaintData(Paint paint, int dataNeeded) { - if ((dataNeeded & _aaNeeded) != 0 && _curAA != paint.isAntiAlias) { - _curAA = paint.isAntiAlias; - _addOp(_curAA ? _CanvasOp.setAA : _CanvasOp.clearAA, 0); + if ((dataNeeded & _aaNeeded) != 0 && _currentAA != paint.isAntiAlias) { + _currentAA = paint.isAntiAlias; + _addOp(_currentAA ? _CanvasOp.setAA : _CanvasOp.clearAA, 0); } - if ((dataNeeded & _ditherNeeded) != 0 && _curDither != paint._dither) { - _curDither = paint._dither; - _addOp(_curDither ? _CanvasOp.setDither : _CanvasOp.clearDither, 0); + if ((dataNeeded & _ditherNeeded) != 0 && _currentDither != paint._dither) { + _currentDither = paint._dither; + _addOp(_currentDither ? _CanvasOp.setDither : _CanvasOp.clearDither, 0); } - if ((dataNeeded & _colorNeeded) != 0 && _curColor != paint.color) { - _curColor = paint.color; + if ((dataNeeded & _colorNeeded) != 0 && _currentColor != paint.color) { + _currentColor = paint.color; _addOp(_CanvasOp.setColor, 1); - _addInt(_curColor.value); + _addInt(_currentColor.value); } - if ((dataNeeded & _blendNeeded) != 0 && _curBlendMode != paint.blendMode) { - _curBlendMode = paint.blendMode; + if ((dataNeeded & _blendNeeded) != 0 && _currentBlendMode != paint.blendMode) { + _currentBlendMode = paint.blendMode; _addOp(_CanvasOp.setBlendMode, 1); - _addInt(_curBlendMode.index); + _addInt(_currentBlendMode.index); } - if ((dataNeeded & _invertColorsNeeded) != 0 && _curInvertColors != paint.invertColors) { - _curInvertColors = paint.invertColors; - _addOp(_curInvertColors ? _CanvasOp.setInvertColors : _CanvasOp.clearInvertColors, 0); + if ((dataNeeded & _invertColorsNeeded) != 0 && _currentInvertColors != paint.invertColors) { + _currentInvertColors = paint.invertColors; + _addOp(_currentInvertColors ? _CanvasOp.setInvertColors : _CanvasOp.clearInvertColors, 0); } if ((dataNeeded & _paintStyleNeeded) != 0) { - if (_curPaintStyle != paint.style) { - _curPaintStyle = paint.style; - _addOp(_curPaintStyle == PaintingStyle.fill ? _CanvasOp.setFillStyle : _CanvasOp.setStrokeStyle, 0); + if (_currentPaintStyle != paint.style) { + _currentPaintStyle = paint.style; + _addOp(_currentPaintStyle == PaintingStyle.fill ? _CanvasOp.setFillStyle : _CanvasOp.setStrokeStyle, 0); } - if (_curPaintStyle == PaintingStyle.stroke) { + if (_currentPaintStyle == PaintingStyle.stroke) { dataNeeded |= _strokeStyleNeeded; } } if ((dataNeeded & _strokeStyleNeeded) != 0) { - if (_curStrokeWidth != paint.strokeWidth) { - _curStrokeWidth = paint.strokeWidth; + if (_currentStrokeWidth != paint.strokeWidth) { + _currentStrokeWidth = paint.strokeWidth; _addOp(_CanvasOp.setStrokeWidth, 1); - _addScalar(_curStrokeWidth); + _addScalar(_currentStrokeWidth); } - if (_curStrokeCap != paint.strokeCap) { - _curStrokeCap = paint.strokeCap; - _addOp(_strokeCapOps[_curStrokeCap.index], 0); + if (_currentStrokeCap != paint.strokeCap) { + _currentStrokeCap = paint.strokeCap; + _addOp(_strokeCapOps[_currentStrokeCap.index], 0); } - if (_curStrokeJoin != paint.strokeJoin) { - _curStrokeJoin = paint.strokeJoin; - _addOp(_strokeJoinOps[_curStrokeJoin.index], 0); + if (_currentStrokeJoin != paint.strokeJoin) { + _currentStrokeJoin = paint.strokeJoin; + _addOp(_strokeJoinOps[_currentStrokeJoin.index], 0); } - if (_curMiterLimit != paint.strokeMiterLimit) { - _curMiterLimit = paint.strokeMiterLimit; + if (_currentMiterLimit != paint.strokeMiterLimit) { + _currentMiterLimit = paint.strokeMiterLimit; _addOp(_CanvasOp.setMiterLimit, 1); - _addScalar(_curMiterLimit); + _addScalar(_currentMiterLimit); } } - if ((dataNeeded & _filterQualityNeeded) != 0 && _curFilterQuality != paint.filterQuality) { - _curFilterQuality = paint.filterQuality; - _addOp(_filterQualityOps[_curFilterQuality.index], 0); + if ((dataNeeded & _filterQualityNeeded) != 0 && _currentFilterQuality != paint.filterQuality) { + _currentFilterQuality = paint.filterQuality; + _addOp(_filterQualityOps[_currentFilterQuality.index], 0); } - if ((dataNeeded & _shaderNeeded) != 0 && _curShader != paint.shader) { + if ((dataNeeded & _shaderNeeded) != 0 && _currentShader != paint.shader) { final Shader? shader = paint.shader; if (shader == null) { _addOp(_CanvasOp.clearShader, 0); @@ -5776,9 +5795,9 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.setShader, 0); _addShader(shader); } - _curShader = paint.shader; + _currentShader = paint.shader; } - if ((dataNeeded & _colorFilterNeeded) != 0 && _curColorFilter != paint.colorFilter) { + if ((dataNeeded & _colorFilterNeeded) != 0 && _currentColorFilter != paint.colorFilter) { final _ColorFilter? filter = paint.colorFilter?._toNativeColorFilter(); if (filter == null) { _addOp(_CanvasOp.clearColorFilter, 0); @@ -5786,9 +5805,9 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.setColorFilter, 0); _addColorFilter(filter); } - _curColorFilter = paint.colorFilter; + _currentColorFilter = paint.colorFilter; } - if ((dataNeeded & _imageFilterNeeded) != 0 && _curImageFilter != paint.imageFilter) { + if ((dataNeeded & _imageFilterNeeded) != 0 && _currentImageFilter != paint.imageFilter) { final _ImageFilter? filter = paint.imageFilter?._toNativeImageFilter(); if (filter == null) { _addOp(_CanvasOp.clearImageFilter, 0); @@ -5796,9 +5815,9 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.setImageFilter, 0); _addImageFilter(filter); } - _curImageFilter = paint.imageFilter; + _currentImageFilter = paint.imageFilter; } - if ((dataNeeded & _maskFilterNeeded) != 0 && _curMaskFilter != paint.maskFilter) { + if ((dataNeeded & _maskFilterNeeded) != 0 && _currentMaskFilter != paint.maskFilter) { final MaskFilter? filter = paint.maskFilter; if (filter == null) { _addOp(_CanvasOp.clearMaskFilter, 0); @@ -5806,7 +5825,7 @@ class _DisplayListCanvas implements Canvas { _addOp(_maskFilterOps[filter._style.index], 1); _addScalar(filter._sigma); } - _curMaskFilter = paint.maskFilter; + _currentMaskFilter = paint.maskFilter; } } @@ -5829,7 +5848,8 @@ class _DisplayListCanvas implements Canvas { _addOp(_CanvasOp.drawLine, 2 * _nOffsetData); _addOffset(p1); _addOffset(p2); - _addBounds(Rect.fromPoints(p1, p2), true); + _addStrokedPointToBounds(p1.dx, p1.dy); + _addStrokedPointToBounds(p2.dx, p2.dy); } @override @@ -5902,11 +5922,11 @@ class _DisplayListCanvas implements Canvas { void drawPoints(PointMode pointMode, List points, Paint paint) { _updatePaintData(paint, _strokeMask); _addOp(_pointOps[pointMode.index], points.length * 2 + 1); - _dataInts[_numData++] = points.length * 2; + _dataInts[_dataCount++] = points.length * 2; final _BoundsAccumulator ptBounds = _BoundsAccumulator(); for (final Offset pt in points) { - _dataFloats[_numData++] = pt.dx; - _dataFloats[_numData++] = pt.dy; + _dataFloats[_dataCount++] = pt.dx; + _dataFloats[_dataCount++] = pt.dy; ptBounds.accumulate(pt.dx, pt.dy); } _addBounds(ptBounds.bounds, true); @@ -6013,12 +6033,12 @@ class _DisplayListCanvas implements Canvas { _addImageData(atlas); _addInt((blendMode ?? BlendMode.src).index); - _dataInts[_numData++] = rectCount * 4; - int rstBase = _numData; - _numData += rectCount * 4; - _dataInts[_numData++] = rectCount * 4; - int rectBase = _numData; - _numData += rectCount * 4; + _dataInts[_dataCount++] = rectCount * 4; + int rstBase = _dataCount; + _dataCount += rectCount * 4; + _dataInts[_dataCount++] = rectCount * 4; + int rectBase = _dataCount; + _dataCount += rectCount * 4; final _BoundsAccumulator rstBounds = _BoundsAccumulator(); for (int i = 0; i < rectCount; i++) { final RSTransform rstTransform = transforms[i]; @@ -6035,9 +6055,9 @@ class _DisplayListCanvas implements Canvas { rstBounds.accumulateBounds(rect, rstTransform); } if (colors != null && colors.isNotEmpty) { - _dataInts[_numData++] = rectCount; + _dataInts[_dataCount++] = rectCount; for (int i = 0; i < rectCount; i++) { - _dataInts[_numData++] = colors[i].value; + _dataInts[_dataCount++] = colors[i].value; } } if (cullRect != null) @@ -6208,9 +6228,9 @@ class _DisplayListPictureRecorder implements PictureRecorder { final Picture picture = _DisplayListPicture._( canvas._cullRect, canvas._drawBounds, - canvas._ops, canvas._numOps, - canvas._data, canvas._numData, - canvas._objData, + canvas._ops, canvas._opCount, + canvas._data, canvas._dataCount, + canvas._nativeRefs, ); canvas._dispose(); return picture; From 9d69ead30b21e382592cf73e596995ae7a230f28 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 21 May 2021 15:01:05 -0700 Subject: [PATCH 36/37] remove unused includes and dependency directories --- flow/BUILD.gn | 1 - flow/layers/display_list_layer.cc | 1 - flow/layers/display_list_layer.h | 2 -- 3 files changed, 4 deletions(-) diff --git a/flow/BUILD.gn b/flow/BUILD.gn index af6cfa143ebb3..656c2988af8f9 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -82,7 +82,6 @@ source_set("flow") { "//flutter/common", "//flutter/common/graphics", "//flutter/fml", - "//flutter/third_party/tonic", "//third_party/skia", ] diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 883ebbd494964..65064d8c19950 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -5,7 +5,6 @@ #include "flutter/flow/layers/display_list_layer.h" #include "flutter/flow/display_list_interpreter.h" -#include "third_party/tonic/typed_data/dart_byte_data.h" namespace flutter { diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h index 24ad236874d68..739b818c528a0 100644 --- a/flow/layers/display_list_layer.h +++ b/flow/layers/display_list_layer.h @@ -11,8 +11,6 @@ #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/skia_gpu_object.h" -#include "third_party/tonic/typed_data/dart_byte_data.h" -#include "third_party/tonic/typed_data/typed_list.h" namespace flutter { From 68b620da252f8e685cc1c09ea0d9f27de52b706e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 21 May 2021 17:17:57 -0700 Subject: [PATCH 37/37] better error handling in DisplayList constructor and more review feedback --- lib/ui/painting.dart | 28 +++++------ lib/ui/painting/display_list.cc | 88 ++++++++++++++------------------- lib/ui/painting/display_list.h | 10 ++-- 3 files changed, 55 insertions(+), 71 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 5319edc520cbd..8a18d35ead9ae 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5923,13 +5923,13 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _strokeMask); _addOp(_pointOps[pointMode.index], points.length * 2 + 1); _dataInts[_dataCount++] = points.length * 2; - final _BoundsAccumulator ptBounds = _BoundsAccumulator(); + final _BoundsAccumulator pointBounds = _BoundsAccumulator(); for (final Offset pt in points) { _dataFloats[_dataCount++] = pt.dx; _dataFloats[_dataCount++] = pt.dy; - ptBounds.accumulate(pt.dx, pt.dy); + pointBounds.accumulate(pt.dx, pt.dy); } - _addBounds(ptBounds.bounds, true); + _addBounds(pointBounds.bounds, true); } static const List<_CanvasOp> _pointOps = <_CanvasOp>[ @@ -5943,11 +5943,11 @@ class _DisplayListCanvas implements Canvas { _updatePaintData(paint, _strokeMask); _addOp(_pointOps[pointMode.index], points.length + 1); _addFloat32List(points); - final _BoundsAccumulator ptBounds = _BoundsAccumulator(); + final _BoundsAccumulator pointBounds = _BoundsAccumulator(); for (int i = 0; i + 1 < points.length; i += 2) { - ptBounds.accumulate(points[i], points[i + 1]); + pointBounds.accumulate(points[i], points[i + 1]); } - _addBounds(ptBounds.bounds, true); + _addBounds(pointBounds.bounds, true); } @override @@ -6159,15 +6159,15 @@ class _DisplayListPicture extends NativeFieldWrapperClass2 implements Picture { Rect drawBounds, Uint8List ops, int numOps, ByteData data, int numDataBytes, - List objects) + List nativeRefs) : _cullRect = cullRect, _drawBounds = drawBounds, _ops = ops, _data = data, - _objData = objects { - _constructor(ops, numOps, data, numDataBytes, objects); + _nativeRefs = nativeRefs { + _constructor(ops, numOps, data, numDataBytes, nativeRefs); } - void _constructor(Uint8List ops, int numOps, ByteData data, int dataBytes, List objects) native 'DisplayList_constructor'; + void _constructor(Uint8List ops, int numOps, ByteData data, int dataBytes, List objects) native 'DisplayList_constructor'; @override Future toImage(int width, int height) { @@ -6175,8 +6175,8 @@ class _DisplayListPicture extends NativeFieldWrapperClass2 implements Picture { throw Exception('Invalid image dimensions.'); final Uint8List? ops = _ops; final ByteData? data = _data; - final List? objects = _objData; - if (ops == null || data == null || objects == null) + final List? nativeRefs = _nativeRefs; + if (ops == null || data == null || nativeRefs == null) throw UnimplementedError('toImage called on disposed Picture'); return _futurize( (_Callback callback) => _toImage(width, height, (_Image? image) { @@ -6198,14 +6198,14 @@ class _DisplayListPicture extends NativeFieldWrapperClass2 implements Picture { _drawBounds = null; _ops = null; _data = null; - _objData = null; + _nativeRefs = null; } Rect? _cullRect; Rect? _drawBounds; Uint8List? _ops; ByteData? _data; - List? _objData; + List? _nativeRefs; @override int get approximateBytesUsed => (_ops?.lengthInBytes ?? 0) + (_data?.lengthInBytes ?? 0); diff --git a/lib/ui/painting/display_list.cc b/lib/ui/painting/display_list.cc index a173021fc8c97..580bb17a3d199 100644 --- a/lib/ui/painting/display_list.cc +++ b/lib/ui/painting/display_list.cc @@ -39,6 +39,18 @@ void DisplayList::RegisterNatives(tonic::DartLibraryNatives* natives) { FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } +#define DISPLAY_LIST_GRAB_OBJECT(holder_field, type, accessor) \ + do { \ + if (obj_index >= numObjects) { \ + FML_LOG(ERROR) << "DisplayList constructor passed too few objects."; \ + return fml::MakeRefCounted(); \ + } \ + DisplayListRefHolder holder; \ + holder.holder_field = \ + tonic::DartConverter::FromDart(objects[obj_index++])->accessor; \ + ref_vector->emplace_back(holder); \ + } while (0) + fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, int numOps, tonic::DartByteData& data, @@ -47,14 +59,12 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, if (numOps < 0 || numOps > ops.num_elements() || numData < 0 || (data.length_in_bytes() % sizeof(float)) != 0 || numData > (int)(data.length_in_bytes() / sizeof(float))) { - Dart_ThrowException( - tonic::ToDart("DisplayList constructor called with bad list lengths.")); - return nullptr; + FML_LOG(ERROR) << "DisplayList constructor called with bad list lengths."; + return fml::MakeRefCounted(); } if (Dart_IsNull(objList) || !Dart_IsList(objList)) { - Dart_ThrowException( - tonic::ToDart("DisplayList constructor called with bad object array.")); - return nullptr; + FML_LOG(ERROR) << "DisplayList constructor called with bad object array."; + return fml::MakeRefCounted(); } const uint8_t* ops_ptr = ops.data(); @@ -68,8 +78,11 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, intptr_t numObjects = 0; Dart_ListLength(objList, &numObjects); Dart_Handle objects[numObjects]; - if (Dart_IsError(Dart_ListGetRange(objList, 0, numObjects, objects))) { - return nullptr; + Dart_Handle result = Dart_ListGetRange(objList, 0, numObjects, objects); + if (Dart_IsError(result)) { + FML_LOG(ERROR) << "Dart Error: " << ::Dart_GetError(result); + Dart_PropagateError(result); + return fml::MakeRefCounted(); } std::shared_ptr> ref_vector = @@ -97,68 +110,35 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, args >>= CANVAS_OP_ARG_SHIFT) { switch (static_cast(args & CANVAS_OP_ARG_MASK)) { case color_filter: { - DisplayListRefHolder holder; - holder.colorFilter = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->filter(); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(colorFilter, ColorFilter, filter()); break; } case image_filter: { - DisplayListRefHolder holder; - holder.imageFilter = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->filter(); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(imageFilter, ImageFilter, filter()); break; } case display_list: { - DisplayListRefHolder holder; - holder.displayList = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->data(); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(displayList, DisplayList, data()); break; } case path: { - DisplayListRefHolder holder; - holder.pathData = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->path() - .serialize(); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(pathData, CanvasPath, path().serialize()); break; } case shader: { - DisplayListRefHolder holder; - holder.shader = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->shader(sampling); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(shader, Shader, shader(sampling)); break; } case image: { - DisplayListRefHolder holder; - holder.image = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->image(); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(image, CanvasImage, image()); break; } case skpicture: { - DisplayListRefHolder holder; - holder.picture = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->picture(); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(picture, Picture, picture()); break; } case vertices: { - DisplayListRefHolder holder; - holder.vertices = - tonic::DartConverter::FromDart(objects[obj_index++]) - ->vertices(); - ref_vector->emplace_back(holder); + DISPLAY_LIST_GRAB_OBJECT(vertices, Vertices, vertices()); break; } case empty: @@ -177,9 +157,8 @@ fml::RefPtr DisplayList::Create(tonic::Uint8List& ops, } } if (obj_index != numObjects) { - FML_LOG(ERROR) << "Bad number of objects: " << obj_index - << " != " << numObjects; - return nullptr; + FML_LOG(ERROR) << "DisplayList constructor passed too many objects."; + return fml::MakeRefCounted(); } return fml::MakeRefCounted( @@ -194,6 +173,11 @@ DisplayList::DisplayList( data_vector_(data_vector), ref_vector_(ref_vector) {} +DisplayList::DisplayList() + : ops_vector_(std::make_shared>()), + data_vector_(std::make_shared>()), + ref_vector_(std::make_shared>()) {} + DisplayList::~DisplayList() = default; Dart_Handle DisplayList::toImage(uint32_t width, diff --git a/lib/ui/painting/display_list.h b/lib/ui/painting/display_list.h index dc97c86b4730e..82699a1bf1450 100644 --- a/lib/ui/painting/display_list.h +++ b/lib/ui/painting/display_list.h @@ -62,11 +62,11 @@ class DisplayList : public RefCountedDartWrappable { } private: - explicit DisplayList( - std::shared_ptr> ops_vector, - std::shared_ptr> data_vector, - std::shared_ptr> ref_vector); - // explicit DisplayList(); + DisplayList(std::shared_ptr> ops_vector, + std::shared_ptr> data_vector, + std::shared_ptr> ref_vector); + + DisplayList(); std::shared_ptr> ops_vector_; std::shared_ptr> data_vector_;