diff options
author | 2017-01-24 12:29:36 -0500 | |
---|---|---|
committer | 2017-01-24 17:59:54 +0000 | |
commit | aee504beb2185e7297b30c02a1541d1306196416 (patch) | |
tree | 6818d12e83a3f0f1cb9ad5576bf0a789855278a6 /src/gpu | |
parent | 5d72f7deb1807c4ee1c1d0901124d5ea07e556f2 (diff) |
Make GrConvolutionEffect only support Gaussian kernels and rename.
Change-Id: Ia874ad5bacc550b7ecec579719242e3354dca34b
Reviewed-on: https://skia-review.googlesource.com/7432
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/effects/GrConvolutionEffect.h | 102 | ||||
-rw-r--r-- | src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp (renamed from src/gpu/effects/GrConvolutionEffect.cpp) | 127 | ||||
-rw-r--r-- | src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h | 78 |
3 files changed, 130 insertions, 177 deletions
diff --git a/src/gpu/effects/GrConvolutionEffect.h b/src/gpu/effects/GrConvolutionEffect.h deleted file mode 100644 index c9a029ace9..0000000000 --- a/src/gpu/effects/GrConvolutionEffect.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrConvolutionEffect_DEFINED -#define GrConvolutionEffect_DEFINED - -#include "Gr1DKernelEffect.h" -#include "GrInvariantOutput.h" - -/** - * A convolution effect. The kernel is specified as an array of 2 * half-width - * + 1 weights. Each texel is multiplied by it's weight and summed to determine - * the output color. The output color is modulated by the input color. - */ -class GrConvolutionEffect : public Gr1DKernelEffect { - -public: - - /// Convolve with an arbitrary user-specified kernel - static sk_sp<GrFragmentProcessor> Make(GrTexture* tex, - Direction dir, - int halfWidth, - const float* kernel, - bool useBounds, - float bounds[2]) { - return sk_sp<GrFragmentProcessor>( - new GrConvolutionEffect(tex, dir, halfWidth, kernel, useBounds, bounds)); - } - - /// Convolve with a Gaussian kernel - static sk_sp<GrFragmentProcessor> MakeGaussian(GrTexture* tex, - Direction dir, - int halfWidth, - float gaussianSigma, - bool useBounds, - float bounds[2]) { - return sk_sp<GrFragmentProcessor>( - new GrConvolutionEffect(tex, dir, halfWidth, gaussianSigma, useBounds, bounds)); - } - - virtual ~GrConvolutionEffect(); - - const float* kernel() const { return fKernel; } - - const float* bounds() const { return fBounds; } - bool useBounds() const { return fUseBounds; } - - const char* name() const override { return "Convolution"; } - - enum { - // This was decided based on the min allowed value for the max texture - // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0 - // on a blur filter gives a kernel width of 25 while a sigma of 5.0 - // would exceed a 32 wide kernel. - kMaxKernelRadius = 12, - // With a C++11 we could have a constexpr version of WidthFromRadius() - // and not have to duplicate this calculation. - kMaxKernelWidth = 2 * kMaxKernelRadius + 1, - }; - -protected: - - float fKernel[kMaxKernelWidth]; - bool fUseBounds; - float fBounds[2]; - -private: - GrConvolutionEffect(GrTexture*, Direction, - int halfWidth, - const float* kernel, - bool useBounds, - float bounds[2]); - - /// Convolve with a Gaussian kernel - GrConvolutionEffect(GrTexture*, Direction, - int halfWidth, - float gaussianSigma, - bool useBounds, - float bounds[2]); - - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - - void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; - - bool onIsEqual(const GrFragmentProcessor&) const override; - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override { - // If the texture was opaque we could know that the output color if we knew the sum of the - // kernel values. - inout->mulByUnknownFourComponents(); - } - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - - typedef Gr1DKernelEffect INHERITED; -}; - -#endif diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp index b4e1ec3e4c..91301ff9ac 100644 --- a/src/gpu/effects/GrConvolutionEffect.cpp +++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp @@ -5,12 +5,12 @@ * found in the LICENSE file. */ -#include "GrConvolutionEffect.h" +#include "GrGaussianConvolutionFragmentProcessor.h" +#include "../private/GrGLSL.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" -#include "../private/GrGLSL.h" // For brevity typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; @@ -25,24 +25,23 @@ protected: void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor&) override; private: - UniformHandle fKernelUni; - UniformHandle fImageIncrementUni; - UniformHandle fBoundsUni; + UniformHandle fKernelUni; + UniformHandle fImageIncrementUni; + UniformHandle fBoundsUni; typedef GrGLSLFragmentProcessor INHERITED; }; void GrGLConvolutionEffect::emitCode(EmitArgs& args) { - const GrConvolutionEffect& ce = args.fFp.cast<GrConvolutionEffect>(); + const GrGaussianConvolutionFragmentProcessor& ce = + args.fFp.cast<GrGaussianConvolutionFragmentProcessor>(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "ImageIncrement"); + fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, + kDefault_GrSLPrecision, "ImageIncrement"); if (ce.useBounds()) { - fBoundsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Bounds"); + fBoundsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, + kDefault_GrSLPrecision, "Bounds"); } int width = Gr1DKernelEffect::WidthFromRadius(ce.radius()); @@ -50,9 +49,8 @@ void GrGLConvolutionEffect::emitCode(EmitArgs& args) { int arrayCount = (width + 3) / 4; SkASSERT(4 * arrayCount >= width); - fKernelUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "Kernel", arrayCount); + fKernelUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, kVec4f_GrSLType, + kDefault_GrSLPrecision, "Kernel", arrayCount); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); @@ -65,11 +63,11 @@ void GrGLConvolutionEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("vec2 coord = %s - %d.0 * %s;", coords2D.c_str(), ce.radius(), imgInc); // Manually unroll loop because some drivers don't; yields 20-30% speedup. - const char* kVecSuffix[4] = { ".x", ".y", ".z", ".w" }; + const char* kVecSuffix[4] = {".x", ".y", ".z", ".w"}; for (int i = 0; i < width; i++) { SkString index; SkString kernelIndex; - index.appendS32(i/4); + index.appendS32(i / 4); kernel.appendArrayAccess(index.c_str(), &kernelIndex); kernelIndex.append(kVecSuffix[i & 0x3]); @@ -79,16 +77,16 @@ void GrGLConvolutionEffect::emitCode(EmitArgs& args) { // to have a bug that caused corruption. const char* bounds = uniformHandler->getUniformCStr(fBoundsUni); const char* component = ce.direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x"; - fragBuilder->codeAppendf("if (coord.%s >= %s.x && coord.%s <= %s.y) {", - component, bounds, component, bounds); + fragBuilder->codeAppendf("if (coord.%s >= %s.x && coord.%s <= %s.y) {", component, + bounds, component, bounds); } - fragBuilder->codeAppendf("\t\t%s += ", args.fOutputColor); + fragBuilder->codeAppendf("%s += ", args.fOutputColor); fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord"); fragBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); if (ce.useBounds()) { fragBuilder->codeAppend("}"); } - fragBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc); + fragBuilder->codeAppendf("coord += %s;\n", imgInc); } SkString modulate; @@ -98,10 +96,11 @@ void GrGLConvolutionEffect::emitCode(EmitArgs& args) { void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& processor) { - const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); + const GrGaussianConvolutionFragmentProcessor& conv = + processor.cast<GrGaussianConvolutionFragmentProcessor>(); GrTexture& texture = *conv.textureSampler(0).texture(); - float imageIncrement[2] = { 0 }; + float imageIncrement[2] = {0}; float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; switch (conv.direction()) { case Gr1DKernelEffect::kX_Direction: @@ -132,43 +131,27 @@ void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { - const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); + const GrGaussianConvolutionFragmentProcessor& conv = + processor.cast<GrGaussianConvolutionFragmentProcessor>(); uint32_t key = conv.radius(); key <<= 2; if (conv.useBounds()) { key |= 0x2; - key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0; + key |= GrGaussianConvolutionFragmentProcessor::kY_Direction == conv.direction() ? 0x1 : 0x0; } b->add32(key); } /////////////////////////////////////////////////////////////////////////////// -GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, - Direction direction, - int radius, - const float* kernel, - bool useBounds, - float bounds[2]) - : INHERITED(texture, direction, radius), fUseBounds(useBounds) { - this->initClassID<GrConvolutionEffect>(); - SkASSERT(radius <= kMaxKernelRadius); - SkASSERT(kernel); - int width = this->width(); - for (int i = 0; i < width; i++) { - fKernel[i] = kernel[i]; - } - memcpy(fBounds, bounds, sizeof(fBounds)); -} - -GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, - Direction direction, - int radius, - float gaussianSigma, - bool useBounds, - float bounds[2]) - : INHERITED(texture, direction, radius), fUseBounds(useBounds) { - this->initClassID<GrConvolutionEffect>(); +GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor(GrTexture* texture, + Direction direction, + int radius, + float gaussianSigma, + bool useBounds, + float bounds[2]) + : INHERITED(texture, direction, radius), fUseBounds(useBounds) { + this->initClassID<GrGaussianConvolutionFragmentProcessor>(); SkASSERT(radius <= kMaxKernelRadius); int width = this->width(); @@ -178,7 +161,7 @@ GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, float x = static_cast<float>(i - this->radius()); // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian // is dropped here, since we renormalize the kernel below. - fKernel[i] = sk_float_exp(- x * x * denom); + fKernel[i] = sk_float_exp(-x * x * denom); sum += fKernel[i]; } // Normalize the kernel @@ -189,22 +172,21 @@ GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, memcpy(fBounds, bounds, sizeof(fBounds)); } -GrConvolutionEffect::~GrConvolutionEffect() { -} +GrGaussianConvolutionFragmentProcessor::~GrGaussianConvolutionFragmentProcessor() {} -void GrConvolutionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { +void GrGaussianConvolutionFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { GrGLConvolutionEffect::GenKey(*this, caps, b); } -GrGLSLFragmentProcessor* GrConvolutionEffect::onCreateGLSLInstance() const { +GrGLSLFragmentProcessor* GrGaussianConvolutionFragmentProcessor::onCreateGLSLInstance() const { return new GrGLConvolutionEffect; } -bool GrConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { - const GrConvolutionEffect& s = sBase.cast<GrConvolutionEffect>(); - return (this->radius() == s.radius() && - this->direction() == s.direction() && +bool GrGaussianConvolutionFragmentProcessor::onIsEqual(const GrFragmentProcessor& sBase) const { + const GrGaussianConvolutionFragmentProcessor& s = + sBase.cast<GrGaussianConvolutionFragmentProcessor>(); + return (this->radius() == s.radius() && this->direction() == s.direction() && this->useBounds() == s.useBounds() && 0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) && 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); @@ -212,27 +194,22 @@ bool GrConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { /////////////////////////////////////////////////////////////////////////////// -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvolutionEffect); +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrGaussianConvolutionFragmentProcessor); -sk_sp<GrFragmentProcessor> GrConvolutionEffect::TestCreate(GrProcessorTestData* d) { - int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : - GrProcessorUnitTest::kAlphaTextureIdx; +sk_sp<GrFragmentProcessor> GrGaussianConvolutionFragmentProcessor::TestCreate( + GrProcessorTestData* d) { + int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx + : GrProcessorUnitTest::kAlphaTextureIdx; Direction dir = d->fRandom->nextBool() ? kX_Direction : kY_Direction; int radius = d->fRandom->nextRangeU(1, kMaxKernelRadius); - float kernel[kMaxKernelWidth]; - for (size_t i = 0; i < SK_ARRAY_COUNT(kernel); ++i) { - kernel[i] = d->fRandom->nextSScalar1(); - } + + bool useBounds = d->fRandom->nextBool(); float bounds[2]; for (size_t i = 0; i < SK_ARRAY_COUNT(bounds); ++i) { bounds[i] = d->fRandom->nextF(); } - bool useBounds = d->fRandom->nextBool(); - return GrConvolutionEffect::Make(d->fTextures[texIdx], - dir, - radius, - kernel, - useBounds, - bounds); + float sigma = radius / 3.f; + return GrGaussianConvolutionFragmentProcessor::Make( + d->fTextures[texIdx], dir, radius, sigma, useBounds, bounds); } diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h new file mode 100644 index 0000000000..da40ec2b93 --- /dev/null +++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h @@ -0,0 +1,78 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGaussianConvolutionFragmentProcessor_DEFINED +#define GrGaussianConvolutionFragmentProcessor_DEFINED + +#include "Gr1DKernelEffect.h" +#include "GrInvariantOutput.h" + +/** + * A 1D Gaussian convolution effect. The kernel is computed as an array of 2 * half-width weights. + * Each texel is multiplied by it's weight and summed to determine the filtered color. The output + * color is set to a modulation of the filtered and input colors. + */ +class GrGaussianConvolutionFragmentProcessor : public Gr1DKernelEffect { +public: + /// Convolve with a Gaussian kernel + static sk_sp<GrFragmentProcessor> Make(GrTexture* tex, + Direction dir, + int halfWidth, + float gaussianSigma, + bool useBounds, + float* bounds) { + return sk_sp<GrFragmentProcessor>(new GrGaussianConvolutionFragmentProcessor( + tex, dir, halfWidth, gaussianSigma, useBounds, bounds)); + } + + virtual ~GrGaussianConvolutionFragmentProcessor(); + + const float* kernel() const { return fKernel; } + + const float* bounds() const { return fBounds; } + bool useBounds() const { return fUseBounds; } + + const char* name() const override { return "GaussianConvolution"; } + + // This was decided based on the min allowed value for the max texture + // samples per fragment program run in DX9SM2 (32). A sigma param of 4.0 + // on a blur filter gives a kernel width of 25 while a sigma of 5.0 + // would exceed a 32 wide kernel. + static const int kMaxKernelRadius = 12; + // With a C++11 we could have a constexpr version of WidthFromRadius() + // and not have to duplicate this calculation. + static const int kMaxKernelWidth = 2 * kMaxKernelRadius + 1; + +private: + /// Convolve with a Gaussian kernel + GrGaussianConvolutionFragmentProcessor(GrTexture*, Direction, int halfWidth, + float gaussianSigma, bool useBounds, float bounds[2]); + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + + bool onIsEqual(const GrFragmentProcessor&) const override; + + void onComputeInvariantOutput(GrInvariantOutput* inout) const override { + // If the texture was opaque we could know that the output color if we knew the sum of the + // kernel values. + inout->mulByUnknownFourComponents(); + } + + GR_DECLARE_FRAGMENT_PROCESSOR_TEST; + + // TODO: Inline the kernel constants into the generated shader code. This may involve pulling + // some of the logic from SkGpuBlurUtils into this class related to radius/sigma calculations. + float fKernel[kMaxKernelWidth]; + bool fUseBounds; + float fBounds[2]; + + typedef Gr1DKernelEffect INHERITED; +}; + +#endif |