mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Migrates Layers and LayerTree and parts of the `flow/` utility classes to use DlGeometry (Impeller) classes.
277 lines
9.7 KiB
C++
277 lines
9.7 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef FLUTTER_FLOW_DIFF_CONTEXT_H_
|
|
#define FLUTTER_FLOW_DIFF_CONTEXT_H_
|
|
|
|
#include <functional>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <vector>
|
|
#include "display_list/utils/dl_matrix_clip_tracker.h"
|
|
#include "flutter/flow/paint_region.h"
|
|
#include "flutter/fml/macros.h"
|
|
|
|
namespace flutter {
|
|
|
|
class Layer;
|
|
|
|
// Represents area that needs to be updated in front buffer (frame_damage) and
|
|
// area that is going to be painted to in back buffer (buffer_damage).
|
|
struct Damage {
|
|
// This is the damage between current and previous frame;
|
|
// If embedder supports partial update, this is the region that needs to be
|
|
// repainted.
|
|
// Corresponds to "surface damage" from EGL_KHR_partial_update.
|
|
DlIRect frame_damage;
|
|
|
|
// Reflects actual change to target framebuffer; This is frame_damage +
|
|
// damage previously acumulated for target framebuffer.
|
|
// All drawing will be clipped to this region. Knowing the affected area
|
|
// upfront may be useful for tile based GPUs.
|
|
// Corresponds to "buffer damage" from EGL_KHR_partial_update.
|
|
DlIRect buffer_damage;
|
|
};
|
|
|
|
// Layer Unique Id to PaintRegion
|
|
using PaintRegionMap = std::map<uint64_t, PaintRegion>;
|
|
|
|
// Tracks state during tree diffing process and computes resulting damage
|
|
class DiffContext {
|
|
public:
|
|
explicit DiffContext(DlISize frame_size,
|
|
PaintRegionMap& this_frame_paint_region_map,
|
|
const PaintRegionMap& last_frame_paint_region_map,
|
|
bool has_raster_cache,
|
|
bool impeller_enabled);
|
|
|
|
// Starts a new subtree.
|
|
void BeginSubtree();
|
|
|
|
// Ends current subtree; All modifications to state (transform, cullrect,
|
|
// dirty) will be restored
|
|
void EndSubtree();
|
|
|
|
// Creates subtree in current scope and closes it on scope exit
|
|
class AutoSubtreeRestore {
|
|
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(AutoSubtreeRestore);
|
|
|
|
public:
|
|
explicit AutoSubtreeRestore(DiffContext* context) : context_(context) {
|
|
context->BeginSubtree();
|
|
}
|
|
~AutoSubtreeRestore() { context_->EndSubtree(); }
|
|
|
|
private:
|
|
DiffContext* context_;
|
|
};
|
|
|
|
// Pushes additional transform for current subtree
|
|
void PushTransform(const DlMatrix& transform);
|
|
|
|
// Pushes cull rect for current subtree
|
|
bool PushCullRect(const DlRect& clip);
|
|
|
|
// Function that adjusts layer bounds (in device coordinates) depending
|
|
// on filter.
|
|
using FilterBoundsAdjustment = std::function<DlRect(DlRect)>;
|
|
|
|
// Pushes filter bounds adjustment to current subtree. Every layer in this
|
|
// subtree will have bounds adjusted by this function.
|
|
void PushFilterBoundsAdjustment(const FilterBoundsAdjustment& filter);
|
|
|
|
// Instruct DiffContext that current layer will paint with integral transform.
|
|
void WillPaintWithIntegralTransform() { state_.integral_transform = true; }
|
|
|
|
// Returns current transform as DlMatrix.
|
|
const DlMatrix& GetMatrix() const;
|
|
|
|
// Return cull rect for current subtree (in local coordinates).
|
|
DlRect GetCullRect() const;
|
|
|
|
// Sets the dirty flag on current subtree.
|
|
//
|
|
// previous_paint_region, which should represent region of previous subtree
|
|
// at this level will be added to damage area.
|
|
//
|
|
// Each paint region added to dirty subtree (through AddPaintRegion) is also
|
|
// added to damage.
|
|
void MarkSubtreeDirty(
|
|
const PaintRegion& previous_paint_region = PaintRegion());
|
|
void MarkSubtreeDirty(const DlRect& previous_paint_region);
|
|
|
|
bool IsSubtreeDirty() const { return state_.dirty; }
|
|
|
|
// Marks that current subtree contains a TextureLayer. This is needed to
|
|
// ensure that we'll Diff the TextureLayer even if inside retained layer.
|
|
void MarkSubtreeHasTextureLayer();
|
|
|
|
// Add layer bounds to current paint region; rect is in "local" (layer)
|
|
// coordinates.
|
|
void AddLayerBounds(const DlRect& rect);
|
|
|
|
// Add entire paint region of retained layer for current subtree. This can
|
|
// only be used in subtrees that are not dirty, otherwise ancestor transforms
|
|
// or clips may result in different paint region.
|
|
void AddExistingPaintRegion(const PaintRegion& region);
|
|
|
|
// The idea of readback region is that if any part of the readback region
|
|
// needs to be repainted, then the whole readback region must be repainted;
|
|
//
|
|
// paint_rect - rectangle where the filter paints contents (in screen
|
|
// coordinates)
|
|
// readback_rect - rectangle where the filter samples from (in screen
|
|
// coordinates)
|
|
void AddReadbackRegion(const DlIRect& paint_rect,
|
|
const DlIRect& readback_rect);
|
|
|
|
// Returns the paint region for current subtree; Each rect in paint region is
|
|
// in screen coordinates; Once a layer accumulates the paint regions of its
|
|
// children, this PaintRegion value can be associated with the current layer
|
|
// using DiffContext::SetLayerPaintRegion.
|
|
PaintRegion CurrentSubtreeRegion() const;
|
|
|
|
// Computes final damage
|
|
//
|
|
// additional_damage is the previously accumulated frame_damage for
|
|
// current framebuffer
|
|
//
|
|
// clip_alignment controls the alignment of resulting frame and surface
|
|
// damage.
|
|
Damage ComputeDamage(const DlIRect& additional_damage,
|
|
int horizontal_clip_alignment = 0,
|
|
int vertical_clip_alignment = 0) const;
|
|
|
|
// Adds the region to current damage. Used for removed layers, where instead
|
|
// of diffing the layer its paint region is direcly added to damage.
|
|
void AddDamage(const PaintRegion& damage);
|
|
|
|
// Associates the paint region with specified layer and current layer tree.
|
|
// The paint region can not be stored directly in layer itself, because same
|
|
// retained layer instance can possibly paint in different locations depending
|
|
// on ancestor layers.
|
|
void SetLayerPaintRegion(const Layer* layer, const PaintRegion& region);
|
|
|
|
// Retrieves the paint region associated with specified layer and previous
|
|
// frame layer tree.
|
|
PaintRegion GetOldLayerPaintRegion(const Layer* layer) const;
|
|
|
|
// Whether or not a raster cache is being used. If so, we must snap
|
|
// all transformations to physical pixels if the layer may be raster
|
|
// cached.
|
|
bool has_raster_cache() const { return has_raster_cache_; }
|
|
|
|
bool impeller_enabled() const { return impeller_enabled_; }
|
|
|
|
class Statistics {
|
|
public:
|
|
// Picture replaced by different picture
|
|
void AddNewPicture() { ++new_pictures_; }
|
|
|
|
// Picture that would require deep comparison but was considered too complex
|
|
// to serialize and thus was treated as new picture
|
|
void AddPictureTooComplexToCompare() { ++pictures_too_complex_to_compare_; }
|
|
|
|
// Picture that has identical instance between frames
|
|
void AddSameInstancePicture() { ++same_instance_pictures_; };
|
|
|
|
// Picture that had to be serialized to compare for equality
|
|
void AddDeepComparePicture() { ++deep_compare_pictures_; }
|
|
|
|
// Picture that had to be serialized to compare (different instances),
|
|
// but were equal
|
|
void AddDifferentInstanceButEqualPicture() {
|
|
++different_instance_but_equal_pictures_;
|
|
};
|
|
|
|
// Logs the statistics to trace counter
|
|
void LogStatistics();
|
|
|
|
private:
|
|
int new_pictures_ = 0;
|
|
int pictures_too_complex_to_compare_ = 0;
|
|
int same_instance_pictures_ = 0;
|
|
int deep_compare_pictures_ = 0;
|
|
int different_instance_but_equal_pictures_ = 0;
|
|
};
|
|
|
|
Statistics& statistics() { return statistics_; }
|
|
|
|
DlRect MapRect(const DlRect& rect);
|
|
|
|
private:
|
|
struct State {
|
|
State();
|
|
|
|
bool dirty = false;
|
|
|
|
size_t rect_index = 0;
|
|
|
|
// In order to replicate paint process closely, DiffContext needs to take
|
|
// into account that some layers are painted with transform translation
|
|
// snapped to integral coordinates.
|
|
//
|
|
// It's not possible to simply snap the transform itself, because culling
|
|
// needs to happen with original (unsnapped) transform, just like it does
|
|
// during paint. This means the integral coordinates must be applied after
|
|
// culling before painting the layer content (either the layer itself, or
|
|
// when starting subtree to paint layer children).
|
|
bool integral_transform = false;
|
|
|
|
// Current transform and clip for the layer
|
|
DisplayListMatrixClipState matrix_clip;
|
|
|
|
// Whether this subtree has filter bounds adjustment function. If so,
|
|
// it will need to be removed from stack when subtree is closed.
|
|
bool has_filter_bounds_adjustment = false;
|
|
|
|
// Whether there is a texture layer in this subtree.
|
|
bool has_texture = false;
|
|
};
|
|
|
|
void MakeTransformIntegral(DisplayListMatrixClipState& matrix_clip);
|
|
|
|
std::shared_ptr<std::vector<DlRect>> rects_;
|
|
State state_;
|
|
DlISize frame_size_;
|
|
std::vector<State> state_stack_;
|
|
std::vector<FilterBoundsAdjustment> filter_bounds_adjustment_stack_;
|
|
|
|
// Applies the filter bounds adjustment stack on provided rect.
|
|
// Rect must be in device coordinates.
|
|
DlRect ApplyFilterBoundsAdjustment(DlRect rect) const;
|
|
|
|
DlRect damage_;
|
|
|
|
PaintRegionMap& this_frame_paint_region_map_;
|
|
const PaintRegionMap& last_frame_paint_region_map_;
|
|
bool has_raster_cache_;
|
|
bool impeller_enabled_;
|
|
|
|
void AddDamage(const DlRect& rect);
|
|
|
|
void AlignRect(DlIRect& rect,
|
|
int horizontal_alignment,
|
|
int vertical_clip_alignment) const;
|
|
|
|
struct Readback {
|
|
// Index of rects_ entry that this readback belongs to. Used to
|
|
// determine if subtree has any readback
|
|
size_t position;
|
|
|
|
// Paint region of the filter performing readback, in screen coordinates.
|
|
DlIRect paint_rect;
|
|
|
|
// Readback area of the filter, in screen coordinates.
|
|
DlIRect readback_rect;
|
|
};
|
|
|
|
std::vector<Readback> readbacks_;
|
|
Statistics statistics_;
|
|
};
|
|
|
|
} // namespace flutter
|
|
|
|
#endif // FLUTTER_FLOW_DIFF_CONTEXT_H_
|