GrConvolutionEffect.cpp revision ae4f96a9e06df44f70c3d5f7324f5a7fabcd1026
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 */ 7 8#include "GrConvolutionEffect.h" 9#include "gl/GrGLProgramStage.h" 10#include "gl/GrGLSL.h" 11#include "gl/GrGLTexture.h" 12#include "GrProgramStageFactory.h" 13 14///////////////////////////////////////////////////////////////////// 15 16class GrGLConvolutionEffect : public GrGLProgramStage { 17 18public: 19 20 GrGLConvolutionEffect(const GrCustomStage* stage); 21 virtual const char* name() const SK_OVERRIDE; 22 virtual void setupVSUnis(VarArray* vsUnis, int stage) SK_OVERRIDE; 23 virtual void setupFSUnis(VarArray* fsUnis, int stage) SK_OVERRIDE; 24 virtual void emitVS(GrStringBuilder* code, 25 const char* vertexCoords) SK_OVERRIDE; 26 virtual void emitFS(GrStringBuilder* code, 27 const char* outputColor, 28 const char* inputColor, 29 const char* samplerName, 30 const char* sampleCoords) SK_OVERRIDE; 31 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE; 32 33 virtual void setData(const GrGLInterface*, const GrCustomStage*, 34 const GrGLTexture*) SK_OVERRIDE; 35 36 static inline StageKey GenKey(const GrCustomStage* s); 37 38protected: 39 40 int fKernelWidth; 41 GrGLShaderVar* fKernelVar; 42 GrGLShaderVar* fImageIncrementVar; 43 44 GrGLint fKernelLocation; 45 GrGLint fImageIncrementLocation; 46 47private: 48 49 typedef GrGLProgramStage INHERITED; 50}; 51 52GrGLConvolutionEffect::GrGLConvolutionEffect(const GrCustomStage* data) 53 : fKernelVar(NULL) 54 , fImageIncrementVar(NULL) 55 , fKernelLocation(0) 56 , fImageIncrementLocation(0) { 57 fKernelWidth = static_cast<const GrConvolutionEffect*>(data)->width(); 58} 59 60const char* GrGLConvolutionEffect::name() const { 61 return GrConvolutionEffect::Name(); 62} 63 64void GrGLConvolutionEffect::setupVSUnis(VarArray* vsUnis, 65 int stage) { 66 fImageIncrementVar = &vsUnis->push_back(); 67 fImageIncrementVar->setType(kVec2f_GrSLType); 68 fImageIncrementVar->setTypeModifier( 69 GrGLShaderVar::kUniform_TypeModifier); 70 (*fImageIncrementVar->accessName()) = "uImageIncrement"; 71 fImageIncrementVar->accessName()->appendS32(stage); 72 fImageIncrementVar->setEmitPrecision(true); 73 74 fImageIncrementLocation = kUseUniform; 75} 76 77void GrGLConvolutionEffect::setupFSUnis(VarArray* fsUnis, 78 int stage) { 79 fKernelVar = &fsUnis->push_back(); 80 fKernelVar->setType(kFloat_GrSLType); 81 fKernelVar->setTypeModifier( 82 GrGLShaderVar::kUniform_TypeModifier); 83 fKernelVar->setArrayCount(fKernelWidth); 84 (*fKernelVar->accessName()) = "uKernel"; 85 fKernelVar->accessName()->appendS32(stage); 86 87 fKernelLocation = kUseUniform; 88 89 // Image increment is used in both vertex & fragment shaders. 90 fsUnis->push_back(*fImageIncrementVar).setEmitPrecision(false); 91} 92 93void GrGLConvolutionEffect::emitVS(GrStringBuilder* code, 94 const char* vertexCoords) { 95 float scale = (fKernelWidth - 1) * 0.5f; 96 code->appendf("\t\t%s -= vec2(%g, %g) * %s;\n", 97 vertexCoords, scale, scale, 98 fImageIncrementVar->getName().c_str()); 99 100} 101 102void GrGLConvolutionEffect::emitFS(GrStringBuilder* code, 103 const char* outputColor, 104 const char* inputColor, 105 const char* samplerName, 106 const char* sampleCoords) { 107 const char* texFunc = "texture2D"; 108 bool complexCoord = false; 109 110 GrStringBuilder modulate; 111 if (NULL != inputColor) { 112 modulate.printf(" * %s", inputColor); 113 } 114 115 // Creates the string "kernel[i]" with workarounds for 116 // possible driver bugs 117 GrStringBuilder kernelIndex; 118 fKernelVar->appendArrayAccess("i", &kernelIndex); 119 120 code->appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n"); 121 code->appendf("\t\tvec2 coord = %s;\n", sampleCoords); 122 code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", 123 fKernelWidth); 124 125 code->appendf("\t\t\tsum += "); 126 this->emitTextureLookup(code, samplerName, "coord"); 127 code->appendf(" * %s;\n", kernelIndex.c_str()); 128 129 code->appendf("\t\t\tcoord += %s;\n", 130 fImageIncrementVar->getName().c_str()); 131 code->appendf("\t\t}\n"); 132 code->appendf("\t\t%s = sum%s;\n", outputColor, modulate.c_str()); 133} 134 135void GrGLConvolutionEffect::initUniforms(const GrGLInterface* gl, 136 int programID) { 137 GR_GL_CALL_RET(gl, fKernelLocation, 138 GetUniformLocation(programID, fKernelVar->getName().c_str())); 139 GR_GL_CALL_RET(gl, fImageIncrementLocation, 140 GetUniformLocation(programID, 141 fImageIncrementVar->getName().c_str())); 142} 143 144void GrGLConvolutionEffect::setData(const GrGLInterface* gl, 145 const GrCustomStage* data, 146 const GrGLTexture* texture) { 147 const GrConvolutionEffect* conv = 148 static_cast<const GrConvolutionEffect*>(data); 149 // the code we generated was for a specific kernel width 150 GrAssert(conv->width() == fKernelWidth); 151 GR_GL_CALL(gl, Uniform1fv(fKernelLocation, 152 fKernelWidth, 153 conv->kernel())); 154 float imageIncrement[2] = { 0 }; 155 switch (conv->direction()) { 156 case GrSamplerState::kX_FilterDirection: 157 imageIncrement[0] = 1.0f / texture->width(); 158 break; 159 case GrSamplerState::kY_FilterDirection: 160 imageIncrement[1] = 1.0f / texture->width(); 161 break; 162 default: 163 GrCrash("Unknown filter direction."); 164 } 165 GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement)); 166} 167 168GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey( 169 const GrCustomStage* s) { 170 return static_cast<const GrConvolutionEffect*>(s)->width(); 171} 172 173///////////////////////////////////////////////////////////////////// 174 175GrConvolutionEffect::GrConvolutionEffect( 176 GrSamplerState::FilterDirection direction, 177 unsigned int kernelWidth, 178 const float* kernel) 179 : fDirection (direction) 180 , fKernelWidth (kernelWidth) { 181 GrAssert(kernelWidth <= MAX_KERNEL_WIDTH); 182 for (unsigned int i = 0; i < kernelWidth; i++) { 183 fKernel[i] = kernel[i]; 184 } 185} 186 187GrConvolutionEffect::~GrConvolutionEffect() { 188 189} 190 191const char* GrConvolutionEffect::name() const { 192 return Name(); 193} 194 195 196const GrProgramStageFactory& GrConvolutionEffect::getFactory() const { 197 return GrTProgramStageFactory<GrConvolutionEffect>::getInstance(); 198} 199 200bool GrConvolutionEffect::isEqual(const GrCustomStage * sBase) const { 201 const GrConvolutionEffect* s = 202 static_cast<const GrConvolutionEffect*>(sBase); 203 204 return (fKernelWidth == s->fKernelWidth && 205 fDirection == s->fDirection && 206 0 == memcmp(fKernel, s->fKernel, fKernelWidth * sizeof(float))); 207} 208 209 210 211