1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/layers/recording_source.h"
#include <algorithm>
#include <utility>
#include "base/numerics/safe_math.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/region.h"
#include "cc/layers/content_layer_client.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/solid_color_analyzer.h"
#include "cc/raster/raster_source.h"
namespace {
// We don't perform per-layer solid color analysis when there are too many skia
// operations.
const int kMaxOpsToAnalyzeForLayer = 10;
} // namespace
namespace cc {
RecordingSource::RecordingSource() = default;
RecordingSource::~RecordingSource() = default;
void RecordingSource::UpdateInvalidationForRecordedBounds(
const gfx::Rect& old_recorded_bounds,
const gfx::Rect& new_recorded_bounds,
Region& invalidation) {
// Invalidate newly-exposed and no-longer-exposed areas.
Region newly_exposed_region(new_recorded_bounds);
newly_exposed_region.Subtract(old_recorded_bounds);
invalidation.Union(newly_exposed_region);
Region no_longer_exposed_region(old_recorded_bounds);
no_longer_exposed_region.Subtract(new_recorded_bounds);
invalidation.Union(no_longer_exposed_region);
}
void RecordingSource::FinishDisplayItemListUpdate() {
TRACE_EVENT0("cc", "RecordingSource::FinishDisplayItemListUpdate");
DetermineIfSolidColor();
display_list_->EmitTraceSnapshot();
directly_composited_image_info_ =
display_list_->GetDirectlyCompositedImageInfo();
if (directly_composited_image_info_) {
// Directly composited images are not guaranteed to fully cover every
// pixel in the layer due to ceiling when calculating the tile content
// rect from the layer bounds.
SetRequiresClear(true);
}
}
void RecordingSource::SetNeedsDisplayRect(const gfx::Rect& layer_rect) {
if (!layer_rect.IsEmpty()) {
// Clamp invalidation to the layer bounds.
invalidation_.Union(gfx::IntersectRects(layer_rect, gfx::Rect(size_)));
}
}
bool RecordingSource::Update(const gfx::Size& layer_size,
float recording_scale_factor,
ContentLayerClient& client,
Region& invalidation) {
invalidation_.Swap(&invalidation);
invalidation_.Clear();
if (size_ == layer_size && invalidation.IsEmpty() && !force_update_) {
return false;
}
size_ = layer_size;
recording_scale_factor_ = recording_scale_factor;
scoped_refptr<DisplayItemList> display_list =
client.PaintContentsToDisplayList();
if (display_list_ == display_list) {
// The client should set force_update_ only if it has a new display list.
CHECK(!force_update_);
return true;
}
force_update_ = false;
// Do the following only if the display list changes. Though we use
// recording_scale_factor in DetermineIfSolidColor(), change of it doesn't
// affect whether the same display list is solid or not.
gfx::Rect layer_rect(size_);
gfx::Rect new_recorded_bounds = layer_rect;
if (can_use_recorded_bounds_) {
if (std::optional<gfx::Rect> display_list_bounds = display_list->bounds()) {
new_recorded_bounds.Intersect(*display_list_bounds);
}
}
if (display_list_ &&
display_list->NeedsAdditionalInvalidationForLCDText(*display_list_)) {
invalidation = layer_rect;
} else if (new_recorded_bounds != recorded_bounds_) {
UpdateInvalidationForRecordedBounds(recorded_bounds_, new_recorded_bounds,
invalidation);
}
recorded_bounds_ = new_recorded_bounds;
display_list_ = std::move(display_list);
FinishDisplayItemListUpdate();
return true;
}
void RecordingSource::SetEmptyBounds() {
size_ = gfx::Size();
is_solid_color_ = false;
recorded_bounds_ = gfx::Rect();
display_list_ = nullptr;
}
void RecordingSource::SetSlowdownRasterScaleFactor(int factor) {
slow_down_raster_scale_factor_for_debug_ = factor;
}
void RecordingSource::SetBackgroundColor(SkColor4f background_color) {
background_color_ = background_color;
}
void RecordingSource::SetRequiresClear(bool requires_clear) {
requires_clear_ = requires_clear;
}
void RecordingSource::SetCanUseRecordedBounds(bool can_use_recorded_bounds) {
if (can_use_recorded_bounds_ == can_use_recorded_bounds) {
return;
}
can_use_recorded_bounds_ = can_use_recorded_bounds;
// To force update.
size_ = gfx::Size();
}
scoped_refptr<RasterSource> RecordingSource::CreateRasterSource() const {
return base::WrapRefCounted(new RasterSource(*this));
}
void RecordingSource::DetermineIfSolidColor() {
DCHECK(display_list_);
is_solid_color_ = false;
solid_color_ = SkColors::kTransparent;
if (display_list_->TotalOpCount() > kMaxOpsToAnalyzeForLayer)
return;
// TODO(crbug.com/41490692): Allow the solid color not to fill the layer.
TRACE_EVENT1("cc", "RecordingSource::DetermineIfSolidColor", "opcount",
display_list_->TotalOpCount());
is_solid_color_ = display_list_->GetColorIfSolidInRect(
gfx::ScaleToRoundedRect(gfx::Rect(size_), recording_scale_factor_),
&solid_color_, kMaxOpsToAnalyzeForLayer);
}
} // namespace cc
|