blob: 609311498dc831b36afa80031bcf82dfc3981af7 [file] [log] [blame]
Khushal7b546572017-11-10 22:05:531// Copyright 2017 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/paint/paint_op_buffer_serializer.h"
6
7#include "base/bind.h"
Khushal515436e22019-04-05 05:03:518#include "base/trace_event/trace_event.h"
Florin Malitae32b0b72017-12-08 00:50:249#include "cc/paint/scoped_raster_flags.h"
Khushal7b546572017-11-10 22:05:5310#include "ui/gfx/skia_util.h"
11
Adrienne Walker9e508a682019-03-06 20:21:2512#include <utility>
13
Khushal7b546572017-11-10 22:05:5314namespace cc {
Khushal92f66912017-11-20 10:08:5015namespace {
16
17class ScopedFlagsOverride {
18 public:
19 ScopedFlagsOverride(PaintOp::SerializeOptions* options,
20 const PaintFlags* flags)
21 : options_(options) {
22 options_->flags_to_serialize = flags;
23 }
24 ~ScopedFlagsOverride() { options_->flags_to_serialize = nullptr; }
25
26 private:
27 PaintOp::SerializeOptions* options_;
28};
29
danakj57baa772018-05-29 15:59:1430// Copied from viz::ClientResourceProvider.
Khushala8d50642018-05-03 01:29:0631SkSurfaceProps ComputeSurfaceProps(bool can_use_lcd_text) {
32 uint32_t flags = 0;
33 // Use unknown pixel geometry to disable LCD text.
34 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
35 if (can_use_lcd_text) {
36 // LegacyFontHost will get LCD text and skia figures out what type to use.
37 surface_props =
38 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
39 }
40 return surface_props;
41}
42
43PlaybackParams MakeParams(const SkCanvas* canvas) {
44 // We don't use an ImageProvider here since the ops are played onto a no-draw
45 // canvas for state tracking and don't need decoded images.
46 return PlaybackParams(nullptr, canvas->getTotalMatrix());
47}
48
49// Use half of the max int as the extent for the SkNoDrawCanvas. The correct
50// clip is applied to the canvas during serialization.
51const int kMaxExtent = std::numeric_limits<int>::max() >> 1;
52
Khushal92f66912017-11-20 10:08:5053} // namespace
Khushal7b546572017-11-10 22:05:5354
Vladimir Levin7273cfe052017-12-13 21:41:4155PaintOpBufferSerializer::PaintOpBufferSerializer(
56 SerializeCallback serialize_cb,
57 ImageProvider* image_provider,
Khushala8d50642018-05-03 01:29:0658 TransferCacheSerializeHelper* transfer_cache,
Khushal33205a72018-11-08 10:12:2959 ClientPaintCache* paint_cache,
Khushala8d50642018-05-03 01:29:0660 SkStrikeServer* strike_server,
Adrienne Walker9e508a682019-03-06 20:21:2561 sk_sp<SkColorSpace> color_space,
Khushal315f2fd2018-05-29 03:20:3962 bool can_use_lcd_text,
Khushalf9750702018-06-09 00:42:1363 bool context_supports_distance_field_text,
64 int max_texture_size,
65 size_t max_texture_bytes)
Khushal7b546572017-11-10 22:05:5366 : serialize_cb_(std::move(serialize_cb)),
Vladimir Levin7273cfe052017-12-13 21:41:4167 image_provider_(image_provider),
Khushala8d50642018-05-03 01:29:0668 transfer_cache_(transfer_cache),
Khushal33205a72018-11-08 10:12:2969 paint_cache_(paint_cache),
Khushala8d50642018-05-03 01:29:0670 strike_server_(strike_server),
71 color_space_(color_space),
72 can_use_lcd_text_(can_use_lcd_text),
Khushal315f2fd2018-05-29 03:20:3973 context_supports_distance_field_text_(
74 context_supports_distance_field_text),
Khushal515436e22019-04-05 05:03:5175 max_texture_size_(max_texture_size),
76 max_texture_bytes_(max_texture_bytes),
Khushalf9750702018-06-09 00:42:1377 text_blob_canvas_(kMaxExtent,
78 kMaxExtent,
Khushalf9750702018-06-09 00:42:1379 ComputeSurfaceProps(can_use_lcd_text),
80 strike_server,
Adrienne Walker9e508a682019-03-06 20:21:2581 std::move(color_space),
Herb Derbye2c214ab2019-08-19 21:54:3382 context_supports_distance_field_text) {
Khushal7b546572017-11-10 22:05:5383 DCHECK(serialize_cb_);
84}
85
86PaintOpBufferSerializer::~PaintOpBufferSerializer() = default;
87
88void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer,
89 const std::vector<size_t>* offsets,
90 const Preamble& preamble) {
Mike Reed16127012019-02-25 18:44:3691 DCHECK(text_blob_canvas_.getTotalMatrix().isIdentity());
Eric Karl9c2725622018-01-06 00:35:3292 static const int kInitialSaveCount = 1;
Mike Reed16127012019-02-25 18:44:3693 DCHECK_EQ(kInitialSaveCount, text_blob_canvas_.getSaveCount());
Eric Karl9c2725622018-01-06 00:35:3294
95 // These SerializeOptions and PlaybackParams use the initial (identity) canvas
96 // matrix, as they are only used for serializing the preamble and the initial
97 // save / final restore. SerializeBuffer will create its own SerializeOptions
98 // and PlaybackParams based on the post-preamble canvas.
Khushalf9750702018-06-09 00:42:1399 PaintOp::SerializeOptions options = MakeSerializeOptions();
Mike Reed16127012019-02-25 18:44:36100 PlaybackParams params = MakeParams(&text_blob_canvas_);
Khushal7b546572017-11-10 22:05:53101
Khushal7b546572017-11-10 22:05:53102 Save(options, params);
103 SerializePreamble(preamble, options, params);
104 SerializeBuffer(buffer, offsets);
Eric Karl9c2725622018-01-06 00:35:32105 RestoreToCount(kInitialSaveCount, options, params);
Khushal7b546572017-11-10 22:05:53106}
107
Vladimir Levinbd083f782018-01-12 23:26:09108void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer) {
Mike Reed16127012019-02-25 18:44:36109 DCHECK(text_blob_canvas_.getTotalMatrix().isIdentity());
Vladimir Levinbd083f782018-01-12 23:26:09110
111 SerializeBuffer(buffer, nullptr);
112}
113
Khushalec01f3472018-05-19 00:36:26114void PaintOpBufferSerializer::Serialize(
115 const PaintOpBuffer* buffer,
116 const gfx::Rect& playback_rect,
117 const gfx::SizeF& post_scale,
118 const SkMatrix& post_matrix_for_analysis) {
Mike Reed16127012019-02-25 18:44:36119 DCHECK(text_blob_canvas_.getTotalMatrix().isIdentity());
Adrienne Walker51c8e382018-02-06 20:30:33120
Khushalf9750702018-06-09 00:42:13121 PaintOp::SerializeOptions options = MakeSerializeOptions();
Mike Reed16127012019-02-25 18:44:36122 PlaybackParams params = MakeParams(&text_blob_canvas_);
Adrienne Walker51c8e382018-02-06 20:30:33123
124 // TODO(khushalsagar): remove this clip rect if it's not needed.
125 if (!playback_rect.IsEmpty()) {
126 ClipRectOp clip_op(gfx::RectToSkRect(playback_rect), SkClipOp::kIntersect,
127 false);
128 SerializeOp(&clip_op, options, params);
129 }
130
131 if (post_scale.width() != 1.f || post_scale.height() != 1.f) {
132 ScaleOp scale_op(post_scale.width(), post_scale.height());
133 SerializeOp(&scale_op, options, params);
134 }
135
Mike Reed16127012019-02-25 18:44:36136 text_blob_canvas_.concat(post_matrix_for_analysis);
Adrienne Walker51c8e382018-02-06 20:30:33137 SerializeBuffer(buffer, nullptr);
138}
139
Adrienne Walker93001342018-06-12 22:08:40140// This function needs to have the exact same behavior as
141// RasterSource::ClearForOpaqueRaster.
142void PaintOpBufferSerializer::ClearForOpaqueRaster(
143 const Preamble& preamble,
144 const PaintOp::SerializeOptions& options,
145 const PlaybackParams& params) {
146 // Clear opaque raster sources. Opaque rasters sources guarantee that all
147 // pixels inside the opaque region are painted. However, due to scaling
148 // it's possible that the last row and column might include pixels that
149 // are not painted. Because this raster source is required to be opaque,
150 // we may need to do extra clearing outside of the clip. This needs to
151 // be done for both full and partial raster.
152
153 // The last texel of this content is not guaranteed to be fully opaque, so
154 // inset by one to generate the fully opaque coverage rect. This rect is
155 // in device space.
156 SkIRect coverage_device_rect = SkIRect::MakeWH(
157 preamble.content_size.width() - preamble.full_raster_rect.x() - 1,
158 preamble.content_size.height() - preamble.full_raster_rect.y() - 1);
159
160 // If not fully covered, we need to clear one texel inside the coverage
161 // rect (because of blending during raster) and one texel outside the canvas
162 // bitmap rect (because of bilinear filtering during draw). See comments
163 // in RasterSource.
164 SkIRect device_column = SkIRect::MakeXYWH(coverage_device_rect.right(), 0, 2,
165 coverage_device_rect.bottom());
166 // row includes the corner, column excludes it.
167 SkIRect device_row = SkIRect::MakeXYWH(0, coverage_device_rect.bottom(),
168 coverage_device_rect.right() + 2, 2);
169
170 bool right_edge =
171 preamble.content_size.width() == preamble.playback_rect.right();
172 bool bottom_edge =
173 preamble.content_size.height() == preamble.playback_rect.bottom();
174
175 // If the playback rect is touching either edge of the content rect
176 // extend it by one pixel to include the extra texel outside the canvas
177 // bitmap rect that was added to device column and row above.
178 SkIRect playback_device_rect = SkIRect::MakeXYWH(
179 preamble.playback_rect.x() - preamble.full_raster_rect.x(),
180 preamble.playback_rect.y() - preamble.full_raster_rect.y(),
181 preamble.playback_rect.width() + (right_edge ? 1 : 0),
182 preamble.playback_rect.height() + (bottom_edge ? 1 : 0));
183
184 // Intersect the device column and row with the playback rect and only
185 // clear inside of that rect if needed.
186 if (device_column.intersect(playback_device_rect)) {
187 Save(options, params);
Mike Kleinb3da5222018-10-04 17:56:44188 ClipRectOp clip_op(SkRect::Make(device_column), SkClipOp::kIntersect,
189 false);
Adrienne Walker93001342018-06-12 22:08:40190 SerializeOp(&clip_op, options, params);
191 DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
192 SerializeOp(&clear_op, options, params);
193 RestoreToCount(1, options, params);
194 }
195 if (device_row.intersect(playback_device_rect)) {
196 Save(options, params);
Mike Kleinb3da5222018-10-04 17:56:44197 ClipRectOp clip_op(SkRect::Make(device_row), SkClipOp::kIntersect, false);
Adrienne Walker93001342018-06-12 22:08:40198 SerializeOp(&clip_op, options, params);
199 DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
200 SerializeOp(&clear_op, options, params);
201 RestoreToCount(1, options, params);
202 }
203}
204
Khushal7b546572017-11-10 22:05:53205void PaintOpBufferSerializer::SerializePreamble(
206 const Preamble& preamble,
207 const PaintOp::SerializeOptions& options,
208 const PlaybackParams& params) {
Adrienne Walker51c8e382018-02-06 20:30:33209 DCHECK(preamble.full_raster_rect.Contains(preamble.playback_rect))
210 << "full: " << preamble.full_raster_rect.ToString()
211 << ", playback: " << preamble.playback_rect.ToString();
212
Adrienne Walker51c8e382018-02-06 20:30:33213 bool is_partial_raster = preamble.full_raster_rect != preamble.playback_rect;
Adrienne Walker93001342018-06-12 22:08:40214 if (!preamble.requires_clear) {
215 ClearForOpaqueRaster(preamble, options, params);
216 } else if (!is_partial_raster) {
217 // If rastering the entire tile, clear to transparent pre-clip. This is so
218 // that any external texels outside of the playback rect also get cleared.
219 // There's not enough information at this point to know if this texture is
220 // being reused from another tile, so the external texels could have been
221 // cleared to some wrong value.
Adrienne Walker51c8e382018-02-06 20:30:33222 DrawColorOp clear(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
223 SerializeOp(&clear, options, params);
Adrienne Walker51c8e382018-02-06 20:30:33224 }
225
226 if (!preamble.full_raster_rect.OffsetFromOrigin().IsZero()) {
227 TranslateOp translate_op(-preamble.full_raster_rect.x(),
228 -preamble.full_raster_rect.y());
Khushal7b546572017-11-10 22:05:53229 SerializeOp(&translate_op, options, params);
230 }
231
232 if (!preamble.playback_rect.IsEmpty()) {
Adrienne Walker51c8e382018-02-06 20:30:33233 ClipRectOp clip_op(gfx::RectToSkRect(preamble.playback_rect),
Khushal9fd411f2018-01-20 02:09:51234 SkClipOp::kIntersect, false);
Khushal7b546572017-11-10 22:05:53235 SerializeOp(&clip_op, options, params);
236 }
237
238 if (!preamble.post_translation.IsZero()) {
239 TranslateOp translate_op(preamble.post_translation.x(),
240 preamble.post_translation.y());
Khushal7b546572017-11-10 22:05:53241 SerializeOp(&translate_op, options, params);
242 }
243
Khushal9fd411f2018-01-20 02:09:51244 if (preamble.post_scale.width() != 1.f ||
245 preamble.post_scale.height() != 1.f) {
246 ScaleOp scale_op(preamble.post_scale.width(), preamble.post_scale.height());
Khushal7b546572017-11-10 22:05:53247 SerializeOp(&scale_op, options, params);
248 }
Adrienne Walker51c8e382018-02-06 20:30:33249
250 // If tile is transparent and this is partial raster, just clear the
251 // section that is being rastered. If this is opaque, trust the raster
252 // to write all the pixels inside of the full_raster_rect.
253 if (preamble.requires_clear && is_partial_raster) {
254 DrawColorOp clear_op(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
255 SerializeOp(&clear_op, options, params);
256 }
Khushal7b546572017-11-10 22:05:53257}
258
259void PaintOpBufferSerializer::SerializeBuffer(
260 const PaintOpBuffer* buffer,
261 const std::vector<size_t>* offsets) {
Vladimir Levinbd083f782018-01-12 23:26:09262 DCHECK(buffer);
Khushalf9750702018-06-09 00:42:13263 PaintOp::SerializeOptions options = MakeSerializeOptions();
Mike Reed16127012019-02-25 18:44:36264 PlaybackParams params = MakeParams(&text_blob_canvas_);
Khushal7b546572017-11-10 22:05:53265
Khushal92f66912017-11-20 10:08:50266 for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter;
267 ++iter) {
Khushal7b546572017-11-10 22:05:53268 const PaintOp* op = *iter;
269
270 // Skip ops outside the current clip if they have images. This saves
271 // performing an unnecessary expensive decode.
272 const bool skip_op = PaintOp::OpHasDiscardableImages(op) &&
Mike Reed16127012019-02-25 18:44:36273 PaintOp::QuickRejectDraw(op, &text_blob_canvas_);
Khushal7b546572017-11-10 22:05:53274 if (skip_op)
275 continue;
276
277 if (op->GetType() != PaintOpType::DrawRecord) {
Khushal92f66912017-11-20 10:08:50278 bool success = false;
279 if (op->IsPaintOpWithFlags()) {
280 success = SerializeOpWithFlags(static_cast<const PaintOpWithFlags*>(op),
281 &options, params, iter.alpha());
282 } else {
283 success = SerializeOp(op, options, params);
284 }
285
286 if (!success)
Khushal7b546572017-11-10 22:05:53287 return;
288 continue;
289 }
290
Mike Reed16127012019-02-25 18:44:36291 int save_count = text_blob_canvas_.getSaveCount();
Khushal7b546572017-11-10 22:05:53292 Save(options, params);
293 SerializeBuffer(static_cast<const DrawRecordOp*>(op)->record.get(),
294 nullptr);
295 RestoreToCount(save_count, options, params);
296 }
297}
298
Khushal92f66912017-11-20 10:08:50299bool PaintOpBufferSerializer::SerializeOpWithFlags(
300 const PaintOpWithFlags* flags_op,
301 PaintOp::SerializeOptions* options,
302 const PlaybackParams& params,
303 uint8_t alpha) {
Khushal67c8c742018-05-16 18:05:05304 // We use a null |image_provider| here because images are decoded during
305 // serialization.
Khushal515436e22019-04-05 05:03:51306 const ScopedRasterFlags scoped_flags(&flags_op->flags, nullptr,
307 options->canvas->getTotalMatrix(),
308 max_texture_size_, alpha);
Florin Malitae32b0b72017-12-08 00:50:24309 const PaintFlags* flags_to_serialize = scoped_flags.flags();
Khushal92f66912017-11-20 10:08:50310 if (!flags_to_serialize)
311 return true;
312
313 ScopedFlagsOverride override_flags(options, flags_to_serialize);
314 return SerializeOp(flags_op, *options, params);
315}
316
Khushal7b546572017-11-10 22:05:53317bool PaintOpBufferSerializer::SerializeOp(
318 const PaintOp* op,
319 const PaintOp::SerializeOptions& options,
320 const PlaybackParams& params) {
Khushal515436e22019-04-05 05:03:51321 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
322 "PaintOpBufferSerializer::SerializeOp", "op",
323 PaintOpTypeToString(op->GetType()));
Khushal7b546572017-11-10 22:05:53324 if (!valid_)
325 return false;
326
Khushale22734582019-02-23 03:38:49327 // Playback on analysis canvas first to make sure the canvas transform is set
328 // correctly for analysis of records in filters.
329 PlaybackOnAnalysisCanvas(op, options, params);
330
Khushal7b546572017-11-10 22:05:53331 size_t bytes = serialize_cb_.Run(op, options);
332 if (!bytes) {
333 valid_ = false;
334 return false;
335 }
336
337 DCHECK_GE(bytes, 4u);
338 DCHECK_EQ(bytes % PaintOpBuffer::PaintOpAlign, 0u);
Khushale22734582019-02-23 03:38:49339 return true;
340}
Khushal7b546572017-11-10 22:05:53341
Khushale22734582019-02-23 03:38:49342void PaintOpBufferSerializer::PlaybackOnAnalysisCanvas(
343 const PaintOp* op,
344 const PaintOp::SerializeOptions& options,
345 const PlaybackParams& params) {
Khushalee6bf43f2018-07-10 01:46:11346 // Only 2 types of ops need to played on the analysis canvas.
347 // 1) Non-draw ops which affect the transform/clip state on the canvas, since
348 // we need the correct ctm at which text and images will be rasterized, and
349 // the clip rect so we can skip sending data for ops which will not be
350 // rasterized.
351 // 2) DrawTextBlob ops since they need to be analyzed by the cache diff canvas
352 // to serialize/lock the requisite glyphs for this op.
353 if (op->IsDrawOp() && op->GetType() != PaintOpType::DrawTextBlob)
Khushale22734582019-02-23 03:38:49354 return;
Khushalee6bf43f2018-07-10 01:46:11355
Khushala8d50642018-05-03 01:29:06356 if (op->IsPaintOpWithFlags() && options.flags_to_serialize) {
357 static_cast<const PaintOpWithFlags*>(op)->RasterWithFlags(
Mike Reed16127012019-02-25 18:44:36358 &text_blob_canvas_, options.flags_to_serialize, params);
Khushala8d50642018-05-03 01:29:06359 } else {
Mike Reed16127012019-02-25 18:44:36360 op->Raster(&text_blob_canvas_, params);
Khushal92f66912017-11-20 10:08:50361 }
Khushal7b546572017-11-10 22:05:53362}
363
364void PaintOpBufferSerializer::Save(const PaintOp::SerializeOptions& options,
365 const PlaybackParams& params) {
366 SaveOp save_op;
Khushal7b546572017-11-10 22:05:53367 SerializeOp(&save_op, options, params);
368}
369
370void PaintOpBufferSerializer::RestoreToCount(
371 int count,
372 const PaintOp::SerializeOptions& options,
373 const PlaybackParams& params) {
374 RestoreOp restore_op;
Mike Reed16127012019-02-25 18:44:36375 while (text_blob_canvas_.getSaveCount() > count) {
Khushal7b546572017-11-10 22:05:53376 if (!SerializeOp(&restore_op, options, params))
377 return;
378 }
379}
380
Khushalf9750702018-06-09 00:42:13381PaintOp::SerializeOptions PaintOpBufferSerializer::MakeSerializeOptions() {
382 return PaintOp::SerializeOptions(
Mike Reed16127012019-02-25 18:44:36383 image_provider_, transfer_cache_, paint_cache_, &text_blob_canvas_,
384 strike_server_, color_space_, can_use_lcd_text_,
385 context_supports_distance_field_text_, max_texture_size_,
386 max_texture_bytes_, text_blob_canvas_.getTotalMatrix());
Khushalf9750702018-06-09 00:42:13387}
388
Vladimir Levin7273cfe052017-12-13 21:41:41389SimpleBufferSerializer::SimpleBufferSerializer(
390 void* memory,
391 size_t size,
392 ImageProvider* image_provider,
Khushala8d50642018-05-03 01:29:06393 TransferCacheSerializeHelper* transfer_cache,
Khushal33205a72018-11-08 10:12:29394 ClientPaintCache* paint_cache,
Khushala8d50642018-05-03 01:29:06395 SkStrikeServer* strike_server,
Adrienne Walker9e508a682019-03-06 20:21:25396 sk_sp<SkColorSpace> color_space,
Khushal315f2fd2018-05-29 03:20:39397 bool can_use_lcd_text,
Khushalf9750702018-06-09 00:42:13398 bool context_supports_distance_field_text,
399 int max_texture_size,
400 size_t max_texture_bytes)
Khushal7b546572017-11-10 22:05:53401 : PaintOpBufferSerializer(
kylechar4bb144d2019-01-11 20:42:07402 base::BindRepeating(&SimpleBufferSerializer::SerializeToMemory,
403 base::Unretained(this)),
Vladimir Levin7273cfe052017-12-13 21:41:41404 image_provider,
Khushala8d50642018-05-03 01:29:06405 transfer_cache,
Khushal33205a72018-11-08 10:12:29406 paint_cache,
Khushala8d50642018-05-03 01:29:06407 strike_server,
Adrienne Walker9e508a682019-03-06 20:21:25408 std::move(color_space),
Khushal315f2fd2018-05-29 03:20:39409 can_use_lcd_text,
Khushalf9750702018-06-09 00:42:13410 context_supports_distance_field_text,
411 max_texture_size,
412 max_texture_bytes),
Khushal7b546572017-11-10 22:05:53413 memory_(memory),
414 total_(size) {}
415
416SimpleBufferSerializer::~SimpleBufferSerializer() = default;
417
418size_t SimpleBufferSerializer::SerializeToMemory(
419 const PaintOp* op,
420 const PaintOp::SerializeOptions& options) {
421 if (written_ == total_)
422 return 0u;
423
424 size_t bytes = op->Serialize(static_cast<char*>(memory_) + written_,
425 total_ - written_, options);
426 if (!bytes)
427 return 0u;
428
429 written_ += bytes;
430 DCHECK_GE(total_, written_);
431 return bytes;
432}
433
434} // namespace cc