|
|
Created:
5 years, 3 months ago by Stephen White Modified:
5 years, 1 month ago CC:
reviews_skia.org Base URL:
https://skia.googlesource.com/skia.git@master Target Ref:
refs/heads/master Project:
skia Visibility:
Public. |
DescriptionChange saveLayer() semantics to take unfiltered bounds.
For optimizing saveLayer() offscreens, it is useful to know the
bounds of the primitive being drawn. Currently, the bounds passed to
saveLayer() are filtered, which makes it difficult to know the original
bounds of the primitive. This CL changes the semantics to accept
unfiltered bounds. This actually simplifies the callsites too. In
order to result in the correct pixels being produced, we then call
computeFastBounds() inside clipRectBounds().
The old behaviour is wrapped in #ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED,
until we can update Chrome's callsites (see
https://codereview.chromium.org/1316243002/).
This change will affect the following GMs:
testimagefilters: saveLayer bounds no longer cause clipping
imagefiltersbase: slight pixel diffs
resizeimagefilter: slight pixel diffs on the "high quality" test case
imagefilterscropexpand: displacement results are now correct
filterfastbounds: slight pixel diffs
matriximagefilter: slight pixel diffs
BUG=skia:3194
skia:4526
Committed: https://skia.googlesource.com/skia/+/87e066ee80e094c8f4ccda3d6c33d907b414b91b
Patch Set 1 #Patch Set 2 : Fix for stroking & other non-filter bounds adjustments #Patch Set 3 : Put new code behind #ifdef. Don't call computeFastBounds() unless we can(). #Patch Set 4 : Update to ToT #Patch Set 5 : Update to ToT #Patch Set 6 : Restore missing stroke fix #Patch Set 7 : Update to ToT #Patch Set 8 : Fix bounds computation for SkCanvas::onDrawBitmap #Patch Set 9 : Update to ToT #Patch Set 10 : Update to ToT #Patch Set 11 : Update to ToT #Patch Set 12 : Update to ToT #
Total comments: 10
Patch Set 13 : Update to ToT #Patch Set 14 : More changes per review comments #
Total comments: 4
Patch Set 15 : Update to ToT; fix comments per review #Messages
Total messages: 50 (20 generated)
senorblanco@chromium.org changed reviewers: + reed@google.com, robertphillips@google.com
Reed and/or Robert: PTAL. (No API changes, but it does change the semantics of the API.)
The CQ bit was checked by senorblanco@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/1 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/1
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
If it helps, this is essentially a partial-revert of https://codereview.chromium.org/141433017: we still pass bounds to SkAutoDrawLooper (that's the part that was not reverted), they're just not passed through computeFastBounds() first (the part that was) until clipRectBounds() does it.
saveLayer(bounds, paint) This is a public call, and can be made even when there is no imagefilter on the paint. Therefore, the bounds needs to be the "answer" as to how large the buffer needs to be . It seems to me that this CL fuzzes that idea for internal callers, since they are not passing the answer, but the original. I can imagine that this may be valid, but at the moment it makes the contract between saveLayer and its callers confusing. If we could land the onMapBounds CL, which separated the idea of the size of the input from the size of the output, would that obviate the need for this CL?
On 2015/08/27 21:13:37, reed1 wrote: > saveLayer(bounds, paint) > > This is a public call, and can be made even when there is no imagefilter on the > paint. Therefore, the bounds needs to be the "answer" as to how large the buffer > needs to be . > It seems to me that this CL fuzzes that idea for internal callers, since they > are not passing the answer, but the original. I can imagine that this may be > valid, but at the moment it makes the contract between saveLayer and its callers > confusing. Actually, it's changing the API for public callers too. (Hence the #ifdef). I think it's clearer this way: you specify the bounds of the primitive(s) you're going to draw, and saveLayer() takes care of allocating the correctly-sized intermediate buffers to make sure all the effects you've added to it get drawn. If you really want to eliminate them, you set a clip, and the effects will stop at the clip. > If we could land the onMapBounds CL, which separated the idea of the size of the > input from the size of the output, would that obviate the need for this CL? I don't think that's enough, since we really need to know the size of the original primitive, in order to optimize the offscreens. Here's where I'm heading (which is a variation on your onMapBounds): https://codereview.chromium.org/1308703007/ and gets rid of all the join() calls. Happy to chat about it via VC if you're not convinced.
The CQ bit was checked by senorblanco@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/20001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/20001
OK, I've added the stanza that adjusts bounds for stroking etc. The GM proved that this was necessary.
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
The CQ bit was checked by senorblanco@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/40001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/40001
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
The CQ bit was checked by senorblanco@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/60001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/60001
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
The CQ bit was checked by senorblanco@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/220001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/220001
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
Is this a valid summary for this change? 1. change the drawFoo methods to pass in un-paint-filtered-bounds to the AutoDrawLooper (via the macros). 2. change the DrawLooper to interpret its "bounds" parameter as this raw-geometry bounds, and apply the paint's filtering (modulo imagefilter) to get a new bounds. 3. patch the saveLayer helper function clipRectBounds to apply a compatibility hack, where it "filters" the (new) bounds, expanding them since the filters themselves still require src-size == dst-size
On 2015/10/27 17:48:53, reed1 wrote: > Is this a valid summary for this change? > > 1. change the drawFoo methods to pass in un-paint-filtered-bounds to the > AutoDrawLooper (via the macros). Correct. > 2. change the DrawLooper to interpret its "bounds" parameter as this > raw-geometry bounds, and apply the paint's filtering (modulo imagefilter) to get > a new bounds. Correct. This just handles stroking for the most part. > 3. patch the saveLayer helper function clipRectBounds to apply a compatibility > hack, where it "filters" the (new) bounds, expanding them since the filters > themselves still require src-size == dst-size Correct.
https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp File src/core/SkCanvas.cpp (right): https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:415: const SkRect* bounds = nullptr) : fOrigPaint(paint) { Lets rename this parameter somehow, so it is clear to the next reader what kind of "bounds" it is. Also, perhaps a comment for the constructor could mention this as well. https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:451: SkRect storage; one way to make the intent of this block clear, could be to create a small helper function that just does this. e.g. /** * There are many bounds in skia. A circle's bounds is just its center extended by its radius. However, if we stroke * a circle, then the "bounds" of that is larger, since it will now draw outside of its raw-bounds by 1/2 the stroke width. * SkPaint has lots of optional effects/attributes that can modify the effective bounds of a given primitive * - maskfilters, patheffects, stroking, etc. * * This function takes a raw bounds and a paint, and returns the conservative "effective" bounds based on the * settings in the paint... with one exception. This function does *not* look at the imagefilter, which can also modify * the effective bounds. It is deliberately ignored. */ static SkRect apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint, const SkRect& rawBounds) { .... return effectiveBounds; } https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:1037: #ifndef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED This bock of code exists solely as a temporary hack to maintain results, until we can update the actual filters. Lets make that obvious to the caller. 1. a comment to that effect 2. Perhaps a different #ifdef FLAG as well, like SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILERS. This can naturally only be valid if we're not in SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, but adding a different flag is another way to document this, and remind us to remove it eventually. https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:1042: bounds = nullptr; I presume we set this to null because we assume that the filter is telling us that it affects all of space, by returning false for canComputeFastBounds? If so, that connection isn't necessarily obvious. I wonder if a different (helper) method could make that clearer. e.g. bool SkImageFilter::affectsAllSpaceOrSomethingLikeThat() const { return this->canComputeFastBounds(); } https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:2000: bounds = &unfiltered.computeFastStrokeBounds(r, &storage); don't we just want r here? bounds = &r;
https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp File src/core/SkCanvas.cpp (right): https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:415: const SkRect* bounds = nullptr) : fOrigPaint(paint) { On 2015/10/27 20:05:40, reed1 wrote: > Lets rename this parameter somehow, so it is clear to the next reader what kind > of "bounds" it is. Also, perhaps a comment for the constructor could mention > this as well. Done. https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:451: SkRect storage; On 2015/10/27 20:05:40, reed1 wrote: > one way to make the intent of this block clear, could be to create a small > helper function that just does this. > > e.g. > > /** > * There are many bounds in skia. A circle's bounds is just its center extended > by its radius. However, if we stroke > * a circle, then the "bounds" of that is larger, since it will now draw outside > of its raw-bounds by 1/2 the stroke width. > * SkPaint has lots of optional effects/attributes that can modify the effective > bounds of a given primitive > * - maskfilters, patheffects, stroking, etc. > * > * This function takes a raw bounds and a paint, and returns the conservative > "effective" bounds based on the > * settings in the paint... with one exception. This function does *not* look at > the imagefilter, which can also modify > * the effective bounds. It is deliberately ignored. > */ > static SkRect apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint, const > SkRect& rawBounds) { > .... > return effectiveBounds; > } Done. https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:1037: #ifndef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED On 2015/10/27 20:05:40, reed1 wrote: > This bock of code exists solely as a temporary hack to maintain results, until > we can update the actual filters. Lets make that obvious to the caller. > > 1. a comment to that effect > 2. Perhaps a different #ifdef FLAG as well, like > SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILERS. This can naturally only be valid if > we're not in SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, but adding a different flag is > another way to document this, and remind us to remove it eventually. Done. https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:1042: bounds = nullptr; On 2015/10/27 20:05:40, reed1 wrote: > I presume we set this to null because we assume that the filter is telling us > that it affects all of space, by returning false for canComputeFastBounds? If > so, that connection isn't necessarily obvious. I wonder if a different (helper) > method could make that clearer. > > e.g. > bool SkImageFilter::affectsAllSpaceOrSomethingLikeThat() const { return > this->canComputeFastBounds(); } Should we just rename canComputeFastBounds(), then? It seems kind of silly two have two methods. https://codereview.chromium.org/1304883004/diff/220001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:2000: bounds = &unfiltered.computeFastStrokeBounds(r, &storage); On 2015/10/27 20:05:40, reed1 wrote: > don't we just want r here? > > bounds = &r; Hmm, yeah. Done.
The CQ bit was checked by senorblanco@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/260001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/260001
Description was changed from ========== Change saveLayer() semantics to take unfiltered bounds. For optimizing saveLayer() offscreens, it is useful to know the bounds of the primitive being drawn. Currently, the bounds passed to saveLayer() are filtered, which makes it difficult to know the original bounds of the primitive. This CL changes the semantics to accept unfiltered bounds. This actually simplifies the callsites too. In order to result in the correct pixels being produced, we then call computeFastBounds() inside clipRectBounds(). The old behaviour is wrapped in #ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, until we can update Chrome's callsites (see https://codereview.chromium.org/1316243002/). This change will affect the following GMs: testimagefilters: saveLayer bounds no longer cause clipping resizeimagefilter: slight pixel diffs on the "high quality" test case imagefilterscropexpand: displacement results are now correct matriximagefilter: slight pixel diffs BUG=skia:3194 ========== to ========== Change saveLayer() semantics to take unfiltered bounds. For optimizing saveLayer() offscreens, it is useful to know the bounds of the primitive being drawn. Currently, the bounds passed to saveLayer() are filtered, which makes it difficult to know the original bounds of the primitive. This CL changes the semantics to accept unfiltered bounds. This actually simplifies the callsites too. In order to result in the correct pixels being produced, we then call computeFastBounds() inside clipRectBounds(). The old behaviour is wrapped in #ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, until we can update Chrome's callsites (see https://codereview.chromium.org/1316243002/). This change will affect the following GMs: testimagefilters: saveLayer bounds no longer cause clipping imagefiltersbase: slight pixel diffs resizeimagefilter: slight pixel diffs on the "high quality" test case imagefilterscropexpand: displacement results are now correct matriximagefilter: slight pixel diffs BUG=skia:3194 ==========
Description was changed from ========== Change saveLayer() semantics to take unfiltered bounds. For optimizing saveLayer() offscreens, it is useful to know the bounds of the primitive being drawn. Currently, the bounds passed to saveLayer() are filtered, which makes it difficult to know the original bounds of the primitive. This CL changes the semantics to accept unfiltered bounds. This actually simplifies the callsites too. In order to result in the correct pixels being produced, we then call computeFastBounds() inside clipRectBounds(). The old behaviour is wrapped in #ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, until we can update Chrome's callsites (see https://codereview.chromium.org/1316243002/). This change will affect the following GMs: testimagefilters: saveLayer bounds no longer cause clipping imagefiltersbase: slight pixel diffs resizeimagefilter: slight pixel diffs on the "high quality" test case imagefilterscropexpand: displacement results are now correct matriximagefilter: slight pixel diffs BUG=skia:3194 ========== to ========== Change saveLayer() semantics to take unfiltered bounds. For optimizing saveLayer() offscreens, it is useful to know the bounds of the primitive being drawn. Currently, the bounds passed to saveLayer() are filtered, which makes it difficult to know the original bounds of the primitive. This CL changes the semantics to accept unfiltered bounds. This actually simplifies the callsites too. In order to result in the correct pixels being produced, we then call computeFastBounds() inside clipRectBounds(). The old behaviour is wrapped in #ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, until we can update Chrome's callsites (see https://codereview.chromium.org/1316243002/). This change will affect the following GMs: testimagefilters: saveLayer bounds no longer cause clipping imagefiltersbase: slight pixel diffs resizeimagefilter: slight pixel diffs on the "high quality" test case imagefilterscropexpand: displacement results are now correct filterfastbounds: slight pixel diffs matriximagefilter: slight pixel diffs BUG=skia:3194 ==========
The CQ bit was unchecked by commit-bot@chromium.org
Dry run: This issue passed the CQ dry run.
https://codereview.chromium.org/1304883004/diff/260001/src/core/SkCanvas.cpp File src/core/SkCanvas.cpp (right): https://codereview.chromium.org/1304883004/diff/260001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:438: public: Well, isn't rawBounds the completely raw bounds - unmodified by the paint at all ? Calling out image filter outsets makes it seem that these bounds are the partiallyCookedBounds. https://codereview.chromium.org/1304883004/diff/260001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:481: if (rawBounds) { // Make rawBounds include all paint outsets except for those due to image filters ?
reed@google.com changed required reviewers: + robertphillips@google.com
I bet we can encapsulate the various states of bounds cooking in some utility class, one that might simplify all the call-sites and even the internalSaveLayer site, but I can experiment w/ that idea after this lands. lgtm
https://codereview.chromium.org/1304883004/diff/260001/src/core/SkCanvas.cpp File src/core/SkCanvas.cpp (right): https://codereview.chromium.org/1304883004/diff/260001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:438: public: On 2015/10/28 16:21:47, robertphillips wrote: > Well, isn't rawBounds the completely raw bounds - unmodified by the paint at all > ? > Calling out image filter outsets makes it seem that these bounds are the > partiallyCookedBounds. Good point. Fixed. https://codereview.chromium.org/1304883004/diff/260001/src/core/SkCanvas.cpp#... src/core/SkCanvas.cpp:481: if (rawBounds) { On 2015/10/28 16:21:47, robertphillips wrote: > // Make rawBounds include all paint outsets except for those due to image > filters > ? Done.
The CQ bit was checked by senorblanco@chromium.org to run a CQ dry run
Dry run: CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/280001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/280001
The CQ bit was unchecked by reed@google.com
regarding "testimagefilters: saveLayer bounds no longer cause clipping " the differences are pretty large, so I want to be sure I understand them. saveLayer(bounds, ...) The bounds "can" clip the result (of the prefiltered drawing), its just that they are not required to. What is happening in our GM?
OK, I just played around with the GM... - It is applying the filter to the layer, not the draw. - the bounds (drawn w/ black hairline) is therefore just applied to the "capture", the unfiltered drawing into the layer. - the new results "correctly" *don't* clip the result (the filtered version). I guess we had a bug all along showing in this GM, and I just didn't know it. lgtm (again)
lgtm
Description was changed from ========== Change saveLayer() semantics to take unfiltered bounds. For optimizing saveLayer() offscreens, it is useful to know the bounds of the primitive being drawn. Currently, the bounds passed to saveLayer() are filtered, which makes it difficult to know the original bounds of the primitive. This CL changes the semantics to accept unfiltered bounds. This actually simplifies the callsites too. In order to result in the correct pixels being produced, we then call computeFastBounds() inside clipRectBounds(). The old behaviour is wrapped in #ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, until we can update Chrome's callsites (see https://codereview.chromium.org/1316243002/). This change will affect the following GMs: testimagefilters: saveLayer bounds no longer cause clipping imagefiltersbase: slight pixel diffs resizeimagefilter: slight pixel diffs on the "high quality" test case imagefilterscropexpand: displacement results are now correct filterfastbounds: slight pixel diffs matriximagefilter: slight pixel diffs BUG=skia:3194 ========== to ========== Change saveLayer() semantics to take unfiltered bounds. For optimizing saveLayer() offscreens, it is useful to know the bounds of the primitive being drawn. Currently, the bounds passed to saveLayer() are filtered, which makes it difficult to know the original bounds of the primitive. This CL changes the semantics to accept unfiltered bounds. This actually simplifies the callsites too. In order to result in the correct pixels being produced, we then call computeFastBounds() inside clipRectBounds(). The old behaviour is wrapped in #ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED, until we can update Chrome's callsites (see https://codereview.chromium.org/1316243002/). This change will affect the following GMs: testimagefilters: saveLayer bounds no longer cause clipping imagefiltersbase: slight pixel diffs resizeimagefilter: slight pixel diffs on the "high quality" test case imagefilterscropexpand: displacement results are now correct filterfastbounds: slight pixel diffs matriximagefilter: slight pixel diffs BUG=skia:3194 skia:4526 ==========
The CQ bit was checked by senorblanco@chromium.org
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1304883004/280001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1304883004/280001
Message was sent while issue was closed.
Committed patchset #15 (id:280001) as https://skia.googlesource.com/skia/+/87e066ee80e094c8f4ccda3d6c33d907b414b91b |