diff options
author | 2016-12-29 09:18:20 -0500 | |
---|---|---|
committer | 2016-12-29 18:35:44 +0000 | |
commit | 615d66d1aed8f0b6510d58658e639b69c4d73b35 (patch) | |
tree | cbbf32051eba73fadf7124f403c3777bc2d7aca0 | |
parent | 85ff84821d5f6c8d48f2af12bdffdd3b5f8baf2c (diff) |
Add ImageToColorSpace helper in SkImageFilter
Share this logic among a couple filters that need it. This also fixes a
bug that showed up in the morhpology GM for GPU color space configs.
Re-land of https://skia-review.googlesource.com/c/6475/
BUG=skia:
Change-Id: If7b8d892cf89fa030bae68bdd3c03118f290f032
Reviewed-on: https://skia-review.googlesource.com/6484
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
-rw-r--r-- | include/core/SkImageFilter.h | 9 | ||||
-rw-r--r-- | src/core/SkImageFilter.cpp | 30 | ||||
-rw-r--r-- | src/effects/SkMatrixConvolutionImageFilter.cpp | 32 | ||||
-rw-r--r-- | src/effects/SkMorphologyImageFilter.cpp | 35 |
4 files changed, 49 insertions, 57 deletions
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h index c2d7261196..86e12e1f4f 100644 --- a/include/core/SkImageFilter.h +++ b/include/core/SkImageFilter.h @@ -386,6 +386,15 @@ protected: */ Context mapContext(const Context& ctx) const; +#if SK_SUPPORT_GPU + /** + * Returns a version of the passed-in image (possibly the original), that is in a colorspace + * with the same gamut as the one from the OutputProperties. This allows filters that do many + * texture samples to guarantee that any color space conversion has happened before running. + */ + static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&); +#endif + private: friend class SkGraphics; static void PurgeCache(); diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp index 2ec441f108..7965091600 100644 --- a/src/core/SkImageFilter.cpp +++ b/src/core/SkImageFilter.cpp @@ -8,6 +8,7 @@ #include "SkImageFilter.h" #include "SkCanvas.h" +#include "SkColorSpace_Base.h" #include "SkFuzzLogging.h" #include "SkImageFilterCache.h" #include "SkLocalMatrixImageFilter.h" @@ -344,6 +345,35 @@ bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds, return dstBounds->intersect(ctx.clipBounds()); } +#if SK_SUPPORT_GPU +sk_sp<SkSpecialImage> SkImageFilter::ImageToColorSpace(SkSpecialImage* src, + const OutputProperties& outProps) { + // There are several conditions that determine if we actually need to convert the source to the + // destination's color space. Rather than duplicate that logic here, just try to make an xform + // object. If that produces something, then both are tagged, and the source is in a different + // gamut than the dest. There is some overhead to making the xform, but those are cached, and + // if we get one back, that means we're about to use it during the conversion anyway. + sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(src->getColorSpace(), + outProps.colorSpace()); + + if (!colorSpaceXform) { + // No xform needed, just return the original image + return sk_ref_sp(src); + } + + sk_sp<SkSpecialSurface> surf(src->makeSurface(outProps, + SkISize::Make(src->width(), src->height()))); + if (!surf) { + return sk_ref_sp(src); + } + + SkCanvas* canvas = surf->getCanvas(); + SkASSERT(canvas); + src->draw(canvas, 0, 0, nullptr); + return surf->makeImageSnapshot(); +} +#endif + // Return a larger (newWidth x newHeight) copy of 'src' with black padding // around it. static sk_sp<SkSpecialImage> pad_image(SkSpecialImage* src, diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp index 40d09d661a..6af8508b5a 100644 --- a/src/effects/SkMatrixConvolutionImageFilter.cpp +++ b/src/effects/SkMatrixConvolutionImageFilter.cpp @@ -10,7 +10,6 @@ #include "SkColorPriv.h" #include "SkReadBuffer.h" #include "SkSpecialImage.h" -#include "SkSpecialSurface.h" #include "SkWriteBuffer.h" #include "SkRect.h" #include "SkUnPreMultiply.h" @@ -282,23 +281,6 @@ static GrTextureDomain::Mode convert_tilemodes(SkMatrixConvolutionImageFilter::T } return GrTextureDomain::kIgnore_Mode; } - -// Return a copy of 'src' transformed to the output's color space -static sk_sp<SkSpecialImage> image_to_color_space(SkSpecialImage* src, - const SkImageFilter::OutputProperties& outProps) { - sk_sp<SkSpecialSurface> surf(src->makeSurface( - outProps, SkISize::Make(src->width(), src->height()))); - if (!surf) { - return sk_ref_sp(src); - } - - SkCanvas* canvas = surf->getCanvas(); - SkASSERT(canvas); - - src->draw(canvas, 0, 0, nullptr); - - return surf->makeImageSnapshot(); -} #endif sk_sp<SkSpecialImage> SkMatrixConvolutionImageFilter::onFilterImage(SkSpecialImage* source, @@ -322,15 +304,11 @@ sk_sp<SkSpecialImage> SkMatrixConvolutionImageFilter::onFilterImage(SkSpecialIma fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE) { GrContext* context = source->getContext(); - // If the input is not yet already in the destination color space, do an explicit up-front - // conversion. This is extremely unlikely (maybe even impossible). Typically, applyCropRect - // will have called pad_image to account for our dilation of bounds, so the result will - // already be moved to the destination color space. If someone makes a filter DAG that - // avoids that, then we use this fall-back, which saves us from having to do the xform - // during the filter itself. - if (input->getColorSpace() != ctx.outputProperties().colorSpace()) { - input = image_to_color_space(input.get(), ctx.outputProperties()); - } + // Ensure the input is in the destination color space. Typically applyCropRect will have + // called pad_image to account for our dilation of bounds, so the result will already be + // moved to the destination color space. If a filter DAG avoids that, then we use this + // fall-back, which saves us from having to do the xform during the filter itself. + input = ImageToColorSpace(input.get(), ctx.outputProperties()); sk_sp<GrTexture> inputTexture(input->asTextureRef(context)); SkASSERT(inputTexture); diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index 42986ce9de..8b5cbaac00 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -13,7 +13,6 @@ #include "SkReadBuffer.h" #include "SkRect.h" #include "SkSpecialImage.h" -#include "SkSpecialSurface.h" #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU @@ -493,9 +492,6 @@ static sk_sp<SkSpecialImage> apply_morphology( sk_sp<SkColorSpace> colorSpace = sk_ref_sp(outputProperties.colorSpace()); GrPixelConfig config = GrRenderableConfigForColorSpace(colorSpace.get()); - // We force the inputs to this filter into the destination color space in the calling code. - SkASSERT(input->getColorSpace() == colorSpace.get()); - // setup new clip const GrFixedClip clip(SkIRect::MakeWH(srcTexture->width(), srcTexture->height())); @@ -546,23 +542,6 @@ static sk_sp<SkSpecialImage> apply_morphology( std::move(srcTexture), std::move(colorSpace), &input->props()); } - -// Return a copy of 'src' transformed to the output's color space -static sk_sp<SkSpecialImage> image_to_color_space(SkSpecialImage* src, - const SkImageFilter::OutputProperties& outProps) { - sk_sp<SkSpecialSurface> surf(src->makeSurface( - outProps, SkISize::Make(src->width(), src->height()))); - if (!surf) { - return sk_ref_sp(src); - } - - SkCanvas* canvas = surf->getCanvas(); - SkASSERT(canvas); - - src->draw(canvas, 0, 0, nullptr); - - return surf->makeImageSnapshot(); -} #endif sk_sp<SkSpecialImage> SkMorphologyImageFilter::onFilterImage(SkSpecialImage* source, @@ -603,15 +582,11 @@ sk_sp<SkSpecialImage> SkMorphologyImageFilter::onFilterImage(SkSpecialImage* sou if (source->isTextureBacked()) { GrContext* context = source->getContext(); - // If the input is not yet already in the destination color space, do an explicit up-front - // conversion. This is extremely unlikely (maybe even impossible). Typically, applyCropRect - // will have called pad_image to account for our dilation of bounds, so the result will - // already be moved to the destination color space. If someone makes a filter DAG that - // avoids that, then we use this fall-back, which saves us from having to do the xform - // during the filter itself. - if (input->getColorSpace() != ctx.outputProperties().colorSpace()) { - input = image_to_color_space(input.get(), ctx.outputProperties()); - } + // Ensure the input is in the destination color space. Typically applyCropRect will have + // called pad_image to account for our dilation of bounds, so the result will already be + // moved to the destination color space. If a filter DAG avoids that, then we use this + // fall-back, which saves us from having to do the xform during the filter itself. + input = ImageToColorSpace(input.get(), ctx.outputProperties()); auto type = (kDilate_Op == this->op()) ? GrMorphologyEffect::kDilate_MorphologyType : GrMorphologyEffect::kErode_MorphologyType; |