blob: 29d1573061d46d447be46458fe48a760a6f24918 [file] [log] [blame]
tomhudson@google.comd8f856c2012-05-10 12:13:36 +00001/*
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
bsalomon@google.com289efe02012-05-21 20:57:59 +000020 GrGLConvolutionEffect(const GrProgramStageFactory& factory,
21 const GrCustomStage* stage);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000022 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
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000033 virtual void setData(const GrGLInterface*, const GrCustomStage*,
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000034 const GrGLTexture*) SK_OVERRIDE;
35
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000036 static inline StageKey GenKey(const GrCustomStage* s);
37
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000038protected:
39
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000040 int fKernelWidth;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000041 GrGLShaderVar* fKernelVar;
42 GrGLShaderVar* fImageIncrementVar;
43
44 GrGLint fKernelLocation;
45 GrGLint fImageIncrementLocation;
46
47private:
48
49 typedef GrGLProgramStage INHERITED;
50};
51
bsalomon@google.com289efe02012-05-21 20:57:59 +000052GrGLConvolutionEffect::GrGLConvolutionEffect(
53 const GrProgramStageFactory& factory,
54 const GrCustomStage* data)
55 : GrGLProgramStage(factory)
56 , fKernelVar(NULL)
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000057 , fImageIncrementVar(NULL)
58 , fKernelLocation(0)
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000059 , fImageIncrementLocation(0) {
60 fKernelWidth = static_cast<const GrConvolutionEffect*>(data)->width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000061}
62
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000063void GrGLConvolutionEffect::setupVSUnis(VarArray* vsUnis,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000064 int stage) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000065 fImageIncrementVar = &vsUnis->push_back();
66 fImageIncrementVar->setType(kVec2f_GrSLType);
67 fImageIncrementVar->setTypeModifier(
68 GrGLShaderVar::kUniform_TypeModifier);
69 (*fImageIncrementVar->accessName()) = "uImageIncrement";
70 fImageIncrementVar->accessName()->appendS32(stage);
71 fImageIncrementVar->setEmitPrecision(true);
72
73 fImageIncrementLocation = kUseUniform;
74}
75
76void GrGLConvolutionEffect::setupFSUnis(VarArray* fsUnis,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000077 int stage) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000078 fKernelVar = &fsUnis->push_back();
79 fKernelVar->setType(kFloat_GrSLType);
80 fKernelVar->setTypeModifier(
81 GrGLShaderVar::kUniform_TypeModifier);
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000082 fKernelVar->setArrayCount(fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000083 (*fKernelVar->accessName()) = "uKernel";
84 fKernelVar->accessName()->appendS32(stage);
85
86 fKernelLocation = kUseUniform;
87
88 // Image increment is used in both vertex & fragment shaders.
89 fsUnis->push_back(*fImageIncrementVar).setEmitPrecision(false);
90}
91
92void GrGLConvolutionEffect::emitVS(GrStringBuilder* code,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000093 const char* vertexCoords) {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000094 float scale = (fKernelWidth - 1) * 0.5f;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000095 code->appendf("\t\t%s -= vec2(%g, %g) * %s;\n",
96 vertexCoords, scale, scale,
97 fImageIncrementVar->getName().c_str());
98
99}
100
101void GrGLConvolutionEffect::emitFS(GrStringBuilder* code,
102 const char* outputColor,
103 const char* inputColor,
104 const char* samplerName,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000105 const char* sampleCoords) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000106 const char* texFunc = "texture2D";
107 bool complexCoord = false;
108
109 GrStringBuilder modulate;
110 if (NULL != inputColor) {
111 modulate.printf(" * %s", inputColor);
112 }
113
114 // Creates the string "kernel[i]" with workarounds for
115 // possible driver bugs
116 GrStringBuilder kernelIndex;
117 fKernelVar->appendArrayAccess("i", &kernelIndex);
118
119 code->appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
120 code->appendf("\t\tvec2 coord = %s;\n", sampleCoords);
121 code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n",
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000122 fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000123
124 code->appendf("\t\t\tsum += ");
125 this->emitTextureLookup(code, samplerName, "coord");
126 code->appendf(" * %s;\n", kernelIndex.c_str());
127
128 code->appendf("\t\t\tcoord += %s;\n",
129 fImageIncrementVar->getName().c_str());
130 code->appendf("\t\t}\n");
131 code->appendf("\t\t%s = sum%s;\n", outputColor, modulate.c_str());
132}
133
134void GrGLConvolutionEffect::initUniforms(const GrGLInterface* gl,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000135 int programID) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000136 GR_GL_CALL_RET(gl, fKernelLocation,
137 GetUniformLocation(programID, fKernelVar->getName().c_str()));
138 GR_GL_CALL_RET(gl, fImageIncrementLocation,
139 GetUniformLocation(programID,
140 fImageIncrementVar->getName().c_str()));
141}
142
143void GrGLConvolutionEffect::setData(const GrGLInterface* gl,
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000144 const GrCustomStage* data,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000145 const GrGLTexture* texture) {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000146 const GrConvolutionEffect* conv =
147 static_cast<const GrConvolutionEffect*>(data);
148 // the code we generated was for a specific kernel width
149 GrAssert(conv->width() == fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000150 GR_GL_CALL(gl, Uniform1fv(fKernelLocation,
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000151 fKernelWidth,
152 conv->kernel()));
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000153 float imageIncrement[2] = { 0 };
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000154 switch (conv->direction()) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000155 case GrSamplerState::kX_FilterDirection:
156 imageIncrement[0] = 1.0f / texture->width();
157 break;
158 case GrSamplerState::kY_FilterDirection:
159 imageIncrement[1] = 1.0f / texture->width();
160 break;
161 default:
162 GrCrash("Unknown filter direction.");
163 }
164 GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
165}
166
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000167GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(
168 const GrCustomStage* s) {
169 return static_cast<const GrConvolutionEffect*>(s)->width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000170}
171
172/////////////////////////////////////////////////////////////////////
173
174GrConvolutionEffect::GrConvolutionEffect(
175 GrSamplerState::FilterDirection direction,
176 unsigned int kernelWidth,
177 const float* kernel)
178 : fDirection (direction)
179 , fKernelWidth (kernelWidth) {
180 GrAssert(kernelWidth <= MAX_KERNEL_WIDTH);
181 for (unsigned int i = 0; i < kernelWidth; i++) {
182 fKernel[i] = kernel[i];
183 }
184}
185
186GrConvolutionEffect::~GrConvolutionEffect() {
187
188}
189
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000190const GrProgramStageFactory& GrConvolutionEffect::getFactory() const {
191 return GrTProgramStageFactory<GrConvolutionEffect>::getInstance();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000192}
193
194bool GrConvolutionEffect::isEqual(const GrCustomStage * sBase) const {
195 const GrConvolutionEffect* s =
196 static_cast<const GrConvolutionEffect*>(sBase);
197
198 return (fKernelWidth == s->fKernelWidth &&
199 fDirection == s->fDirection &&
200 0 == memcmp(fKernel, s->fKernel, fKernelWidth * sizeof(float)));
201}
202
203
204