Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrConvolutionEffect.h" | 8 #include "GrConvolutionEffect.h" |
| 9 #include "gl/GrGLProcessor.h" | 9 #include "gl/GrGLProcessor.h" |
| 10 #include "gl/GrGLTexture.h" | 10 #include "gl/GrGLTexture.h" |
| 11 #include "gl/builders/GrGLProgramBuilder.h" | 11 #include "gl/builders/GrGLProgramBuilder.h" |
| 12 | 12 |
| 13 // For brevity | 13 // For brevity |
| 14 typedef GrGLProgramDataManager::UniformHandle UniformHandle; | 14 typedef GrGLProgramDataManager::UniformHandle UniformHandle; |
| 15 | 15 |
| 16 /** | |
| 17 * Base class with shared functionality for GrGLBoundedConvolutionEffect and | |
| 18 * GrGLBilerpConvolutionEffect. | |
| 19 */ | |
| 16 class GrGLConvolutionEffect : public GrGLFragmentProcessor { | 20 class GrGLConvolutionEffect : public GrGLFragmentProcessor { |
| 17 public: | 21 public: |
| 18 GrGLConvolutionEffect(const GrProcessor&); | 22 GrGLConvolutionEffect(const GrProcessor&); |
| 23 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor KeyBuilder*); | |
| 24 | |
| 25 protected: | |
| 26 int radius() const { return fRadius; } | |
| 27 int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); } | |
| 28 Gr1DKernelEffect::Direction direction() const { return fDirection; } | |
| 29 void getImageIncrement(const GrConvolutionEffect&, float (*)[2]) const; | |
| 30 | |
| 31 private: | |
| 32 int fRadius; | |
| 33 Gr1DKernelEffect::Direction fDirection; | |
| 34 | |
| 35 typedef GrGLFragmentProcessor INHERITED; | |
| 36 }; | |
| 37 | |
| 38 GrGLConvolutionEffect::GrGLConvolutionEffect(const GrProcessor& processor) { | |
| 39 const GrConvolutionEffect& c = processor.cast<GrConvolutionEffect>(); | |
| 40 fRadius = c.radius(); | |
| 41 fDirection = c.direction(); | |
| 42 } | |
| 43 | |
| 44 void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, | |
| 45 const GrGLSLCaps&, | |
| 46 GrProcessorKeyBuilder* b) { | |
| 47 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); | |
| 48 uint32_t key = conv.radius(); | |
| 49 key <<= 2; | |
| 50 if (conv.useBounds()) { | |
| 51 key |= 0x2; | |
| 52 key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0 ; | |
| 53 } | |
| 54 b->add32(key); | |
| 55 } | |
| 56 | |
| 57 void GrGLConvolutionEffect::getImageIncrement(const GrConvolutionEffect& conv, | |
| 58 float (*imageIncrement)[2]) const { | |
| 59 GrTexture& texture = *conv.texture(0); | |
| 60 (*imageIncrement)[0] = (*imageIncrement)[1] = 0; | |
| 61 float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; | |
| 62 switch (conv.direction()) { | |
| 63 case Gr1DKernelEffect::kX_Direction: | |
| 64 (*imageIncrement)[0] = 1.0f / texture.width(); | |
| 65 break; | |
| 66 case Gr1DKernelEffect::kY_Direction: | |
| 67 (*imageIncrement)[1] = ySign / texture.height(); | |
| 68 break; | |
| 69 default: | |
| 70 SkFAIL("Unknown filter direction."); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 /////////////////////////////////////////////////////////////////////////////// | |
| 75 | |
| 76 /** | |
| 77 * Applies a convolution effect which restricts samples to the provided bounds | |
| 78 * using shader logic. | |
| 79 */ | |
| 80 class GrGLBoundedConvolutionEffect : public GrGLConvolutionEffect { | |
| 81 public: | |
| 82 GrGLBoundedConvolutionEffect(const GrProcessor& processor) : INHERITED(proce ssor) {} | |
| 19 | 83 |
| 20 virtual void emitCode(GrGLFPBuilder*, | 84 virtual void emitCode(GrGLFPBuilder*, |
| 21 const GrFragmentProcessor&, | 85 const GrFragmentProcessor&, |
| 22 const char* outputColor, | 86 const char* outputColor, |
| 23 const char* inputColor, | 87 const char* inputColor, |
| 24 const TransformedCoordsArray&, | 88 const TransformedCoordsArray&, |
| 25 const TextureSamplerArray&) override; | 89 const TextureSamplerArray&) override; |
| 26 | 90 |
| 27 void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) overri de; | 91 void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) overri de; |
| 28 | 92 |
| 29 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor KeyBuilder*); | |
| 30 | |
| 31 private: | 93 private: |
| 32 int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); } | |
| 33 bool useBounds() const { return fUseBounds; } | |
| 34 Gr1DKernelEffect::Direction direction() const { return fDirection; } | |
| 35 | |
| 36 int fRadius; | |
| 37 bool fUseBounds; | |
| 38 Gr1DKernelEffect::Direction fDirection; | |
| 39 UniformHandle fKernelUni; | 94 UniformHandle fKernelUni; |
| 40 UniformHandle fImageIncrementUni; | 95 UniformHandle fImageIncrementUni; |
| 41 UniformHandle fBoundsUni; | 96 UniformHandle fBoundsUni; |
| 42 | 97 |
| 43 typedef GrGLFragmentProcessor INHERITED; | 98 typedef GrGLConvolutionEffect INHERITED; |
| 44 }; | 99 }; |
| 45 | 100 |
| 46 GrGLConvolutionEffect::GrGLConvolutionEffect(const GrProcessor& processor) { | 101 void GrGLBoundedConvolutionEffect::emitCode(GrGLFPBuilder* builder, |
| 47 const GrConvolutionEffect& c = processor.cast<GrConvolutionEffect>(); | 102 const GrFragmentProcessor& processor , |
| 48 fRadius = c.radius(); | 103 const char* outputColor, |
| 49 fUseBounds = c.useBounds(); | 104 const char* inputColor, |
| 50 fDirection = c.direction(); | 105 const TransformedCoordsArray& coords , |
| 51 } | 106 const TextureSamplerArray& samplers) { |
| 107 fImageIncrementUni = | |
| 108 builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2f_GrS LType, | |
| 109 kDefault_GrSLPrecision, "ImageIncrement"); | |
| 52 | 110 |
| 53 void GrGLConvolutionEffect::emitCode(GrGLFPBuilder* builder, | 111 fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, k Vec2f_GrSLType, |
| 54 const GrFragmentProcessor&, | 112 kDefault_GrSLPrecision, "Bounds"); |
| 55 const char* outputColor, | 113 |
| 56 const char* inputColor, | 114 fKernelUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibili ty, kFloat_GrSLType, |
| 57 const TransformedCoordsArray& coords, | 115 kDefault_GrSLPrecision, "Kernel", this ->width()); |
| 58 const TextureSamplerArray& samplers) { | |
| 59 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visib ility, | |
| 60 kVec2f_GrSLType, kDefault_GrSLPreci sion, | |
| 61 "ImageIncrement"); | |
| 62 if (this->useBounds()) { | |
| 63 fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibilit y, | |
| 64 kVec2f_GrSLType, kDefault_GrSLPrecision , | |
| 65 "Bounds"); | |
| 66 } | |
| 67 fKernelUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibili ty, | |
| 68 kFloat_GrSLType, kDefault_GrSLPrecisio n, | |
| 69 "Kernel", this->width()); | |
| 70 | 116 |
| 71 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 117 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
| 72 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); | 118 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); |
| 73 | 119 |
| 74 fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor); | 120 fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor); |
| 75 | 121 |
| 76 int width = this->width(); | 122 int width = this->width(); |
| 77 const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni); | 123 const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni); |
| 78 const char* imgInc = builder->getUniformCStr(fImageIncrementUni); | 124 const char* imgInc = builder->getUniformCStr(fImageIncrementUni); |
| 79 | 125 |
| 80 fsBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str( ), fRadius, imgInc); | 126 fsBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str( ), this->radius(), |
| 127 imgInc); | |
| 81 | 128 |
| 82 // Manually unroll loop because some drivers don't; yields 20-30% speedup. | 129 // Manually unroll loop because some drivers don't; yields 20-30% speedup. |
| 83 for (int i = 0; i < width; i++) { | 130 for (int i = 0; i < width; i++) { |
| 84 SkString index; | 131 SkString index; |
| 85 SkString kernelIndex; | 132 SkString kernelIndex; |
| 86 index.appendS32(i); | 133 index.appendS32(i); |
| 87 kernel.appendArrayAccess(index.c_str(), &kernelIndex); | 134 kernel.appendArrayAccess(index.c_str(), &kernelIndex); |
| 88 fsBuilder->codeAppendf("\t\t%s += ", outputColor); | 135 fsBuilder->codeAppendf("\t\t%s += ", outputColor); |
| 89 fsBuilder->appendTextureLookup(samplers[0], "coord"); | 136 fsBuilder->appendTextureLookup(samplers[0], "coord"); |
| 90 if (this->useBounds()) { | 137 const char* bounds = builder->getUniformCStr(fBoundsUni); |
| 91 const char* bounds = builder->getUniformCStr(fBoundsUni); | 138 const char* component = this->direction() == Gr1DKernelEffect::kY_Direct ion ? "y" : "x"; |
| 92 const char* component = this->direction() == Gr1DKernelEffect::kY_Di rection ? "y" : "x"; | 139 fsBuilder->codeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s.y)", component, bounds, |
| 93 fsBuilder->codeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s. y)", | 140 component, bounds); |
| 94 component, bounds, component, bounds); | |
| 95 } | |
| 96 fsBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); | 141 fsBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); |
| 97 fsBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc); | 142 fsBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc); |
| 98 } | 143 } |
| 99 | 144 |
| 100 SkString modulate; | 145 SkString modulate; |
| 101 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); | 146 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); |
| 102 fsBuilder->codeAppend(modulate.c_str()); | 147 fsBuilder->codeAppend(modulate.c_str()); |
| 103 } | 148 } |
| 104 | 149 |
| 105 void GrGLConvolutionEffect::setData(const GrGLProgramDataManager& pdman, | 150 void GrGLBoundedConvolutionEffect::setData(const GrGLProgramDataManager& pdman, |
| 106 const GrProcessor& processor) { | 151 const GrProcessor& processor) { |
| 107 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); | 152 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); |
| 153 | |
| 154 // the code we generated was for a specific kernel radius | |
| 155 SkASSERT(conv.radius() == this->radius()); | |
| 156 | |
| 157 // the code we generated was for a specific bounding mode. | |
| 158 SkASSERT(conv.useBounds() == true); | |
| 159 | |
| 108 GrTexture& texture = *conv.texture(0); | 160 GrTexture& texture = *conv.texture(0); |
| 109 // the code we generated was for a specific kernel radius | 161 float imageIncrement[2]; |
| 110 SkASSERT(conv.radius() == fRadius); | 162 getImageIncrement(conv, &imageIncrement); |
| 111 float imageIncrement[2] = { 0 }; | |
| 112 float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; | |
| 113 switch (conv.direction()) { | |
| 114 case Gr1DKernelEffect::kX_Direction: | |
| 115 imageIncrement[0] = 1.0f / texture.width(); | |
| 116 break; | |
| 117 case Gr1DKernelEffect::kY_Direction: | |
| 118 imageIncrement[1] = ySign / texture.height(); | |
| 119 break; | |
| 120 default: | |
| 121 SkFAIL("Unknown filter direction."); | |
| 122 } | |
| 123 pdman.set2fv(fImageIncrementUni, 1, imageIncrement); | 163 pdman.set2fv(fImageIncrementUni, 1, imageIncrement); |
| 124 if (conv.useBounds()) { | 164 const float* bounds = conv.bounds(); |
| 125 const float* bounds = conv.bounds(); | 165 if (Gr1DKernelEffect::kY_Direction == conv.direction() && |
| 126 if (Gr1DKernelEffect::kY_Direction == conv.direction() && | 166 texture.origin() != kTopLeft_GrSurfaceOrigin) { |
| 127 texture.origin() != kTopLeft_GrSurfaceOrigin) { | 167 pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); |
| 128 pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); | 168 } else { |
| 129 } else { | 169 pdman.set2f(fBoundsUni, bounds[0], bounds[1]); |
| 130 pdman.set2f(fBoundsUni, bounds[0], bounds[1]); | |
| 131 } | |
| 132 } | 170 } |
| 133 pdman.set1fv(fKernelUni, this->width(), conv.kernel()); | 171 pdman.set1fv(fKernelUni, this->width(), conv.kernel()); |
| 134 } | 172 } |
| 135 | 173 |
| 136 void GrGLConvolutionEffect::GenKey(const GrProcessor& processor, const GrGLSLCap s&, | 174 /////////////////////////////////////////////////////////////////////////////// |
| 137 GrProcessorKeyBuilder* b) { | 175 |
| 176 /** | |
| 177 * Applies a convolution effect which applies the convolution using a bilinear | |
| 178 * sampling optimization to use half as many samples. | |
| 179 */ | |
| 180 class GrGLBilerpConvolutionEffect : public GrGLConvolutionEffect { | |
|
Stephen White
2015/06/26 21:28:31
<bikeshed> is this really a bilinear fetch? Or ess
ericrk
2015/06/29 17:33:21
yup - that's better :D
| |
| 181 public: | |
| 182 GrGLBilerpConvolutionEffect(const GrProcessor& processor) : INHERITED(proces sor) {} | |
| 183 | |
| 184 virtual void emitCode(GrGLFPBuilder*, | |
| 185 const GrFragmentProcessor&, | |
| 186 const char* outputColor, | |
| 187 const char* inputColor, | |
| 188 const TransformedCoordsArray&, | |
| 189 const TextureSamplerArray&) override; | |
| 190 | |
| 191 void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) overri de; | |
| 192 | |
| 193 private: | |
| 194 int bilerpSampleCount() const; | |
| 195 | |
| 196 // Bounded uniforms | |
| 197 UniformHandle fSampleWeightUni; | |
| 198 UniformHandle fSampleOffsetUni; | |
| 199 | |
| 200 typedef GrGLConvolutionEffect INHERITED; | |
| 201 }; | |
| 202 | |
| 203 void GrGLBilerpConvolutionEffect::emitCode(GrGLFPBuilder* builder, | |
| 204 const GrFragmentProcessor& processor, | |
| 205 const char* outputColor, | |
| 206 const char* inputColor, | |
| 207 const TransformedCoordsArray& coords, | |
| 208 const TextureSamplerArray& samplers) { | |
| 209 int sampleCount = bilerpSampleCount(); | |
| 210 | |
| 211 fSampleOffsetUni = | |
|
Stephen White
2015/06/26 21:28:31
How many uniform values does this add up to? You m
ericrk
2015/06/29 17:33:21
I think we're safe (assuming we keep the limit of
Stephen White
2015/06/29 19:04:06
Yep; makes sense. Thanks!
| |
| 212 builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility, kVec2 f_GrSLType, | |
| 213 kDefault_GrSLPrecision, "SampleOffset", sampleC ount); | |
| 214 fSampleWeightUni = | |
| 215 builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility, kFloa t_GrSLType, | |
| 216 kDefault_GrSLPrecision, "SampleWeight", sampleC ount); | |
| 217 | |
| 218 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | |
| 219 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); | |
| 220 | |
| 221 fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor); | |
|
bsalomon
2015/06/26 21:07:33
You don't really need the \t's anymore (we now "pr
ericrk
2015/06/26 21:28:22
removed the \t\ts throughout the file
| |
| 222 | |
| 223 const GrGLShaderVar& kernel = builder->getUniformVariable(fSampleWeightUni); | |
| 224 const GrGLShaderVar& imgInc = builder->getUniformVariable(fSampleOffsetUni); | |
| 225 | |
| 226 fsBuilder->codeAppendf("\t\tvec2 coord; \n"); | |
| 227 | |
| 228 // Manually unroll loop because some drivers don't; yields 20-30% speedup. | |
| 229 for (int i = 0; i < sampleCount; i++) { | |
| 230 SkString index; | |
| 231 SkString weightIndex; | |
| 232 SkString offsetIndex; | |
| 233 index.appendS32(i); | |
| 234 kernel.appendArrayAccess(index.c_str(), &weightIndex); | |
| 235 imgInc.appendArrayAccess(index.c_str(), &offsetIndex); | |
| 236 fsBuilder->codeAppendf("\t\tcoord = %s + %s;\n", coords2D.c_str(), offse tIndex.c_str()); | |
| 237 fsBuilder->codeAppendf("\t\t%s += ", outputColor); | |
| 238 fsBuilder->appendTextureLookup(samplers[0], "coord"); | |
| 239 fsBuilder->codeAppendf(" * %s;\n", weightIndex.c_str()); | |
| 240 } | |
| 241 | |
| 242 SkString modulate; | |
| 243 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); | |
| 244 fsBuilder->codeAppend(modulate.c_str()); | |
| 245 } | |
| 246 | |
| 247 void GrGLBilerpConvolutionEffect::setData(const GrGLProgramDataManager& pdman, | |
| 248 const GrProcessor& processor) { | |
| 138 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); | 249 const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); |
| 139 uint32_t key = conv.radius(); | 250 |
| 140 key <<= 2; | 251 // the code we generated was for a specific kernel radius |
| 141 if (conv.useBounds()) { | 252 SkASSERT(conv.radius() == this->radius()); |
| 142 key |= 0x2; | 253 |
| 143 key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0 ; | 254 // the code we generated was for a specific bounding mode. |
| 255 SkASSERT(conv.useBounds() == false); | |
|
bsalomon
2015/06/26 21:07:34
!conv.useBounds()?
ericrk
2015/06/26 21:28:22
yup
| |
| 256 | |
| 257 int sampleCount = bilerpSampleCount(); | |
| 258 SkAutoTArray<float> imageIncrements(sampleCount * 2); // X and Y floats per sample. | |
| 259 SkAutoTArray<float> kernel(sampleCount); | |
| 260 | |
| 261 float baseImageIncrement[2]; | |
| 262 getImageIncrement(conv, &baseImageIncrement); | |
| 263 | |
| 264 for (int i = 0; i < sampleCount; i++) { | |
| 265 int sampleIndex1 = i * 2; | |
| 266 int sampleIndex2 = sampleIndex1 + 1; | |
| 267 | |
| 268 // If we have an odd number of samples in our filter, the last sample wo n't use | |
| 269 // the bilinear optimization (it will be pixel aligned). | |
| 270 if (sampleIndex2 >= this->width()) { | |
| 271 sampleIndex2 = sampleIndex1; | |
| 272 } | |
| 273 | |
| 274 float kernelWeight1 = conv.kernel()[sampleIndex1]; | |
| 275 float kernelWeight2 = conv.kernel()[sampleIndex2]; | |
| 276 | |
| 277 float totalKernalWeight = | |
|
Stephen White
2015/06/26 21:28:31
Nit: kernal -> kernel?
| |
| 278 (sampleIndex1 == sampleIndex2) ? kernelWeight1 : (kernelWeight1 + ke rnelWeight2); | |
| 279 | |
| 280 float sampleRatio = | |
| 281 (sampleIndex1 == sampleIndex2) ? 0 : kernelWeight2 / (kernelWeight1 + kernelWeight2); | |
| 282 | |
| 283 imageIncrements[i * 2] = (-this->radius() + i * 2 + sampleRatio) * baseI mageIncrement[0]; | |
| 284 imageIncrements[i * 2 + 1] = | |
| 285 (-this->radius() + i * 2 + sampleRatio) * baseImageIncrement[1]; | |
| 286 | |
| 287 kernel[i] = totalKernalWeight; | |
| 144 } | 288 } |
| 145 b->add32(key); | 289 pdman.set2fv(fSampleOffsetUni, sampleCount, imageIncrements.get()); |
| 290 pdman.set1fv(fSampleWeightUni, sampleCount, kernel.get()); | |
| 291 } | |
| 292 | |
| 293 int GrGLBilerpConvolutionEffect::bilerpSampleCount() const { | |
| 294 // We use a bilinear optimization to only sample once for each two pixel ali gned | |
| 295 // samples in the kernel. If we have an odd number of samples, we will have to | |
| 296 // skip this optimization for the last sample. Because of this we always rou nd | |
| 297 // up our sample count (by adding 1 before dividing). | |
| 298 return (this->width() + 1) / 2; | |
| 146 } | 299 } |
| 147 | 300 |
| 148 /////////////////////////////////////////////////////////////////////////////// | 301 /////////////////////////////////////////////////////////////////////////////// |
| 149 | 302 |
| 150 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, | 303 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, |
| 151 Direction direction, | 304 Direction direction, |
| 152 int radius, | 305 int radius, |
| 153 const float* kernel, | 306 const float* kernel, |
| 154 bool useBounds, | 307 bool useBounds, |
| 155 float bounds[2]) | 308 float bounds[2]) |
| 156 : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) { | 309 : Gr1DKernelEffect(texture, |
| 310 direction, | |
| 311 radius, | |
| 312 useBounds ? GrTextureParams::FilterMode::kNone_FilterMode | |
| 313 : GrTextureParams::FilterMode::kBilerp_FilterMo de) | |
| 314 , fUseBounds(useBounds) { | |
| 157 this->initClassID<GrConvolutionEffect>(); | 315 this->initClassID<GrConvolutionEffect>(); |
| 158 SkASSERT(radius <= kMaxKernelRadius); | 316 SkASSERT(radius <= kMaxKernelRadius); |
| 159 SkASSERT(kernel); | 317 SkASSERT(kernel); |
| 160 int width = this->width(); | 318 int width = this->width(); |
| 161 for (int i = 0; i < width; i++) { | 319 for (int i = 0; i < width; i++) { |
| 162 fKernel[i] = kernel[i]; | 320 fKernel[i] = kernel[i]; |
| 163 } | 321 } |
| 164 memcpy(fBounds, bounds, sizeof(fBounds)); | 322 memcpy(fBounds, bounds, sizeof(fBounds)); |
| 165 } | 323 } |
| 166 | 324 |
| 167 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, | 325 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture, |
| 168 Direction direction, | 326 Direction direction, |
| 169 int radius, | 327 int radius, |
| 170 float gaussianSigma, | 328 float gaussianSigma, |
| 171 bool useBounds, | 329 bool useBounds, |
| 172 float bounds[2]) | 330 float bounds[2]) |
| 173 : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) { | 331 : Gr1DKernelEffect(texture, |
| 332 direction, | |
| 333 radius, | |
| 334 useBounds ? GrTextureParams::FilterMode::kNone_FilterMode | |
| 335 : GrTextureParams::FilterMode::kBilerp_FilterMo de) | |
| 336 , fUseBounds(useBounds) { | |
| 174 this->initClassID<GrConvolutionEffect>(); | 337 this->initClassID<GrConvolutionEffect>(); |
| 175 SkASSERT(radius <= kMaxKernelRadius); | 338 SkASSERT(radius <= kMaxKernelRadius); |
| 176 int width = this->width(); | 339 int width = this->width(); |
| 177 | 340 |
| 178 float sum = 0.0f; | 341 float sum = 0.0f; |
| 179 float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma); | 342 float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma); |
| 180 for (int i = 0; i < width; ++i) { | 343 for (int i = 0; i < width; ++i) { |
| 181 float x = static_cast<float>(i - this->radius()); | 344 float x = static_cast<float>(i - this->radius()); |
| 182 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian | 345 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian |
| 183 // is dropped here, since we renormalize the kernel below. | 346 // is dropped here, since we renormalize the kernel below. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 194 | 357 |
| 195 GrConvolutionEffect::~GrConvolutionEffect() { | 358 GrConvolutionEffect::~GrConvolutionEffect() { |
| 196 } | 359 } |
| 197 | 360 |
| 198 void GrConvolutionEffect::getGLProcessorKey(const GrGLSLCaps& caps, | 361 void GrConvolutionEffect::getGLProcessorKey(const GrGLSLCaps& caps, |
| 199 GrProcessorKeyBuilder* b) const { | 362 GrProcessorKeyBuilder* b) const { |
| 200 GrGLConvolutionEffect::GenKey(*this, caps, b); | 363 GrGLConvolutionEffect::GenKey(*this, caps, b); |
| 201 } | 364 } |
| 202 | 365 |
| 203 GrGLFragmentProcessor* GrConvolutionEffect::createGLInstance() const { | 366 GrGLFragmentProcessor* GrConvolutionEffect::createGLInstance() const { |
| 204 return SkNEW_ARGS(GrGLConvolutionEffect, (*this)); | 367 // We support a bilinear optimization which (when feasible) uses half the nu mber |
| 368 // of samples to apply the kernel. This is not always applicable, as the | |
| 369 // bilinear sampling optimization does not support bounded sampling. | |
| 370 if (this->useBounds()) { | |
| 371 return SkNEW_ARGS(GrGLBoundedConvolutionEffect, (*this)); | |
| 372 } else { | |
| 373 return SkNEW_ARGS(GrGLBilerpConvolutionEffect, (*this)); | |
| 374 } | |
| 205 } | 375 } |
| 206 | 376 |
| 207 bool GrConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { | 377 bool GrConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) const { |
| 208 const GrConvolutionEffect& s = sBase.cast<GrConvolutionEffect>(); | 378 const GrConvolutionEffect& s = sBase.cast<GrConvolutionEffect>(); |
| 209 return (this->radius() == s.radius() && | 379 return (this->radius() == s.radius() && |
| 210 this->direction() == s.direction() && | 380 this->direction() == s.direction() && |
| 211 this->useBounds() == s.useBounds() && | 381 this->useBounds() == s.useBounds() && |
| 212 0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) && | 382 0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) && |
| 213 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); | 383 0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float))); |
| 214 } | 384 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 235 } | 405 } |
| 236 | 406 |
| 237 bool useBounds = random->nextBool(); | 407 bool useBounds = random->nextBool(); |
| 238 return GrConvolutionEffect::Create(textures[texIdx], | 408 return GrConvolutionEffect::Create(textures[texIdx], |
| 239 dir, | 409 dir, |
| 240 radius, | 410 radius, |
| 241 kernel, | 411 kernel, |
| 242 useBounds, | 412 useBounds, |
| 243 bounds); | 413 bounds); |
| 244 } | 414 } |
| OLD | NEW |