Add color space xform fallback to GrMorphologyEffect
authorBrian Osman <brianosman@google.com>
Wed, 21 Dec 2016 18:36:02 +0000 (13:36 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Wed, 21 Dec 2016 19:30:37 +0000 (19:30 +0000)
99% of the time (or maybe 100%?) morphology will trigger pad_image,
so the input texture will already be in the destimation color space.
If that doesn't happen, then just force the source to be converted,
which keeps the morphology effect and driver code simple.

BUG=skia:

Change-Id: I98876af4f9e9a5da031973213ed76349752ce68f
Reviewed-on: https://skia-review.googlesource.com/6388
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>

src/effects/SkMorphologyImageFilter.cpp

index 130f099..42986ce 100644 (file)
@@ -13,6 +13,7 @@
 #include "SkReadBuffer.h"
 #include "SkRect.h"
 #include "SkSpecialImage.h"
+#include "SkSpecialSurface.h"
 #include "SkWriteBuffer.h"
 
 #if SK_SUPPORT_GPU
@@ -492,6 +493,9 @@ 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()));
 
@@ -507,7 +511,7 @@ static sk_sp<SkSpecialImage> apply_morphology(
             return nullptr;
         }
 
-        apply_morphology_pass(context->textureProvider(), 
+        apply_morphology_pass(context->textureProvider(),
                               dstRTContext.get(), clip, srcTexture.get(),
                               srcRect, dstRect, radius.fWidth, morphType,
                               Gr1DKernelEffect::kX_Direction);
@@ -542,6 +546,23 @@ 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,
@@ -582,6 +603,16 @@ 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());
+        }
+
         auto type = (kDilate_Op == this->op()) ? GrMorphologyEffect::kDilate_MorphologyType
                                                : GrMorphologyEffect::kErode_MorphologyType;
         sk_sp<SkSpecialImage> result(apply_morphology(context, input.get(), srcBounds, type,