OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/playback/raster_source.h" | 5 #include "cc/playback/raster_source.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
10 #include "cc/base/region.h" | 10 #include "cc/base/region.h" |
11 #include "cc/debug/debug_colors.h" | 11 #include "cc/debug/debug_colors.h" |
12 #include "cc/playback/display_item_list.h" | 12 #include "cc/playback/display_item_list.h" |
13 #include "cc/playback/image_hijack_canvas.h" | 13 #include "cc/playback/image_hijack_canvas.h" |
14 #include "cc/playback/skip_image_canvas.h" | 14 #include "cc/playback/skip_image_canvas.h" |
15 #include "skia/ext/analysis_canvas.h" | 15 #include "skia/ext/analysis_canvas.h" |
16 #include "third_party/skia/include/core/SkCanvas.h" | 16 #include "third_party/skia/include/core/SkCanvas.h" |
17 #include "third_party/skia/include/core/SkClipStack.h" | |
17 #include "third_party/skia/include/core/SkPictureRecorder.h" | 18 #include "third_party/skia/include/core/SkPictureRecorder.h" |
18 #include "ui/gfx/geometry/rect_conversions.h" | 19 #include "ui/gfx/geometry/rect_conversions.h" |
19 | 20 |
20 namespace cc { | 21 namespace cc { |
21 | 22 |
22 scoped_refptr<RasterSource> RasterSource::CreateFromRecordingSource( | 23 scoped_refptr<RasterSource> RasterSource::CreateFromRecordingSource( |
23 const RecordingSource* other, | 24 const RecordingSource* other, |
24 bool can_use_lcd_text) { | 25 bool can_use_lcd_text) { |
25 return make_scoped_refptr(new RasterSource(other, can_use_lcd_text)); | 26 return make_scoped_refptr(new RasterSource(other, can_use_lcd_text)); |
26 } | 27 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 } | 62 } |
62 | 63 |
63 RasterSource::~RasterSource() { | 64 RasterSource::~RasterSource() { |
64 } | 65 } |
65 | 66 |
66 void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas, | 67 void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas, |
67 const gfx::Rect& canvas_bitmap_rect, | 68 const gfx::Rect& canvas_bitmap_rect, |
68 const gfx::Rect& canvas_playback_rect, | 69 const gfx::Rect& canvas_playback_rect, |
69 float contents_scale, | 70 float contents_scale, |
70 const PlaybackSettings& settings) const { | 71 const PlaybackSettings& settings) const { |
71 if (!settings.playback_to_shared_canvas) { | 72 SkIRect raster_bounds = gfx::RectToSkIRect(canvas_bitmap_rect); |
ajuma
2016/06/23 17:57:37
Is it worth intersecting this with size_?
trchen
2016/06/23 22:18:24
(I assume you meant interest_rect as in PrepareFor
| |
72 PrepareForPlaybackToCanvas(raster_canvas, canvas_bitmap_rect, | 73 if (!canvas_playback_rect.IsEmpty() && |
73 canvas_playback_rect, contents_scale); | 74 !raster_bounds.intersect(gfx::RectToSkIRect(canvas_playback_rect))) |
74 } | 75 return; |
76 | |
77 raster_canvas->save(); | |
78 raster_canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); | |
79 raster_canvas->clipRect(SkRect::MakeFromIRect(raster_bounds)); | |
80 raster_canvas->scale(contents_scale, contents_scale); | |
81 PlaybackToCanvas(raster_canvas, settings); | |
82 raster_canvas->restore(); | |
83 } | |
84 | |
85 void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas, | |
86 const PlaybackSettings& settings) const { | |
87 if (!settings.playback_to_shared_canvas) | |
88 PrepareForPlaybackToCanvas(raster_canvas); | |
75 | 89 |
76 if (settings.skip_images) { | 90 if (settings.skip_images) { |
77 SkipImageCanvas canvas(raster_canvas); | 91 SkipImageCanvas canvas(raster_canvas); |
78 RasterCommon(&canvas, nullptr, canvas_bitmap_rect, canvas_playback_rect, | 92 RasterCommon(&canvas, nullptr); |
79 contents_scale); | |
80 } else if (settings.use_image_hijack_canvas) { | 93 } else if (settings.use_image_hijack_canvas) { |
81 const SkImageInfo& info = raster_canvas->imageInfo(); | 94 const SkImageInfo& info = raster_canvas->imageInfo(); |
82 | 95 |
83 ImageHijackCanvas canvas(info.width(), info.height(), | 96 ImageHijackCanvas canvas(info.width(), info.height(), |
84 image_decode_controller_); | 97 image_decode_controller_); |
85 // Before adding the canvas, make sure that the ImageHijackCanvas is aware | 98 // Before adding the canvas, make sure that the ImageHijackCanvas is aware |
86 // of the current transform, which may affect the clip bounds. Since we | 99 // of the current transform and clip, which may affect the clip bounds. |
87 // query the clip bounds of the current canvas to get the list of draw | 100 // Since we query the clip bounds of the current canvas to get the list of |
88 // commands to process, this is important to produce correct content. | 101 // draw commands to process, this is important to produce correct content. |
102 SkIRect raster_bounds; | |
103 raster_canvas->getClipDeviceBounds(&raster_bounds); | |
104 canvas.clipRect(SkRect::MakeFromIRect(raster_bounds)); | |
89 canvas.setMatrix(raster_canvas->getTotalMatrix()); | 105 canvas.setMatrix(raster_canvas->getTotalMatrix()); |
90 canvas.addCanvas(raster_canvas); | 106 canvas.addCanvas(raster_canvas); |
91 | 107 |
92 RasterCommon(&canvas, nullptr, canvas_bitmap_rect, canvas_playback_rect, | 108 RasterCommon(&canvas, nullptr); |
93 contents_scale); | |
94 } else { | 109 } else { |
95 RasterCommon(raster_canvas, nullptr, canvas_bitmap_rect, | 110 RasterCommon(raster_canvas, nullptr); |
96 canvas_playback_rect, contents_scale); | |
97 } | 111 } |
98 } | 112 } |
99 | 113 |
100 void RasterSource::PrepareForPlaybackToCanvas( | 114 void RasterSource::PrepareForPlaybackToCanvas(SkCanvas* canvas) const { |
101 SkCanvas* canvas, | |
102 const gfx::Rect& canvas_bitmap_rect, | |
103 const gfx::Rect& canvas_playback_rect, | |
104 float contents_scale) const { | |
105 // TODO(hendrikw): See if we can split this up into separate functions. | 115 // TODO(hendrikw): See if we can split this up into separate functions. |
106 bool partial_update = canvas_bitmap_rect != canvas_playback_rect; | |
107 | 116 |
108 if (!partial_update) | 117 if (canvas->getClipStack()->quickContains( |
118 SkRect::MakeFromIRect(canvas->imageInfo().bounds()))) { | |
109 canvas->discard(); | 119 canvas->discard(); |
110 if (clear_canvas_with_debug_color_) { | |
111 // Any non-painted areas in the content bounds will be left in this color. | |
112 if (!partial_update) { | |
113 canvas->clear(DebugColors::NonPaintedFillColor()); | |
114 } else { | |
115 canvas->save(); | |
116 canvas->clipRect(gfx::RectToSkRect( | |
117 canvas_playback_rect - canvas_bitmap_rect.OffsetFromOrigin())); | |
118 canvas->drawColor(DebugColors::NonPaintedFillColor()); | |
119 canvas->restore(); | |
120 } | |
121 } | 120 } |
122 | 121 |
123 // If this raster source has opaque contents, it is guaranteeing that it will | 122 // If this raster source has opaque contents, it is guaranteeing that it will |
124 // draw an opaque rect the size of the layer. If it is not, then we must | 123 // draw an opaque rect the size of the layer. If it is not, then we must |
125 // clear this canvas ourselves. | 124 // clear this canvas ourselves. |
126 if (requires_clear_) { | 125 if (requires_clear_) { |
127 TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD); | 126 canvas->clear(SK_ColorTRANSPARENT); |
128 // Clearing is about ~4x faster than drawing a rect even if the content | 127 return; |
129 // isn't covering a majority of the canvas. | 128 } |
130 if (!partial_update) { | |
131 canvas->clear(SK_ColorTRANSPARENT); | |
132 } else { | |
133 canvas->save(); | |
134 canvas->clipRect(gfx::RectToSkRect( | |
135 canvas_playback_rect - canvas_bitmap_rect.OffsetFromOrigin())); | |
136 canvas->drawColor(SK_ColorTRANSPARENT, SkXfermode::kClear_Mode); | |
137 canvas->restore(); | |
138 } | |
139 } else { | |
140 // Even if completely covered, for rasterizations that touch the edge of the | |
141 // layer, we also need to raster the background color underneath the last | |
142 // texel (since the recording won't cover it) and outside the last texel | |
143 // (due to linear filtering when using this texture). | |
144 gfx::Rect content_rect = | |
145 gfx::ScaleToEnclosingRect(gfx::Rect(size_), contents_scale); | |
146 | 129 |
147 // The final texel of content may only be partially covered by a | 130 if (clear_canvas_with_debug_color_) |
148 // rasterization; this rect represents the content rect that is fully | 131 canvas->clear(DebugColors::NonPaintedFillColor()); |
149 // covered by content. | |
150 gfx::Rect deflated_content_rect = content_rect; | |
151 deflated_content_rect.Inset(0, 0, 1, 1); | |
152 deflated_content_rect.Intersect(canvas_playback_rect); | |
153 if (!deflated_content_rect.Contains(canvas_playback_rect)) { | |
154 if (clear_canvas_with_debug_color_) { | |
155 // Any non-painted areas outside of the content bounds are left in | |
156 // this color. If this is seen then it means that cc neglected to | |
157 // rerasterize a tile that used to intersect with the content rect | |
158 // after the content bounds grew. | |
159 canvas->save(); | |
160 canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); | |
161 canvas->clipRect(gfx::RectToSkRect(content_rect), | |
162 SkRegion::kDifference_Op); | |
163 canvas->drawColor(DebugColors::MissingResizeInvalidations(), | |
164 SkXfermode::kSrc_Mode); | |
165 canvas->restore(); | |
166 } | |
167 | 132 |
168 // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X | 133 // If the canvas wants us to raster with complex transform, it is hard to |
169 // faster than clearing, so special case this. | 134 // determine the exact region we must clear. Just clear everything. |
170 canvas->save(); | 135 // TODO(trchen): Optimize the common case that transformed content bounds |
171 canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); | 136 // covers the whole clip region. |
172 gfx::Rect inflated_content_rect = content_rect; | 137 if (!canvas->getTotalMatrix().rectStaysRect()) { |
173 // Only clear edges that will be inside the canvas_playback_rect, else we | 138 canvas->clear(SK_ColorTRANSPARENT); |
174 // clear things that are still valid from a previous raster. | 139 return; |
175 inflated_content_rect.Inset(0, 0, -1, -1); | |
176 inflated_content_rect.Intersect(canvas_playback_rect); | |
177 canvas->clipRect(gfx::RectToSkRect(inflated_content_rect), | |
178 SkRegion::kReplace_Op); | |
179 canvas->clipRect(gfx::RectToSkRect(deflated_content_rect), | |
180 SkRegion::kDifference_Op); | |
181 canvas->drawColor(background_color_, SkXfermode::kSrc_Mode); | |
182 canvas->restore(); | |
183 } | |
184 } | 140 } |
141 | |
142 SkRect content_device_rect; | |
143 canvas->getTotalMatrix().mapRect( | |
144 &content_device_rect, SkRect::MakeWH(size_.width(), size_.height())); | |
145 | |
146 // The final texel of content may only be partially covered by a | |
147 // rasterization; this rect represents the content rect that is fully | |
148 // covered by content. | |
149 SkIRect opaque_rect; | |
150 content_device_rect.roundIn(&opaque_rect); | |
151 | |
152 SkIRect raster_bounds; | |
153 canvas->getClipDeviceBounds(&raster_bounds); | |
154 | |
155 if (opaque_rect.contains(raster_bounds)) | |
156 return; | |
157 | |
158 // Even if completely covered, for rasterizations that touch the edge of the | |
159 // layer, we also need to raster the background color underneath the last | |
160 // texel (since the recording won't cover it) and outside the last texel | |
161 // (due to linear filtering when using this texture). | |
162 SkIRect interest_rect; | |
163 content_device_rect.roundOut(&interest_rect); | |
164 interest_rect.outset(1, 1); | |
165 | |
166 if (clear_canvas_with_debug_color_) { | |
167 // Any non-painted areas outside of the content bounds are left in | |
168 // this color. If this is seen then it means that cc neglected to | |
169 // rerasterize a tile that used to intersect with the content rect | |
170 // after the content bounds grew. | |
171 canvas->save(); | |
172 // Use clipRegion to bypass CTM because the rects are device rects. | |
173 SkRegion interest_region; | |
174 interest_region.setRect(interest_rect); | |
175 canvas->clipRegion(interest_region, SkRegion::kDifference_Op); | |
176 canvas->clear(DebugColors::MissingResizeInvalidations()); | |
177 canvas->restore(); | |
178 } | |
179 | |
180 // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X | |
enne (OOO)
2016/08/29 20:22:52
This comment seems no longer true.
| |
181 // faster than clearing, so special case this. | |
182 canvas->save(); | |
183 // Use clipRegion to bypass CTM because the rects are device rects. | |
184 SkRegion interest_region; | |
185 interest_region.setRect(interest_rect); | |
186 interest_region.op(opaque_rect, SkRegion::kDifference_Op); | |
187 canvas->clipRegion(interest_region); | |
188 canvas->clear(background_color_); | |
189 canvas->restore(); | |
185 } | 190 } |
186 | 191 |
187 void RasterSource::RasterCommon(SkCanvas* canvas, | 192 void RasterSource::RasterCommon(SkCanvas* canvas, |
188 SkPicture::AbortCallback* callback, | 193 SkPicture::AbortCallback* callback) const { |
189 const gfx::Rect& canvas_bitmap_rect, | |
190 const gfx::Rect& canvas_playback_rect, | |
191 float contents_scale) const { | |
192 canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); | |
193 gfx::Rect content_rect = | |
194 gfx::ScaleToEnclosingRect(gfx::Rect(size_), contents_scale); | |
195 content_rect.Intersect(canvas_playback_rect); | |
196 | |
197 canvas->clipRect(gfx::RectToSkRect(content_rect), SkRegion::kIntersect_Op); | |
198 | |
199 DCHECK(display_list_.get()); | 194 DCHECK(display_list_.get()); |
200 gfx::Rect canvas_target_playback_rect = | |
201 canvas_playback_rect - canvas_bitmap_rect.OffsetFromOrigin(); | |
202 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); | 195 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); |
203 for (int i = 0; i < repeat_count; ++i) { | 196 for (int i = 0; i < repeat_count; ++i) |
204 display_list_->Raster(canvas, callback, canvas_target_playback_rect, | 197 display_list_->Raster(canvas, callback); |
205 contents_scale); | |
206 } | |
207 } | 198 } |
208 | 199 |
209 sk_sp<SkPicture> RasterSource::GetFlattenedPicture() { | 200 sk_sp<SkPicture> RasterSource::GetFlattenedPicture() { |
210 TRACE_EVENT0("cc", "RasterSource::GetFlattenedPicture"); | 201 TRACE_EVENT0("cc", "RasterSource::GetFlattenedPicture"); |
211 | 202 |
212 gfx::Rect display_list_rect(size_); | |
213 SkPictureRecorder recorder; | 203 SkPictureRecorder recorder; |
214 SkCanvas* canvas = recorder.beginRecording(display_list_rect.width(), | 204 SkCanvas* canvas = recorder.beginRecording(size_.width(), size_.height()); |
215 display_list_rect.height()); | 205 if (!size_.IsEmpty()) { |
216 if (!display_list_rect.IsEmpty()) { | 206 PrepareForPlaybackToCanvas(canvas); |
217 PrepareForPlaybackToCanvas(canvas, display_list_rect, display_list_rect, | 207 RasterCommon(canvas, nullptr); |
218 1.f); | |
219 RasterCommon(canvas, nullptr, display_list_rect, display_list_rect, 1.f); | |
220 } | 208 } |
221 | 209 |
222 return recorder.finishRecordingAsPicture(); | 210 return recorder.finishRecordingAsPicture(); |
223 } | 211 } |
224 | 212 |
225 size_t RasterSource::GetPictureMemoryUsage() const { | 213 size_t RasterSource::GetPictureMemoryUsage() const { |
226 if (!display_list_) | 214 if (!display_list_) |
227 return 0; | 215 return 0; |
228 return display_list_->ApproximateMemoryUsage() + | 216 return display_list_->ApproximateMemoryUsage() + |
229 painter_reported_memory_usage_; | 217 painter_reported_memory_usage_; |
230 } | 218 } |
231 | 219 |
232 bool RasterSource::PerformSolidColorAnalysis(const gfx::Rect& content_rect, | 220 bool RasterSource::PerformSolidColorAnalysis(const gfx::Rect& content_rect, |
233 float contents_scale, | 221 float contents_scale, |
234 SkColor* color) const { | 222 SkColor* color) const { |
235 TRACE_EVENT0("cc", "RasterSource::PerformSolidColorAnalysis"); | 223 TRACE_EVENT0("cc", "RasterSource::PerformSolidColorAnalysis"); |
236 | 224 |
237 gfx::Rect layer_rect = | 225 gfx::Rect layer_rect = |
238 gfx::ScaleToEnclosingRect(content_rect, 1.0f / contents_scale); | 226 gfx::ScaleToEnclosingRect(content_rect, 1.0f / contents_scale); |
239 | 227 |
240 layer_rect.Intersect(gfx::Rect(size_)); | 228 layer_rect.Intersect(gfx::Rect(size_)); |
241 skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height()); | 229 skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height()); |
242 RasterCommon(&canvas, &canvas, layer_rect, layer_rect, 1.0f); | 230 canvas.translate(-layer_rect.x(), -layer_rect.y()); |
231 RasterCommon(&canvas, &canvas); | |
243 return canvas.GetColorIfSolid(color); | 232 return canvas.GetColorIfSolid(color); |
244 } | 233 } |
245 | 234 |
246 void RasterSource::GetDiscardableImagesInRect( | 235 void RasterSource::GetDiscardableImagesInRect( |
247 const gfx::Rect& layer_rect, | 236 const gfx::Rect& layer_rect, |
248 float raster_scale, | 237 float raster_scale, |
249 std::vector<DrawImage>* images) const { | 238 std::vector<DrawImage>* images) const { |
250 DCHECK_EQ(0u, images->size()); | 239 DCHECK_EQ(0u, images->size()); |
251 display_list_->GetDiscardableImagesInRect(layer_rect, raster_scale, images); | 240 display_list_->GetDiscardableImagesInRect(layer_rect, raster_scale, images); |
252 } | 241 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
312 DCHECK(image_decode_controller); | 301 DCHECK(image_decode_controller); |
313 image_decode_controller_ = image_decode_controller; | 302 image_decode_controller_ = image_decode_controller; |
314 } | 303 } |
315 | 304 |
316 RasterSource::PlaybackSettings::PlaybackSettings() | 305 RasterSource::PlaybackSettings::PlaybackSettings() |
317 : playback_to_shared_canvas(false), | 306 : playback_to_shared_canvas(false), |
318 skip_images(false), | 307 skip_images(false), |
319 use_image_hijack_canvas(true) {} | 308 use_image_hijack_canvas(true) {} |
320 | 309 |
321 } // namespace cc | 310 } // namespace cc |
OLD | NEW |