Chromium Code Reviews| 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 |