LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/effects - GrMatrixConvolutionEffect.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 148 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2014 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : #include "GrMatrixConvolutionEffect.h"
       8             : 
       9             : #include "GrTextureProxy.h"
      10             : #include "glsl/GrGLSLFragmentProcessor.h"
      11             : #include "glsl/GrGLSLFragmentShaderBuilder.h"
      12             : #include "glsl/GrGLSLProgramDataManager.h"
      13             : #include "glsl/GrGLSLUniformHandler.h"
      14             : #include "../private/GrGLSL.h"
      15             : 
      16           0 : class GrGLMatrixConvolutionEffect : public GrGLSLFragmentProcessor {
      17             : public:
      18             :     void emitCode(EmitArgs&) override;
      19             : 
      20             :     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
      21             : 
      22             : protected:
      23             :     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
      24             : 
      25             : private:
      26             :     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
      27             : 
      28             :     UniformHandle               fKernelUni;
      29             :     UniformHandle               fImageIncrementUni;
      30             :     UniformHandle               fKernelOffsetUni;
      31             :     UniformHandle               fGainUni;
      32             :     UniformHandle               fBiasUni;
      33             :     GrTextureDomain::GLDomain   fDomain;
      34             : 
      35             :     typedef GrGLSLFragmentProcessor INHERITED;
      36             : };
      37             : 
      38           0 : void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) {
      39           0 :     const GrMatrixConvolutionEffect& mce = args.fFp.cast<GrMatrixConvolutionEffect>();
      40           0 :     const GrTextureDomain& domain = mce.domain();
      41             : 
      42           0 :     int kWidth = mce.kernelSize().width();
      43           0 :     int kHeight = mce.kernelSize().height();
      44             : 
      45           0 :     int arrayCount = (kWidth * kHeight + 3) / 4;
      46           0 :     SkASSERT(4 * arrayCount >= kWidth * kHeight);
      47             : 
      48           0 :     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
      49             :     fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
      50             :                                                     kVec2f_GrSLType, kDefault_GrSLPrecision,
      51           0 :                                                     "ImageIncrement");
      52             :     fKernelUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag,
      53             :                                                  kVec4f_GrSLType, kDefault_GrSLPrecision,
      54             :                                                  "Kernel",
      55           0 :                                                  arrayCount);
      56             :     fKernelOffsetUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
      57             :                                                   kVec2f_GrSLType, kDefault_GrSLPrecision,
      58           0 :                                                   "KernelOffset");
      59             :     fGainUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
      60           0 :                                           kFloat_GrSLType, kDefault_GrSLPrecision, "Gain");
      61             :     fBiasUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
      62           0 :                                           kFloat_GrSLType, kDefault_GrSLPrecision, "Bias");
      63             : 
      64           0 :     const char* kernelOffset = uniformHandler->getUniformCStr(fKernelOffsetUni);
      65           0 :     const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni);
      66           0 :     const char* kernel = uniformHandler->getUniformCStr(fKernelUni);
      67           0 :     const char* gain = uniformHandler->getUniformCStr(fGainUni);
      68           0 :     const char* bias = uniformHandler->getUniformCStr(fBiasUni);
      69             : 
      70           0 :     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
      71           0 :     SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
      72           0 :     fragBuilder->codeAppend("vec4 sum = vec4(0, 0, 0, 0);");
      73           0 :     fragBuilder->codeAppendf("vec2 coord = %s - %s * %s;", coords2D.c_str(), kernelOffset, imgInc);
      74           0 :     fragBuilder->codeAppend("vec4 c;");
      75             : 
      76           0 :     const char* kVecSuffix[4] = { ".x", ".y", ".z", ".w" };
      77           0 :     for (int y = 0; y < kHeight; y++) {
      78           0 :         for (int x = 0; x < kWidth; x++) {
      79           0 :             GrGLSLShaderBuilder::ShaderBlock block(fragBuilder);
      80           0 :             int offset = y*kWidth + x;
      81             : 
      82           0 :             fragBuilder->codeAppendf("float k = %s[%d]%s;", kernel, offset / 4,
      83           0 :                                      kVecSuffix[offset & 0x3]);
      84           0 :             SkString coord;
      85           0 :             coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc);
      86           0 :             fDomain.sampleTexture(fragBuilder,
      87             :                                   uniformHandler,
      88             :                                   args.fShaderCaps,
      89             :                                   domain,
      90             :                                   "c",
      91             :                                   coord,
      92           0 :                                   args.fTexSamplers[0]);
      93           0 :             if (!mce.convolveAlpha()) {
      94           0 :                 fragBuilder->codeAppend("c.rgb /= c.a;");
      95           0 :                 fragBuilder->codeAppend("c.rgb = clamp(c.rgb, 0.0, 1.0);");
      96             :             }
      97           0 :             fragBuilder->codeAppend("sum += c * k;");
      98             :         }
      99             :     }
     100           0 :     if (mce.convolveAlpha()) {
     101           0 :         fragBuilder->codeAppendf("%s = sum * %s + %s;", args.fOutputColor, gain, bias);
     102           0 :         fragBuilder->codeAppendf("%s.a = clamp(%s.a, 0, 1);", args.fOutputColor, args.fOutputColor);
     103           0 :         fragBuilder->codeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);",
     104           0 :                                  args.fOutputColor, args.fOutputColor, args.fOutputColor);
     105             :     } else {
     106           0 :         fDomain.sampleTexture(fragBuilder,
     107             :                               uniformHandler,
     108             :                               args.fShaderCaps,
     109             :                               domain,
     110             :                               "c",
     111             :                               coords2D,
     112           0 :                               args.fTexSamplers[0]);
     113           0 :         fragBuilder->codeAppendf("%s.a = c.a;", args.fOutputColor);
     114           0 :         fragBuilder->codeAppendf("%s.rgb = clamp(sum.rgb * %s + %s, 0, 1);", args.fOutputColor, gain, bias);
     115           0 :         fragBuilder->codeAppendf("%s.rgb *= %s.a;", args.fOutputColor, args.fOutputColor);
     116             :     }
     117             : 
     118           0 :     SkString modulate;
     119           0 :     GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
     120           0 :     fragBuilder->codeAppend(modulate.c_str());
     121           0 : }
     122             : 
     123           0 : void GrGLMatrixConvolutionEffect::GenKey(const GrProcessor& processor,
     124             :                                          const GrShaderCaps&, GrProcessorKeyBuilder* b) {
     125           0 :     const GrMatrixConvolutionEffect& m = processor.cast<GrMatrixConvolutionEffect>();
     126           0 :     SkASSERT(m.kernelSize().width() <= 0x7FFF && m.kernelSize().height() <= 0xFFFF);
     127           0 :     uint32_t key = m.kernelSize().width() << 16 | m.kernelSize().height();
     128           0 :     key |= m.convolveAlpha() ? 1U << 31 : 0;
     129           0 :     b->add32(key);
     130           0 :     b->add32(GrTextureDomain::GLDomain::DomainKey(m.domain()));
     131           0 : }
     132             : 
     133           0 : void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman,
     134             :                                             const GrFragmentProcessor& processor) {
     135           0 :     const GrMatrixConvolutionEffect& conv = processor.cast<GrMatrixConvolutionEffect>();
     136           0 :     GrTexture* texture = conv.textureSampler(0).texture();
     137             : 
     138             :     float imageIncrement[2];
     139           0 :     float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f;
     140           0 :     imageIncrement[0] = 1.0f / texture->width();
     141           0 :     imageIncrement[1] = ySign / texture->height();
     142           0 :     pdman.set2fv(fImageIncrementUni, 1, imageIncrement);
     143           0 :     pdman.set2fv(fKernelOffsetUni, 1, conv.kernelOffset());
     144           0 :     int kernelCount = conv.kernelSize().width() * conv.kernelSize().height();
     145           0 :     int arrayCount = (kernelCount + 3) / 4;
     146           0 :     SkASSERT(4 * arrayCount >= kernelCount);
     147           0 :     pdman.set4fv(fKernelUni, arrayCount, conv.kernel());
     148           0 :     pdman.set1f(fGainUni, conv.gain());
     149           0 :     pdman.set1f(fBiasUni, conv.bias());
     150           0 :     fDomain.setData(pdman, conv.domain(), texture);
     151           0 : }
     152             : 
     153           0 : GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrResourceProvider* resourceProvider,
     154             :                                                      sk_sp<GrTextureProxy> proxy,
     155             :                                                      const SkIRect& bounds,
     156             :                                                      const SkISize& kernelSize,
     157             :                                                      const SkScalar* kernel,
     158             :                                                      SkScalar gain,
     159             :                                                      SkScalar bias,
     160             :                                                      const SkIPoint& kernelOffset,
     161             :                                                      GrTextureDomain::Mode tileMode,
     162           0 :                                                      bool convolveAlpha)
     163             :     // To advertise either the modulation or opaqueness optimizations we'd have to examine the
     164             :     // parameters.
     165             :     : INHERITED(resourceProvider, kNone_OptimizationFlags, proxy, nullptr, SkMatrix::I())
     166             :     , fKernelSize(kernelSize)
     167             :     , fGain(SkScalarToFloat(gain))
     168           0 :     , fBias(SkScalarToFloat(bias) / 255.0f)
     169             :     , fConvolveAlpha(convolveAlpha)
     170           0 :     , fDomain(proxy.get(), GrTextureDomain::MakeTexelDomainForMode(bounds, tileMode), tileMode) {
     171           0 :     this->initClassID<GrMatrixConvolutionEffect>();
     172           0 :     for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
     173           0 :         fKernel[i] = SkScalarToFloat(kernel[i]);
     174             :     }
     175           0 :     fKernelOffset[0] = static_cast<float>(kernelOffset.x());
     176           0 :     fKernelOffset[1] = static_cast<float>(kernelOffset.y());
     177           0 : }
     178             : 
     179           0 : void GrMatrixConvolutionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
     180             :                                                       GrProcessorKeyBuilder* b) const {
     181           0 :     GrGLMatrixConvolutionEffect::GenKey(*this, caps, b);
     182           0 : }
     183             : 
     184           0 : GrGLSLFragmentProcessor* GrMatrixConvolutionEffect::onCreateGLSLInstance() const  {
     185           0 :     return new GrGLMatrixConvolutionEffect;
     186             : }
     187             : 
     188           0 : bool GrMatrixConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
     189           0 :     const GrMatrixConvolutionEffect& s = sBase.cast<GrMatrixConvolutionEffect>();
     190           0 :     return fKernelSize == s.kernelSize() &&
     191           0 :            !memcmp(fKernel, s.kernel(),
     192           0 :                    fKernelSize.width() * fKernelSize.height() * sizeof(float)) &&
     193           0 :            fGain == s.gain() &&
     194           0 :            fBias == s.bias() &&
     195           0 :            fKernelOffset == s.kernelOffset() &&
     196           0 :            fConvolveAlpha == s.convolveAlpha() &&
     197           0 :            fDomain == s.domain();
     198             : }
     199             : 
     200           0 : static void fill_in_2D_gaussian_kernel(float* kernel, int width, int height,
     201             :                                        SkScalar sigmaX, SkScalar sigmaY) {
     202           0 :     SkASSERT(width * height <= MAX_KERNEL_SIZE);
     203           0 :     const float sigmaXDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX)));
     204           0 :     const float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY)));
     205           0 :     const int xRadius = width / 2;
     206           0 :     const int yRadius = height / 2;
     207             : 
     208           0 :     float sum = 0.0f;
     209           0 :     for (int x = 0; x < width; x++) {
     210           0 :         float xTerm = static_cast<float>(x - xRadius);
     211           0 :         xTerm = xTerm * xTerm * sigmaXDenom;
     212           0 :         for (int y = 0; y < height; y++) {
     213           0 :             float yTerm = static_cast<float>(y - yRadius);
     214           0 :             float xyTerm = sk_float_exp(-(xTerm + yTerm * yTerm * sigmaYDenom));
     215             :             // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
     216             :             // is dropped here, since we renormalize the kernel below.
     217           0 :             kernel[y * width + x] = xyTerm;
     218           0 :             sum += xyTerm;
     219             :         }
     220             :     }
     221             :     // Normalize the kernel
     222           0 :     float scale = 1.0f / sum;
     223           0 :     for (int i = 0; i < width * height; ++i) {
     224           0 :         kernel[i] *= scale;
     225             :     }
     226           0 : }
     227             : 
     228             : 
     229             : // Static function to create a 2D convolution
     230           0 : sk_sp<GrFragmentProcessor> GrMatrixConvolutionEffect::MakeGaussian(
     231             :                                                             GrResourceProvider* resourceProvider,
     232             :                                                             sk_sp<GrTextureProxy> proxy,
     233             :                                                             const SkIRect& bounds,
     234             :                                                             const SkISize& kernelSize,
     235             :                                                             SkScalar gain,
     236             :                                                             SkScalar bias,
     237             :                                                             const SkIPoint& kernelOffset,
     238             :                                                             GrTextureDomain::Mode tileMode,
     239             :                                                             bool convolveAlpha,
     240             :                                                             SkScalar sigmaX,
     241             :                                                             SkScalar sigmaY) {
     242             :     float kernel[MAX_KERNEL_SIZE];
     243             : 
     244           0 :     fill_in_2D_gaussian_kernel(kernel, kernelSize.width(), kernelSize.height(), sigmaX, sigmaY);
     245             : 
     246             :     return sk_sp<GrFragmentProcessor>(
     247           0 :         new GrMatrixConvolutionEffect(resourceProvider, std::move(proxy), bounds, kernelSize,
     248           0 :                                       kernel, gain, bias, kernelOffset, tileMode, convolveAlpha));
     249             : }
     250             : 
     251             : GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMatrixConvolutionEffect);
     252             : 
     253             : #if GR_TEST_UTILS
     254           0 : sk_sp<GrFragmentProcessor> GrMatrixConvolutionEffect::TestCreate(GrProcessorTestData* d) {
     255           0 :     int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
     256           0 :                                         : GrProcessorUnitTest::kAlphaTextureIdx;
     257           0 :     sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
     258             : 
     259           0 :     int width = d->fRandom->nextRangeU(1, MAX_KERNEL_SIZE);
     260           0 :     int height = d->fRandom->nextRangeU(1, MAX_KERNEL_SIZE / width);
     261           0 :     SkISize kernelSize = SkISize::Make(width, height);
     262           0 :     std::unique_ptr<SkScalar[]> kernel(new SkScalar[width * height]);
     263           0 :     for (int i = 0; i < width * height; i++) {
     264           0 :         kernel.get()[i] = d->fRandom->nextSScalar1();
     265             :     }
     266           0 :     SkScalar gain = d->fRandom->nextSScalar1();
     267           0 :     SkScalar bias = d->fRandom->nextSScalar1();
     268           0 :     SkIPoint kernelOffset = SkIPoint::Make(d->fRandom->nextRangeU(0, kernelSize.width()),
     269           0 :                                            d->fRandom->nextRangeU(0, kernelSize.height()));
     270           0 :     SkIRect bounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()),
     271           0 :                                        d->fRandom->nextRangeU(0, proxy->height()),
     272           0 :                                        d->fRandom->nextRangeU(0, proxy->width()),
     273           0 :                                        d->fRandom->nextRangeU(0, proxy->height()));
     274             :     GrTextureDomain::Mode tileMode =
     275           0 :             static_cast<GrTextureDomain::Mode>(d->fRandom->nextRangeU(0, 2));
     276           0 :     bool convolveAlpha = d->fRandom->nextBool();
     277             :     return GrMatrixConvolutionEffect::Make(d->resourceProvider(),
     278           0 :                                            std::move(proxy),
     279             :                                            bounds,
     280             :                                            kernelSize,
     281           0 :                                            kernel.get(),
     282             :                                            gain,
     283             :                                            bias,
     284             :                                            kernelOffset,
     285             :                                            tileMode,
     286           0 :                                            convolveAlpha);
     287             : }
     288             : #endif

Generated by: LCOV version 1.13