| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 "GrGLProgramBuilder.h" | 8 #include "GrGLProgramBuilder.h" |
| 9 #include "gl/GrGLGeometryProcessor.h" | 9 #include "gl/GrGLGeometryProcessor.h" |
| 10 #include "gl/GrGLProgram.h" | 10 #include "gl/GrGLProgram.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) | 22 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) |
| 23 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X) | 23 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X) |
| 24 | 24 |
| 25 // ES2 FS only guarantees mediump and lowp support | 25 // ES2 FS only guarantees mediump and lowp support |
| 26 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar:
:kMedium_Precision; | 26 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar:
:kMedium_Precision; |
| 27 | 27 |
| 28 ////////////////////////////////////////////////////////////////////////////// | 28 ////////////////////////////////////////////////////////////////////////////// |
| 29 | 29 |
| 30 const int GrGLProgramBuilder::kVarsPerBlock = 8; | 30 const int GrGLProgramBuilder::kVarsPerBlock = 8; |
| 31 | 31 |
| 32 // Below are some helper classes which help keep the create and emit pipeline ge
neral |
| 33 template <class Derived> |
| 34 struct FragmentStageClassMap { |
| 35 static const GrFragmentProcessor* GetProcessor(const GrOptDrawState& opt, in
t index) { |
| 36 SkASSERT(Derived::GetStage(opt, index)->getProcessor()); |
| 37 return Derived::GetStage(opt, index)->getProcessor(); |
| 38 } |
| 39 typedef GrFragmentProcessor Processor; |
| 40 typedef GrFragmentStage ProcessorStaged; |
| 41 typedef GrGLFragmentProcessor GLProcessor; |
| 42 }; |
| 43 |
| 44 struct ColorStageClassMap : public FragmentStageClassMap<ColorStageClassMap> { |
| 45 static int GetCount(const GrOptDrawState& opt) { return opt.numColorStages()
; } |
| 46 static const GrFragmentStage* GetStage(const GrOptDrawState& opt, int index)
{ |
| 47 return &opt.getColorStage(index); |
| 48 } |
| 49 }; |
| 50 |
| 51 struct CoverageStageClassMap : public FragmentStageClassMap<CoverageStageClassMa
p> { |
| 52 static int GetCount(const GrOptDrawState& opt) { return opt.numCoverageStage
s(); } |
| 53 static const GrFragmentStage* GetStage(const GrOptDrawState& opt, int index)
{ |
| 54 return &opt.getCoverageStage(index); |
| 55 } |
| 56 }; |
| 57 |
| 58 struct GeometryProcessorClassMap { |
| 59 static int GetCount(const GrOptDrawState& opt) { return 1; } |
| 60 static const GrGeometryProcessor* GetStage(const GrOptDrawState& opt, int in
dex) { |
| 61 SkASSERT(0 == index && opt.hasGeometryProcessor()); |
| 62 return opt.getGeometryProcessor(); |
| 63 } |
| 64 static const GrGeometryProcessor* GetProcessor(const GrOptDrawState& opt, in
t index) { |
| 65 return GetStage(opt, index); |
| 66 } |
| 67 typedef GrGeometryProcessor Processor; |
| 68 typedef GrGeometryProcessor ProcessorStaged; |
| 69 typedef GrGLGeometryProcessor GLProcessor; |
| 70 }; |
| 71 |
| 72 ////////////////////////////////////////////////////////////////////////////////
////////////////// |
| 73 |
| 32 GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState, | 74 GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState, |
| 33 const GrGLProgramDesc& desc, | 75 const GrGLProgramDesc& desc, |
| 34 GrGpu::DrawType drawType, | 76 GrGpu::DrawType drawType, |
| 35 const GrGeometryStage* geometryPr
ocessor, | |
| 36 const GrFragmentStage* colorStage
s[], | |
| 37 const GrFragmentStage* coverageSt
ages[], | |
| 38 GrGpuGL* gpu) { | 77 GrGpuGL* gpu) { |
| 39 // create a builder. This will be handed off to effects so they can use it
to add | 78 // create a builder. This will be handed off to effects so they can use it
to add |
| 40 // uniforms, varyings, textures, etc | 79 // uniforms, varyings, textures, etc |
| 41 SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(desc, | 80 SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(desc, |
| 42 optState, | 81 optState, |
| 43 drawType, | 82 drawType, |
| 44 SkToBool(geom
etryProcessor), | 83 optState.hasG
eometryProcessor(), |
| 45 gpu)); | 84 gpu)); |
| 46 | 85 |
| 47 GrGLProgramBuilder* pb = builder.get(); | 86 GrGLProgramBuilder* pb = builder.get(); |
| 48 const GrGLProgramDesc::KeyHeader& header = pb->header(); | 87 const GrGLProgramDesc::KeyHeader& header = pb->header(); |
| 49 | 88 |
| 50 // emit code to read the dst copy texture, if necessary | 89 // emit code to read the dst copy texture, if necessary |
| 51 if (GrGLFragmentShaderBuilder::kNoDstRead_DstReadKey != header.fDstReadKey | 90 if (GrGLFragmentShaderBuilder::kNoDstRead_DstReadKey != header.fDstReadKey |
| 52 && !gpu->glCaps().fbFetchSupport()) { | 91 && !gpu->glCaps().fbFetchSupport()) { |
| 53 pb->fFS.emitCodeToReadDstTexture(); | 92 pb->fFS.emitCodeToReadDstTexture(); |
| 54 } | 93 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 67 pb->fVS.codeAppend("gl_PointSize = 1.0;"); | 106 pb->fVS.codeAppend("gl_PointSize = 1.0;"); |
| 68 } | 107 } |
| 69 if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) { | 108 if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) { |
| 70 pb->fVS.setupBuiltinVertexAttribute("Color", &inputColor); | 109 pb->fVS.setupBuiltinVertexAttribute("Color", &inputColor); |
| 71 } | 110 } |
| 72 if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) { | 111 if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) { |
| 73 pb->fVS.setupBuiltinVertexAttribute("Coverage", &inputCoverage); | 112 pb->fVS.setupBuiltinVertexAttribute("Coverage", &inputCoverage); |
| 74 } | 113 } |
| 75 } | 114 } |
| 76 | 115 |
| 77 pb->createAndEmitProcessors(geometryProcessor, colorStages, coverageStages,
&inputColor, | 116 bool useLocalCoords = pb->fVS.hasExplicitLocalCoords(); |
| 78 &inputCoverage); | 117 pb->createAndEmitProcessors<ColorStageClassMap>(EffectKeyProvider::kColor_Ef
fectType, |
| 118 useLocalCoords, |
| 119 &pb->fColorEffects, |
| 120 &inputColor); |
| 121 if (optState.hasGeometryProcessor()) { |
| 122 pb->fVS.emitAttributes(*optState.getGeometryProcessor()); |
| 123 pb->createAndEmitProcessors<GeometryProcessorClassMap>( |
| 124 EffectKeyProvider::kGeometryProcessor_EffectType, |
| 125 false, |
| 126 &pb->fGeometryProcessor, |
| 127 &inputCoverage); |
| 128 } |
| 129 pb->createAndEmitProcessors<CoverageStageClassMap>(EffectKeyProvider::kCover
age_EffectType, |
| 130 useLocalCoords, |
| 131 &pb->fCoverageEffects, |
| 132 &inputCoverage); |
| 79 | 133 |
| 80 if (hasVertexShader) { | 134 if (hasVertexShader) { |
| 81 pb->fVS.transformSkiaToGLCoords(); | 135 pb->fVS.transformSkiaToGLCoords(); |
| 82 } | 136 } |
| 83 | 137 |
| 84 // write the secondary color output if necessary | 138 // write the secondary color output if necessary |
| 85 if (GrOptDrawState::kNone_SecondaryOutputType != header.fSecondaryOutputType
) { | 139 if (GrOptDrawState::kNone_SecondaryOutputType != header.fSecondaryOutputType
) { |
| 86 pb->fFS.enableSecondaryOutput(inputColor, inputCoverage); | 140 pb->fFS.enableSecondaryOutput(inputColor, inputCoverage); |
| 87 } | 141 } |
| 88 | 142 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 this->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 272 this->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| 219 kVec4f_GrSLType, | 273 kVec4f_GrSLType, |
| 220 "Coverage", | 274 "Coverage", |
| 221 &name); | 275 &name); |
| 222 *inputCoverage = GrGLSLExpr4(name); | 276 *inputCoverage = GrGLSLExpr4(name); |
| 223 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) { | 277 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) { |
| 224 *inputCoverage = GrGLSLExpr4(1); | 278 *inputCoverage = GrGLSLExpr4(1); |
| 225 } | 279 } |
| 226 } | 280 } |
| 227 | 281 |
| 228 void GrGLProgramBuilder::createAndEmitProcessors(const GrGeometryStage* geometry
Processor, | 282 template <class ClassMap> |
| 229 const GrFragmentStage* colorSta
ges[], | 283 void GrGLProgramBuilder::createAndEmitProcessors(const EffectKeyProvider::Effect
Type type, |
| 230 const GrFragmentStage* coverage
Stages[], | 284 bool useLocalCoords, |
| 231 GrGLSLExpr4* inputColor, | 285 SkAutoTUnref<GrGLInstalledProce
ssors>* installProc, |
| 232 GrGLSLExpr4* inputCoverage) { | 286 GrGLSLExpr4* fsInOutColor) { |
| 233 bool useLocalCoords = fVS.hasExplicitLocalCoords(); | 287 // setup key provider and install point |
| 288 EffectKeyProvider keyProvider(&fDesc, type); |
| 289 int numProcs = ClassMap::GetCount(fOptState); |
| 290 GrGLInstalledProcessors* ip = SkNEW_ARGS(GrGLInstalledProcessors, (numProcs,
useLocalCoords)); |
| 234 | 291 |
| 235 EffectKeyProvider colorKeyProvider(&fDesc, EffectKeyProvider::kColor_EffectT
ype); | |
| 236 int numColorEffects = fDesc.numColorEffects(); | |
| 237 GrGLInstalledProcessors* ip = SkNEW_ARGS(GrGLInstalledProcessors, (numColorE
ffects, | |
| 238 useLocalC
oords)); | |
| 239 this->createAndEmitProcessors<GrFragmentStage>(colorStages, numColorEffects,
colorKeyProvider, | |
| 240 inputColor, ip); | |
| 241 fColorEffects.reset(ip); | |
| 242 | |
| 243 if (geometryProcessor) { | |
| 244 fVS.emitAttributes(*geometryProcessor->getProcessor()); | |
| 245 EffectKeyProvider gpKeyProvider(&fDesc, EffectKeyProvider::kGeometryProc
essor_EffectType); | |
| 246 ip = SkNEW_ARGS(GrGLInstalledProcessors, (1, useLocalCoords)); | |
| 247 this->createAndEmitProcessors<GrGeometryStage>(&geometryProcessor, 1, gp
KeyProvider, | |
| 248 inputCoverage, ip); | |
| 249 fGeometryProcessor.reset(ip); | |
| 250 } | |
| 251 | |
| 252 EffectKeyProvider coverageKeyProvider(&fDesc, EffectKeyProvider::kCoverage_E
ffectType); | |
| 253 int numCoverageEffects = fDesc.numCoverageEffects(); | |
| 254 ip = SkNEW_ARGS(GrGLInstalledProcessors, (numCoverageEffects, useLocalCoords
)); | |
| 255 this->createAndEmitProcessors<GrFragmentStage>(coverageStages, numCoverageEf
fects, | |
| 256 coverageKeyProvider, inputCov
erage, ip); | |
| 257 fCoverageEffects.reset(ip); | |
| 258 } | |
| 259 | |
| 260 template <class ProcessorStage> | |
| 261 void GrGLProgramBuilder::createAndEmitProcessors(const ProcessorStage* processSt
ages[], | |
| 262 int effectCnt, | |
| 263 const EffectKeyProvider& keyPro
vider, | |
| 264 GrGLSLExpr4* fsInOutColor, | |
| 265 GrGLInstalledProcessors* instal
ledProcessors) { | |
| 266 bool effectEmitted = false; | 292 bool effectEmitted = false; |
| 267 | 293 |
| 268 GrGLSLExpr4 inColor = *fsInOutColor; | 294 GrGLSLExpr4 inColor = *fsInOutColor; |
| 269 GrGLSLExpr4 outColor; | 295 GrGLSLExpr4 outColor; |
| 270 | 296 |
| 271 for (int e = 0; e < effectCnt; ++e) { | 297 for (int e = 0; e < numProcs; ++e) { |
| 272 // Program builders have a bit of state we need to clear with each effec
t | 298 // Program builders have a bit of state we need to clear with each effec
t |
| 273 AutoStageAdvance adv(this); | 299 AutoStageAdvance adv(this); |
| 274 const ProcessorStage& stage = *processStages[e]; | |
| 275 SkASSERT(stage.getProcessor()); | |
| 276 | 300 |
| 277 if (inColor.isZeros()) { | 301 if (inColor.isZeros()) { |
| 278 SkString inColorName; | 302 SkString inColorName; |
| 279 | 303 |
| 280 // Effects have no way to communicate zeros, they treat an empty str
ing as ones. | 304 // Effects have no way to communicate zeros, they treat an empty str
ing as ones. |
| 281 this->nameVariable(&inColorName, '\0', "input"); | 305 this->nameVariable(&inColorName, '\0', "input"); |
| 282 fFS.codeAppendf("vec4 %s = %s;", inColorName.c_str(), inColor.c_str(
)); | 306 fFS.codeAppendf("vec4 %s = %s;", inColorName.c_str(), inColor.c_str(
)); |
| 283 inColor = inColorName; | 307 inColor = inColorName; |
| 284 } | 308 } |
| 285 | 309 |
| 286 // create var to hold stage result | 310 // create var to hold stage result |
| 287 SkString outColorName; | 311 SkString outColorName; |
| 288 this->nameVariable(&outColorName, '\0', "output"); | 312 this->nameVariable(&outColorName, '\0', "output"); |
| 289 fFS.codeAppendf("vec4 %s;", outColorName.c_str()); | 313 fFS.codeAppendf("vec4 %s;", outColorName.c_str()); |
| 290 outColor = outColorName; | 314 outColor = outColorName; |
| 291 | 315 |
| 292 SkASSERT(installedProcessors); | 316 SkASSERT(ip); |
| 293 const typename ProcessorStage::Processor& processor = *stage.getProcesso
r(); | 317 const typename ClassMap::Processor& processor = *ClassMap::GetProcessor(
fOptState, e); |
| 294 SkSTArray<2, GrGLProcessor::TransformedCoords> coords(processor.numTrans
forms()); | |
| 295 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(processor.numTextur
es()); | |
| 296 | 318 |
| 297 this->emitTransforms(stage, &coords, installedProcessors); | 319 typename ClassMap::GLProcessor* glProc = processor.getFactory().createGL
Instance(processor); |
| 298 this->emitSamplers(processor, &samplers, installedProcessors); | 320 ip->addEffect(glProc); |
| 299 | |
| 300 typename ProcessorStage::GLProcessor* glEffect = | |
| 301 processor.getFactory().createGLInstance(processor); | |
| 302 installedProcessors->addEffect(glEffect); | |
| 303 | 321 |
| 304 // Enclose custom code in a block to avoid namespace conflicts | 322 // Enclose custom code in a block to avoid namespace conflicts |
| 305 SkString openBrace; | 323 SkString openBrace; |
| 306 openBrace.printf("{ // Stage %d: %s\n", fStageIndex, glEffect->name()); | 324 openBrace.printf("{ // Stage %d: %s\n", fStageIndex, glProc->name()); |
| 307 fFS.codeAppend(openBrace.c_str()); | 325 fFS.codeAppend(openBrace.c_str()); |
| 308 fVS.codeAppend(openBrace.c_str()); | 326 fVS.codeAppend(openBrace.c_str()); |
| 309 | 327 |
| 310 glEffect->emitCode(this, processor, keyProvider.get(e), outColor.c_str()
, | 328 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(processor.numTextur
es()); |
| 311 inColor.isOnes() ? NULL : inColor.c_str(), coords, sa
mplers); | 329 this->emitSamplers(processor, &samplers, ip); |
| 330 |
| 331 this->emit(*ClassMap::GetStage(fOptState, e), keyProvider.get(e), outCol
or.c_str(), |
| 332 inColor.isOnes() ? NULL : inColor.c_str(), samplers, ip, glPr
oc); |
| 333 |
| 334 fFS.codeAppend("}"); |
| 335 fVS.codeAppend("}"); |
| 312 | 336 |
| 313 // We have to check that effects and the code they emit are consistent,
ie if an effect | 337 // We have to check that effects and the code they emit are consistent,
ie if an effect |
| 314 // asks for dst color, then the emit code needs to follow suit | 338 // asks for dst color, then the emit code needs to follow suit |
| 315 verify(processor); | 339 verify(processor); |
| 316 fFS.codeAppend("}"); | |
| 317 fVS.codeAppend("}"); | |
| 318 | 340 |
| 319 inColor = outColor; | 341 inColor = outColor; |
| 320 effectEmitted = true; | 342 effectEmitted = true; |
| 321 } | 343 } |
| 322 | 344 |
| 323 if (effectEmitted) { | 345 if (effectEmitted) { |
| 324 *fsInOutColor = outColor; | 346 *fsInOutColor = outColor; |
| 325 } | 347 } |
| 348 |
| 349 // write to output array |
| 350 SkASSERT(installProc); |
| 351 installProc->reset(ip); |
| 352 } |
| 353 |
| 354 void GrGLProgramBuilder::emit(const GrFragmentStage& fs, |
| 355 const GrProcessorKey& key, |
| 356 const char* outColor, |
| 357 const char* inColor, |
| 358 const GrGLProcessor::TextureSamplerArray& samplers
, |
| 359 GrGLInstalledProcessors* ip, |
| 360 GrGLFragmentProcessor* glProc) { |
| 361 // Fragment processors can have coord transforms |
| 362 const GrFragmentProcessor* fp = fs.getProcessor(); |
| 363 SkSTArray<2, GrGLProcessor::TransformedCoords> coords(fp->numTransforms()); |
| 364 this->emitTransforms(fs, &coords, ip); |
| 365 |
| 366 glProc->emitCode(this, *fp, key, outColor, inColor, coords, samplers); |
| 367 } |
| 368 |
| 369 void GrGLProgramBuilder::emit(const GrGeometryProcessor& gp, |
| 370 const GrProcessorKey& key, |
| 371 const char* outColor, |
| 372 const char* inColor, |
| 373 const GrGLProcessor::TextureSamplerArray& samplers
, |
| 374 GrGLInstalledProcessors* ip, |
| 375 GrGLGeometryProcessor* glProc) { |
| 376 // TODO remove coords from emit code signature, probably best to use a struc
t here so these |
| 377 // updates are less painful |
| 378 SkSTArray<2, GrGLProcessor::TransformedCoords> coords; |
| 379 glProc->emitCode(this, gp, key, outColor, inColor, coords, samplers); |
| 326 } | 380 } |
| 327 | 381 |
| 328 void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) { | 382 void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) { |
| 329 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); | 383 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); |
| 330 } | 384 } |
| 331 | 385 |
| 332 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { | 386 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { |
| 333 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); | 387 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); |
| 334 SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor()); | 388 SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor()); |
| 335 } | 389 } |
| 336 | 390 |
| 337 void GrGLProgramBuilder::emitTransforms(const GrProcessorStage& effectStage, | 391 void GrGLProgramBuilder::emitTransforms(const GrFragmentStage& effectStage, |
| 338 GrGLProcessor::TransformedCoordsArray* o
utCoords, | 392 GrGLProcessor::TransformedCoordsArray* o
utCoords, |
| 339 GrGLInstalledProcessors* installedProces
sors) { | 393 GrGLInstalledProcessors* installedProces
sors) { |
| 340 SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = | 394 SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = |
| 341 installedProcessors->addTransforms(); | 395 installedProcessors->addTransforms(); |
| 342 const GrProcessor* effect = effectStage.getProcessor(); | 396 const GrFragmentProcessor* effect = effectStage.getProcessor(); |
| 343 int numTransforms = effect->numTransforms(); | 397 int numTransforms = effect->numTransforms(); |
| 344 transforms.push_back_n(numTransforms); | 398 transforms.push_back_n(numTransforms); |
| 345 | 399 |
| 346 for (int t = 0; t < numTransforms; t++) { | 400 for (int t = 0; t < numTransforms; t++) { |
| 347 const char* uniName = "StageMatrix"; | 401 const char* uniName = "StageMatrix"; |
| 348 GrSLType varyingType = | 402 GrSLType varyingType = |
| 349 effectStage.isPerspectiveCoordTransform(t, fVS.hasExplicitLocalC
oords()) ? | 403 effectStage.isPerspectiveCoordTransform(t, fVS.hasExplicitLocalC
oords()) ? |
| 350 kVec3f_GrSLType : | 404 kVec3f_GrSLType : |
| 351 kVec2f_GrSLType; | 405 kVec2f_GrSLType; |
| 352 | 406 |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 } | 564 } |
| 511 | 565 |
| 512 //////////////////////////////////////////////////////////////////////////////// | 566 //////////////////////////////////////////////////////////////////////////////// |
| 513 | 567 |
| 514 GrGLInstalledProcessors::~GrGLInstalledProcessors() { | 568 GrGLInstalledProcessors::~GrGLInstalledProcessors() { |
| 515 int numEffects = fGLProcessors.count(); | 569 int numEffects = fGLProcessors.count(); |
| 516 for (int e = 0; e < numEffects; ++e) { | 570 for (int e = 0; e < numEffects; ++e) { |
| 517 SkDELETE(fGLProcessors[e]); | 571 SkDELETE(fGLProcessors[e]); |
| 518 } | 572 } |
| 519 } | 573 } |
| OLD | NEW |