blob: 563d1a405137050cde586df01ff33e5338d58218 [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.comae4f96a2012-05-18 19:54:48 +000020 GrGLConvolutionEffect(const GrCustomStage* stage);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000021 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
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.comae4f96a2012-05-18 19:54:48 +000052GrGLConvolutionEffect::GrGLConvolutionEffect(const GrCustomStage* data)
53 : fKernelVar(NULL)
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000054 , fImageIncrementVar(NULL)
55 , fKernelLocation(0)
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000056 , fImageIncrementLocation(0) {
57 fKernelWidth = static_cast<const GrConvolutionEffect*>(data)->width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000058}
59
tomhudson@google.comf1d88062012-05-10 12:43:21 +000060const char* GrGLConvolutionEffect::name() const {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000061 return GrConvolutionEffect::Name();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000062}
63
64void GrGLConvolutionEffect::setupVSUnis(VarArray* vsUnis,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000065 int stage) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000066 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,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000078 int stage) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000079 fKernelVar = &fsUnis->push_back();
80 fKernelVar->setType(kFloat_GrSLType);
81 fKernelVar->setTypeModifier(
82 GrGLShaderVar::kUniform_TypeModifier);
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000083 fKernelVar->setArrayCount(fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000084 (*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,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000094 const char* vertexCoords) {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000095 float scale = (fKernelWidth - 1) * 0.5f;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000096 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,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000106 const char* sampleCoords) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000107 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",
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000123 fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000124
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,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000136 int programID) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000137 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,
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000145 const GrCustomStage* data,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000146 const GrGLTexture* texture) {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000147 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);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000151 GR_GL_CALL(gl, Uniform1fv(fKernelLocation,
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000152 fKernelWidth,
153 conv->kernel()));
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000154 float imageIncrement[2] = { 0 };
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000155 switch (conv->direction()) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000156 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
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000168GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(
169 const GrCustomStage* s) {
170 return static_cast<const GrConvolutionEffect*>(s)->width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000171}
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 {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000192 return Name();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000193}
194
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000195
196const GrProgramStageFactory& GrConvolutionEffect::getFactory() const {
197 return GrTProgramStageFactory<GrConvolutionEffect>::getInstance();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000198}
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