Flutter Engine
picture_layer.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/flow/layers/picture_layer.h"
6 
7 #include "flutter/fml/logging.h"
8 #include "third_party/skia/include/core/SkSerialProcs.h"
9 
10 namespace flutter {
11 
12 PictureLayer::PictureLayer(const SkPoint& offset,
14  bool is_complex,
15  bool will_change)
16  : offset_(offset),
17  picture_(std::move(picture)),
18  is_complex_(is_complex),
19  will_change_(will_change) {}
20 
21 #ifdef FLUTTER_ENABLE_DIFF_CONTEXT
22 
23 bool PictureLayer::IsReplacing(DiffContext* context, const Layer* layer) const {
24  // Only return true for identical pictures; This way
25  // ContainerLayer::DiffChildren can detect when a picture layer got inserted
26  // between other picture layers
27  auto picture_layer = layer->as_picture_layer();
28  return picture_layer != nullptr && offset_ == picture_layer->offset_ &&
29  Compare(context->statistics(), this, picture_layer);
30 }
31 
32 void PictureLayer::Diff(DiffContext* context, const Layer* old_layer) {
33  DiffContext::AutoSubtreeRestore subtree(context);
34  if (!context->IsSubtreeDirty()) {
35 #ifndef NDEBUG
36  FML_DCHECK(old_layer);
37  auto prev = old_layer->as_picture_layer();
38  DiffContext::Statistics dummy_statistics;
39  // IsReplacing has already determined that the picture is same
40  FML_DCHECK(prev->offset_ == offset_ &&
41  Compare(dummy_statistics, this, prev));
42 #endif
43  }
44  context->PushTransform(SkMatrix::Translate(offset_.x(), offset_.y()));
45 #ifndef SUPPORT_FRACTIONAL_TRANSLATION
46  context->SetTransform(
47  RasterCache::GetIntegralTransCTM(context->GetTransform()));
48 #endif
49  context->AddLayerBounds(picture()->cullRect());
50  context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
51 }
52 
53 bool PictureLayer::Compare(DiffContext::Statistics& statistics,
54  const PictureLayer* l1,
55  const PictureLayer* l2) {
56  const auto& pic1 = l1->picture_.skia_object();
57  const auto& pic2 = l2->picture_.skia_object();
58 
59  if (pic1.get() == pic2.get()) {
60  statistics.AddSameInstancePicture();
61  return true;
62  }
63  auto op_cnt_1 = pic1->approximateOpCount();
64  auto op_cnt_2 = pic2->approximateOpCount();
65  if (op_cnt_1 != op_cnt_2 || pic1->cullRect() != pic2->cullRect()) {
66  statistics.AddNewPicture();
67  return false;
68  }
69 
70  if (op_cnt_1 > 10) {
71  statistics.AddPictureTooComplexToCompare();
72  return false;
73  }
74 
75  statistics.AddDeepComparePicture();
76 
77  // TODO(knopp) we don't actually need the data; this could be done without
78  // allocations by implementing stream that calculates SHA hash and
79  // comparing those hashes
80  auto d1 = l1->SerializedPicture();
81  auto d2 = l2->SerializedPicture();
82  auto res = d1->equals(d2.get());
83  if (res) {
84  statistics.AddDifferentInstanceButEqualPicture();
85  } else {
86  statistics.AddNewPicture();
87  }
88  return res;
89 }
90 
91 sk_sp<SkData> PictureLayer::SerializedPicture() const {
92  if (!cached_serialized_picture_) {
93  SkSerialProcs procs = {
94  nullptr,
95  nullptr,
96  [](SkImage* i, void* ctx) {
97  auto id = i->uniqueID();
98  return SkData::MakeWithCopy(&id, sizeof(id));
99  },
100  nullptr,
101  [](SkTypeface* tf, void* ctx) {
102  auto id = tf->uniqueID();
103  return SkData::MakeWithCopy(&id, sizeof(id));
104  },
105  nullptr,
106  };
107  cached_serialized_picture_ = picture_.skia_object()->serialize(&procs);
108  }
109  return cached_serialized_picture_;
110 }
111 
112 #endif // FLUTTER_ENABLE_DIFF_CONTEXT
113 
114 void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
115  TRACE_EVENT0("flutter", "PictureLayer::Preroll");
116 
117  SkPicture* sk_picture = picture();
118 
119  if (auto* cache = context->raster_cache) {
120  TRACE_EVENT0("flutter", "PictureLayer::RasterCache (Preroll)");
121  cache->Prepare(context, sk_picture, is_complex_, will_change_, matrix,
122  offset_);
123  }
124 
125  SkRect bounds = sk_picture->cullRect().makeOffset(offset_.x(), offset_.y());
126  set_paint_bounds(bounds);
127 }
128 
129 void PictureLayer::Paint(PaintContext& context) const {
130  TRACE_EVENT0("flutter", "PictureLayer::Paint");
131  FML_DCHECK(picture_.skia_object());
132  FML_DCHECK(needs_painting(context));
133 
134  SkAutoCanvasRestore save(context.leaf_nodes_canvas, true);
135  context.leaf_nodes_canvas->translate(offset_.x(), offset_.y());
136 #ifndef SUPPORT_FRACTIONAL_TRANSLATION
138  context.leaf_nodes_canvas->getTotalMatrix()));
139 #endif
140 
141  if (context.raster_cache &&
142  context.raster_cache->Draw(*picture(), *context.leaf_nodes_canvas)) {
143  TRACE_EVENT_INSTANT0("flutter", "raster cache hit");
144  return;
145  }
146  picture()->playback(context.leaf_nodes_canvas);
147 }
148 
149 } // namespace flutter
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:90
#define FML_DCHECK(condition)
Definition: logging.h:86
void Preroll(PrerollContext *frame, const SkMatrix &matrix) override
#define TRACE_EVENT_INSTANT0(category_group, name)
Definition: trace_event.h:119
Definition: ref_ptr.h:252
void Paint(PaintContext &context) const override
bool needs_painting(PaintContext &context) const
Definition: layer.h:249
const RasterCache * raster_cache
Definition: layer.h:151
sk_sp< SkiaObjectType > skia_object() const
bool Draw(const SkPicture &picture, SkCanvas &canvas) const
SkCanvas * leaf_nodes_canvas
Definition: layer.h:145
void set_paint_bounds(const SkRect &paint_bounds)
Definition: layer.h:240
RasterCache * raster_cache
Definition: layer.h:43
PictureLayer(const SkPoint &offset, SkiaGPUObject< SkPicture > picture, bool is_complex, bool will_change)
static SkMatrix GetIntegralTransCTM(const SkMatrix &ctm)
Snap the translation components of the matrix to integers.
Definition: raster_cache.h:122
SkPicture * picture() const
Definition: picture_layer.h:23