aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/effects/GrConvolutionEffect.cpp
diff options
context:
space:
mode:
authorGravatar tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-05-10 12:13:36 +0000
committerGravatar tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-05-10 12:13:36 +0000
commitd8f856c32b679d9f5a9926feac005e2c0186f83f (patch)
tree9a5c91574e05899e7a6abe3df5ce591acf898d9b /src/gpu/effects/GrConvolutionEffect.cpp
parent96a162eb71a9613ebadf8689128a6b2f50fe8f0d (diff)
Move convolution from code in GrGLProgram to new GrConvolutionEffect
class. This is the first test of the new Ganesh shader pipeline. Also includes some cleanup of the gpu.gyp file: added src/gpu, allowing us to remove ../ from many #include directives. http://codereview.appspot.com/6199053/ git-svn-id: http://skia.googlecode.com/svn/trunk@3887 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/effects/GrConvolutionEffect.cpp')
-rw-r--r--src/gpu/effects/GrConvolutionEffect.cpp257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
new file mode 100644
index 0000000000..e4ddd2932b
--- /dev/null
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrConvolutionEffect.h"
+#include "gl/GrGLProgramStage.h"
+#include "gl/GrGLSL.h"
+#include "gl/GrGLTexture.h"
+#include "GrProgramStageFactory.h"
+
+/////////////////////////////////////////////////////////////////////
+
+class GrGLConvolutionEffect : public GrGLProgramStage {
+
+public:
+
+ GrGLConvolutionEffect(GrConvolutionEffect* data);
+ virtual const char* name() const SK_OVERRIDE;
+ virtual void setupVSUnis(VarArray* vsUnis, int stage) SK_OVERRIDE;
+ virtual void setupFSUnis(VarArray* fsUnis, int stage) SK_OVERRIDE;
+ virtual void emitVS(GrStringBuilder* code,
+ const char* vertexCoords) SK_OVERRIDE;
+ virtual void emitFS(GrStringBuilder* code,
+ const char* outputColor,
+ const char* inputColor,
+ const char* samplerName,
+ const char* sampleCoords) SK_OVERRIDE;
+ virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
+
+ virtual void setData(const GrGLInterface*, GrCustomStage*,
+ const GrGLTexture*) SK_OVERRIDE;
+
+protected:
+
+ GrConvolutionEffect* fData;
+
+ GrGLShaderVar* fKernelVar;
+ GrGLShaderVar* fImageIncrementVar;
+
+ GrGLint fKernelLocation;
+ GrGLint fImageIncrementLocation;
+
+private:
+
+ typedef GrGLProgramStage INHERITED;
+};
+
+GrGLConvolutionEffect::GrGLConvolutionEffect(GrConvolutionEffect* data)
+ : fData(data)
+ , fKernelVar(NULL)
+ , fImageIncrementVar(NULL)
+ , fKernelLocation(0)
+ , fImageIncrementLocation(0)
+{
+
+}
+
+const char* GrGLConvolutionEffect::name() const SK_OVERRIDE {
+ return fData->name();
+}
+
+void GrGLConvolutionEffect::setupVSUnis(VarArray* vsUnis,
+ int stage) SK_OVERRIDE {
+ fImageIncrementVar = &vsUnis->push_back();
+ fImageIncrementVar->setType(kVec2f_GrSLType);
+ fImageIncrementVar->setTypeModifier(
+ GrGLShaderVar::kUniform_TypeModifier);
+ (*fImageIncrementVar->accessName()) = "uImageIncrement";
+ fImageIncrementVar->accessName()->appendS32(stage);
+ fImageIncrementVar->setEmitPrecision(true);
+
+ fImageIncrementLocation = kUseUniform;
+}
+
+void GrGLConvolutionEffect::setupFSUnis(VarArray* fsUnis,
+ int stage) SK_OVERRIDE {
+ fKernelVar = &fsUnis->push_back();
+ fKernelVar->setType(kFloat_GrSLType);
+ fKernelVar->setTypeModifier(
+ GrGLShaderVar::kUniform_TypeModifier);
+ fKernelVar->setArrayCount(fData->fKernelWidth);
+ (*fKernelVar->accessName()) = "uKernel";
+ fKernelVar->accessName()->appendS32(stage);
+
+ fKernelLocation = kUseUniform;
+
+ // Image increment is used in both vertex & fragment shaders.
+ fsUnis->push_back(*fImageIncrementVar).setEmitPrecision(false);
+}
+
+void GrGLConvolutionEffect::emitVS(GrStringBuilder* code,
+ const char* vertexCoords) SK_OVERRIDE {
+ float scale = (fData->fKernelWidth - 1) * 0.5f;
+ code->appendf("\t\t%s -= vec2(%g, %g) * %s;\n",
+ vertexCoords, scale, scale,
+ fImageIncrementVar->getName().c_str());
+
+}
+
+void GrGLConvolutionEffect::emitFS(GrStringBuilder* code,
+ const char* outputColor,
+ const char* inputColor,
+ const char* samplerName,
+ const char* sampleCoords) SK_OVERRIDE {
+ const char* texFunc = "texture2D";
+ bool complexCoord = false;
+
+ GrStringBuilder modulate;
+ if (NULL != inputColor) {
+ modulate.printf(" * %s", inputColor);
+ }
+
+ // Creates the string "kernel[i]" with workarounds for
+ // possible driver bugs
+ GrStringBuilder kernelIndex;
+ fKernelVar->appendArrayAccess("i", &kernelIndex);
+
+ code->appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
+ code->appendf("\t\tvec2 coord = %s;\n", sampleCoords);
+ code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n",
+ fData->fKernelWidth);
+
+ code->appendf("\t\t\tsum += ");
+ this->emitTextureLookup(code, samplerName, "coord");
+ code->appendf(" * %s;\n", kernelIndex.c_str());
+
+ code->appendf("\t\t\tcoord += %s;\n",
+ fImageIncrementVar->getName().c_str());
+ code->appendf("\t\t}\n");
+ code->appendf("\t\t%s = sum%s;\n", outputColor, modulate.c_str());
+}
+
+void GrGLConvolutionEffect::initUniforms(const GrGLInterface* gl,
+ int programID) SK_OVERRIDE {
+ GR_GL_CALL_RET(gl, fKernelLocation,
+ GetUniformLocation(programID, fKernelVar->getName().c_str()));
+ GR_GL_CALL_RET(gl, fImageIncrementLocation,
+ GetUniformLocation(programID,
+ fImageIncrementVar->getName().c_str()));
+}
+
+void GrGLConvolutionEffect::setData(const GrGLInterface* gl,
+ GrCustomStage* data,
+ const GrGLTexture* texture) SK_OVERRIDE {
+ fData = static_cast<GrConvolutionEffect*>(data);
+ GR_GL_CALL(gl, Uniform1fv(fKernelLocation,
+ fData->fKernelWidth,
+ fData->fKernel));
+ float imageIncrement[2] = { 0 };
+ switch (fData->fDirection) {
+ case GrSamplerState::kX_FilterDirection:
+ imageIncrement[0] = 1.0f / texture->width();
+ break;
+ case GrSamplerState::kY_FilterDirection:
+ imageIncrement[1] = 1.0f / texture->width();
+ break;
+ default:
+ GrCrash("Unknown filter direction.");
+ }
+ GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
+}
+
+/////////////////////////////////////////////////////////////////////
+// TODO: stageKey() and sEffectId are the only non-boilerplate in
+// this class; we ought to be able to templatize?
+
+class GrConvolutionEffectFactory : public GrProgramStageFactory {
+
+public:
+
+ virtual ~GrConvolutionEffectFactory();
+
+ virtual uint16_t stageKey(const GrCustomStage* s) SK_OVERRIDE;
+ virtual GrGLProgramStage* createGLInstance(GrCustomStage* s) SK_OVERRIDE;
+
+ static GrConvolutionEffectFactory* getInstance();
+
+protected:
+
+ GrConvolutionEffectFactory();
+
+ // TODO: find a more reliable installation than hand-coding
+ // id values like '1'.
+ static const int sEffectId = 1;
+
+private:
+
+ typedef GrProgramStageFactory INHERITED;
+};
+
+GrConvolutionEffectFactory::~GrConvolutionEffectFactory() {
+
+}
+
+uint16_t GrConvolutionEffectFactory::stageKey(const GrCustomStage* s)
+ SK_OVERRIDE {
+ const GrConvolutionEffect* c =
+ static_cast<const GrConvolutionEffect*>(s);
+ GrAssert(c->width() < 256);
+ return (sEffectId << 8) | (c->width() & 0xff);
+}
+
+GrGLProgramStage* GrConvolutionEffectFactory::createGLInstance(
+ GrCustomStage* s) SK_OVERRIDE {
+ return new GrGLConvolutionEffect(static_cast<GrConvolutionEffect*>(s));
+}
+
+GrConvolutionEffectFactory* GrConvolutionEffectFactory::getInstance() {
+ static GrConvolutionEffectFactory* instance =
+ new GrConvolutionEffectFactory;
+ return instance;
+}
+
+GrConvolutionEffectFactory::GrConvolutionEffectFactory() {
+
+}
+
+/////////////////////////////////////////////////////////////////////
+
+GrConvolutionEffect::GrConvolutionEffect(
+ GrSamplerState::FilterDirection direction,
+ unsigned int kernelWidth,
+ const float* kernel)
+ : fDirection (direction)
+ , fKernelWidth (kernelWidth) {
+ GrAssert(kernelWidth <= MAX_KERNEL_WIDTH);
+ for (unsigned int i = 0; i < kernelWidth; i++) {
+ fKernel[i] = kernel[i];
+ }
+}
+
+GrConvolutionEffect::~GrConvolutionEffect() {
+
+}
+
+const char* GrConvolutionEffect::name() const {
+ return "Convolution";
+}
+
+GrProgramStageFactory* GrConvolutionEffect::getFactory() const {
+ return GrConvolutionEffectFactory::getInstance();
+}
+
+bool GrConvolutionEffect::isEqual(const GrCustomStage * sBase) const {
+ const GrConvolutionEffect* s =
+ static_cast<const GrConvolutionEffect*>(sBase);
+
+ return (fKernelWidth == s->fKernelWidth &&
+ fDirection == s->fDirection &&
+ 0 == memcmp(fKernel, s->fKernel, fKernelWidth * sizeof(float)));
+}
+
+
+