blob: 0dd1606c81d8edccd29b08a57ab0671aceb81b56 [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.com23cb2292012-05-30 18:26:03 +000022 virtual void setupVariables(GrGLShaderBuilder* state,
23 int stage) SK_OVERRIDE;
tomhudson@google.com6a820b62012-05-24 15:10:14 +000024 virtual void emitVS(GrGLShaderBuilder* state,
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000025 const char* vertexCoords) SK_OVERRIDE;
tomhudson@google.com6a820b62012-05-24 15:10:14 +000026 virtual void emitFS(GrGLShaderBuilder* state,
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000027 const char* outputColor,
28 const char* inputColor,
tomhudson@google.com6a820b62012-05-24 15:10:14 +000029 const char* samplerName) SK_OVERRIDE;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000030 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
31
tomhudson@google.com6a820b62012-05-24 15:10:14 +000032 virtual void setData(const GrGLInterface*,
33 const GrGLTexture&,
34 GrCustomStage*,
35 int stageNum) SK_OVERRIDE;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000036
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000037 static inline StageKey GenKey(const GrCustomStage* s);
38
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000039protected:
40
tomhudson@google.com23cb2292012-05-30 18:26:03 +000041 unsigned int fKernelWidth;
42 const GrGLShaderVar* fKernelVar;
43 const GrGLShaderVar* fImageIncrementVar;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000044
tomhudson@google.com23cb2292012-05-30 18:26:03 +000045 GrGLint fKernelLocation;
46 GrGLint fImageIncrementLocation;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000047
48private:
49
50 typedef GrGLProgramStage INHERITED;
51};
52
bsalomon@google.com289efe02012-05-21 20:57:59 +000053GrGLConvolutionEffect::GrGLConvolutionEffect(
54 const GrProgramStageFactory& factory,
55 const GrCustomStage* data)
56 : GrGLProgramStage(factory)
57 , fKernelVar(NULL)
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000058 , fImageIncrementVar(NULL)
59 , fKernelLocation(0)
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000060 , fImageIncrementLocation(0) {
61 fKernelWidth = static_cast<const GrConvolutionEffect*>(data)->width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000062}
63
tomhudson@google.com23cb2292012-05-30 18:26:03 +000064void GrGLConvolutionEffect::setupVariables(GrGLShaderBuilder* state,
65 int stage) {
66 fImageIncrementVar = &state->addUniform(
67 GrGLShaderBuilder::kBoth_VariableLifetime,
68 kVec2f_GrSLType, "uImageIncrement", stage);
69 fKernelVar = &state->addUniform(
70 GrGLShaderBuilder::kFragment_VariableLifetime,
71 kFloat_GrSLType, "uKernel", stage, fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000072
73 fImageIncrementLocation = kUseUniform;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000074 fKernelLocation = kUseUniform;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000075}
76
tomhudson@google.com6a820b62012-05-24 15:10:14 +000077void GrGLConvolutionEffect::emitVS(GrGLShaderBuilder* state,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000078 const char* vertexCoords) {
tomhudson@google.com6a820b62012-05-24 15:10:14 +000079 GrStringBuilder* code = &state->fVSCode;
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000080 float scale = (fKernelWidth - 1) * 0.5f;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000081 code->appendf("\t\t%s -= vec2(%g, %g) * %s;\n",
82 vertexCoords, scale, scale,
83 fImageIncrementVar->getName().c_str());
84
85}
86
tomhudson@google.com6a820b62012-05-24 15:10:14 +000087void GrGLConvolutionEffect::emitFS(GrGLShaderBuilder* state,
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000088 const char* outputColor,
89 const char* inputColor,
tomhudson@google.com6a820b62012-05-24 15:10:14 +000090 const char* samplerName) {
91 GrStringBuilder* code = &state->fFSCode;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000092 const char* texFunc = "texture2D";
93 bool complexCoord = false;
94
95 GrStringBuilder modulate;
96 if (NULL != inputColor) {
97 modulate.printf(" * %s", inputColor);
98 }
99
100 // Creates the string "kernel[i]" with workarounds for
101 // possible driver bugs
102 GrStringBuilder kernelIndex;
103 fKernelVar->appendArrayAccess("i", &kernelIndex);
104
105 code->appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000106 code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000107 code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n",
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000108 fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000109
110 code->appendf("\t\t\tsum += ");
tomhudson@google.com52598142012-05-24 17:44:30 +0000111 state->emitTextureLookup(samplerName, "coord");
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000112 code->appendf(" * %s;\n", kernelIndex.c_str());
113
114 code->appendf("\t\t\tcoord += %s;\n",
115 fImageIncrementVar->getName().c_str());
116 code->appendf("\t\t}\n");
117 code->appendf("\t\t%s = sum%s;\n", outputColor, modulate.c_str());
118}
119
120void GrGLConvolutionEffect::initUniforms(const GrGLInterface* gl,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000121 int programID) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000122 GR_GL_CALL_RET(gl, fKernelLocation,
123 GetUniformLocation(programID, fKernelVar->getName().c_str()));
124 GR_GL_CALL_RET(gl, fImageIncrementLocation,
125 GetUniformLocation(programID,
126 fImageIncrementVar->getName().c_str()));
127}
128
129void GrGLConvolutionEffect::setData(const GrGLInterface* gl,
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000130 const GrGLTexture& texture,
131 GrCustomStage* data,
132 int stageNum) {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000133 const GrConvolutionEffect* conv =
134 static_cast<const GrConvolutionEffect*>(data);
135 // the code we generated was for a specific kernel width
136 GrAssert(conv->width() == fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000137 GR_GL_CALL(gl, Uniform1fv(fKernelLocation,
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000138 fKernelWidth,
139 conv->kernel()));
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000140 float imageIncrement[2] = { 0 };
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000141 switch (conv->direction()) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000142 case GrSamplerState::kX_FilterDirection:
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000143 imageIncrement[0] = 1.0f / texture.width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000144 break;
145 case GrSamplerState::kY_FilterDirection:
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000146 imageIncrement[1] = 1.0f / texture.width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000147 break;
148 default:
149 GrCrash("Unknown filter direction.");
150 }
151 GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
152}
153
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000154GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(
155 const GrCustomStage* s) {
156 return static_cast<const GrConvolutionEffect*>(s)->width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000157}
158
159/////////////////////////////////////////////////////////////////////
160
161GrConvolutionEffect::GrConvolutionEffect(
162 GrSamplerState::FilterDirection direction,
163 unsigned int kernelWidth,
164 const float* kernel)
165 : fDirection (direction)
166 , fKernelWidth (kernelWidth) {
167 GrAssert(kernelWidth <= MAX_KERNEL_WIDTH);
168 for (unsigned int i = 0; i < kernelWidth; i++) {
169 fKernel[i] = kernel[i];
170 }
171}
172
173GrConvolutionEffect::~GrConvolutionEffect() {
174
175}
176
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000177const GrProgramStageFactory& GrConvolutionEffect::getFactory() const {
178 return GrTProgramStageFactory<GrConvolutionEffect>::getInstance();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000179}
180
181bool GrConvolutionEffect::isEqual(const GrCustomStage * sBase) const {
182 const GrConvolutionEffect* s =
183 static_cast<const GrConvolutionEffect*>(sBase);
184
185 return (fKernelWidth == s->fKernelWidth &&
186 fDirection == s->fDirection &&
187 0 == memcmp(fKernel, s->fKernel, fKernelWidth * sizeof(float)));
188}
189
190
191