diff options
author | 2012-05-10 12:13:36 +0000 | |
---|---|---|
committer | 2012-05-10 12:13:36 +0000 | |
commit | d8f856c32b679d9f5a9926feac005e2c0186f83f (patch) | |
tree | 9a5c91574e05899e7a6abe3df5ce591acf898d9b /src/gpu/effects/GrConvolutionEffect.cpp | |
parent | 96a162eb71a9613ebadf8689128a6b2f50fe8f0d (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.cpp | 257 |
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))); +} + + + |