aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2016-12-29 09:18:20 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-12-29 18:35:44 +0000
commit615d66d1aed8f0b6510d58658e639b69c4d73b35 (patch)
treecbbf32051eba73fadf7124f403c3777bc2d7aca0
parent85ff84821d5f6c8d48f2af12bdffdd3b5f8baf2c (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.h9
-rw-r--r--src/core/SkImageFilter.cpp30
-rw-r--r--src/effects/SkMatrixConvolutionImageFilter.cpp32
-rw-r--r--src/effects/SkMorphologyImageFilter.cpp35
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;