Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 108 additions & 7 deletions display_list/display_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void DisplayList::ComputeBounds() {
}

void DisplayList::ComputeRTree() {
RTreeBoundsAccumulator accumulator;
RTreeBoundsAccumulator accumulator(&rtree_op_indices_);
DisplayListBoundsCalculator calculator(accumulator, &bounds_cull_);
Dispatch(calculator);
if (calculator.is_unbounded()) {
Expand All @@ -72,17 +72,102 @@ void DisplayList::ComputeRTree() {
rtree_ = accumulator.rtree();
}

class Culler {
public:
virtual bool init(DispatchContext& context) = 0;
virtual void update(DispatchContext& context) = 0;
};
class NopCuller : public Culler {
public:
static NopCuller instance;

bool init(DispatchContext& context) override {
context.next_render_index = 0;
return true;
}
void update(DispatchContext& context) override {}
};
NopCuller NopCuller::instance = NopCuller();
class VectorCuller : public Culler {
public:
VectorCuller(const std::vector<uint32_t>& op_indices,
const std::vector<int>& rect_indices)
: op_indices_(op_indices),
cur_(rect_indices.begin()),
end_(rect_indices.end()) {}

bool init(DispatchContext& context) override {
if (cur_ < end_) {
context.next_render_index = op_indices_[*cur_++];
return true;
} else {
context.next_render_index = std::numeric_limits<uint32_t>::max();
return false;
}
}
void update(DispatchContext& context) override {
if (++context.cur_index > context.next_render_index) {
while (cur_ < end_) {
context.next_render_index = op_indices_[*cur_++];
if (context.next_render_index >= context.cur_index) {
// It should be rare that we have duplicate indices
// but if we do, then having a while loop is a cheap
// insurance for those cases.
return;
}
}
context.next_render_index = std::numeric_limits<uint32_t>::max();
}
}

private:
const std::vector<uint32_t>& op_indices_;
std::vector<int>::const_iterator cur_;
std::vector<int>::const_iterator end_;
};

void DisplayList::Dispatch(Dispatcher& ctx) const {
uint8_t* ptr = storage_.get();
Dispatch(ctx, ptr, ptr + byte_count_, NopCuller::instance);
}
void DisplayList::Dispatch(Dispatcher& ctx, const SkRect& cull_rect) {
if (cull_rect.isEmpty()) {
return;
}
if (cull_rect.contains(bounds())) {
Dispatch(ctx);
return;
}
uint8_t* ptr = storage_.get();
std::vector<int> rect_indices;
rtree()->search(cull_rect, &rect_indices);
VectorCuller culler(rtree_op_indices_, rect_indices);
Dispatch(ctx, ptr, ptr + byte_count_, culler);
}

void DisplayList::Dispatch(Dispatcher& dispatcher,
uint8_t* ptr,
uint8_t* end) const {
uint8_t* end,
Culler& culler) const {
DispatchContext context = {
.dispatcher = dispatcher,

.cur_index = 0,

.next_restore_index = std::numeric_limits<uint32_t>::max(),
};
if (!culler.init(context)) {
return;
}

while (ptr < end) {
auto op = reinterpret_cast<const DLOp*>(ptr);
ptr += op->size;
FML_DCHECK(ptr <= end);
switch (op->type) {
#define DL_OP_DISPATCH(name) \
case DisplayListOpType::k##name: \
static_cast<const name##Op*>(op)->dispatch(dispatcher); \
#define DL_OP_DISPATCH(name) \
case DisplayListOpType::k##name: \
static_cast<const name##Op*>(op)->dispatch(context); \
break;

FOR_EACH_DISPLAY_LIST_OP(DL_OP_DISPATCH)
Expand All @@ -93,6 +178,7 @@ void DisplayList::Dispatch(Dispatcher& dispatcher,
FML_DCHECK(false);
return;
}
culler.update(context);
}
}

Expand Down Expand Up @@ -187,16 +273,31 @@ static bool CompareOps(uint8_t* ptrA,
}

void DisplayList::RenderTo(DisplayListBuilder* builder,
SkScalar opacity) const {
SkScalar opacity,
bool cull) {
// TODO(100983): Opacity is not respected and attributes are not reset.
if (!builder) {
return;
}
if (cull) {
SkRect clip_bounds = builder->getLocalClipBounds();
if (!clip_bounds.contains(bounds())) {
Dispatch(*builder, clip_bounds);
return;
}
}
Dispatch(*builder);
}

void DisplayList::RenderTo(SkCanvas* canvas, SkScalar opacity) const {
void DisplayList::RenderTo(SkCanvas* canvas, SkScalar opacity, bool cull) {
DisplayListCanvasDispatcher dispatcher(canvas, opacity);
if (cull) {
SkRect clip_bounds = canvas->getLocalClipBounds();
if (!clip_bounds.contains(bounds())) {
Dispatch(dispatcher, clip_bounds);
return;
}
}
Dispatch(dispatcher);
}

Expand Down
22 changes: 15 additions & 7 deletions display_list/display_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ class SaveLayerOptions {
};
};

class Culler;

// The base class that contains a sequence of rendering operations
// for dispatch to a Dispatcher. These objects must be instantiated
// through an instance of DisplayListBuilder::build().
Expand All @@ -224,15 +226,16 @@ class DisplayList : public SkRefCnt {

~DisplayList();

void Dispatch(Dispatcher& ctx) const {
uint8_t* ptr = storage_.get();
Dispatch(ctx, ptr, ptr + byte_count_);
}
void Dispatch(Dispatcher& ctx) const;
void Dispatch(Dispatcher& ctx, const SkRect& cull_rect);

void RenderTo(DisplayListBuilder* builder,
SkScalar opacity = SK_Scalar1) const;
SkScalar opacity = SK_Scalar1,
bool cull = true);

void RenderTo(SkCanvas* canvas, SkScalar opacity = SK_Scalar1) const;
void RenderTo(SkCanvas* canvas,
SkScalar opacity = SK_Scalar1,
bool cull = true);

// SkPicture always includes nested bytes, but nested ops are
// only included if requested. The defaults used here for these
Expand Down Expand Up @@ -296,6 +299,7 @@ class DisplayList : public SkRefCnt {
uint32_t unique_id_;
SkRect bounds_;
sk_sp<const DlRTree> rtree_;
std::vector<uint32_t> rtree_op_indices_;

// Only used for drawPaint() and drawColor()
SkRect bounds_cull_;
Expand All @@ -304,7 +308,11 @@ class DisplayList : public SkRefCnt {

void ComputeBounds();
void ComputeRTree();
void Dispatch(Dispatcher& ctx, uint8_t* ptr, uint8_t* end) const;

void Dispatch(Dispatcher& ctx,
uint8_t* ptr,
uint8_t* end,
Culler& culler) const;

friend class DisplayListBuilder;
};
Expand Down
23 changes: 15 additions & 8 deletions display_list/display_list_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static void CopyV(void* dst, const S* src, int n, Rest&&... rest) {
}

template <typename T, typename... Args>
void* DisplayListBuilder::Push(size_t pod, int op_inc, Args&&... args) {
void* DisplayListBuilder::Push(size_t pod, int render_op_inc, Args&&... args) {
size_t size = SkAlignPtr(sizeof(T) + pod);
FML_DCHECK(size < (1 << 24));
if (used_ + size > allocated_) {
Expand All @@ -44,7 +44,8 @@ void* DisplayListBuilder::Push(size_t pod, int op_inc, Args&&... args) {
new (op) T{std::forward<Args>(args)...};
op->type = T::kType;
op->size = size;
op_count_ += op_inc;
render_op_count_ += render_op_inc;
op_index_++;
return op + 1;
}

Expand All @@ -53,10 +54,10 @@ sk_sp<DisplayList> DisplayListBuilder::Build() {
restore();
}
size_t bytes = used_;
int count = op_count_;
int count = render_op_count_;
size_t nested_bytes = nested_bytes_;
int nested_count = nested_op_count_;
used_ = allocated_ = op_count_ = 0;
used_ = allocated_ = render_op_count_ = op_index_ = 0;
nested_bytes_ = nested_op_count_ = 0;
storage_.realloc(bytes);
bool compatible = layer_stack_.back().is_group_opacity_compatible();
Expand Down Expand Up @@ -423,7 +424,9 @@ void DisplayListBuilder::setAttributesFromPaint(

void DisplayListBuilder::checkForDeferredSave() {
if (current_layer_->has_deferred_save_op_) {
size_t save_offset = used_;
Push<SaveOp>(0, 1);
current_layer_->save_offset = save_offset;
current_layer_->has_deferred_save_op_ = false;
}
}
Expand All @@ -436,7 +439,10 @@ void DisplayListBuilder::save() {

void DisplayListBuilder::restore() {
if (layer_stack_.size() > 1) {
SaveOpBase* op = reinterpret_cast<SaveOpBase*>(storage_.get() +
current_layer_->save_offset);
if (!current_layer_->has_deferred_save_op_) {
op->restore_index = op_index_;
Push<RestoreOp>(0, 1);
}
// Grab the current layer info before we push the restore
Expand All @@ -445,6 +451,9 @@ void DisplayListBuilder::restore() {
layer_stack_.pop_back();
current_layer_ = &layer_stack_.back();
if (layer_info.has_layer) {
// Layers are never deferred for now, we need to update the
// following code if we ever do saveLayer culling...
FML_DCHECK(!layer_info.has_deferred_save_op_);
if (layer_info.is_group_opacity_compatible()) {
// We are now going to go back and modify the matching saveLayer
// call to add the option indicating it can distribute an opacity
Expand All @@ -458,8 +467,6 @@ void DisplayListBuilder::restore() {
// in the DisplayList are only allowed *during* the build phase.
// Once built, the DisplayList records must remain read only to
// ensure consistency of rendering and |Equals()| behavior.
SaveLayerOp* op = reinterpret_cast<SaveLayerOp*>(
storage_.get() + layer_info.save_layer_offset);
op->options = op->options.with_can_distribute_opacity();
}
} else {
Expand All @@ -486,11 +493,11 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds,
size_t save_layer_offset = used_;
if (backdrop) {
bounds //
? Push<SaveLayerBackdropBoundsOp>(0, 1, *bounds, options, backdrop)
? Push<SaveLayerBackdropBoundsOp>(0, 1, options, *bounds, backdrop)
: Push<SaveLayerBackdropOp>(0, 1, options, backdrop);
} else {
bounds //
? Push<SaveLayerBoundsOp>(0, 1, *bounds, options)
? Push<SaveLayerBoundsOp>(0, 1, options, *bounds)
: Push<SaveLayerOp>(0, 1, options);
}
CheckLayerOpacityCompatibility(options.renders_with_attributes());
Expand Down
9 changes: 5 additions & 4 deletions display_list/display_list_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ class DisplayListBuilder final : public virtual Dispatcher,
SkAutoTMalloc<uint8_t> storage_;
size_t used_ = 0;
size_t allocated_ = 0;
int op_count_ = 0;
int render_op_count_ = 0;
int op_index_ = 0;

// bytes and ops from |drawPicture| and |drawDisplayList|
size_t nested_bytes_ = 0;
Expand All @@ -384,9 +385,9 @@ class DisplayListBuilder final : public virtual Dispatcher,
struct LayerInfo {
LayerInfo(const SkM44& matrix,
const SkRect& clip_bounds,
size_t save_layer_offset = 0,
size_t save_offset = 0,
bool has_layer = false)
: save_layer_offset(save_layer_offset),
: save_offset(save_offset),
has_layer(has_layer),
cannot_inherit_opacity(false),
has_compatible_op(false),
Expand All @@ -407,7 +408,7 @@ class DisplayListBuilder final : public virtual Dispatcher,
// the records inside the saveLayer that may impact how the saveLayer
// is handled (e.g., |cannot_inherit_opacity| == false).
// This offset is only valid if |has_layer| is true.
size_t save_layer_offset;
size_t save_offset;

bool has_deferred_save_op_ = false;

Expand Down
12 changes: 10 additions & 2 deletions display_list/display_list_canvas_recorder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ namespace flutter {
} while (0)

DisplayListCanvasRecorder::DisplayListCanvasRecorder(const SkRect& bounds)
: SkCanvasVirtualEnforcer(bounds.width(), bounds.height()),
builder_(sk_make_sp<DisplayListBuilder>(bounds)) {}
: SkCanvasVirtualEnforcer(bounds.right(), bounds.bottom()),
builder_(sk_make_sp<DisplayListBuilder>(bounds)) {
if (bounds.isSorted()) {
SkCanvasVirtualEnforcer::onClipRect(bounds, SkClipOp::kIntersect,
ClipEdgeStyle::kHard_ClipEdgeStyle);
}
}

sk_sp<DisplayList> DisplayListCanvasRecorder::Build() {
CHECK_DISPOSE(nullptr);
Expand Down Expand Up @@ -56,20 +61,23 @@ void DisplayListCanvasRecorder::onClipRect(const SkRect& rect,
CHECK_DISPOSE();
builder_->clipRect(rect, clip_op,
edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle);
SkCanvasVirtualEnforcer::onClipRect(rect, clip_op, edge_style);
}
void DisplayListCanvasRecorder::onClipRRect(const SkRRect& rrect,
SkClipOp clip_op,
ClipEdgeStyle edge_style) {
CHECK_DISPOSE();
builder_->clipRRect(rrect, clip_op,
edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle);
SkCanvasVirtualEnforcer::onClipRRect(rrect, clip_op, edge_style);
}
void DisplayListCanvasRecorder::onClipPath(const SkPath& path,
SkClipOp clip_op,
ClipEdgeStyle edge_style) {
CHECK_DISPOSE();
builder_->clipPath(path, clip_op,
edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle);
SkCanvasVirtualEnforcer::onClipPath(path, clip_op, edge_style);
}

void DisplayListCanvasRecorder::willSave() {
Expand Down
Loading