Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@Hixie
Copy link
Contributor

@Hixie Hixie commented Jul 27, 2017

fyi @abarth a lot of these docs are basically your words massaged into doc form.

/// ## Using saveLayer with clips
///
/// When a rectanglular clip operation (from [clipRect]) is not axis-aligned
/// with the display, or when the clip operation is not rectalinear (e.g.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the display

Technically with the raster buffer, which isn't necessarily the screen if there's a rotation or perspective transform between the current raster buffer and the screen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

/// using [saveLayer], the first drawing will be anti-aliased with the
/// background first, and then the second will be anti-aliased with the result
/// of blending the first drawing and the background. On the other hand, if
/// [saveLayer] is used immediately after establishing the clip, the second
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to call saveLayer before you establish the clip

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I had at first but I couldn't understand it. Surely if the clip is inside the layer, it's the problem all over again (it has to apply the clip to each drawn shape)? And if the clip is outside the layer, then when it comes time to place the inner layer into the outer layer, then it applies the clip all at once, as described here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the mental model is that that the clip is applied when you call restore(). Specifically, it's part of the pipeline of transformations (e.g., filters, clips, blends, etc) that is applied to the temporary buffer as it is copied into the parent buffer. Conceptually, it would probably make more sense to combine the call with the saveLayer call, as the filters and blends are, but that's not how the Skia API is set up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but if that's the case, shouldn't that mean you don't get the problem ever? Is it just clips that are at the start of the display list that work out, and clips later in the display list are hosed? Or?

I don't understand why "draw clip draw draw" would fail but "clip draw draw" would not. why are the two clips in "clip draw clip draw" handled differently?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend either experimenting with https://fiddle.skia.org/ or asking the Skia team.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paints a clean white rounded rect:

  void paint(Canvas canvas, Size size) {
    Rect rect = Offset.zero & size;
    canvas.clipRRect(new RRect.fromRectXY(rect, 130.0, 130.0));
    canvas.saveLayer(rect, new Paint());
    canvas.drawPaint(new Paint()..color = Colors.red);
    canvas.drawPaint(new Paint()..color = Colors.white);
    canvas.restore();
  }

This paints a white rounded rect with a red outline:

  void paint(Canvas canvas, Size size) {
    Rect rect = Offset.zero & size;
    canvas.saveLayer(rect, new Paint());
    canvas.clipRRect(new RRect.fromRectXY(rect, 130.0, 130.0));
    canvas.drawPaint(new Paint()..color = Colors.red);
    canvas.drawPaint(new Paint()..color = Colors.white);
    canvas.restore();
  }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/// be anti-aliased with the background when the layer is clipped and
/// composited (when [restore] is called).
///
/// This point is moot if the clip only clips one draw operation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that work? I would have expected Skia not to produce correct results for an RRect clip without a save layer even if you only have one draw operation. You're correct that Skia could optimize that case to work, but I don't think they implement that optimization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested it, but what could it do other than the right behaviour?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My money is on a rectangular clip that's the bounding box of the path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paints a clean white rounded rect in a green area:

  void paint(Canvas canvas, Size size) {
    Rect rect = Offset.zero & size;
    canvas.save();
    canvas.drawPaint(new Paint()..color = Colors.green);
    canvas.clipRRect(new RRect.fromRectXY(rect, 130.0, 130.0));
    canvas.drawPaint(new Paint()..color = Colors.white);
    canvas.restore();
  }

///
/// ## Performance considerations
///
/// Generally speaking [saveLayer] is very expensive.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say "relatively expensive" rather than "very expensive". I think that's the terminology we've used elsewhere to describe this cost (e.g., in https://docs.flutter.io/flutter/widgets/Opacity-class.html).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// processing units, the hardware that handles graphics), but most of them
/// involve batching commands and reordering them for performance. When layers
/// are used, they cause the rendering pipeline to have to switch render
/// target (from one layer to another). Render target switches effectively
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/effectively/can/

/// (layer) is restored.
///
/// For these reasons, creating a new layer ends up being more or less the
/// most expensive operation that one can perform with the [Canvas] API.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this sentence is true. I'm sure there are more expensive operations that we expose (or will eventually expose), such as convolution image filters.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

@abarth
Copy link
Contributor

abarth commented Jul 28, 2017

LGTM

@Hixie
Copy link
Contributor Author

Hixie commented Jul 28, 2017

I added the examples mentioned above to the docs.

Will land on green.

Will verify the call sites that use saveLayer.

@Hixie Hixie merged commit 6bba112 into flutter:master Jul 28, 2017
@Hixie Hixie deleted the docs branch July 28, 2017 21:38
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants