| 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 | 9 |
| 10 #include "GrAutoLocaleSetter.h" | 10 #include "GrAutoLocaleSetter.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 // uniforms, varyings, textures, etc | 35 // uniforms, varyings, textures, etc |
| 36 SkAutoTDelete<GrGLProgramBuilder> builder(new GrGLProgramBuilder(gpu, args))
; | 36 SkAutoTDelete<GrGLProgramBuilder> builder(new GrGLProgramBuilder(gpu, args))
; |
| 37 | 37 |
| 38 GrGLProgramBuilder* pb = builder.get(); | 38 GrGLProgramBuilder* pb = builder.get(); |
| 39 | 39 |
| 40 // TODO: Once all stages can handle taking a float or vec4 and correctly han
dling them we can | 40 // TODO: Once all stages can handle taking a float or vec4 and correctly han
dling them we can |
| 41 // seed correctly here | 41 // seed correctly here |
| 42 GrGLSLExpr4 inputColor; | 42 GrGLSLExpr4 inputColor; |
| 43 GrGLSLExpr4 inputCoverage; | 43 GrGLSLExpr4 inputCoverage; |
| 44 | 44 |
| 45 if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) { | 45 if (!pb->emitAndInstallProcs(&inputColor, |
| 46 &inputCoverage, |
| 47 gpu->glCaps().maxFragmentTextureUnits())) { |
| 48 pb->cleanupFragmentProcessors(); |
| 46 return nullptr; | 49 return nullptr; |
| 47 } | 50 } |
| 48 | 51 |
| 49 return pb->finalize(); | 52 return pb->finalize(); |
| 50 } | 53 } |
| 51 | 54 |
| 52 ///////////////////////////////////////////////////////////////////////////// | 55 ///////////////////////////////////////////////////////////////////////////// |
| 53 | 56 |
| 54 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args) | 57 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args) |
| 55 : INHERITED(args) | 58 : INHERITED(args) |
| 56 , fGeometryProcessor(nullptr) | |
| 57 , fXferProcessor(nullptr) | |
| 58 , fGpu(gpu) | 59 , fGpu(gpu) |
| 59 , fSamplerUniforms(4) | 60 , fSamplerUniforms(4) |
| 60 , fVaryingHandler(this) | 61 , fVaryingHandler(this) |
| 61 , fUniformHandler(this) { | 62 , fUniformHandler(this) { |
| 62 } | 63 } |
| 63 | 64 |
| 64 const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { | 65 const GrCaps* GrGLProgramBuilder::caps() const { |
| 65 return this->fGpu->ctxInfo().caps()->glslCaps(); | 66 return fGpu->caps(); |
| 66 } | 67 } |
| 67 | 68 |
| 68 bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr
4* inputCoverage) { | 69 const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { |
| 69 // First we loop over all of the installed processors and collect coord tran
sforms. These will | 70 return fGpu->ctxInfo().caps()->glslCaps(); |
| 70 // be sent to the GrGLSLPrimitiveProcessor in its emitCode function | |
| 71 const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); | |
| 72 int totalTextures = primProc.numTextures(); | |
| 73 const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits(); | |
| 74 | |
| 75 for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) { | |
| 76 const GrFragmentProcessor& processor = this->pipeline().getFragmentProce
ssor(i); | |
| 77 | |
| 78 if (!primProc.hasTransformedLocalCoords()) { | |
| 79 SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransfor
ms.push_back(); | |
| 80 processor.gatherCoordTransforms(&procCoords); | |
| 81 } | |
| 82 | |
| 83 totalTextures += processor.numTextures(); | |
| 84 if (totalTextures >= maxTextureUnits) { | |
| 85 GrCapsDebugf(fGpu->caps(), "Program would use too many texture units
\n"); | |
| 86 return false; | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 this->emitAndInstallProc(primProc, inputColor, inputCoverage); | |
| 91 | |
| 92 fFragmentProcessors.reset(new GrGLInstalledFragProcs); | |
| 93 int numProcs = this->pipeline().numFragmentProcessors(); | |
| 94 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors
(), inputColor); | |
| 95 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(),
numProcs, | |
| 96 inputCoverage); | |
| 97 this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColo
r, *inputCoverage, | |
| 98 this->pipeline().ignoresCoverage()); | |
| 99 this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOu
tput()); | |
| 100 return true; | |
| 101 } | |
| 102 | |
| 103 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset, | |
| 104 int numProcs, | |
| 105 GrGLSLExpr4* inOut) { | |
| 106 for (int i = procOffset; i < numProcs; ++i) { | |
| 107 GrGLSLExpr4 output; | |
| 108 const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i)
; | |
| 109 this->emitAndInstallProc(fp, i, *inOut, &output); | |
| 110 *inOut = output; | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseNam
e) { | |
| 115 // create var to hold stage result. If we already have a valid output name,
just use that | |
| 116 // otherwise create a new mangled one. This name is only valid if we are re
ordering stages | |
| 117 // and have to tell stage exactly where to put its output. | |
| 118 SkString outName; | |
| 119 if (output->isValid()) { | |
| 120 outName = output->c_str(); | |
| 121 } else { | |
| 122 this->nameVariable(&outName, '\0', baseName); | |
| 123 } | |
| 124 fFS.codeAppendf("vec4 %s;", outName.c_str()); | |
| 125 *output = outName; | |
| 126 } | |
| 127 | |
| 128 // TODO Processors cannot output zeros because an empty string is all 1s | |
| 129 // the fix is to allow effects to take the GrGLSLExpr4 directly | |
| 130 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, | |
| 131 int index, | |
| 132 const GrGLSLExpr4& input, | |
| 133 GrGLSLExpr4* output) { | |
| 134 // Program builders have a bit of state we need to clear with each effect | |
| 135 AutoStageAdvance adv(this); | |
| 136 this->nameExpression(output, "output"); | |
| 137 | |
| 138 // Enclose custom code in a block to avoid namespace conflicts | |
| 139 SkString openBrace; | |
| 140 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); | |
| 141 fFS.codeAppend(openBrace.c_str()); | |
| 142 | |
| 143 this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullpt
r : input.c_str()); | |
| 144 | |
| 145 fFS.codeAppend("}"); | |
| 146 } | |
| 147 | |
| 148 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc, | |
| 149 GrGLSLExpr4* outputColor, | |
| 150 GrGLSLExpr4* outputCoverage) { | |
| 151 // Program builders have a bit of state we need to clear with each effect | |
| 152 AutoStageAdvance adv(this); | |
| 153 this->nameExpression(outputColor, "outputColor"); | |
| 154 this->nameExpression(outputCoverage, "outputCoverage"); | |
| 155 | |
| 156 // Enclose custom code in a block to avoid namespace conflicts | |
| 157 SkString openBrace; | |
| 158 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); | |
| 159 fFS.codeAppend(openBrace.c_str()); | |
| 160 fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); | |
| 161 | |
| 162 this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str()
); | |
| 163 | |
| 164 fFS.codeAppend("}"); | |
| 165 } | |
| 166 | |
| 167 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, | |
| 168 int index, | |
| 169 const char* outColor, | |
| 170 const char* inColor) { | |
| 171 GrGLInstalledFragProc* ifp = new GrGLInstalledFragProc; | |
| 172 | |
| 173 ifp->fGLProc.reset(fp.createGLSLInstance()); | |
| 174 | |
| 175 SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures()); | |
| 176 this->emitSamplers(fp, &samplers, ifp); | |
| 177 | |
| 178 GrGLSLFragmentProcessor::EmitArgs args(&fFS, | |
| 179 &fUniformHandler, | |
| 180 this->glslCaps(), | |
| 181 fp, | |
| 182 outColor, | |
| 183 inColor, | |
| 184 fOutCoords[index], | |
| 185 samplers); | |
| 186 ifp->fGLProc->emitCode(args); | |
| 187 | |
| 188 // We have to check that effects and the code they emit are consistent, ie i
f an effect | |
| 189 // asks for dst color, then the emit code needs to follow suit | |
| 190 verify(fp); | |
| 191 fFragmentProcessors->fProcs.push_back(ifp); | |
| 192 } | |
| 193 | |
| 194 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp, | |
| 195 const char* outColor, | |
| 196 const char* outCoverage) { | |
| 197 SkASSERT(!fGeometryProcessor); | |
| 198 fGeometryProcessor = new GrGLInstalledGeoProc; | |
| 199 | |
| 200 fGeometryProcessor->fGLProc.reset(gp.createGLSLInstance(*fGpu->glCaps().glsl
Caps())); | |
| 201 | |
| 202 SkSTArray<4, GrGLSLTextureSampler> samplers(gp.numTextures()); | |
| 203 this->emitSamplers(gp, &samplers, fGeometryProcessor); | |
| 204 | |
| 205 GrGLSLGeometryProcessor::EmitArgs args(&fVS, | |
| 206 &fFS, | |
| 207 &fVaryingHandler, | |
| 208 &fUniformHandler, | |
| 209 this->glslCaps(), | |
| 210 gp, | |
| 211 outColor, | |
| 212 outCoverage, | |
| 213 samplers, | |
| 214 fCoordTransforms, | |
| 215 &fOutCoords); | |
| 216 fGeometryProcessor->fGLProc->emitCode(args); | |
| 217 | |
| 218 // We have to check that effects and the code they emit are consistent, ie i
f an effect | |
| 219 // asks for dst color, then the emit code needs to follow suit | |
| 220 verify(gp); | |
| 221 } | |
| 222 | |
| 223 void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, | |
| 224 const GrGLSLExpr4& colorIn, | |
| 225 const GrGLSLExpr4& coverageIn, | |
| 226 bool ignoresCoverage) { | |
| 227 // Program builders have a bit of state we need to clear with each effect | |
| 228 AutoStageAdvance adv(this); | |
| 229 | |
| 230 SkASSERT(!fXferProcessor); | |
| 231 fXferProcessor = new GrGLInstalledXferProc; | |
| 232 | |
| 233 fXferProcessor->fGLProc.reset(xp.createGLSLInstance()); | |
| 234 | |
| 235 // Enable dual source secondary output if we have one | |
| 236 if (xp.hasSecondaryOutput()) { | |
| 237 fFS.enableSecondaryOutput(); | |
| 238 } | |
| 239 | |
| 240 if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { | |
| 241 fFS.enableCustomOutput(); | |
| 242 } | |
| 243 | |
| 244 SkString openBrace; | |
| 245 openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); | |
| 246 fFS.codeAppend(openBrace.c_str()); | |
| 247 | |
| 248 SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); | |
| 249 this->emitSamplers(xp, &samplers, fXferProcessor); | |
| 250 | |
| 251 GrGLSLXferProcessor::EmitArgs args(&fFS, | |
| 252 &fUniformHandler, | |
| 253 this->glslCaps(), | |
| 254 xp, colorIn.c_str(), | |
| 255 ignoresCoverage ? nullptr : coverageIn.c_
str(), | |
| 256 fFS.getPrimaryColorOutputName(), | |
| 257 fFS.getSecondaryColorOutputName(), | |
| 258 samplers); | |
| 259 fXferProcessor->fGLProc->emitCode(args); | |
| 260 | |
| 261 // We have to check that effects and the code they emit are consistent, ie i
f an effect | |
| 262 // asks for dst color, then the emit code needs to follow suit | |
| 263 verify(xp); | |
| 264 fFS.codeAppend("}"); | |
| 265 } | |
| 266 | |
| 267 void GrGLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { | |
| 268 // Swizzle the fragment shader outputs if necessary. | |
| 269 GrSwizzle swizzle; | |
| 270 swizzle.setFromKey(this->desc().header().fOutputSwizzle); | |
| 271 if (swizzle != GrSwizzle::RGBA()) { | |
| 272 fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(), | |
| 273 fFS.getPrimaryColorOutputName(), | |
| 274 swizzle.c_str()); | |
| 275 if (hasSecondaryOutput) { | |
| 276 fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(), | |
| 277 fFS.getSecondaryColorOutputName(), | |
| 278 swizzle.c_str()); | |
| 279 } | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { | |
| 284 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); | |
| 285 } | |
| 286 | |
| 287 void GrGLProgramBuilder::verify(const GrXferProcessor& xp) { | |
| 288 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); | |
| 289 } | |
| 290 | |
| 291 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { | |
| 292 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); | |
| 293 } | 71 } |
| 294 | 72 |
| 295 static GrSLType get_sampler_type(const GrTextureAccess& access) { | 73 static GrSLType get_sampler_type(const GrTextureAccess& access) { |
| 296 GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture()); | 74 GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture()); |
| 297 if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) { | 75 if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) { |
| 298 return kSamplerExternal_GrSLType; | 76 return kSamplerExternal_GrSLType; |
| 299 } else { | 77 } else { |
| 300 SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D); | 78 SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D); |
| 301 return kSampler2D_GrSLType; | 79 return kSampler2D_GrSLType; |
| 302 } | 80 } |
| 303 } | 81 } |
| 304 | 82 |
| 305 template <class Proc> | |
| 306 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, | 83 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, |
| 307 GrGLSLTextureSampler::TextureSamplerArray*
outSamplers, | 84 GrGLSLTextureSampler::TextureSamplerArray*
outSamplers) { |
| 308 GrGLInstalledProc<Proc>* ip) { | |
| 309 SkDEBUGCODE(ip->fSamplersIdx = fSamplerUniforms.count();) | |
| 310 int numTextures = processor.numTextures(); | 85 int numTextures = processor.numTextures(); |
| 311 UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextur
es); | 86 UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextur
es); |
| 312 SkString name; | 87 SkString name; |
| 313 for (int t = 0; t < numTextures; ++t) { | 88 for (int t = 0; t < numTextures; ++t) { |
| 314 name.printf("Sampler%d", t); | 89 name.printf("Sampler%d", t); |
| 315 GrSLType samplerType = get_sampler_type(processor.textureAccess(t)); | 90 GrSLType samplerType = get_sampler_type(processor.textureAccess(t)); |
| 316 localSamplerUniforms[t] = | 91 localSamplerUniforms[t] = |
| 317 fUniformHandler.addUniform(GrGLSLUniformHandler::kFragment_Visibilit
y, | 92 fUniformHandler.addUniform(GrGLSLUniformHandler::kFragment_Visibilit
y, |
| 318 samplerType, kDefault_GrSLPrecision, | 93 samplerType, kDefault_GrSLPrecision, |
| 319 name.c_str()); | 94 name.c_str()); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 349 *shaderIds->append() = shaderId; | 124 *shaderIds->append() = shaderId; |
| 350 | 125 |
| 351 return true; | 126 return true; |
| 352 } | 127 } |
| 353 | 128 |
| 354 GrGLProgram* GrGLProgramBuilder::finalize() { | 129 GrGLProgram* GrGLProgramBuilder::finalize() { |
| 355 // verify we can get a program id | 130 // verify we can get a program id |
| 356 GrGLuint programID; | 131 GrGLuint programID; |
| 357 GL_CALL_RET(programID, CreateProgram()); | 132 GL_CALL_RET(programID, CreateProgram()); |
| 358 if (0 == programID) { | 133 if (0 == programID) { |
| 134 this->cleanupFragmentProcessors(); |
| 359 return nullptr; | 135 return nullptr; |
| 360 } | 136 } |
| 361 | 137 |
| 362 // compile shaders and bind attributes / uniforms | 138 // compile shaders and bind attributes / uniforms |
| 363 SkTDArray<GrGLuint> shadersToDelete; | 139 SkTDArray<GrGLuint> shadersToDelete; |
| 364 fVS.finalize(GrGLSLUniformHandler::kVertex_Visibility); | 140 fVS.finalize(GrGLSLUniformHandler::kVertex_Visibility); |
| 365 if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &sha
dersToDelete)) { | 141 if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &sha
dersToDelete)) { |
| 366 this->cleanupProgram(programID, shadersToDelete); | 142 this->cleanupProgram(programID, shadersToDelete); |
| 367 return nullptr; | 143 return nullptr; |
| 368 } | 144 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 GL_CALL_RET(location, GetProgramResourceLocation( | 243 GL_CALL_RET(location, GetProgramResourceLocation( |
| 468 programID, | 244 programID, |
| 469 GR_GL_FRAGMENT_INPUT, | 245 GR_GL_FRAGMENT_INPUT, |
| 470 fVaryingHandler.fPathProcVaryingInfos[i].
fVariable.c_str())); | 246 fVaryingHandler.fPathProcVaryingInfos[i].
fVariable.c_str())); |
| 471 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location; | 247 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location; |
| 472 } | 248 } |
| 473 } | 249 } |
| 474 | 250 |
| 475 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGL
uint>& shaderIDs) { | 251 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGL
uint>& shaderIDs) { |
| 476 GL_CALL(DeleteProgram(programID)); | 252 GL_CALL(DeleteProgram(programID)); |
| 477 cleanupShaders(shaderIDs); | 253 this->cleanupShaders(shaderIDs); |
| 254 this->cleanupFragmentProcessors(); |
| 478 } | 255 } |
| 479 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { | 256 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { |
| 480 for (int i = 0; i < shaderIDs.count(); ++i) { | 257 for (int i = 0; i < shaderIDs.count(); ++i) { |
| 481 GL_CALL(DeleteShader(shaderIDs[i])); | 258 GL_CALL(DeleteShader(shaderIDs[i])); |
| 482 } | 259 } |
| 483 } | 260 } |
| 484 | 261 |
| 485 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { | 262 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { |
| 486 return new GrGLProgram(fGpu, | 263 return new GrGLProgram(fGpu, |
| 487 this->desc(), | 264 this->desc(), |
| 488 fUniformHandles, | 265 fUniformHandles, |
| 489 programID, | 266 programID, |
| 490 fUniformHandler.fUniforms, | 267 fUniformHandler.fUniforms, |
| 491 fVaryingHandler.fPathProcVaryingInfos, | 268 fVaryingHandler.fPathProcVaryingInfos, |
| 492 fGeometryProcessor, | 269 fGeometryProcessor, |
| 493 fXferProcessor, | 270 fXferProcessor, |
| 494 fFragmentProcessors.get(), | 271 fFragmentProcessors, |
| 495 &fSamplerUniforms); | 272 &fSamplerUniforms); |
| 496 } | 273 } |
| 497 | 274 |
| 498 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
| 499 | |
| 500 GrGLInstalledFragProcs::~GrGLInstalledFragProcs() { | |
| 501 int numProcs = fProcs.count(); | |
| 502 for (int i = 0; i < numProcs; ++i) { | |
| 503 delete fProcs[i]; | |
| 504 } | |
| 505 } | |
| OLD | NEW |