-
Notifications
You must be signed in to change notification settings - Fork 6k
More documentation, mainly around saveLayer. #3932
Conversation
lib/ui/painting.dart
Outdated
| /// ## 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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();
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my. Sounds like I've misunderstood how this API works. You might want to check call sites like https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/rendering/object.dart#L358 and https://github.com/flutter/engine/blob/master/flow/layers/clip_rrect_layer.cc#L50 which sound like they're wrong.
lib/ui/painting.dart
Outdated
| /// 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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();
}
lib/ui/painting.dart
Outdated
| /// | ||
| /// ## Performance considerations | ||
| /// | ||
| /// Generally speaking [saveLayer] is very expensive. |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
lib/ui/painting.dart
Outdated
| /// 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/effectively/can/
lib/ui/painting.dart
Outdated
| /// (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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
|
I added the examples mentioned above to the docs. Will land on green. Will verify the call sites that use saveLayer. |

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