blob: 943bb968c718c7bc3fcc484a3a60bd4ec6b8cf8c [file] [log] [blame]
// 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_LAYERS_LAYER_H_
#define FLUTTER_FLOW_LAYERS_LAYER_H_
#include <algorithm>
#include <memory>
#include <unordered_set>
#include <vector>
#include "flutter/common/graphics/texture.h"
#include "flutter/display_list/dl_canvas.h"
#include "flutter/flow/diff_context.h"
#include "flutter/flow/embedded_views.h"
#include "flutter/flow/layer_snapshot_store.h"
#include "flutter/flow/layers/layer_state_stack.h"
#include "flutter/flow/raster_cache.h"
#include "flutter/flow/stopwatch.h"
#include "flutter/fml/build_config.h"
#include "flutter/fml/compiler_specific.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/trace_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h"
class GrDirectContext;
namespace flutter {
namespace testing {
class MockLayer;
} // namespace testing
class ContainerLayer;
class DisplayListLayer;
class PerformanceOverlayLayer;
class TextureLayer;
class RasterCacheItem;
static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
// This should be an exact copy of the Clip enum in painting.dart.
enum Clip { kNone, kHardEdge, kAntiAlias, kAntiAliasWithSaveLayer };
struct PrerollContext {
RasterCache* raster_cache;
GrDirectContext* gr_context;
ExternalViewEmbedder* view_embedder;
LayerStateStack& state_stack;
sk_sp<SkColorSpace> dst_color_space;
bool surface_needs_readback;
// These allow us to paint in the end of subtree Preroll.
const Stopwatch& raster_time;
const Stopwatch& ui_time;
std::shared_ptr<TextureRegistry> texture_registry;
// These allow us to track properties like elevation, opacity, and the
// presence of a platform view during Preroll.
bool has_platform_view = false;
// These allow us to track properties like elevation, opacity, and the
// presence of a texture layer during Preroll.
bool has_texture_layer = false;
// The list of flags that describe which rendering state attributes
// (such as opacity, ColorFilter, ImageFilter) a given layer can
// render itself without requiring the parent to perform a protective
// saveLayer with those attributes.
// For containers, the flags will be set to the intersection (logical
// and) of all of the state bits that all of the children can render
// or to 0 if some of the children overlap and, as such, cannot apply
// those attributes individually and separately.
int renderable_state_flags = 0;
std::vector<RasterCacheItem*>* raster_cached_entries;
};
struct PaintContext {
// When splitting the scene into multiple canvases (e.g when embedding
// a platform view on iOS) during the paint traversal we apply any state
// changes which affect children (i.e. saveLayer attributes) to the
// state_stack and any local rendering state changes for leaf layers to
// the canvas or builder.
// When we switch a canvas or builder (when painting a PlatformViewLayer)
// the new canvas receives all of the stateful changes from the state_stack
// to put it into the exact same state that the outgoing canvas had at the
// time it was swapped out.
// The state stack lazily applies saveLayer calls to its current canvas,
// allowing leaf layers to report that they can handle rendering some of
// its state attributes themselves via the |applyState| method.
LayerStateStack& state_stack;
DlCanvas* canvas;
// Whether current canvas is an overlay canvas. Used to determine if the
// raster cache is painting to a surface that will be displayed above a
// platform view, in which case it will attempt to preserve the R-Tree.
bool rendering_above_platform_view = false;
GrDirectContext* gr_context;
sk_sp<SkColorSpace> dst_color_space;
ExternalViewEmbedder* view_embedder;
const Stopwatch& raster_time;
const Stopwatch& ui_time;
std::shared_ptr<TextureRegistry> texture_registry;
const RasterCache* raster_cache;
// Snapshot store to collect leaf layer snapshots. The store is non-null
// only when leaf layer tracing is enabled.
LayerSnapshotStore* layer_snapshot_store = nullptr;
bool enable_leaf_layer_tracing = false;
bool impeller_enabled = false;
impeller::AiksContext* aiks_context;
};
// Represents a single composited layer. Created on the UI thread but then
// subsequently used on the Rasterizer thread.
class Layer {
public:
// The state attribute flags that represent which attributes a
// layer can render if it plans to use a saveLayer call in its
// |Paint| method.
static constexpr int kSaveLayerRenderFlags =
LayerStateStack::kCallerCanApplyOpacity |
LayerStateStack::kCallerCanApplyColorFilter |
LayerStateStack::kCallerCanApplyImageFilter;
// The state attribute flags that represent which attributes a
// layer can render if it will be rendering its content/children
// from a cached representation.
static constexpr int kRasterCacheRenderFlags =
LayerStateStack::kCallerCanApplyOpacity;
Layer();
virtual ~Layer();
void AssignOldLayer(Layer* old_layer) {
original_layer_id_ = old_layer->original_layer_id_;
}
// Used to establish link between old layer and new layer that replaces it.
// If this method returns true, it is assumed that this layer replaces the old
// layer in tree and is able to diff with it.
virtual bool IsReplacing(DiffContext* context, const Layer* old_layer) const {
return original_layer_id_ == old_layer->original_layer_id_;
}
// Performs diff with given layer
virtual void Diff(DiffContext* context, const Layer* old_layer) {}
// Used when diffing retained layer; In case the layer is identical, it
// doesn't need to be diffed, but the paint region needs to be stored in diff
// context so that it can be used in next frame
virtual void PreservePaintRegion(DiffContext* context) {
// retained layer means same instance so 'this' is used to index into both
// current and old region
context->SetLayerPaintRegion(this, context->GetOldLayerPaintRegion(this));
}
virtual void Preroll(PrerollContext* context) = 0;
// Used during Preroll by layers that employ a saveLayer to manage the
// PrerollContext settings with values affected by the saveLayer mechanism.
// This object must be created before calling Preroll on the children to
// set up the state for the children and then restore the state upon
// destruction.
class AutoPrerollSaveLayerState {
public:
[[nodiscard]] static AutoPrerollSaveLayerState Create(
PrerollContext* preroll_context,
bool save_layer_is_active = true,
bool layer_itself_performs_readback = false);
~AutoPrerollSaveLayerState();
private:
AutoPrerollSaveLayerState(PrerollContext* preroll_context,
bool save_layer_is_active,
bool layer_itself_performs_readback);
PrerollContext* preroll_context_;
bool save_layer_is_active_;
bool layer_itself_performs_readback_;
bool prev_surface_needs_readback_;
};
virtual void Paint(PaintContext& context) const = 0;
virtual void PaintChildren(PaintContext& context) const { FML_DCHECK(false); }
bool subtree_has_platform_view() const { return subtree_has_platform_view_; }
void set_subtree_has_platform_view(bool value) {
subtree_has_platform_view_ = value;
}
// Returns the paint bounds in the layer's local coordinate system
// as determined during Preroll(). The bounds should include any
// transform, clip or distortions performed by the layer itself,
// but not any similar modifications inherited from its ancestors.
const SkRect& paint_bounds() const { return paint_bounds_; }
// This must be set by the time Preroll() returns otherwise the layer will
// be assumed to have empty paint bounds (paints no content).
// The paint bounds should be independent of the context outside of this
// layer as the layer may be painted under different conditions than
// the Preroll context. The most common example of this condition is
// that we might Preroll the layer with a cull_rect established by a
// clip layer above it but then we might be asked to paint anyway if
// another layer above us needs to cache its children. During the
// paint operation that arises due to the caching, the clip will
// be the bounds of the layer needing caching, not the cull_rect
// that we saw in the overall Preroll operation.
void set_paint_bounds(const SkRect& paint_bounds) {
paint_bounds_ = paint_bounds;
}
// Determines if the layer has any content.
bool is_empty() const { return paint_bounds_.isEmpty(); }
// Determines if the Paint() method is necessary based on the properties
// of the indicated PaintContext object.
bool needs_painting(PaintContext& context) const {
if (subtree_has_platform_view_) {
// Workaround for the iOS embedder. The iOS embedder expects that
// if we preroll it, then we will later call its Paint() method.
// Now that we preroll all layers without any culling, we may
// call its Preroll() without calling its Paint(). For now, we
// will not perform paint culling on any subtree that has a
// platform view.
// See https://github.com/flutter/flutter/issues/81419
return true;
}
return !context.state_stack.painting_is_nop() &&
!context.state_stack.content_culled(paint_bounds_);
}
// Propagated unique_id of the first layer in "chain" of replacement layers
// that can be diffed.
uint64_t original_layer_id() const { return original_layer_id_; }
uint64_t unique_id() const { return unique_id_; }
virtual RasterCacheKeyID caching_key_id() const {
return RasterCacheKeyID(unique_id_, RasterCacheKeyType::kLayer);
}
virtual const ContainerLayer* as_container_layer() const { return nullptr; }
virtual const DisplayListLayer* as_display_list_layer() const {
return nullptr;
}
virtual const TextureLayer* as_texture_layer() const { return nullptr; }
virtual const PerformanceOverlayLayer* as_performance_overlay_layer() const {
return nullptr;
}
virtual const testing::MockLayer* as_mock_layer() const { return nullptr; }
private:
SkRect paint_bounds_;
uint64_t unique_id_;
uint64_t original_layer_id_;
bool subtree_has_platform_view_ = false;
static uint64_t NextUniqueID();
FML_DISALLOW_COPY_AND_ASSIGN(Layer);
};
} // namespace flutter
#endif // FLUTTER_FLOW_LAYERS_LAYER_H_