SkCanvas::kStrict_SrcRectConstraint disables mipmapping.

The implementation is inconsistent across CPU and GPU.

CPU currently always implements kStrict even when kFast is passed.
For mipmapping this means computing a set of levels from the subset,
which is an expensive.

GPU limits the texture sampling coordinates to the subset in the
base level. However, higher level mipmap pixels that map back to
a footprint outside the subset are still sampled. So GPU pays a
higher shader complexity cost without really providing the benefit
of kStrict.

We are adding anisotropic filtering, which will not work well with
kStrict, and thus will also be disabled by kStrict.


Must land after https://chromium-review.googlesource.com/c/chromium/src/+/3571661

Bug: skia:10481
Bug: skia:13078
Bug: skia:13036
Canary-Chromium-CL: 3571661
Change-Id: I011b8698a3f9fafa9b819486873c8ff54df6299e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/527284
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2022-04-05 09:40:21 -04:00 committed by SkCQ
parent 44832b292d
commit 072e09b26d
3 changed files with 39 additions and 4 deletions

View File

@ -9,6 +9,13 @@ Milestone 102
* GrContextOptions::fSharpenMipmappedTextures is removed. MIP LOD is now always
biased on the GPU backend. The CPU backend implementation is modified to match
this behavior.
* Passing SkCanvas::kStrict_SrcRectConstraint disables mipmapping. The old behavior differed
between GPU and CPU. CPU always computed a new set of mipmap based on the subset. GPU restricted
the sampling coordinates to the subset in the base level but upper level pixels that map to
pixels outside the subset in the base level were still used. To get the previous CPU behavior
use SkImage::makeSubset() to make a subset image and draw that. The previous GPU behavior is
similar, though not exactly, equivalent to making a mipmapped image shader from the original
image and applying that to a rectangle.
* * *

View File

@ -1445,6 +1445,7 @@ public:
SrcRectConstraint controls the behavior at the edge of source SkRect,
provided to drawImageRect() when there is any filtering. If kStrict is set,
then extra code is used to ensure it nevers samples outside of the src-rect.
kStrict_SrcRectConstraint disables the use of mipmaps.
*/
enum SrcRectConstraint {
kStrict_SrcRectConstraint, //!< sample only inside bounds; slower

View File

@ -2253,14 +2253,40 @@ void SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
auto layer = this->aboutToDraw(this, realPaint, &bounds);
if (layer) {
this->topDevice()->drawImageRect(image, nullptr, bounds, sampling,
layer->paint(), kStrict_SrcRectConstraint);
layer->paint(), kFast_SrcRectConstraint);
}
}
static SkSamplingOptions clean_sampling_for_constraint(
const SkSamplingOptions& sampling,
SkCanvas::SrcRectConstraint constraint) {
#if !defined(SK_LEGACY_ALLOW_STRICT_CONSTRAINT_MIPMAPPING)
if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
sampling.mipmap != SkMipmapMode::kNone) {
return SkSamplingOptions(sampling.filter);
}
#endif
return sampling;
}
static SkCanvas::SrcRectConstraint clean_constraint_for_image_bounds(
SkCanvas::SrcRectConstraint constraint,
const SkRect& src,
const SkImage* image) {
#if defined(SK_DISABLE_STRICT_CONSTRAINT_FOR_ENTIRE_IMAGE)
if (constraint == SkCanvas::kStrict_SrcRectConstraint && src.contains(image->bounds())) {
return SkCanvas::kFast_SrcRectConstraint;
}
#endif
return constraint;
}
void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
const SkSamplingOptions& sampling, const SkPaint* paint,
SrcRectConstraint constraint) {
SkPaint realPaint = clean_paint_for_drawImage(paint);
constraint = clean_constraint_for_image_bounds(constraint, src, image);
SkSamplingOptions realSampling = clean_sampling_for_constraint(sampling, constraint);
if (this->internalQuickReject(dst, realPaint)) {
return;
@ -2270,7 +2296,7 @@ void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const S
image->isOpaque() ? kOpaque_ShaderOverrideOpacity
: kNotOpaque_ShaderOverrideOpacity);
if (layer) {
this->topDevice()->drawImageRect(image, &src, dst, sampling, layer->paint(), constraint);
this->topDevice()->drawImageRect(image, &src, dst, realSampling, layer->paint(), constraint);
}
}
@ -2633,6 +2659,7 @@ void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
}
SkPaint realPaint = clean_paint_for_drawImage(paint);
SkSamplingOptions realSampling = clean_sampling_for_constraint(sampling, constraint);
// We could calculate the set's dstRect union to always check quickReject(), but we can't reject
// individual entries and Chromium's occlusion culling already makes it likely that at least one
@ -2662,8 +2689,8 @@ void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
auto layer = this->aboutToDraw(this, realPaint, setBoundsValid ? &setBounds : nullptr);
if (layer) {
this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling,
layer->paint(), constraint);
this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices,
realSampling, layer->paint(), constraint);
}
}