180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/* 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 The Android Open Source Project 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file. 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkMatrixConvolutionImageFilter.h" 980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkBitmap.h" 1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkColorPriv.h" 1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkFlattenableBuffers.h" 1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkRect.h" 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkUnPreMultiply.h" 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if SK_SUPPORT_GPU 16363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "gl/GrGLEffect.h" 17363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "gl/GrGLEffectMatrix.h" 18363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "effects/GrSingleTextureEffect.h" 19363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "GrTBackendEffectFactory.h" 20363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "GrTexture.h" 21363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkMatrix.h" 22363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, bool convolveAlpha, SkImageFilter* input) 2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru : INHERITED(input), 2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernelSize(kernelSize), 2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fGain(gain), 2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fBias(bias), 3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTarget(target), 3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTileMode(tileMode), 3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fConvolveAlpha(convolveAlpha) { 3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight; 3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernel = SkNEW_ARRAY(SkScalar, size); 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru memcpy(fKernel, kernel, size * sizeof(SkScalar)); 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(kernelSize.fWidth >= 1 && kernelSize.fHeight >= 1); 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(target.fX >= 0 && target.fX < kernelSize.fWidth); 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(target.fY >= 0 && target.fY < kernelSize.fHeight); 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { 4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernelSize.fWidth = buffer.readInt(); 4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernelSize.fHeight = buffer.readInt(); 4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32_t size = fKernelSize.fWidth * fKernelSize.fHeight; 4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernel = SkNEW_ARRAY(SkScalar, size); 46d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkDEBUGCODE(uint32_t readSize = )buffer.readScalarArray(fKernel); 4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(readSize == size); 4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fGain = buffer.readScalar(); 4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fBias = buffer.readScalar(); 50363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fTarget.fX = buffer.readInt(); 51363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fTarget.fY = buffer.readInt(); 5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTileMode = (TileMode) buffer.readInt(); 5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fConvolveAlpha = buffer.readBool(); 5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMatrixConvolutionImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru this->INHERITED::flatten(buffer); 5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writeInt(fKernelSize.fWidth); 5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writeInt(fKernelSize.fHeight); 6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writeScalarArray(fKernel, fKernelSize.fWidth * fKernelSize.fHeight); 6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writeScalar(fGain); 6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writeScalar(fBias); 63363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger buffer.writeInt(fTarget.fX); 64363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger buffer.writeInt(fTarget.fY); 6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writeInt((int) fTileMode); 6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writeBool(fConvolveAlpha); 6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMatrixConvolutionImageFilter::~SkMatrixConvolutionImageFilter() { 7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru delete[] fKernel; 7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass UncheckedPixelFetcher { 7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return *src.getAddr32(x, y); 7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass ClampPixelFetcher { 8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x = SkClampMax(x, src.width() - 1); 8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru y = SkClampMax(y, src.height() - 1); 8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return *src.getAddr32(x, y); 8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass RepeatPixelFetcher { 9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x %= src.width(); 9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru y %= src.height(); 9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (x < 0) { 9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x += src.width(); 9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (y < 0) { 9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru y += src.height(); 9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return *src.getAddr32(x, y); 10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass ClampToBlackPixelFetcher { 10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { 10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (x < 0 || x >= src.width() || y < 0 || y >= src.height()) { 10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return 0; 10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return *src.getAddr32(x, y); 11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutemplate<class PixelFetcher, bool convolveAlpha> 11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int y = rect.fTop; y < rect.fBottom; ++y) { 11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPMColor* dptr = result->getAddr32(rect.fLeft, y); 11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int x = rect.fLeft; x < rect.fRight; ++x) { 12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar sumA = 0, sumR = 0, sumG = 0, sumB = 0; 12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int cy = 0; cy < fKernelSize.fHeight; cy++) { 12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int cx = 0; cx < fKernelSize.fWidth; cx++) { 12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPMColor s = PixelFetcher::fetch(src, x + cx - fTarget.fX, y + cy - fTarget.fY); 12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar k = fKernel[cy * fKernelSize.fWidth + cx]; 12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (convolveAlpha) { 12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sumA += SkScalarMul(SkIntToScalar(SkGetPackedA32(s)), k); 12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sumR += SkScalarMul(SkIntToScalar(SkGetPackedR32(s)), k); 12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sumG += SkScalarMul(SkIntToScalar(SkGetPackedG32(s)), k); 13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sumB += SkScalarMul(SkIntToScalar(SkGetPackedB32(s)), k); 13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int a = convolveAlpha 13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ? SkClampMax(SkScalarFloorToInt(SkScalarMul(sumA, fGain) + fBias), 255) 13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru : 255; 13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int r = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumR, fGain) + fBias), a); 13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int g = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumG, fGain) + fBias), a); 13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int b = SkClampMax(SkScalarFloorToInt(SkScalarMul(sumB, fGain) + fBias), a); 13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!convolveAlpha) { 14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru a = SkGetPackedA32(PixelFetcher::fetch(src, x, y)); 14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dptr++ = SkPreMultiplyARGB(a, r, g, b); 14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dptr++ = SkPackARGB32(a, r, g, b); 14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutemplate<class PixelFetcher> 15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMatrixConvolutionImageFilter::filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fConvolveAlpha) { 15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterPixels<PixelFetcher, true>(src, result, rect); 15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterPixels<PixelFetcher, false>(src, result, rect); 15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMatrixConvolutionImageFilter::filterInteriorPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterPixels<UncheckedPixelFetcher>(src, result, rect); 16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMatrixConvolutionImageFilter::filterBorderPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect) { 16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru switch (fTileMode) { 16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case kClamp_TileMode: 16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterPixels<ClampPixelFetcher>(src, result, rect); 16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case kRepeat_TileMode: 16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterPixels<RepeatPixelFetcher>(src, result, rect); 16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case kClampToBlack_TileMode: 17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterPixels<ClampToBlackPixelFetcher>(src, result, rect); 17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 176096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger// FIXME: This should be refactored to SkImageFilterUtils for 17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// use by other filters. For now, we assume the input is always 17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// premultiplied and unpremultiply it 17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic SkBitmap unpremultiplyBitmap(const SkBitmap& src) 18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{ 18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkAutoLockPixels alp(src); 18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!src.getPixels()) { 18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return SkBitmap(); 18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkBitmap result; 18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru result.setConfig(src.config(), src.width(), src.height()); 18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru result.allocPixels(); 18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!result.getPixels()) { 18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return SkBitmap(); 19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int y = 0; y < src.height(); ++y) { 19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const uint32_t* srcRow = src.getAddr32(0, y); 19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32_t* dstRow = result.getAddr32(0, y); 19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int x = 0; x < src.width(); ++x) { 19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstRow[x] = SkUnPreMultiply::PMColorToColor(srcRow[x]); 19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return result; 19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, 20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkBitmap& source, 20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkMatrix& matrix, 20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkBitmap* result, 20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIPoint* loc) { 206779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger SkBitmap src = source; 207779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, loc)) { 208779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger return false; 209779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger } 210779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger 21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (src.config() != SkBitmap::kARGB_8888_Config) { 21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!fConvolveAlpha && !src.isOpaque()) { 21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru src = unpremultiplyBitmap(src); 21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkAutoLockPixels alp(src); 22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!src.getPixels()) { 22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru result->setConfig(src.config(), src.width(), src.height()); 22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru result->allocPixels(); 22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIRect interior = SkIRect::MakeXYWH(fTarget.fX, fTarget.fY, 22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru src.width() - fKernelSize.fWidth + 1, 22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru src.height() - fKernelSize.fHeight + 1); 23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIRect top = SkIRect::MakeWH(src.width(), fTarget.fY); 23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIRect bottom = SkIRect::MakeLTRB(0, interior.bottom(), 23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru src.width(), src.height()); 23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIRect left = SkIRect::MakeXYWH(0, interior.top(), 23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTarget.fX, interior.height()); 23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIRect right = SkIRect::MakeLTRB(interior.right(), interior.top(), 23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru src.width(), interior.bottom()); 23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterBorderPixels(src, result, top); 23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterBorderPixels(src, result, left); 23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterInteriorPixels(src, result, interior); 24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterBorderPixels(src, result, right); 24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru filterBorderPixels(src, result, bottom); 24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return true; 24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if SK_SUPPORT_GPU 24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////////////// 24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass GrGLMatrixConvolutionEffect; 25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass GrMatrixConvolutionEffect : public GrSingleTextureEffect { 25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru typedef SkMatrixConvolutionImageFilter::TileMode TileMode; 254d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger static GrEffectRef* Create(GrTexture* texture, 255d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkISize& kernelSize, 256d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkScalar* kernel, 257d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkScalar gain, 258d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkScalar bias, 259d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkIPoint& target, 260d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger TileMode tileMode, 261d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger bool convolveAlpha) { 262d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger AutoEffectUnref effect(SkNEW_ARGS(GrMatrixConvolutionEffect, (texture, 263d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger kernelSize, 264d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger kernel, 265d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger gain, 266d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger bias, 267d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger target, 268d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger tileMode, 269d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger convolveAlpha))); 270d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return CreateEffectRef(effect); 271d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru virtual ~GrMatrixConvolutionEffect(); 27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 274d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger virtual void getConstantColorComponents(GrColor* color, 275d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger uint32_t* validFlags) const SK_OVERRIDE { 276d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger // TODO: Try to do better? 277d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger *validFlags = 0; 278d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 279d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static const char* Name() { return "MatrixConvolution"; } 28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkISize& kernelSize() const { return fKernelSize; } 28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const float* target() const { return fTarget; } 28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const float* kernel() const { return fKernel; } 28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float gain() const { return fGain; } 28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float bias() const { return fBias; } 28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TileMode tileMode() const { return fTileMode; } 28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool convolveAlpha() const { return fConvolveAlpha; } 28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 289363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger typedef GrGLMatrixConvolutionEffect GLEffect; 29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 291363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate: 294d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger GrMatrixConvolutionEffect(GrTexture*, 295d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkISize& kernelSize, 296d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkScalar* kernel, 297d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkScalar gain, 298d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkScalar bias, 299d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkIPoint& target, 300d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger TileMode tileMode, 301d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger bool convolveAlpha); 302d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 303d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; 304d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkISize fKernelSize; 30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float *fKernel; 30780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float fGain; 30880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float fBias; 30980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float fTarget[2]; 31080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TileMode fTileMode; 31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool fConvolveAlpha; 31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 313363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger GR_DECLARE_EFFECT_TEST; 31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru typedef GrSingleTextureEffect INHERITED; 31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 318363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerclass GrGLMatrixConvolutionEffect : public GrGLEffect { 31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 320363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger GrGLMatrixConvolutionEffect(const GrBackendEffectFactory& factory, 321e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrDrawEffect& effect); 322363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger virtual void emitCode(GrGLShaderBuilder*, 323e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrDrawEffect&, 324363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger EffectKey, 325363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* outputColor, 326363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* inputColor, 327363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const TextureSamplerArray&) SK_OVERRIDE; 328363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 329e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 330363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 331e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate: 33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru typedef GrGLUniformManager::UniformHandle UniformHandle; 33580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru typedef SkMatrixConvolutionImageFilter::TileMode TileMode; 336363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkISize fKernelSize; 337363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger TileMode fTileMode; 338363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool fConvolveAlpha; 339363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 340363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger UniformHandle fKernelUni; 341363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger UniformHandle fImageIncrementUni; 342363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger UniformHandle fTargetUni; 343363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger UniformHandle fGainUni; 344363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger UniformHandle fBiasUni; 345363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 346363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger GrGLEffectMatrix fEffectMatrix; 347363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 348363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger typedef GrGLEffect INHERITED; 34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 351363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerGrGLMatrixConvolutionEffect::GrGLMatrixConvolutionEffect(const GrBackendEffectFactory& factory, 352e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrDrawEffect& drawEffect) 353363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger : INHERITED(factory) 35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fKernelUni(GrGLUniformManager::kInvalidUniformHandle) 35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle) 35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fTargetUni(GrGLUniformManager::kInvalidUniformHandle) 35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fGainUni(GrGLUniformManager::kInvalidUniformHandle) 358e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger , fBiasUni(GrGLUniformManager::kInvalidUniformHandle) 359e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger , fEffectMatrix(drawEffect.castEffect<GrMatrixConvolutionEffect>().coordsType()) { 360e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvolutionEffect>(); 36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernelSize = m.kernelSize(); 36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTileMode = m.tileMode(); 36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fConvolveAlpha = m.convolveAlpha(); 36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 36680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void appendTextureLookup(GrGLShaderBuilder* builder, 36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const GrGLShaderBuilder::TextureSampler& sampler, 36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const char* coord, 36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkMatrixConvolutionImageFilter::TileMode tileMode) { 37080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString clampedCoord; 37180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru switch (tileMode) { 37280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case SkMatrixConvolutionImageFilter::kClamp_TileMode: 37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru clampedCoord.printf("clamp(%s, 0.0, 1.0)", coord); 37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru coord = clampedCoord.c_str(); 37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case SkMatrixConvolutionImageFilter::kRepeat_TileMode: 37780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru clampedCoord.printf("fract(%s)", coord); 37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru coord = clampedCoord.c_str(); 37980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode: 381096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("clamp(%s, 0.0, 1.0) != %s ? vec4(0, 0, 0, 0) : ", coord, coord); 38280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 384096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, sampler, coord); 38580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 38680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 387363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder, 388e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrDrawEffect&, 389363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger EffectKey key, 390363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* outputColor, 391363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* inputColor, 392363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const TextureSamplerArray& samplers) { 393363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* coords; 394e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords); 395363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 396363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger kVec2f_GrSLType, "ImageIncrement"); 397363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType, 398363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger kFloat_GrSLType, "Kernel", fKernelSize.width() * fKernelSize.height()); 399363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fTargetUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 400363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger kVec2f_GrSLType, "Target"); 401363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fGainUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 402363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger kFloat_GrSLType, "Gain"); 403363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fBiasUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 404363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger kFloat_GrSLType, "Bias"); 405363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 40680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const char* target = builder->getUniformCStr(fTargetUni); 40780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const char* imgInc = builder->getUniformCStr(fImageIncrementUni); 40880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const char* kernel = builder->getUniformCStr(fKernelUni); 40980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const char* gain = builder->getUniformCStr(fGainUni); 41080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const char* bias = builder->getUniformCStr(fBiasUni); 41180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int kWidth = fKernelSize.width(); 41280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int kHeight = fKernelSize.height(); 41380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 414096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend("\t\tvec4 sum = vec4(0, 0, 0, 0);\n"); 415096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\tvec2 coord = %s - %s * %s;\n", coords, target, imgInc); 416096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\tfor (int y = 0; y < %d; y++) {\n", kHeight); 417096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t\tfor (int x = 0; x < %d; x++) {\n", kWidth); 418096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t\t\tfloat k = %s[y * %d + x];\n", kernel, kWidth); 419096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t\t\tvec2 coord2 = coord + vec2(x, y) * %s;\n", imgInc); 420096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend("\t\t\t\tvec4 c = "); 42180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru appendTextureLookup(builder, samplers[0], "coord2", fTileMode); 422096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend(";\n"); 42380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!fConvolveAlpha) { 424096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend("\t\t\t\tc.rgb /= c.a;\n"); 42580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 426096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend("\t\t\t\tsum += c * k;\n"); 427096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend("\t\t\t}\n"); 428096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend("\t\t}\n"); 42980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fConvolveAlpha) { 430096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t%s = sum * %s + %s;\n", outputColor, gain, bias); 431096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t%s.rgb = clamp(%s.rgb, 0.0, %s.a);\n", outputColor, outputColor, outputColor); 43280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 433096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend("\t\tvec4 c = "); 434363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger appendTextureLookup(builder, samplers[0], coords, fTileMode); 435096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppend(";\n"); 436096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t%s.a = c.a;\n", outputColor); 437096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t%s.rgb = sum.rgb * %s + %s;\n", outputColor, gain, bias); 438096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); 43980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 44080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 44180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 44280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace { 44380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 44480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint encodeXY(int x, int y) { 44580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(x >= 1 && y >= 1 && x * y <= 32); 44680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (y < x) 44780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return 0x40 | encodeXY(y, x); 44880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru else 44980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return (0x40 >> x) | (y - x); 45080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 45180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 45280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 45380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 454e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek SollenbergerGrGLEffect::EffectKey GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect, 455e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrGLCaps&) { 456e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvolutionEffect>(); 457363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger EffectKey key = encodeXY(m.kernelSize().width(), m.kernelSize().height()); 45880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru key |= m.tileMode() << 7; 45980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru key |= m.convolveAlpha() ? 1 << 9 : 0; 460363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger key <<= GrGLEffectMatrix::kKeyBits; 461363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger EffectKey matrixKey = GrGLEffectMatrix::GenKey(m.getMatrix(), 462e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger drawEffect, 463e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger m.coordsType(), 464363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger m.texture(0)); 465363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return key | matrixKey; 46680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 46780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 46880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid GrGLMatrixConvolutionEffect::setData(const GrGLUniformManager& uman, 469e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrDrawEffect& drawEffect) { 470e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger const GrMatrixConvolutionEffect& conv = drawEffect.castEffect<GrMatrixConvolutionEffect>(); 471e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger GrTexture& texture = *conv.texture(0); 47280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // the code we generated was for a specific kernel size 473e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger GrAssert(conv.kernelSize() == fKernelSize); 474e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger GrAssert(conv.tileMode() == fTileMode); 47580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float imageIncrement[2]; 476d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger float ySign = texture.origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; 47780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru imageIncrement[0] = 1.0f / texture.width(); 478d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger imageIncrement[1] = ySign / texture.height(); 47980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement); 480e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger uman.set2fv(fTargetUni, 0, 1, conv.target()); 481e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger uman.set1fv(fKernelUni, 0, fKernelSize.width() * fKernelSize.height(), conv.kernel()); 482e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger uman.set1f(fGainUni, conv.gain()); 483e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger uman.set1f(fBiasUni, conv.bias()); 484363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fEffectMatrix.setData(uman, 485e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger conv.getMatrix(), 486e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger drawEffect, 487e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger conv.texture(0)); 48880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 48980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 49080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruGrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture, 49180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkISize& kernelSize, 49280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkScalar* kernel, 49380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar gain, 49480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar bias, 49580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkIPoint& target, 49680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TileMode tileMode, 49780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool convolveAlpha) 498363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger : INHERITED(texture, MakeDivByTextureWHMatrix(texture)), 49980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernelSize(kernelSize), 50080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fGain(SkScalarToFloat(gain)), 50180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fBias(SkScalarToFloat(bias) / 255.0f), 50280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTileMode(tileMode), 50380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fConvolveAlpha(convolveAlpha) { 50480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernel = new float[kernelSize.width() * kernelSize.height()]; 50580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) { 50680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernel[i] = SkScalarToFloat(kernel[i]); 50780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 508363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fTarget[0] = static_cast<float>(target.x()); 509363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fTarget[1] = static_cast<float>(target.y()); 51080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 51180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 51280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruGrMatrixConvolutionEffect::~GrMatrixConvolutionEffect() { 51380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru delete[] fKernel; 51480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 51580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 516363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst GrBackendEffectFactory& GrMatrixConvolutionEffect::getFactory() const { 517363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return GrTBackendEffectFactory<GrMatrixConvolutionEffect>::getInstance(); 51880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 51980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 520d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenbergerbool GrMatrixConvolutionEffect::onIsEqual(const GrEffect& sBase) const { 521d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const GrMatrixConvolutionEffect& s = CastEffect<GrMatrixConvolutionEffect>(sBase); 522d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return this->texture(0) == s.texture(0) && 52380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fKernelSize == s.kernelSize() && 52480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru !memcmp(fKernel, s.kernel(), fKernelSize.width() * fKernelSize.height() * sizeof(float)) && 52580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fGain == s.gain() && 52680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fBias == s.bias() && 52780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTarget == s.target() && 52880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fTileMode == s.tileMode() && 52980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fConvolveAlpha == s.convolveAlpha(); 53080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 53180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 532363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerGR_DEFINE_EFFECT_TEST(GrMatrixConvolutionEffect); 53380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 53480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// A little bit less than the minimum # uniforms required by DX9SM2 (32). 53580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Allows for a 5x5 kernel (or 25x1, for that matter). 53680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define MAX_KERNEL_SIZE 25 53780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 538096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerGrEffectRef* GrMatrixConvolutionEffect::TestCreate(SkMWCRandom* random, 539d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger GrContext* context, 5407839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger const GrDrawTargetCaps&, 541d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger GrTexture* textures[]) { 542363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : 543363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger GrEffectUnitTest::kAlphaTextureIdx; 54480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int width = random->nextRangeU(1, MAX_KERNEL_SIZE); 54580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int height = random->nextRangeU(1, MAX_KERNEL_SIZE / width); 54680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkISize kernelSize = SkISize::Make(width, height); 547e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger SkAutoTDeleteArray<SkScalar> kernel(new SkScalar[width * height]); 54880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < width * height; i++) { 549e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger kernel.get()[i] = random->nextSScalar1(); 55080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 55180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar gain = random->nextSScalar1(); 55280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar bias = random->nextSScalar1(); 55380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIPoint target = SkIPoint::Make(random->nextRangeU(0, kernelSize.width()), 55480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru random->nextRangeU(0, kernelSize.height())); 55580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TileMode tileMode = static_cast<TileMode>(random->nextRangeU(0, 2)); 55680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool convolveAlpha = random->nextBool(); 557d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return GrMatrixConvolutionEffect::Create(textures[texIdx], 558d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger kernelSize, 559e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger kernel.get(), 560d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger gain, 561d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger bias, 562d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger target, 563d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger tileMode, 564d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger convolveAlpha); 56580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 56680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 567d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenbergerbool SkMatrixConvolutionImageFilter::asNewEffect(GrEffectRef** effect, 568e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger GrTexture* texture, 569e27eefc4844477cee5d32f51ab45ff62020cdb36Derek Sollenberger const SkIPoint&) const { 5707839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger if (!effect) { 5717839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger return fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE; 57280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 5737839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger SkASSERT(fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE); 5747839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger *effect = GrMatrixConvolutionEffect::Create(texture, 5757839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger fKernelSize, 5767839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger fKernel, 5777839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger fGain, 5787839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger fBias, 5797839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger fTarget, 5807839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger fTileMode, 5817839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger fConvolveAlpha); 5827839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger return true; 58380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 58480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 58580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////////////// 58680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 58780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 588