Index: src/effects/SkMatrixConvolutionImageFilter.cpp |
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp |
index 3104336628e13d32ad27384452c0e47607bc32f9..51e3b6faa72f6af926c98d3d181a97a60263c58e 100644 |
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp |
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp |
@@ -8,13 +8,16 @@ |
#include "SkMatrixConvolutionImageFilter.h" |
#include "SkBitmap.h" |
#include "SkColorPriv.h" |
-#include "SkDevice.h" |
#include "SkReadBuffer.h" |
+#include "SkSpecialImage.h" |
+#include "SkSpecialSurface.h" |
#include "SkWriteBuffer.h" |
#include "SkRect.h" |
#include "SkUnPreMultiply.h" |
#if SK_SUPPORT_GPU |
+#include "GrContext.h" |
+#include "GrDrawContext.h" |
#include "effects/GrMatrixConvolutionEffect.h" |
#endif |
@@ -242,18 +245,19 @@ void SkMatrixConvolutionImageFilter::filterBorderPixels(const SkBitmap& src, |
// FIXME: This should be refactored to SkImageFilterUtils for |
// use by other filters. For now, we assume the input is always |
// premultiplied and unpremultiply it |
-static SkBitmap unpremultiplyBitmap(SkImageFilter::Proxy* proxy, const SkBitmap& src) |
+static SkBitmap unpremultiply_bitmap(const SkBitmap& src) |
{ |
SkAutoLockPixels alp(src); |
if (!src.getPixels()) { |
return SkBitmap(); |
} |
- SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height())); |
- if (!device) { |
+ |
+ const SkImageInfo info = SkImageInfo::MakeN32(src.width(), src.height(), src.alphaType()); |
+ SkBitmap result; |
+ if (!result.tryAllocPixels(info)) { |
return SkBitmap(); |
} |
- SkBitmap result = device->accessBitmap(false); |
- SkAutoLockPixels alp_result(result); |
+ SkAutoLockPixels resultLock(result); |
for (int y = 0; y < src.height(); ++y) { |
const uint32_t* srcRow = src.getAddr32(0, y); |
uint32_t* dstRow = result.getAddr32(0, y); |
@@ -264,46 +268,103 @@ static SkBitmap unpremultiplyBitmap(SkImageFilter::Proxy* proxy, const SkBitmap& |
return result; |
} |
-bool SkMatrixConvolutionImageFilter::onFilterImageDeprecated(Proxy* proxy, |
- const SkBitmap& source, |
- const Context& ctx, |
- SkBitmap* result, |
- SkIPoint* offset) const { |
- SkBitmap src = source; |
- SkIPoint srcOffset = SkIPoint::Make(0, 0); |
- if (!this->filterInputDeprecated(0, proxy, source, ctx, &src, &srcOffset)) { |
- return false; |
+#if SK_SUPPORT_GPU |
+ |
+static GrTextureDomain::Mode convert_tilemodes(SkMatrixConvolutionImageFilter::TileMode tileMode) { |
+ switch (tileMode) { |
+ case SkMatrixConvolutionImageFilter::kClamp_TileMode: |
+ return GrTextureDomain::kClamp_Mode; |
+ case SkMatrixConvolutionImageFilter::kRepeat_TileMode: |
+ return GrTextureDomain::kRepeat_Mode; |
+ case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode: |
+ return GrTextureDomain::kDecal_Mode; |
+ default: |
+ SkASSERT(false); |
} |
+ return GrTextureDomain::kIgnore_Mode; |
+} |
- if (src.colorType() != kN32_SkColorType) { |
- return false; |
+#endif |
+ |
+sk_sp<SkSpecialImage> SkMatrixConvolutionImageFilter::onFilterImage(SkSpecialImage* source, |
+ const Context& ctx, |
+ SkIPoint* offset) const { |
+ SkIPoint inputOffset = SkIPoint::Make(0, 0); |
+ sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); |
+ if (!input) { |
+ return nullptr; |
} |
SkIRect bounds; |
- if (!this->applyCropRectDeprecated(this->mapContext(ctx), proxy, src, &srcOffset, |
- &bounds, &src)) { |
- return false; |
+ input = this->applyCropRect(this->mapContext(ctx), input.get(), &inputOffset, &bounds); |
+ if (!input) { |
+ return nullptr; |
} |
- if (!fConvolveAlpha && !src.isOpaque()) { |
- src = unpremultiplyBitmap(proxy, src); |
+#if SK_SUPPORT_GPU |
+ // Note: if the kernel is too big, the GPU path falls back to SW |
+ if (source->isTextureBacked() && |
+ fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE) { |
+ GrContext* context = source->getContext(); |
+ |
+ sk_sp<GrTexture> inputTexture(input->asTextureRef(context)); |
+ SkASSERT(inputTexture); |
+ |
+ offset->fX = bounds.left(); |
+ offset->fY = bounds.top(); |
+ bounds.offset(-inputOffset); |
+ |
+ // SRGBTODO: handle sRGB here |
+ sk_sp<GrFragmentProcessor> fp(GrMatrixConvolutionEffect::Create( |
+ inputTexture.get(), |
+ bounds, |
+ fKernelSize, |
+ fKernel, |
+ fGain, |
+ fBias, |
+ fKernelOffset, |
+ convert_tilemodes(fTileMode), |
+ fConvolveAlpha)); |
+ if (!fp) { |
+ return nullptr; |
+ } |
+ |
+ return DrawWithFP(context, std::move(fp), bounds, source->internal_getProxy()); |
} |
+#endif |
- SkAutoLockPixels alp(src); |
- if (!src.getPixels()) { |
- return false; |
+ SkBitmap inputBM; |
+ |
+ if (!input->getROPixels(&inputBM)) { |
+ return nullptr; |
} |
- SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); |
- if (!device) { |
- return false; |
+ if (inputBM.colorType() != kN32_SkColorType) { |
+ return nullptr; |
} |
- *result = device->accessBitmap(false); |
- SkAutoLockPixels alp_result(*result); |
+ |
+ if (!fConvolveAlpha && !inputBM.isOpaque()) { |
+ inputBM = unpremultiply_bitmap(inputBM); |
+ } |
+ |
+ SkAutoLockPixels alp(inputBM); |
+ if (!inputBM.getPixels()) { |
+ return nullptr; |
+ } |
+ |
+ const SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), |
+ inputBM.alphaType()); |
+ |
+ SkBitmap dst; |
+ if (!dst.tryAllocPixels(info)) { |
+ return nullptr; |
+ } |
+ |
+ SkAutoLockPixels dstLock(dst); |
offset->fX = bounds.fLeft; |
offset->fY = bounds.fTop; |
- bounds.offset(-srcOffset); |
+ bounds.offset(-inputOffset); |
SkIRect interior = SkIRect::MakeXYWH(bounds.left() + fKernelOffset.fX, |
bounds.top() + fKernelOffset.fY, |
bounds.width() - fKernelSize.fWidth + 1, |
@@ -315,12 +376,14 @@ bool SkMatrixConvolutionImageFilter::onFilterImageDeprecated(Proxy* proxy, |
interior.left(), interior.bottom()); |
SkIRect right = SkIRect::MakeLTRB(interior.right(), interior.top(), |
bounds.right(), interior.bottom()); |
- filterBorderPixels(src, result, top, bounds); |
- filterBorderPixels(src, result, left, bounds); |
- filterInteriorPixels(src, result, interior, bounds); |
- filterBorderPixels(src, result, right, bounds); |
- filterBorderPixels(src, result, bottom, bounds); |
- return true; |
+ this->filterBorderPixels(inputBM, &dst, top, bounds); |
+ this->filterBorderPixels(inputBM, &dst, left, bounds); |
+ this->filterInteriorPixels(inputBM, &dst, interior, bounds); |
+ this->filterBorderPixels(inputBM, &dst, right, bounds); |
+ this->filterBorderPixels(inputBM, &dst, bottom, bounds); |
+ return SkSpecialImage::MakeFromRaster(source->internal_getProxy(), |
+ SkIRect::MakeWH(bounds.width(), bounds.height()), |
+ dst); |
} |
SkIRect SkMatrixConvolutionImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, |
@@ -343,44 +406,6 @@ bool SkMatrixConvolutionImageFilter::affectsTransparentBlack() const { |
return true; |
} |
-#if SK_SUPPORT_GPU |
- |
-static GrTextureDomain::Mode convert_tilemodes( |
- SkMatrixConvolutionImageFilter::TileMode tileMode) { |
- switch (tileMode) { |
- case SkMatrixConvolutionImageFilter::kClamp_TileMode: |
- return GrTextureDomain::kClamp_Mode; |
- case SkMatrixConvolutionImageFilter::kRepeat_TileMode: |
- return GrTextureDomain::kRepeat_Mode; |
- case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode: |
- return GrTextureDomain::kDecal_Mode; |
- default: |
- SkASSERT(false); |
- } |
- return GrTextureDomain::kIgnore_Mode; |
-} |
- |
-bool SkMatrixConvolutionImageFilter::asFragmentProcessor(GrFragmentProcessor** fp, |
- GrTexture* texture, |
- const SkMatrix&, |
- const SkIRect& bounds) const { |
- if (!fp) { |
- return fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE; |
- } |
- SkASSERT(fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE); |
- *fp = GrMatrixConvolutionEffect::Create(texture, |
- bounds, |
- fKernelSize, |
- fKernel, |
- fGain, |
- fBias, |
- fKernelOffset, |
- convert_tilemodes(fTileMode), |
- fConvolveAlpha); |
- return true; |
-} |
-#endif |
- |
#ifndef SK_IGNORE_TO_STRING |
void SkMatrixConvolutionImageFilter::toString(SkString* str) const { |
str->appendf("SkMatrixConvolutionImageFilter: ("); |