1 // Copyright 2012 The Chromium 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 "cc/layers/picture_layer.h"
6
7 #include "base/auto_reset.h"
8 #include "base/debug/crash_logging.h"
9 #include "base/debug/dump_without_crashing.h"
10 #include "base/trace_event/trace_event.h"
11 #include "cc/layers/content_layer_client.h"
12 #include "cc/layers/picture_layer_impl.h"
13 #include "cc/layers/recording_source.h"
14 #include "cc/paint/paint_record.h"
15 #include "cc/trees/layer_tree_host.h"
16 #include "cc/trees/layer_tree_impl.h"
17 #include "cc/trees/transform_node.h"
18 #include "ui/gfx/geometry/rect_conversions.h"
19
20 namespace cc {
21
22 PictureLayer::PictureLayerInputs::PictureLayerInputs() = default;
23
24 PictureLayer::PictureLayerInputs::~PictureLayerInputs() = default;
25
Create(ContentLayerClient * client)26 scoped_refptr<PictureLayer> PictureLayer::Create(ContentLayerClient* client) {
27 return base::WrapRefCounted(new PictureLayer(client));
28 }
29
PictureLayer(ContentLayerClient * client)30 PictureLayer::PictureLayer(ContentLayerClient* client)
31 : instrumentation_object_tracker_(id()), update_source_frame_number_(-1) {
32 picture_layer_inputs_.client = client;
33 }
34
PictureLayer(ContentLayerClient * client,std::unique_ptr<RecordingSource> source)35 PictureLayer::PictureLayer(ContentLayerClient* client,
36 std::unique_ptr<RecordingSource> source)
37 : PictureLayer(client) {
38 recording_source_ = std::move(source);
39 }
40
41 PictureLayer::~PictureLayer() = default;
42
CreateLayerImpl(LayerTreeImpl * tree_impl)43 std::unique_ptr<LayerImpl> PictureLayer::CreateLayerImpl(
44 LayerTreeImpl* tree_impl) {
45 return PictureLayerImpl::Create(tree_impl, id());
46 }
47
PushPropertiesTo(LayerImpl * base_layer)48 void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
49 // TODO(enne): http://crbug.com/918126 debugging
50 CHECK(this);
51
52 PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
53
54 Layer::PushPropertiesTo(base_layer);
55 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
56 "PictureLayer::PushPropertiesTo");
57 DropRecordingSourceContentIfInvalid();
58
59 layer_impl->SetNearestNeighbor(picture_layer_inputs_.nearest_neighbor);
60 layer_impl->SetUseTransformedRasterization(
61 ShouldUseTransformedRasterization());
62 layer_impl->set_gpu_raster_max_texture_size(
63 layer_tree_host()->device_viewport_rect().size());
64 layer_impl->SetIsBackdropFilterMask(is_backdrop_filter_mask());
65 layer_impl->SetDirectlyCompositedImageSize(
66 picture_layer_inputs_.directly_composited_image_size);
67
68 // TODO(enne): http://crbug.com/918126 debugging
69 CHECK(this);
70 if (!recording_source_) {
71 bool valid_host = layer_tree_host();
72 bool has_parent = parent();
73 bool parent_has_host = parent() && parent()->layer_tree_host();
74
75 auto str = base::StringPrintf("vh: %d, hp: %d, phh: %d", valid_host,
76 has_parent, parent_has_host);
77 static auto* crash_key = base::debug::AllocateCrashKeyString(
78 "issue918126", base::debug::CrashKeySize::Size32);
79 base::debug::SetCrashKeyString(crash_key, str);
80 base::debug::DumpWithoutCrashing();
81 }
82
83 layer_impl->UpdateRasterSource(recording_source_->CreateRasterSource(),
84 &last_updated_invalidation_, nullptr, nullptr);
85 DCHECK(last_updated_invalidation_.IsEmpty());
86 }
87
SetLayerTreeHost(LayerTreeHost * host)88 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
89 Layer::SetLayerTreeHost(host);
90
91 if (!host)
92 return;
93
94 if (!recording_source_)
95 recording_source_.reset(new RecordingSource);
96 recording_source_->SetSlowdownRasterScaleFactor(
97 host->GetDebugState().slow_down_raster_scale_factor);
98
99 // Source frame numbers are relative the LayerTreeHost, so this needs
100 // to be reset.
101 update_source_frame_number_ = -1;
102 }
103
SetNeedsDisplayRect(const gfx::Rect & layer_rect)104 void PictureLayer::SetNeedsDisplayRect(const gfx::Rect& layer_rect) {
105 DCHECK(!layer_tree_host() || !layer_tree_host()->in_paint_layer_contents());
106 if (recording_source_)
107 recording_source_->SetNeedsDisplayRect(layer_rect);
108 Layer::SetNeedsDisplayRect(layer_rect);
109 }
110
Update()111 bool PictureLayer::Update() {
112 update_source_frame_number_ = layer_tree_host()->SourceFrameNumber();
113 bool updated = Layer::Update();
114
115 gfx::Size layer_size = bounds();
116
117 recording_source_->SetBackgroundColor(SafeOpaqueBackgroundColor());
118 recording_source_->SetRequiresClear(
119 !contents_opaque() &&
120 !picture_layer_inputs_.client->FillsBoundsCompletely());
121
122 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "PictureLayer::Update",
123 "source_frame_number", layer_tree_host()->SourceFrameNumber());
124 devtools_instrumentation::ScopedLayerTreeTask update_layer(
125 devtools_instrumentation::kUpdateLayer, id(), layer_tree_host()->GetId());
126
127 // UpdateAndExpandInvalidation will give us an invalidation that covers
128 // anything not explicitly recorded in this frame. We give this region
129 // to the impl side so that it drops tiles that may not have a recording
130 // for them.
131 DCHECK(picture_layer_inputs_.client);
132
133 auto recorded_viewport = picture_layer_inputs_.client->PaintableRegion();
134
135 updated |= recording_source_->UpdateAndExpandInvalidation(
136 &last_updated_invalidation_, layer_size, recorded_viewport);
137
138 if (updated) {
139 picture_layer_inputs_.display_list =
140 picture_layer_inputs_.client->PaintContentsToDisplayList(
141 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
142 picture_layer_inputs_.painter_reported_memory_usage =
143 picture_layer_inputs_.client->GetApproximateUnsharedMemoryUsage();
144 recording_source_->UpdateDisplayItemList(
145 picture_layer_inputs_.display_list,
146 picture_layer_inputs_.painter_reported_memory_usage,
147 layer_tree_host()->recording_scale_factor());
148
149 SetNeedsPushProperties();
150 IncreasePaintCount();
151 } else {
152 // If this invalidation did not affect the recording source, then it can be
153 // cleared as an optimization.
154 last_updated_invalidation_.Clear();
155 }
156
157 return updated;
158 }
159
GetPicture() const160 sk_sp<SkPicture> PictureLayer::GetPicture() const {
161 // We could either flatten the RecordingSource into a single SkPicture, or
162 // paint a fresh one depending on what we intend to do with it. For now we
163 // just paint a fresh one to get consistent results.
164 if (!DrawsContent())
165 return nullptr;
166
167 gfx::Size layer_size = bounds();
168 RecordingSource recording_source;
169 Region recording_invalidation;
170
171 gfx::Rect new_recorded_viewport =
172 picture_layer_inputs_.client->PaintableRegion();
173 scoped_refptr<DisplayItemList> display_list =
174 picture_layer_inputs_.client->PaintContentsToDisplayList(
175 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
176 size_t painter_reported_memory_usage =
177 picture_layer_inputs_.client->GetApproximateUnsharedMemoryUsage();
178
179 recording_source.UpdateAndExpandInvalidation(
180 &recording_invalidation, layer_size, new_recorded_viewport);
181 recording_source.UpdateDisplayItemList(
182 display_list, painter_reported_memory_usage,
183 layer_tree_host()->recording_scale_factor());
184
185 scoped_refptr<RasterSource> raster_source =
186 recording_source.CreateRasterSource();
187 return raster_source->GetFlattenedPicture();
188 }
189
ClearClient()190 void PictureLayer::ClearClient() {
191 picture_layer_inputs_.client = nullptr;
192 UpdateDrawsContent(HasDrawableContent());
193 }
194
SetNearestNeighbor(bool nearest_neighbor)195 void PictureLayer::SetNearestNeighbor(bool nearest_neighbor) {
196 if (picture_layer_inputs_.nearest_neighbor == nearest_neighbor)
197 return;
198
199 picture_layer_inputs_.nearest_neighbor = nearest_neighbor;
200 SetNeedsCommit();
201 }
202
SetTransformedRasterizationAllowed(bool allowed)203 void PictureLayer::SetTransformedRasterizationAllowed(bool allowed) {
204 if (picture_layer_inputs_.transformed_rasterization_allowed == allowed)
205 return;
206
207 picture_layer_inputs_.transformed_rasterization_allowed = allowed;
208 SetNeedsCommit();
209 }
210
HasDrawableContent() const211 bool PictureLayer::HasDrawableContent() const {
212 return picture_layer_inputs_.client && Layer::HasDrawableContent();
213 }
214
SetIsBackdropFilterMask(bool is_backdrop_filter_mask)215 void PictureLayer::SetIsBackdropFilterMask(bool is_backdrop_filter_mask) {
216 if (picture_layer_inputs_.is_backdrop_filter_mask == is_backdrop_filter_mask)
217 return;
218
219 picture_layer_inputs_.is_backdrop_filter_mask = is_backdrop_filter_mask;
220 SetNeedsCommit();
221 }
222
RunMicroBenchmark(MicroBenchmark * benchmark)223 void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) {
224 benchmark->RunOnLayer(this);
225 }
226
CaptureContent(const gfx::Rect & rect,std::vector<NodeId> * content)227 void PictureLayer::CaptureContent(const gfx::Rect& rect,
228 std::vector<NodeId>* content) {
229 if (!DrawsContent())
230 return;
231
232 const DisplayItemList* display_item_list = GetDisplayItemList();
233 if (!display_item_list)
234 return;
235
236 // We could run into this situation as CaptureContent could start at any time.
237 if (transform_tree_index() == TransformTree::kInvalidNodeId)
238 return;
239
240 gfx::Transform inverse_screen_space_transform;
241 if (!ScreenSpaceTransform().GetInverse(&inverse_screen_space_transform))
242 return;
243 gfx::Rect transformed = MathUtil::ProjectEnclosingClippedRect(
244 inverse_screen_space_transform, rect);
245
246 transformed.Intersect(gfx::Rect(bounds()));
247 if (transformed.IsEmpty())
248 return;
249
250 display_item_list->CaptureContent(transformed, content);
251 }
252
DropRecordingSourceContentIfInvalid()253 void PictureLayer::DropRecordingSourceContentIfInvalid() {
254 int source_frame_number = layer_tree_host()->SourceFrameNumber();
255 gfx::Size recording_source_bounds = recording_source_->GetSize();
256
257 gfx::Size layer_bounds = bounds();
258
259 // If update called, then recording source size must match bounds pushed to
260 // impl layer.
261 DCHECK(update_source_frame_number_ != source_frame_number ||
262 layer_bounds == recording_source_bounds)
263 << " bounds " << layer_bounds.ToString() << " recording source "
264 << recording_source_bounds.ToString();
265
266 if (update_source_frame_number_ != source_frame_number &&
267 recording_source_bounds != layer_bounds) {
268 // Update may not get called for the layer (if it's not in the viewport
269 // for example), even though it has resized making the recording source no
270 // longer valid. In this case just destroy the recording source.
271 recording_source_->SetEmptyBounds();
272 picture_layer_inputs_.display_list = nullptr;
273 picture_layer_inputs_.painter_reported_memory_usage = 0;
274 }
275 }
276
ShouldUseTransformedRasterization() const277 bool PictureLayer::ShouldUseTransformedRasterization() const {
278 if (!picture_layer_inputs_.transformed_rasterization_allowed)
279 return false;
280
281 // Background color overfill is undesirable with transformed rasterization.
282 // However, without background overfill, the tiles will be non-opaque on
283 // external edges, and layer opaque region can't be computed in layer space
284 // due to rounding under extreme scaling. This defeats many opaque layer
285 // optimization. Prefer optimization over quality for this particular case.
286 if (contents_opaque())
287 return false;
288
289 const TransformTree& transform_tree =
290 layer_tree_host()->property_trees()->transform_tree;
291 DCHECK(!transform_tree.needs_update());
292 auto* transform_node = transform_tree.Node(transform_tree_index());
293 DCHECK(transform_node);
294 // TODO(pdr): This is a workaround for https://crbug.com/708951 to avoid
295 // crashing when there's no transform node. This workaround should be removed.
296 if (!transform_node)
297 return false;
298
299 if (transform_node->to_screen_is_potentially_animated)
300 return false;
301
302 const gfx::Transform& to_screen =
303 transform_tree.ToScreen(transform_tree_index());
304 if (!to_screen.IsScaleOrTranslation())
305 return false;
306
307 float origin_x =
308 to_screen.matrix().getFloat(0, 3) + offset_to_transform_parent().x();
309 float origin_y =
310 to_screen.matrix().getFloat(1, 3) + offset_to_transform_parent().y();
311 if (origin_x - floorf(origin_x) == 0.f && origin_y - floorf(origin_y) == 0.f)
312 return false;
313
314 return true;
315 }
316
GetDisplayItemList()317 const DisplayItemList* PictureLayer::GetDisplayItemList() {
318 return picture_layer_inputs_.display_list.get();
319 }
320
321 } // namespace cc
322