Skip to content

Commit

Permalink
Wire up OpacityLayer to Scenic (flutter#14577)
Browse files Browse the repository at this point in the history
A previous version of this change also removed
system compositing of PhysicalShapeLayers on
Fuchsia. In this reland, keep using system
composting for PhysicalShapeLayers.

Co-authored-by: David Worsham <[email protected]>
  • Loading branch information
mikejurka and arbreng authored Dec 19, 2019
1 parent 1d3bb8c commit 1f7bb9d
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 97 deletions.
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

0 comments on commit 1f7bb9d

Please sign in to comment.