Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
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
17 changes: 16 additions & 1 deletion flow/layers/child_scene_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,25 @@ ChildSceneLayer::ChildSceneLayer(zx_koid_t layer_id,
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ChildSceneLayer::Preroll");
set_needs_system_composite(true);

// An alpha "hole punch" is required if the frame behind us is not opaque.
if (!context->is_opaque) {
set_paint_bounds(
SkRect::MakeXYWH(offset_.fX, offset_.fY, size_.fWidth, size_.fHeight));
}
}

void ChildSceneLayer::Paint(PaintContext& context) const {
FML_NOTREACHED() << "This layer never needs painting.";
TRACE_EVENT0("flutter", "ChildSceneLayer::Paint");
FML_DCHECK(needs_painting());

// If we are being rendered into our own frame using the system compositor,
// then it is neccesary to "punch a hole" in the canvas/frame behind us so
// that group opacity looks correct.
SkPaint paint;
paint.setColor(SK_ColorTRANSPARENT);
paint.setBlendMode(SkBlendMode::kSrc);
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
}

void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
Expand Down
20 changes: 17 additions & 3 deletions flow/layers/fuchsia_system_composited_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,21 @@
namespace flutter {

FuchsiaSystemCompositedLayer::FuchsiaSystemCompositedLayer(SkColor color,
SkAlpha opacity,
float elevation)
: ElevatedContainerLayer(elevation), color_(color) {}
: ElevatedContainerLayer(elevation), color_(color), opacity_(opacity) {}

void FuchsiaSystemCompositedLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "FuchsiaSystemCompositedLayer::Preroll");

const float parent_is_opaque = context->is_opaque;
context->mutators_stack.PushOpacity(opacity_);
context->is_opaque = parent_is_opaque && (opacity_ == SK_AlphaOPAQUE);
ElevatedContainerLayer::Preroll(context, matrix);
context->is_opaque = parent_is_opaque;
context->mutators_stack.Pop();
}

void FuchsiaSystemCompositedLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
Expand All @@ -28,14 +41,15 @@ void FuchsiaSystemCompositedLayer::UpdateScene(SceneUpdateContext& context) {

TRACE_EVENT_INSTANT0("flutter", "retained cache miss, creating");
// If we can't find an existing retained surface, create one.
SceneUpdateContext::Frame frame(context, rrect_, color_, elevation(), this);
SceneUpdateContext::Frame frame(context, rrect_, color_, opacity_ / 255.0f,
elevation(), this);
for (auto& layer : layers()) {
if (layer->needs_painting()) {
frame.AddPaintLayer(layer.get());
}
}

ContainerLayer::UpdateScene(context);
ElevatedContainerLayer::UpdateScene(context);
}

} // namespace flutter
5 changes: 4 additions & 1 deletion flow/layers/fuchsia_system_composited_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ class FuchsiaSystemCompositedLayer : public ElevatedContainerLayer {
public:
static bool can_system_composite() { return true; }

FuchsiaSystemCompositedLayer(SkColor color, float elevation);
FuchsiaSystemCompositedLayer(SkColor color, SkAlpha opacity, float elevation);

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void UpdateScene(SceneUpdateContext& context) override;

void set_dimensions(SkRRect rrect) { rrect_ = rrect; }

SkColor color() const { return color_; }
SkAlpha opacity() const { return opacity_; }

private:
SkRRect rrect_ = SkRRect::MakeEmpty();
SkColor color_ = SK_ColorTRANSPARENT;
SkAlpha opacity_ = SK_AlphaOPAQUE;

FML_DISALLOW_COPY_AND_ASSIGN(FuchsiaSystemCompositedLayer);
};
Expand Down
5 changes: 3 additions & 2 deletions flow/layers/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ struct PrerollContext {
float frame_physical_depth;
float frame_device_pixel_ratio;

// These allow us to track properties like elevation and opacity which stack
// with each other during Preroll.
// These allow us to track properties like elevation, opacity, and the
// prescence of a platform view during Preroll.
float total_elevation = 0.0f;
bool has_platform_view = false;
bool is_opaque = true;
};

// Represents a single composited layer. Created on the UI thread but then
Expand Down
70 changes: 55 additions & 15 deletions flow/layers/opacity_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,29 @@

namespace flutter {

OpacityLayer::OpacityLayer(int alpha, const SkPoint& offset)
: alpha_(alpha), offset_(offset) {
// The OpacityLayer has no real "elevation", but we want to avoid Z-fighting
// when using the system compositor. Choose a small but non-zero value for
// this.
constexpr float kOpacityElevationWhenUsingSystemCompositor = 0.01f;

#if !defined(OS_FUCHSIA)
void OpacityLayerBase::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
const float parent_is_opaque = context->is_opaque;

context->mutators_stack.PushOpacity(opacity_);
context->is_opaque = parent_is_opaque && (opacity_ == SK_AlphaOPAQUE);
ContainerLayer::Preroll(context, matrix);
context->is_opaque = parent_is_opaque;
context->mutators_stack.Pop();
}
#endif

OpacityLayer::OpacityLayer(SkAlpha opacity, const SkPoint& offset)
: OpacityLayerBase(SK_ColorTRANSPARENT,
opacity,
kOpacityElevationWhenUsingSystemCompositor),
offset_(offset) {
// Ensure OpacityLayer has only one direct child.
//
// This is needed to ensure that retained rendering can always be applied to
Expand All @@ -31,34 +52,54 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
ContainerLayer* container = GetChildContainer();
FML_DCHECK(!container->layers().empty()); // OpacityLayer can't be a leaf.

// Factor in the offset during Preroll. |OpacityLayerBase| will handle the
// opacity.
SkMatrix child_matrix = matrix;
child_matrix.postTranslate(offset_.fX, offset_.fY);
context->mutators_stack.PushTransform(
SkMatrix::MakeTrans(offset_.fX, offset_.fY));
context->mutators_stack.PushOpacity(alpha_);
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context);
ContainerLayer::Preroll(context, child_matrix);
context->mutators_stack.Pop();
OpacityLayerBase::Preroll(context, child_matrix);
context->mutators_stack.Pop();
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));

if (!context->has_platform_view && context->raster_cache &&
SkRect::Intersects(context->cull_rect, paint_bounds())) {
SkMatrix ctm = child_matrix;
// When using the system compositor, do not include the offset since we are
// rendering as a separate piece of geometry and the offset will be baked into
// that geometry's transform.
if (OpacityLayerBase::can_system_composite() && needs_system_composite()) {
set_dimensions(SkRRect::MakeRect(paint_bounds()));
} else {
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));

if (!context->has_platform_view && context->raster_cache &&
SkRect::Intersects(context->cull_rect, paint_bounds())) {
SkMatrix ctm = child_matrix;
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
ctm = RasterCache::GetIntegralTransCTM(ctm);
ctm = RasterCache::GetIntegralTransCTM(ctm);
#endif
context->raster_cache->Prepare(context, container, ctm);
context->raster_cache->Prepare(context, container, ctm);
}
}
}

#if defined(OS_FUCHSIA)

void OpacityLayer::UpdateScene(SceneUpdateContext& context) {
SceneUpdateContext::Transform transform(
context, SkMatrix::MakeTrans(offset_.fX, offset_.fY));

// OpacityLayerBase will handle applying the opacity itself.
OpacityLayerBase::UpdateScene(context);
}

#endif

void OpacityLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
FML_DCHECK(needs_painting());

SkPaint paint;
paint.setAlpha(alpha_);
paint.setAlpha(opacity());

SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->translate(offset_.fX, offset_.fY);
Expand All @@ -85,16 +126,15 @@ void OpacityLayer::Paint(PaintContext& context) const {
// RasterCache::GetIntegralTransCTM optimization.
//
// Note that the following lines are only accessible when the raster cache is
// not available (e.g., when we're using the software backend in golden
// tests).
// not available, or when a cache miss occurs.
SkRect saveLayerBounds;
paint_bounds()
.makeOffset(-offset_.fX, -offset_.fY)
.roundOut(&saveLayerBounds);

Layer::AutoSaveLayer save_layer =
Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint);
PaintChildren(context);
OpacityLayerBase::Paint(context);
}

ContainerLayer* OpacityLayer::GetChildContainer() const {
Expand Down
41 changes: 33 additions & 8 deletions flow/layers/opacity_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,42 @@
#ifndef FLUTTER_FLOW_LAYERS_OPACITY_LAYER_H_
#define FLUTTER_FLOW_LAYERS_OPACITY_LAYER_H_

#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/layers/elevated_container_layer.h"
#if defined(OS_FUCHSIA)
#include "flutter/flow/layers/fuchsia_system_composited_layer.h"
#endif

namespace flutter {

#if !defined(OS_FUCHSIA)
class OpacityLayerBase : public ContainerLayer {
public:
static bool can_system_composite() { return false; }

OpacityLayerBase(SkColor color, SkAlpha opacity, float elevation)
: color_(color), opacity_(opacity) {}

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;

void set_dimensions(SkRRect rrect) {}

SkColor color() const { return color_; }
SkAlpha opacity() const { return opacity_; }
float elevation() const { return 0; }

private:
SkColor color_;
SkAlpha opacity_;
};
#else
using OpacityLayerBase = FuchsiaSystemCompositedLayer;
#endif

// Don't add an OpacityLayer with no children to the layer tree. Painting an
// OpacityLayer is very costly due to the saveLayer call. If there's no child,
// having the OpacityLayer or not has the same effect. In debug_unopt build,
// |Preroll| will assert if there are no children.
class OpacityLayer : public ContainerLayer {
class OpacityLayer : public OpacityLayerBase {
public:
// An offset is provided here because OpacityLayer.addToScene method in the
// Flutter framework can take an optional offset argument.
Expand All @@ -25,21 +52,19 @@ class OpacityLayer : public ContainerLayer {
// the retained rendering inefficient as a small offset change could propagate
// to many leaf layers. Therefore we try to capture that offset here to stop
// the propagation as repainting the OpacityLayer is expensive.
OpacityLayer(int alpha, const SkPoint& offset);
OpacityLayer(SkAlpha alpha, const SkPoint& offset);

void Add(std::shared_ptr<Layer> layer) override;

void Preroll(PrerollContext* context, const SkMatrix& matrix) override;

#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif
void Paint(PaintContext& context) const override;

// TODO(chinmaygarde): Once SCN-139 is addressed, introduce a new node in the
// session scene hierarchy.

private:
ContainerLayer* GetChildContainer() const;

int alpha_;
SkPoint offset_;

FML_DISALLOW_COPY_AND_ASSIGN(OpacityLayer);
Expand Down
9 changes: 7 additions & 2 deletions flow/layers/physical_shape_layer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ PhysicalShapeLayer::PhysicalShapeLayer(SkColor color,
float elevation,
const SkPath& path,
Clip clip_behavior)
#if !defined(OS_FUCHSIA)
: PhysicalShapeLayerBase(color, elevation),
#else
: PhysicalShapeLayerBase(color, /*opacity=*/1.f, elevation),
#endif
shadow_color_(shadow_color),
path_(path),
isRect_(false),
Expand Down Expand Up @@ -94,8 +98,9 @@ void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) {

TRACE_EVENT_INSTANT0("flutter", "cache miss, creating");
// If we can't find an existing retained surface, create one.
SceneUpdateContext::Frame frame(context, frameRRect_, color(), elevation(),
this);
SceneUpdateContext::Frame frame(context, frameRRect_, color(), opacity(),
elevation(), this);

for (auto& layer : layers()) {
if (layer->needs_painting()) {
frame.AddPaintLayer(layer.get());
Expand Down
Loading