123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "cc/paint/paint_op_buffer_serializer.h"
- #include <limits>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/trace_event/trace_event.h"
- #include "cc/paint/clear_for_opaque_raster.h"
- #include "cc/paint/scoped_raster_flags.h"
- #include "skia/ext/legacy_display_globals.h"
- #include "third_party/skia/include/core/SkColorSpace.h"
- #include "ui/gfx/geometry/skia_conversions.h"
- namespace cc {
- namespace {
- PlaybackParams MakeParams(const SkCanvas* canvas) {
- // We don't use an ImageProvider here since the ops are played onto a no-draw
- // canvas for state tracking and don't need decoded images.
- PlaybackParams params(nullptr, canvas->getLocalToDevice());
- params.is_analyzing = true;
- return params;
- }
- std::unique_ptr<SkCanvas> MakeAnalysisCanvas(
- const PaintOp::SerializeOptions& options) {
- // Use half of the max int as the extent for the SkNoDrawCanvas. The correct
- // clip is applied to the canvas during serialization.
- const int kMaxExtent = std::numeric_limits<int>::max() >> 1;
- return options.strike_server
- ? options.strike_server->makeAnalysisCanvas(
- kMaxExtent, kMaxExtent,
- skia::LegacyDisplayGlobals::ComputeSurfaceProps(
- options.can_use_lcd_text),
- options.color_space,
- options.context_supports_distance_field_text)
- : std::make_unique<SkNoDrawCanvas>(kMaxExtent, kMaxExtent);
- }
- } // namespace
- PaintOpBufferSerializer::PaintOpBufferSerializer(
- SerializeCallback serialize_cb,
- const PaintOp::SerializeOptions& options)
- : serialize_cb_(std::move(serialize_cb)), options_(options) {
- DCHECK(serialize_cb_);
- }
- PaintOpBufferSerializer::~PaintOpBufferSerializer() = default;
- void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets,
- const Preamble& preamble) {
- std::unique_ptr<SkCanvas> canvas = MakeAnalysisCanvas(options_);
- // These PlaybackParams use the initial (identity) canvas matrix, as they are
- // only used for serializing the preamble and the initial save / final restore
- // SerializeBuffer will create its own PlaybackParams based on the
- // post-preamble canvas.
- PlaybackParams params = MakeParams(canvas.get());
- int saveCount = canvas->getSaveCount();
- Save(canvas.get(), params);
- SerializePreamble(canvas.get(), preamble, params);
- SerializeBuffer(canvas.get(), buffer, offsets);
- RestoreToCount(canvas.get(), saveCount, params);
- }
- void PaintOpBufferSerializer::SerializeAndDestroy(
- PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets,
- const Preamble& preamble) {
- std::unique_ptr<SkCanvas> canvas = MakeAnalysisCanvas(options_);
- // These PlaybackParams use the initial (identity) canvas matrix, as they are
- // only used for serializing the preamble and the initial save / final restore
- // SerializeBuffer will create its own PlaybackParams based on the
- // post-preamble canvas.
- PlaybackParams params = MakeParams(canvas.get());
- int saveCount = canvas->getSaveCount();
- Save(canvas.get(), params);
- SerializePreamble(canvas.get(), preamble, params);
- SerializeBufferAndDestroy(canvas.get(), buffer, offsets);
- RestoreToCount(canvas.get(), saveCount, params);
- }
- void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer) {
- std::unique_ptr<SkCanvas> canvas = MakeAnalysisCanvas(options_);
- SerializeBuffer(canvas.get(), buffer, nullptr);
- }
- void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer,
- const gfx::Rect& playback_rect,
- const gfx::SizeF& post_scale) {
- std::unique_ptr<SkCanvas> canvas = MakeAnalysisCanvas(options_);
- PlaybackParams params = MakeParams(canvas.get());
- // TODO(khushalsagar): remove this clip rect if it's not needed.
- if (!playback_rect.IsEmpty()) {
- ClipRectOp clip_op(gfx::RectToSkRect(playback_rect), SkClipOp::kIntersect,
- false);
- SerializeOp(canvas.get(), &clip_op, nullptr, params);
- }
- if (post_scale.width() != 1.f || post_scale.height() != 1.f) {
- ScaleOp scale_op(post_scale.width(), post_scale.height());
- SerializeOp(canvas.get(), &scale_op, nullptr, params);
- }
- SerializeBuffer(canvas.get(), buffer, nullptr);
- }
- // This function needs to have the exact same behavior as
- // RasterSource::ClearForOpaqueRaster.
- void PaintOpBufferSerializer::ClearForOpaqueRaster(
- SkCanvas* canvas,
- const Preamble& preamble,
- const PlaybackParams& params) {
- gfx::Rect outer_rect;
- gfx::Rect inner_rect;
- if (!CalculateClearForOpaqueRasterRects(
- preamble.post_translation, preamble.post_scale, preamble.content_size,
- preamble.full_raster_rect, preamble.playback_rect, outer_rect,
- inner_rect))
- return;
- Save(canvas, params);
- ClipRectOp outer_clip_op(gfx::RectToSkRect(outer_rect), SkClipOp::kIntersect,
- false);
- SerializeOp(canvas, &outer_clip_op, nullptr, params);
- if (!inner_rect.IsEmpty()) {
- ClipRectOp inner_clip_op(gfx::RectToSkRect(inner_rect),
- SkClipOp::kDifference, false);
- SerializeOp(canvas, &inner_clip_op, nullptr, params);
- }
- DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
- SerializeOp(canvas, &clear_op, nullptr, params);
- RestoreToCount(canvas, 1, params);
- }
- void PaintOpBufferSerializer::SerializePreamble(SkCanvas* canvas,
- const Preamble& preamble,
- const PlaybackParams& params) {
- DCHECK(preamble.full_raster_rect.Contains(preamble.playback_rect))
- << "full: " << preamble.full_raster_rect.ToString()
- << ", playback: " << preamble.playback_rect.ToString();
- // NOTE: The following code should be kept consistent with
- // RasterSource::PlaybackToCanvas().
- bool is_partial_raster = preamble.full_raster_rect != preamble.playback_rect;
- if (!preamble.requires_clear) {
- ClearForOpaqueRaster(canvas, preamble, params);
- } else if (!is_partial_raster) {
- // If rastering the entire tile, clear to transparent pre-clip. This is so
- // that any external texels outside of the playback rect also get cleared.
- // There's not enough information at this point to know if this texture is
- // being reused from another tile, so the external texels could have been
- // cleared to some wrong value.
- DrawColorOp clear(SkColors::kTransparent, SkBlendMode::kSrc);
- SerializeOp(canvas, &clear, nullptr, params);
- }
- if (!preamble.full_raster_rect.OffsetFromOrigin().IsZero()) {
- TranslateOp translate_op(-preamble.full_raster_rect.x(),
- -preamble.full_raster_rect.y());
- SerializeOp(canvas, &translate_op, nullptr, params);
- }
- if (!preamble.playback_rect.IsEmpty()) {
- ClipRectOp clip_op(gfx::RectToSkRect(preamble.playback_rect),
- SkClipOp::kIntersect, false);
- SerializeOp(canvas, &clip_op, nullptr, params);
- }
- if (!preamble.post_translation.IsZero()) {
- TranslateOp translate_op(preamble.post_translation.x(),
- preamble.post_translation.y());
- SerializeOp(canvas, &translate_op, nullptr, params);
- }
- if (preamble.post_scale.x() != 1.f || preamble.post_scale.y() != 1.f) {
- ScaleOp scale_op(preamble.post_scale.x(), preamble.post_scale.y());
- SerializeOp(canvas, &scale_op, nullptr, params);
- }
- // If tile is transparent and this is partial raster, just clear the
- // section that is being rastered. If this is opaque, trust the raster
- // to write all the pixels inside of the full_raster_rect.
- if (preamble.requires_clear && is_partial_raster) {
- DrawColorOp clear_op(SkColors::kTransparent, SkBlendMode::kSrc);
- SerializeOp(canvas, &clear_op, nullptr, params);
- }
- }
- bool PaintOpBufferSerializer::WillSerializeNextOp(const PaintOp* op,
- SkCanvas* canvas,
- PlaybackParams params,
- uint8_t alpha) {
- // Skip ops outside the current clip if they have images. This saves
- // performing an unnecessary expensive decode.
- bool skip_op = PaintOp::OpHasDiscardableImages(op) &&
- PaintOp::QuickRejectDraw(op, canvas);
- // Skip text ops if there is no SkStrikeServer.
- skip_op |=
- op->GetType() == PaintOpType::DrawTextBlob && !options_.strike_server;
- if (skip_op)
- return true;
- if (op->GetType() == PaintOpType::DrawRecord) {
- int save_count = canvas->getSaveCount();
- Save(canvas, params);
- SerializeBuffer(canvas, static_cast<const DrawRecordOp*>(op)->record.get(),
- nullptr);
- RestoreToCount(canvas, save_count, params);
- return true;
- }
- if (op->GetType() == PaintOpType::DrawImageRect &&
- static_cast<const DrawImageRectOp*>(op)->image.IsPaintWorklet()) {
- DCHECK(options_.image_provider);
- const DrawImageRectOp* draw_op = static_cast<const DrawImageRectOp*>(op);
- ImageProvider::ScopedResult result =
- options_.image_provider->GetRasterContent(DrawImage(draw_op->image));
- if (!result || !result.paint_record())
- return true;
- int save_count = canvas->getSaveCount();
- Save(canvas, params);
- // The following ops are copying the canvas's ops from
- // DrawImageRectOp::RasterWithFlags.
- SkM44 trans = SkM44(SkMatrix::RectToRect(draw_op->src, draw_op->dst));
- ConcatOp concat_op(trans);
- bool success = SerializeOp(canvas, &concat_op, nullptr, params);
- if (!success)
- return false;
- ClipRectOp clip_rect_op(draw_op->src, SkClipOp::kIntersect, false);
- success = SerializeOp(canvas, &clip_rect_op, nullptr, params);
- if (!success)
- return false;
- // In DrawImageRectOp::RasterWithFlags, the save layer uses the
- // flags_to_serialize or default(null) flags. At this point in the
- // serialization, flags_to_serialize is always null as well.
- SaveLayerOp save_layer_op(&draw_op->src, nullptr);
- success = SerializeOpWithFlags(canvas, &save_layer_op, params, 255);
- if (!success)
- return false;
- SerializeBuffer(canvas, result.paint_record(), nullptr);
- RestoreToCount(canvas, save_count, params);
- return true;
- } else {
- if (op->IsPaintOpWithFlags()) {
- return SerializeOpWithFlags(
- canvas, static_cast<const PaintOpWithFlags*>(op), params, alpha);
- } else {
- return SerializeOp(canvas, op, nullptr, params);
- }
- }
- }
- void PaintOpBufferSerializer::SerializeBuffer(
- SkCanvas* canvas,
- const PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets) {
- DCHECK(buffer);
- // This updates the original_ctm to reflect the canvas transformation at
- // start of this call to SerializeBuffer.
- PlaybackParams params = MakeParams(canvas);
- for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter;
- ++iter) {
- const PaintOp* op = *iter;
- if (!WillSerializeNextOp(op, canvas, params, iter.alpha())) {
- return;
- }
- }
- }
- void PaintOpBufferSerializer::SerializeBufferAndDestroy(
- SkCanvas* canvas,
- PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets) {
- DCHECK(buffer);
- // This updates the original_ctm to reflect the canvas transformation at
- // start of this call to SerializeBuffer.
- PlaybackParams params = MakeParams(canvas);
- bool destroy_op_only = false;
- for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter;
- ++iter) {
- PaintOp* op = const_cast<PaintOp*>(*iter);
- if (!destroy_op_only) {
- // If serialization failed, destroy PaintOps in |buffer|.
- destroy_op_only = !WillSerializeNextOp(op, canvas, params, iter.alpha());
- }
- op->DestroyThis();
- }
- // Each PaintOp in |buffer| is destroyed. Update the flag |ops_destroyed| to
- // true, so it skip calling destruction in PaintOpsBuffer::Reset().
- const_cast<PaintOpBuffer*>(buffer)->MarkOpsDestroyed();
- }
- bool PaintOpBufferSerializer::SerializeOpWithFlags(
- SkCanvas* canvas,
- const PaintOpWithFlags* flags_op,
- const PlaybackParams& params,
- uint8_t alpha) {
- // We use a null |image_provider| here because images are decoded during
- // serialization.
- const ScopedRasterFlags scoped_flags(
- &flags_op->flags, nullptr, canvas->getTotalMatrix(),
- options_.max_texture_size, alpha / 255.0f);
- const PaintFlags* flags_to_serialize = scoped_flags.flags();
- if (!flags_to_serialize)
- return true;
- return SerializeOp(canvas, flags_op, flags_to_serialize, params);
- }
- bool PaintOpBufferSerializer::SerializeOp(SkCanvas* canvas,
- const PaintOp* op,
- const PaintFlags* flags_to_serialize,
- const PlaybackParams& params) {
- TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "PaintOpBufferSerializer::SerializeOp", "op",
- PaintOpTypeToString(op->GetType()));
- if (!valid_)
- return false;
- // Playback on analysis canvas first to make sure the canvas transform is set
- // correctly for analysis of records in filters.
- PlaybackOnAnalysisCanvas(canvas, op, flags_to_serialize, params);
- size_t bytes =
- serialize_cb_.Run(op, options_, flags_to_serialize,
- canvas->getLocalToDevice(), params.original_ctm);
- if (!bytes) {
- valid_ = false;
- return false;
- }
- DCHECK_GE(bytes, 4u);
- DCHECK_EQ(bytes % PaintOpBuffer::PaintOpAlign, 0u);
- return true;
- }
- void PaintOpBufferSerializer::PlaybackOnAnalysisCanvas(
- SkCanvas* canvas,
- const PaintOp* op,
- const PaintFlags* flags_to_serialize,
- const PlaybackParams& params) {
- // Only 2 types of ops need to played on the analysis canvas.
- // 1) Non-draw ops which affect the transform/clip state on the canvas, since
- // we need the correct ctm at which text and images will be rasterized, and
- // the clip rect so we can skip sending data for ops which will not be
- // rasterized.
- // 2) DrawTextBlob ops since they need to be analyzed by the cache diff canvas
- // to serialize/lock the requisite glyphs for this op.
- if (op->IsDrawOp() && op->GetType() != PaintOpType::DrawTextBlob)
- return;
- if (op->IsPaintOpWithFlags() && flags_to_serialize) {
- static_cast<const PaintOpWithFlags*>(op)->RasterWithFlags(
- canvas, flags_to_serialize, params);
- } else {
- op->Raster(canvas, params);
- }
- }
- void PaintOpBufferSerializer::Save(SkCanvas* canvas,
- const PlaybackParams& params) {
- SaveOp save_op;
- SerializeOp(canvas, &save_op, nullptr, params);
- }
- void PaintOpBufferSerializer::RestoreToCount(SkCanvas* canvas,
- int count,
- const PlaybackParams& params) {
- RestoreOp restore_op;
- while (canvas->getSaveCount() > count) {
- if (!SerializeOp(canvas, &restore_op, nullptr, params))
- return;
- }
- }
- SimpleBufferSerializer::SimpleBufferSerializer(
- void* memory,
- size_t size,
- const PaintOp::SerializeOptions& options)
- : PaintOpBufferSerializer(
- base::BindRepeating(&SimpleBufferSerializer::SerializeToMemory,
- base::Unretained(this)),
- options),
- memory_(memory),
- total_(size) {}
- SimpleBufferSerializer::~SimpleBufferSerializer() = default;
- size_t SimpleBufferSerializer::SerializeToMemory(
- const PaintOp* op,
- const PaintOp::SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- if (written_ == total_)
- return 0u;
- size_t bytes =
- op->Serialize(static_cast<char*>(memory_) + written_, total_ - written_,
- options, flags_to_serialize, current_ctm, original_ctm);
- if (!bytes)
- return 0u;
- written_ += bytes;
- DCHECK_GE(total_, written_);
- return bytes;
- }
- } // namespace cc
|