blob: 8ccf5859e49c99c8524571df8073a741e5871851 [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;
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.com6a820b62012-05-24 15:10:14 +000041 unsigned int fKernelWidth;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000042 GrGLShaderVar* fKernelVar;
43 GrGLShaderVar* fImageIncrementVar;
44
45 GrGLint fKernelLocation;
46 GrGLint fImageIncrementLocation;
47
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.comd8f856c2012-05-10 12:13:36 +000064void 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
tomhudson@google.com6a820b62012-05-24 15:10:14 +000093void GrGLConvolutionEffect::emitVS(GrGLShaderBuilder* state,
tomhudson@google.comf1d88062012-05-10 12:43:21 +000094 const char* vertexCoords) {
tomhudson@google.com6a820b62012-05-24 15:10:14 +000095 GrStringBuilder* code = &state->fVSCode;
bsalomon@google.comae4f96a2012-05-18 19:54:48 +000096 float scale = (fKernelWidth - 1) * 0.5f;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000097 code->appendf("\t\t%s -= vec2(%g, %g) * %s;\n",
98 vertexCoords, scale, scale,
99 fImageIncrementVar->getName().c_str());
100
101}
102
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000103void GrGLConvolutionEffect::emitFS(GrGLShaderBuilder* state,
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000104 const char* outputColor,
105 const char* inputColor,
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000106 const char* samplerName) {
107 GrStringBuilder* code = &state->fFSCode;
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000108 const char* texFunc = "texture2D";
109 bool complexCoord = false;
110
111 GrStringBuilder modulate;
112 if (NULL != inputColor) {
113 modulate.printf(" * %s", inputColor);
114 }
115
116 // Creates the string "kernel[i]" with workarounds for
117 // possible driver bugs
118 GrStringBuilder kernelIndex;
119 fKernelVar->appendArrayAccess("i", &kernelIndex);
120
121 code->appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000122 code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000123 code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n",
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000124 fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000125
126 code->appendf("\t\t\tsum += ");
127 this->emitTextureLookup(code, samplerName, "coord");
128 code->appendf(" * %s;\n", kernelIndex.c_str());
129
130 code->appendf("\t\t\tcoord += %s;\n",
131 fImageIncrementVar->getName().c_str());
132 code->appendf("\t\t}\n");
133 code->appendf("\t\t%s = sum%s;\n", outputColor, modulate.c_str());
134}
135
136void GrGLConvolutionEffect::initUniforms(const GrGLInterface* gl,
tomhudson@google.comf1d88062012-05-10 12:43:21 +0000137 int programID) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000138 GR_GL_CALL_RET(gl, fKernelLocation,
139 GetUniformLocation(programID, fKernelVar->getName().c_str()));
140 GR_GL_CALL_RET(gl, fImageIncrementLocation,
141 GetUniformLocation(programID,
142 fImageIncrementVar->getName().c_str()));
143}
144
145void GrGLConvolutionEffect::setData(const GrGLInterface* gl,
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000146 const GrGLTexture& texture,
147 GrCustomStage* data,
148 int stageNum) {
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000149 const GrConvolutionEffect* conv =
150 static_cast<const GrConvolutionEffect*>(data);
151 // the code we generated was for a specific kernel width
152 GrAssert(conv->width() == fKernelWidth);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000153 GR_GL_CALL(gl, Uniform1fv(fKernelLocation,
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000154 fKernelWidth,
155 conv->kernel()));
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000156 float imageIncrement[2] = { 0 };
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000157 switch (conv->direction()) {
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000158 case GrSamplerState::kX_FilterDirection:
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000159 imageIncrement[0] = 1.0f / texture.width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000160 break;
161 case GrSamplerState::kY_FilterDirection:
tomhudson@google.com6a820b62012-05-24 15:10:14 +0000162 imageIncrement[1] = 1.0f / texture.width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000163 break;
164 default:
165 GrCrash("Unknown filter direction.");
166 }
167 GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
168}
169
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000170GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(
171 const GrCustomStage* s) {
172 return static_cast<const GrConvolutionEffect*>(s)->width();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000173}
174
175/////////////////////////////////////////////////////////////////////
176
177GrConvolutionEffect::GrConvolutionEffect(
178 GrSamplerState::FilterDirection direction,
179 unsigned int kernelWidth,
180 const float* kernel)
181 : fDirection (direction)
182 , fKernelWidth (kernelWidth) {
183 GrAssert(kernelWidth <= MAX_KERNEL_WIDTH);
184 for (unsigned int i = 0; i < kernelWidth; i++) {
185 fKernel[i] = kernel[i];
186 }
187}
188
189GrConvolutionEffect::~GrConvolutionEffect() {
190
191}
192
bsalomon@google.comae4f96a2012-05-18 19:54:48 +0000193const GrProgramStageFactory& GrConvolutionEffect::getFactory() const {
194 return GrTProgramStageFactory<GrConvolutionEffect>::getInstance();
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000195}
196
197bool GrConvolutionEffect::isEqual(const GrCustomStage * sBase) const {
198 const GrConvolutionEffect* s =
199 static_cast<const GrConvolutionEffect*>(sBase);
200
201 return (fKernelWidth == s->fKernelWidth &&
202 fDirection == s->fDirection &&
203 0 == memcmp(fKernel, s->fKernel, fKernelWidth * sizeof(float)));
204}
205
206
207