gfx/skia/trunk/src/gpu/effects/GrConvolutionEffect.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * Copyright 2012 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  */
     8 #include "GrConvolutionEffect.h"
     9 #include "gl/GrGLEffect.h"
    10 #include "gl/GrGLSL.h"
    11 #include "gl/GrGLTexture.h"
    12 #include "GrTBackendEffectFactory.h"
    14 // For brevity
    15 typedef GrGLUniformManager::UniformHandle UniformHandle;
    17 class GrGLConvolutionEffect : public GrGLEffect {
    18 public:
    19     GrGLConvolutionEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
    21     virtual void emitCode(GrGLShaderBuilder*,
    22                           const GrDrawEffect&,
    23                           EffectKey,
    24                           const char* outputColor,
    25                           const char* inputColor,
    26                           const TransformedCoordsArray&,
    27                           const TextureSamplerArray&) SK_OVERRIDE;
    29     virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE;
    31     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
    33 private:
    34     int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); }
    35     bool useBounds() const { return fUseBounds; }
    36     Gr1DKernelEffect::Direction direction() const { return fDirection; }
    38     int                 fRadius;
    39     bool                fUseBounds;
    40     Gr1DKernelEffect::Direction    fDirection;
    41     UniformHandle       fKernelUni;
    42     UniformHandle       fImageIncrementUni;
    43     UniformHandle       fBoundsUni;
    45     typedef GrGLEffect INHERITED;
    46 };
    48 GrGLConvolutionEffect::GrGLConvolutionEffect(const GrBackendEffectFactory& factory,
    49                                              const GrDrawEffect& drawEffect)
    50     : INHERITED(factory) {
    51     const GrConvolutionEffect& c = drawEffect.castEffect<GrConvolutionEffect>();
    52     fRadius = c.radius();
    53     fUseBounds = c.useBounds();
    54     fDirection = c.direction();
    55 }
    57 void GrGLConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
    58                                      const GrDrawEffect&,
    59                                      EffectKey key,
    60                                      const char* outputColor,
    61                                      const char* inputColor,
    62                                      const TransformedCoordsArray& coords,
    63                                      const TextureSamplerArray& samplers) {
    64     SkString coords2D = builder->ensureFSCoords2D(coords, 0);
    65     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
    66                                              kVec2f_GrSLType, "ImageIncrement");
    67     if (this->useBounds()) {
    68         fBoundsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
    69                                          kVec2f_GrSLType, "Bounds");
    70     }
    71     fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
    72                                           kFloat_GrSLType, "Kernel", this->width());
    74     builder->fsCodeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
    76     int width = this->width();
    77     const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni);
    78     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
    80     builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str(), fRadius, imgInc);
    82     // Manually unroll loop because some drivers don't; yields 20-30% speedup.
    83     for (int i = 0; i < width; i++) {
    84         SkString index;
    85         SkString kernelIndex;
    86         index.appendS32(i);
    87         kernel.appendArrayAccess(index.c_str(), &kernelIndex);
    88         builder->fsCodeAppendf("\t\t%s += ", outputColor);
    89         builder->fsAppendTextureLookup(samplers[0], "coord");
    90         if (this->useBounds()) {
    91             const char* bounds = builder->getUniformCStr(fBoundsUni);
    92             const char* component = this->direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x";
    93             builder->fsCodeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s.y)",
    94                 component, bounds, component, bounds);
    95         }
    96         builder->fsCodeAppendf(" * %s;\n", kernelIndex.c_str());
    97         builder->fsCodeAppendf("\t\tcoord += %s;\n", imgInc);
    98     }
   100     SkString modulate;
   101     GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
   102     builder->fsCodeAppend(modulate.c_str());
   103 }
   105 void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman,
   106                                     const GrDrawEffect& drawEffect) {
   107     const GrConvolutionEffect& conv = drawEffect.castEffect<GrConvolutionEffect>();
   108     GrTexture& texture = *conv.texture(0);
   109     // the code we generated was for a specific kernel radius
   110     SkASSERT(conv.radius() == fRadius);
   111     float imageIncrement[2] = { 0 };
   112     float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f;
   113     switch (conv.direction()) {
   114         case Gr1DKernelEffect::kX_Direction:
   115             imageIncrement[0] = 1.0f / texture.width();
   116             break;
   117         case Gr1DKernelEffect::kY_Direction:
   118             imageIncrement[1] = ySign / texture.height();
   119             break;
   120         default:
   121             GrCrash("Unknown filter direction.");
   122     }
   123     uman.set2fv(fImageIncrementUni, 1, imageIncrement);
   124     if (conv.useBounds()) {
   125         const float* bounds = conv.bounds();
   126         if (Gr1DKernelEffect::kY_Direction == conv.direction() &&
   127             texture.origin() != kTopLeft_GrSurfaceOrigin) {
   128             uman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]);
   129         } else {
   130             uman.set2f(fBoundsUni, bounds[0], bounds[1]);
   131         }
   132     }
   133     uman.set1fv(fKernelUni, this->width(), conv.kernel());
   134 }
   136 GrGLEffect::EffectKey GrGLConvolutionEffect::GenKey(const GrDrawEffect& drawEffect,
   137                                                     const GrGLCaps&) {
   138     const GrConvolutionEffect& conv = drawEffect.castEffect<GrConvolutionEffect>();
   139     EffectKey key = conv.radius();
   140     key <<= 2;
   141     if (conv.useBounds()) {
   142         key |= 0x2;
   143         key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0;
   144     }
   145     return key;
   146 }
   148 ///////////////////////////////////////////////////////////////////////////////
   150 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture,
   151                                          Direction direction,
   152                                          int radius,
   153                                          const float* kernel,
   154                                          bool useBounds,
   155                                          float bounds[2])
   156     : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) {
   157     SkASSERT(radius <= kMaxKernelRadius);
   158     SkASSERT(NULL != kernel);
   159     int width = this->width();
   160     for (int i = 0; i < width; i++) {
   161         fKernel[i] = kernel[i];
   162     }
   163     memcpy(fBounds, bounds, sizeof(fBounds));
   164 }
   166 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture,
   167                                          Direction direction,
   168                                          int radius,
   169                                          float gaussianSigma,
   170                                          bool useBounds,
   171                                          float bounds[2])
   172     : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) {
   173     SkASSERT(radius <= kMaxKernelRadius);
   174     int width = this->width();
   176     float sum = 0.0f;
   177     float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma);
   178     for (int i = 0; i < width; ++i) {
   179         float x = static_cast<float>(i - this->radius());
   180         // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
   181         // is dropped here, since we renormalize the kernel below.
   182         fKernel[i] = sk_float_exp(- x * x * denom);
   183         sum += fKernel[i];
   184     }
   185     // Normalize the kernel
   186     float scale = 1.0f / sum;
   187     for (int i = 0; i < width; ++i) {
   188         fKernel[i] *= scale;
   189     }
   190     memcpy(fBounds, bounds, sizeof(fBounds));
   191 }
   193 GrConvolutionEffect::~GrConvolutionEffect() {
   194 }
   196 const GrBackendEffectFactory& GrConvolutionEffect::getFactory() const {
   197     return GrTBackendEffectFactory<GrConvolutionEffect>::getInstance();
   198 }
   200 bool GrConvolutionEffect::onIsEqual(const GrEffect& sBase) const {
   201     const GrConvolutionEffect& s = CastEffect<GrConvolutionEffect>(sBase);
   202     return (this->texture(0) == s.texture(0) &&
   203             this->radius() == s.radius() &&
   204             this->direction() == s.direction() &&
   205             this->useBounds() == s.useBounds() &&
   206             0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) &&
   207             0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float)));
   208 }
   210 ///////////////////////////////////////////////////////////////////////////////
   212 GR_DEFINE_EFFECT_TEST(GrConvolutionEffect);
   214 GrEffectRef* GrConvolutionEffect::TestCreate(SkRandom* random,
   215                                              GrContext*,
   216                                              const GrDrawTargetCaps&,
   217                                              GrTexture* textures[]) {
   218     int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
   219                                       GrEffectUnitTest::kAlphaTextureIdx;
   220     Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
   221     int radius = random->nextRangeU(1, kMaxKernelRadius);
   222     float kernel[kMaxKernelWidth];
   223     for (size_t i = 0; i < SK_ARRAY_COUNT(kernel); ++i) {
   224         kernel[i] = random->nextSScalar1();
   225     }
   226     float bounds[2];
   227     for (size_t i = 0; i < SK_ARRAY_COUNT(bounds); ++i) {
   228         bounds[i] = random->nextF();
   229     }
   231     bool useBounds = random->nextBool();
   232     return GrConvolutionEffect::Create(textures[texIdx],
   233                                        dir,
   234                                        radius,
   235                                        kernel,
   236                                        useBounds,
   237                                        bounds);
   238 }

mercurial