aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-01-24 12:29:36 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-01-24 17:59:54 +0000
commitaee504beb2185e7297b30c02a1541d1306196416 (patch)
tree6818d12e83a3f0f1cb9ad5576bf0a789855278a6 /src/gpu
parent5d72f7deb1807c4ee1c1d0901124d5ea07e556f2 (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.h102
-rw-r--r--src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp (renamed from src/gpu/effects/GrConvolutionEffect.cpp)127
-rw-r--r--src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h78
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