Chromium Code Reviews| 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" | |
| 9 #include "gl/GrGLGeometryProcessor.h" | |
| 8 #include "gl/GrGLProgram.h" | 10 #include "gl/GrGLProgram.h" |
| 9 #include "gl/GrGLSLPrettyPrint.h" | 11 #include "gl/GrGLSLPrettyPrint.h" |
| 10 #include "gl/GrGLUniformHandle.h" | 12 #include "gl/GrGLUniformHandle.h" |
| 13 #include "../GrGpuGL.h" | |
| 11 #include "GrCoordTransform.h" | 14 #include "GrCoordTransform.h" |
| 12 #include "../GrGpuGL.h" | 15 #include "GrGLLegacyNvprProgramBuilder.h" |
| 13 #include "GrGLFragmentShaderBuilder.h" | 16 #include "GrGLNvprProgramBuilder.h" |
| 14 #include "GrGLProgramBuilder.h" | 17 #include "GrGLProgramBuilder.h" |
| 15 #include "GrTexture.h" | 18 #include "GrTexture.h" |
| 16 #include "GrGLVertexShaderBuilder.h" | |
| 17 #include "SkRTConf.h" | 19 #include "SkRTConf.h" |
| 18 #include "SkTraceEvent.h" | 20 #include "SkTraceEvent.h" |
| 19 | 21 |
| 20 namespace { | |
| 21 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) | 22 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) |
| 22 #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) |
| 23 | 24 |
| 24 // number of each input/output type in a single allocation block | |
| 25 static const int kVarsPerBlock = 8; | |
| 26 | |
| 27 // ES2 FS only guarantees mediump and lowp support | 25 // ES2 FS only guarantees mediump and lowp support |
| 28 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar: :kMedium_Precision; | 26 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar: :kMedium_Precision; |
| 29 } | |
| 30 | |
| 31 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
| 32 | |
| 33 bool GrGLProgramBuilder::genProgram(const GrGeometryStage* geometryProcessor, | |
| 34 const GrFragmentStage* colorStages[], | |
| 35 const GrFragmentStage* coverageStages[]) { | |
| 36 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); | |
| 37 | |
| 38 fFS.emitCodeBeforeEffects(); | |
| 39 | |
| 40 /////////////////////////////////////////////////////////////////////////// | |
| 41 // get the initial color and coverage to feed into the first effect in each effect chain | |
| 42 | |
| 43 GrGLSLExpr4 inputColor; | |
| 44 GrGLSLExpr4 inputCoverage; | |
| 45 | |
| 46 if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { | |
| 47 const char* name; | |
| 48 fUniformHandles.fColorUni = | |
| 49 this->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
| 50 kVec4f_GrSLType, | |
| 51 "Color", | |
| 52 &name); | |
| 53 inputColor = GrGLSLExpr4(name); | |
| 54 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) { | |
| 55 inputColor = GrGLSLExpr4(1); | |
| 56 } | |
| 57 | |
| 58 if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { | |
| 59 const char* name; | |
| 60 fUniformHandles.fCoverageUni = | |
| 61 this->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
| 62 kVec4f_GrSLType, | |
| 63 "Coverage", | |
| 64 &name); | |
| 65 inputCoverage = GrGLSLExpr4(name); | |
| 66 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) { | |
| 67 inputCoverage = GrGLSLExpr4(1); | |
| 68 } | |
| 69 | |
| 70 // Subclasses drive effect emitting | |
| 71 this->createAndEmitEffects(geometryProcessor, colorStages, coverageStages, & inputColor, | |
| 72 &inputCoverage); | |
| 73 | |
| 74 fFS.emitCodeAfterEffects(inputColor, inputCoverage); | |
| 75 | |
| 76 if (!this->finish()) { | |
| 77 return false; | |
| 78 } | |
| 79 | |
| 80 return true; | |
| 81 } | |
| 82 | 27 |
| 83 ////////////////////////////////////////////////////////////////////////////// | 28 ////////////////////////////////////////////////////////////////////////////// |
| 84 | 29 |
| 30 const int GrGLProgramBuilder::kVarsPerBlock = 8; | |
| 31 | |
| 32 GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrGLProgramDesc& desc, | |
| 33 GrGpu::DrawType drawType, | |
| 34 const GrGeometryStage* geometryPr ocessor, | |
| 35 const GrFragmentStage* colorStage s[], | |
| 36 const GrFragmentStage* coverageSt ages[], | |
| 37 GrGpuGL* gpu) { | |
| 38 // create a builder. This will be handed off to effects so they can use it to add | |
| 39 // uniforms, varyings, textures, etc | |
| 40 SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(desc, | |
| 41 drawType, | |
| 42 SkToBool(geom etryProcessor), | |
| 43 gpu)); | |
| 44 | |
| 45 GrGLProgramBuilder* pb = builder.get(); | |
| 46 const GrGLProgramDesc::KeyHeader& header = pb->header(); | |
| 47 | |
| 48 // emit code to read the dst copy texture, if necessary | |
| 49 if (GrGLFragmentShaderBuilder::kNoDstRead_DstReadKey != header.fDstReadKey | |
| 50 && !gpu->glCaps().fbFetchSupport()) { | |
| 51 pb->fFS.emitCodeToReadDstTexture(); | |
| 52 } | |
| 53 | |
| 54 // get the initial color and coverage to feed into the first effect in each effect chain | |
| 55 GrGLSLExpr4 inputColor, inputCoverage; | |
| 56 pb->setupUniformColorAndCoverageIfNeeded(&inputColor, &inputCoverage); | |
| 57 | |
| 58 // if we have a vertex shader(we don't only if we are using NVPR or NVPR ES) , then we may have | |
| 59 // to setup a few more things like builtin vertex attributes | |
| 60 bool hasVertexShader = !header.fUseFragShaderOnly; | |
| 61 if (hasVertexShader) { | |
| 62 pb->fVS.setupLocalCoords(); | |
| 63 pb->fVS.transformGLToSkiaCoords(); | |
| 64 if (header.fEmitsPointSize) { | |
| 65 pb->fVS.codeAppend("gl_PointSize = 1.0;"); | |
| 66 } | |
| 67 if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) { | |
| 68 pb->fVS.setupBuiltinVertexAttribute("Color", &inputColor); | |
| 69 } | |
| 70 if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) { | |
| 71 pb->fVS.setupBuiltinVertexAttribute("Coverage", &inputCoverage); | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 pb->createAndEmitProcessors(geometryProcessor, colorStages, coverageStages, &inputColor, | |
| 76 &inputCoverage); | |
| 77 | |
| 78 if (hasVertexShader) { | |
| 79 pb->fVS.transformSkiaToGLCoords(); | |
| 80 } | |
| 81 | |
| 82 // write the secondary color output if necessary | |
| 83 if (GrOptDrawState::kNone_SecondaryOutputType != header.fSecondaryOutputType ) { | |
| 84 pb->fFS.enableSecondaryOutput(inputColor, inputCoverage); | |
| 85 } | |
| 86 | |
| 87 pb->fFS.combineColorAndCoverage(inputColor, inputCoverage); | |
| 88 | |
| 89 return pb->compileBindLinkCreate(); | |
| 90 } | |
| 91 | |
| 92 GrGLProgramBuilder* | |
| 93 GrGLProgramBuilder::CreateProgramBuilder(const GrGLProgramDesc& desc, | |
| 94 GrGpu::DrawType drawType, | |
| 95 bool hasGeometryProcessor, | |
| 96 GrGpuGL* gpu) { | |
| 97 if (desc.getHeader().fUseFragShaderOnly) { | |
| 98 SkASSERT(gpu->glCaps().pathRenderingSupport()); | |
| 99 SkASSERT(gpu->glPathRendering()->texturingMode() == | |
| 100 GrGLPathRendering::FixedFunction_TexturingMode); | |
| 101 SkASSERT(!hasGeometryProcessor); | |
| 102 return SkNEW_ARGS(GrGLLegacyNvprProgramBuilder, (gpu, desc)); | |
| 103 } else if (GrGpu::IsPathRenderingDrawType(drawType)) { | |
| 104 SkASSERT(gpu->glCaps().pathRenderingSupport()); | |
| 105 SkASSERT(gpu->glPathRendering()->texturingMode() == | |
| 106 GrGLPathRendering::SeparableShaders_TexturingMode); | |
| 107 SkASSERT(!hasGeometryProcessor); | |
| 108 return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, desc)); | |
| 109 } else { | |
| 110 return SkNEW_ARGS(GrGLProgramBuilder, (gpu, desc)); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 ///////////////////////////////////////////////////////////////////////////// | |
| 115 | |
| 85 GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, | 116 GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, |
| 86 const GrGLProgramDesc& desc) | 117 const GrGLProgramDesc& desc) |
| 87 : fEffectEmitter(NULL) | 118 : fVS(this) |
| 88 , fFragOnly(SkToBool(desc.getHeader().fUseFragShaderOnly)) | 119 , fGS(this) |
| 89 , fTexCoordSetCnt(0) | |
| 90 , fProgramID(0) | |
| 91 , fFS(this, desc) | 120 , fFS(this, desc) |
| 92 , fSeparableVaryingInfos(kVarsPerBlock) | 121 , fOutOfStage(true) |
| 93 , fGrProcessorEmitter(this) | 122 , fStageIndex(-1) |
| 94 , fDesc(desc) | 123 , fDesc(desc) |
| 95 , fGpu(gpu) | 124 , fGpu(gpu) |
| 96 , fUniforms(kVarsPerBlock) { | 125 , fUniforms(kVarsPerBlock) { |
| 97 } | 126 } |
| 98 | 127 |
| 128 void GrGLProgramBuilder::addVarying(GrSLType type, | |
| 129 const char* name, | |
| 130 const char** vsOutName, | |
| 131 const char** fsInName, | |
| 132 GrGLShaderVar::Precision fsPrecision) { | |
| 133 SkString* fsInputName = fVS.addVarying(type, name, vsOutName); | |
| 134 fFS.addVarying(type, fsInputName->c_str(), fsInName, fsPrecision); | |
| 135 } | |
| 136 | |
| 99 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* na me) { | 137 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* na me) { |
| 100 if ('\0' == prefix) { | 138 if ('\0' == prefix) { |
| 101 *out = name; | 139 *out = name; |
| 102 } else { | 140 } else { |
| 103 out->printf("%c%s", prefix, name); | 141 out->printf("%c%s", prefix, name); |
| 104 } | 142 } |
| 105 if (fCodeStage.inStageCode()) { | 143 if (!fOutOfStage) { |
| 106 if (out->endsWith('_')) { | 144 if (out->endsWith('_')) { |
| 107 // Names containing "__" are reserved. | 145 // Names containing "__" are reserved. |
| 108 out->append("x"); | 146 out->append("x"); |
| 109 } | 147 } |
| 110 out->appendf("_Stage%d", fCodeStage.stageIndex()); | 148 out->appendf("_Stage%d", fStageIndex); |
| 111 } | 149 } |
| 112 } | 150 } |
| 113 | 151 |
| 114 GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32 _t visibility, | 152 GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32 _t visibility, |
| 115 GrSLTy pe type, | 153 GrSLTy pe type, |
| 116 const char* name, | 154 const char* name, |
| 117 int co unt, | 155 int co unt, |
| 118 const char** outName) { | 156 const char** outName) { |
| 119 SkASSERT(name && strlen(name)); | 157 SkASSERT(name && strlen(name)); |
| 120 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFr agment_Visibility); | 158 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFr agment_Visibility); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 135 // the fragment and vertex precisions must match | 173 // the fragment and vertex precisions must match |
| 136 uni.fVariable.setPrecision(kDefaultFragmentPrecision); | 174 uni.fVariable.setPrecision(kDefaultFragmentPrecision); |
| 137 } | 175 } |
| 138 | 176 |
| 139 if (outName) { | 177 if (outName) { |
| 140 *outName = uni.fVariable.c_str(); | 178 *outName = uni.fVariable.c_str(); |
| 141 } | 179 } |
| 142 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUnifor ms.count() - 1); | 180 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUnifor ms.count() - 1); |
| 143 } | 181 } |
| 144 | 182 |
| 145 void GrGLProgramBuilder::appendDecls(const VarArray& vars, SkString* out) const { | |
| 146 for (int i = 0; i < vars.count(); ++i) { | |
| 147 vars[i].appendDecl(this->ctxInfo(), out); | |
| 148 out->append(";\n"); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, | 183 void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, |
| 153 SkString* out) const { | 184 SkString* out) const { |
| 154 for (int i = 0; i < fUniforms.count(); ++i) { | 185 for (int i = 0; i < fUniforms.count(); ++i) { |
| 155 if (fUniforms[i].fVisibility & visibility) { | 186 if (fUniforms[i].fVisibility & visibility) { |
| 156 fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out); | 187 fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out); |
| 157 out->append(";\n"); | 188 out->append(";\n"); |
| 158 } | 189 } |
| 159 } | 190 } |
| 160 } | 191 } |
| 161 | 192 |
| 162 void GrGLProgramBuilder::createAndEmitEffects(const GrFragmentStage* effectStage s[], | 193 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const { |
| 163 int effectCnt, | 194 return fGpu->ctxInfo(); |
| 164 const GrGLProgramDesc::EffectKeyPr ovider& keyProvider, | 195 } |
| 165 GrGLSLExpr4* fsInOutColor) { | 196 |
| 197 void GrGLProgramBuilder::setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* input Color, | |
| 198 GrGLSLExpr4* input Coverage) { | |
| 199 const GrGLProgramDesc::KeyHeader& header = this->header(); | |
| 200 if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { | |
| 201 const char* name; | |
| 202 fUniformHandles.fColorUni = | |
| 203 this->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
| 204 kVec4f_GrSLType, | |
| 205 "Color", | |
| 206 &name); | |
| 207 *inputColor = GrGLSLExpr4(name); | |
| 208 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) { | |
| 209 *inputColor = GrGLSLExpr4(1); | |
| 210 } | |
| 211 if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { | |
| 212 const char* name; | |
| 213 fUniformHandles.fCoverageUni = | |
| 214 this->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
| 215 kVec4f_GrSLType, | |
| 216 "Coverage", | |
| 217 &name); | |
| 218 *inputCoverage = GrGLSLExpr4(name); | |
| 219 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) { | |
| 220 *inputCoverage = GrGLSLExpr4(1); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void GrGLProgramBuilder::createAndEmitProcessors(const GrGeometryStage* geometry Processor, | |
| 225 const GrFragmentStage* colorSta ges[], | |
| 226 const GrFragmentStage* coverage Stages[], | |
| 227 GrGLSLExpr4* inputColor, | |
| 228 GrGLSLExpr4* inputCoverage) { | |
| 229 bool useLocalCoords = fVS.hasExplicitLocalCoords(); | |
| 230 | |
| 231 EffectKeyProvider colorKeyProvider(&fDesc, EffectKeyProvider::kColor_EffectT ype); | |
| 232 int numColorEffects = fDesc.numColorEffects(); | |
| 233 GrGLInstalledProcessors* ip = SkNEW_ARGS(GrGLInstalledProcessors, (numColorE ffects, | |
| 234 useLocalC oords)); | |
| 235 this->createAndEmitProcessors<GrFragmentStage>(colorStages, numColorEffects, colorKeyProvider, | |
| 236 inputColor, ip); | |
| 237 fColorEffects.reset(ip); | |
| 238 | |
| 239 if (geometryProcessor) { | |
| 240 fVS.emitAttributes(*geometryProcessor->getProcessor()); | |
| 241 EffectKeyProvider gpKeyProvider(&fDesc, EffectKeyProvider::kGeometryProc essor_EffectType); | |
| 242 ip = SkNEW_ARGS(GrGLInstalledProcessors, (1, useLocalCoords)); | |
| 243 this->createAndEmitProcessors<GrGeometryStage>(&geometryProcessor, 1, gp KeyProvider, | |
| 244 inputCoverage, ip); | |
| 245 fGeometryProcessor.reset(ip); | |
| 246 } | |
| 247 | |
| 248 EffectKeyProvider coverageKeyProvider(&fDesc, EffectKeyProvider::kCoverage_E ffectType); | |
| 249 int numCoverageEffects = fDesc.numCoverageEffects(); | |
| 250 ip = SkNEW_ARGS(GrGLInstalledProcessors, (numCoverageEffects, useLocalCoords )); | |
| 251 this->createAndEmitProcessors<GrFragmentStage>(coverageStages, numCoverageEf fects, | |
| 252 coverageKeyProvider, inputCov erage, ip); | |
| 253 fCoverageEffects.reset(ip); | |
| 254 } | |
| 255 | |
| 256 template <class ProcessorStage> | |
| 257 void GrGLProgramBuilder::createAndEmitProcessors(const ProcessorStage* processSt ages[], | |
| 258 int effectCnt, | |
| 259 const EffectKeyProvider& keyPro vider, | |
| 260 GrGLSLExpr4* fsInOutColor, | |
| 261 GrGLInstalledProcessors* instal ledProcessors) { | |
| 166 bool effectEmitted = false; | 262 bool effectEmitted = false; |
| 167 | 263 |
| 168 GrGLSLExpr4 inColor = *fsInOutColor; | 264 GrGLSLExpr4 inColor = *fsInOutColor; |
| 169 GrGLSLExpr4 outColor; | 265 GrGLSLExpr4 outColor; |
| 170 | 266 |
| 171 for (int e = 0; e < effectCnt; ++e) { | 267 for (int e = 0; e < effectCnt; ++e) { |
| 172 fGrProcessorEmitter.set(effectStages[e]->getFragmentProcessor()); | 268 // Program builders have a bit of state we need to clear with each effec t |
| 173 fEffectEmitter = &fGrProcessorEmitter; | 269 this->reset(); |
| 174 // calls into the subclass to emit the actual effect into the program ef fect object | 270 const ProcessorStage& stage = *processStages[e]; |
| 175 this->emitEffect(*effectStages[e], e, keyProvider, &inColor, &outColor); | 271 SkASSERT(stage.getProcessor()); |
| 272 | |
| 273 if (inColor.isZeros()) { | |
| 274 SkString inColorName; | |
| 275 | |
| 276 // Effects have no way to communicate zeros, they treat an empty str ing as ones. | |
| 277 this->nameVariable(&inColorName, '\0', "input"); | |
| 278 fFS.codeAppendf("vec4 %s = %s;", inColorName.c_str(), inColor.c_str( )); | |
| 279 inColor = inColorName; | |
| 280 } | |
| 281 | |
| 282 // create var to hold stage result | |
| 283 SkString outColorName; | |
| 284 this->nameVariable(&outColorName, '\0', "output"); | |
| 285 fFS.codeAppendf("vec4 %s;", outColorName.c_str()); | |
| 286 outColor = outColorName; | |
| 287 | |
| 288 SkASSERT(installedProcessors); | |
| 289 const typename ProcessorStage::Processor& processor = *stage.getProcesso r(); | |
| 290 SkSTArray<2, GrGLProcessor::TransformedCoords> coords(processor.numTrans forms()); | |
| 291 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(processor.numTextur es()); | |
| 292 | |
| 293 this->emitTransforms(stage, &coords, installedProcessors); | |
| 294 this->emitSamplers(processor, &samplers, installedProcessors); | |
| 295 | |
| 296 typename ProcessorStage::GLProcessor* glEffect = | |
| 297 processor.getFactory().createGLInstance(processor); | |
| 298 installedProcessors->addEffect(glEffect); | |
| 299 | |
| 300 // Enclose custom code in a block to avoid namespace conflicts | |
| 301 SkString openBrace; | |
| 302 openBrace.printf("{ // Stage %d: %s\n", fStageIndex, glEffect->name()); | |
| 303 fFS.codeAppend(openBrace.c_str()); | |
| 304 | |
| 305 glEffect->emitCode(this, processor, keyProvider.get(e), outColor.c_str() , inColor.c_str(), | |
| 306 coords, samplers); | |
| 307 | |
| 308 // We have to check that effects and the code they emit are consistent, ie if an effect | |
| 309 // asks for dst color, then the emit code needs to follow suit | |
| 310 verify(processor); | |
| 311 fFS.codeAppend("}"); | |
| 312 | |
| 313 inColor = outColor; | |
| 176 effectEmitted = true; | 314 effectEmitted = true; |
| 177 } | 315 } |
| 178 | 316 |
| 179 if (effectEmitted) { | 317 if (effectEmitted) { |
| 180 *fsInOutColor = outColor; | 318 *fsInOutColor = outColor; |
| 181 } | 319 } |
| 182 } | 320 } |
| 183 | 321 |
| 184 void GrGLProgramBuilder::emitEffect(const GrProcessorStage& effectStage, | 322 void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) { |
| 185 int effectIndex, | 323 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); |
| 186 const GrGLProgramDesc::EffectKeyProvider& ke yProvider, | |
| 187 GrGLSLExpr4* inColor, | |
| 188 GrGLSLExpr4* outColor) { | |
| 189 SkASSERT(effectStage.getProcessor()); | |
| 190 CodeStage::AutoStageRestore csar(&fCodeStage, &effectStage); | |
| 191 | |
| 192 if (inColor->isZeros()) { | |
| 193 SkString inColorName; | |
| 194 | |
| 195 // Effects have no way to communicate zeros, they treat an empty string as ones. | |
| 196 this->nameVariable(&inColorName, '\0', "input"); | |
| 197 fFS.codeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor->c_str ()); | |
| 198 *inColor = inColorName; | |
| 199 } | |
| 200 | |
| 201 // create var to hold stage result | |
| 202 SkString outColorName; | |
| 203 this->nameVariable(&outColorName, '\0', "output"); | |
| 204 fFS.codeAppendf("\tvec4 %s;\n", outColorName.c_str()); | |
| 205 *outColor = outColorName; | |
| 206 | |
| 207 this->emitEffect(effectStage, keyProvider.get(effectIndex), outColor->c_str( ), | |
| 208 inColor->isOnes() ? NULL : inColor->c_str(), fCodeStage.sta geIndex()); | |
| 209 | |
| 210 *inColor = *outColor; | |
| 211 } | 324 } |
| 212 | 325 |
| 213 void GrGLProgramBuilder::emitSamplers(const GrProcessor& effect, | 326 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { |
| 214 GrGLProcessor::TextureSamplerArray* outSam plers) { | 327 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); |
| 215 SkTArray<GrGLProgramEffects::Sampler, true>& samplers = | 328 SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor()); |
| 216 this->getProgramEffects()->addSamplers(); | 329 } |
| 217 int numTextures = effect.numTextures(); | 330 |
| 331 void GrGLProgramBuilder::emitTransforms(const GrProcessorStage& effectStage, | |
| 332 GrGLProcessor::TransformedCoordsArray* o utCoords, | |
| 333 GrGLInstalledProcessors* installedProces sors) { | |
| 334 SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = | |
| 335 installedProcessors->addTransforms(); | |
| 336 const GrProcessor* effect = effectStage.getProcessor(); | |
| 337 int numTransforms = effect->numTransforms(); | |
| 338 transforms.push_back_n(numTransforms); | |
| 339 | |
| 340 for (int t = 0; t < numTransforms; t++) { | |
| 341 const char* uniName = "StageMatrix"; | |
| 342 GrSLType varyingType = | |
| 343 effectStage.isPerspectiveCoordTransform(t, fVS.hasExplicitLocalC oords()) ? | |
| 344 kVec3f_GrSLType : | |
| 345 kVec2f_GrSLType; | |
| 346 | |
| 347 SkString suffixedUniName; | |
| 348 if (0 != t) { | |
| 349 suffixedUniName.append(uniName); | |
| 350 suffixedUniName.appendf("_%i", t); | |
| 351 uniName = suffixedUniName.c_str(); | |
| 352 } | |
| 353 transforms[t].fHandle = this->addUniform(GrGLProgramBuilder::kVertex_Vis ibility, | |
| 354 kMat33f_GrSLType, | |
| 355 uniName, | |
| 356 &uniName).toShaderBuilderIndex( ); | |
| 357 | |
| 358 const char* varyingName = "MatrixCoord"; | |
| 359 SkString suffixedVaryingName; | |
| 360 if (0 != t) { | |
| 361 suffixedVaryingName.append(varyingName); | |
| 362 suffixedVaryingName.appendf("_%i", t); | |
| 363 varyingName = suffixedVaryingName.c_str(); | |
| 364 } | |
| 365 const char* vsVaryingName; | |
| 366 const char* fsVaryingName; | |
| 367 this->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingNam e); | |
| 368 | |
| 369 const GrGLShaderVar& coords = | |
| 370 kPosition_GrCoordSet == effect->coordTransform(t).sourceCoords() ? | |
| 371 fVS.positionAttribute() : | |
| 372 fVS.localCoordsAttribute(); | |
| 373 | |
| 374 // varying = matrix * coords (logically) | |
| 375 SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingTyp e); | |
| 376 if (kVec2f_GrSLType == varyingType) { | |
| 377 fVS.codeAppendf("%s = (%s * vec3(%s, 1)).xy;", | |
| 378 vsVaryingName, uniName, coords.c_str()); | |
| 379 } else { | |
| 380 fVS.codeAppendf("%s = %s * vec3(%s, 1);", | |
| 381 vsVaryingName, uniName, coords.c_str()); | |
| 382 } | |
| 383 SkNEW_APPEND_TO_TARRAY(outCoords, GrGLProcessor::TransformedCoords, | |
| 384 (SkString(fsVaryingName), varyingType)); | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, | |
| 389 GrGLProcessor::TextureSamplerArray* outSam plers, | |
| 390 GrGLInstalledProcessors* installedProcesso rs) { | |
| 391 SkTArray<GrGLInstalledProcessors::Sampler, true>& samplers = installedProces sors->addSamplers(); | |
| 392 int numTextures = processor.numTextures(); | |
| 218 samplers.push_back_n(numTextures); | 393 samplers.push_back_n(numTextures); |
| 219 SkString name; | 394 SkString name; |
| 220 for (int t = 0; t < numTextures; ++t) { | 395 for (int t = 0; t < numTextures; ++t) { |
| 221 name.printf("Sampler%d", t); | 396 name.printf("Sampler%d", t); |
| 222 samplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Vi sibility, | 397 samplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Vi sibility, |
| 223 kSampler2D_GrSLType, | 398 kSampler2D_GrSLType, |
| 224 name.c_str()); | 399 name.c_str()); |
| 225 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler, | 400 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler, |
| 226 (samplers[t].fUniform, effect.textureAccess(t))); | 401 (samplers[t].fUniform, processor.textureAccess(t) )); |
| 227 } | 402 } |
| 228 } | 403 } |
| 229 | 404 |
| 230 bool GrGLProgramBuilder::finish() { | 405 GrGLProgram* GrGLProgramBuilder::compileBindLinkCreate() { |
|
bsalomon
2014/10/06 18:49:40
finalize()?
| |
| 231 SkASSERT(0 == fProgramID); | 406 // verify we can get a program id |
| 232 GL_CALL_RET(fProgramID, CreateProgram()); | 407 GrGLuint programID; |
| 233 if (!fProgramID) { | 408 GL_CALL_RET(programID, CreateProgram()); |
| 234 return false; | 409 if (0 == programID) { |
| 410 return NULL; | |
| 235 } | 411 } |
| 236 | 412 |
| 413 // compile shaders and bind attributes / uniforms | |
| 237 SkTDArray<GrGLuint> shadersToDelete; | 414 SkTDArray<GrGLuint> shadersToDelete; |
| 238 | 415 if (!fFS.compileAndAttachShaders(programID, &shadersToDelete)) { |
| 239 if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) { | 416 this->cleanupProgram(programID, shadersToDelete); |
| 240 GL_CALL(DeleteProgram(fProgramID)); | 417 return NULL; |
| 241 return false; | |
| 242 } | 418 } |
| 243 | 419 if (!this->header().fUseFragShaderOnly) { |
| 244 this->bindProgramLocations(fProgramID); | 420 if (!fVS.compileAndAttachShaders(programID, &shadersToDelete)) { |
| 245 | 421 this->cleanupProgram(programID, shadersToDelete); |
| 246 GL_CALL(LinkProgram(fProgramID)); | 422 return NULL; |
| 423 } | |
| 424 fVS.bindVertexAttributes(programID); | |
| 425 } | |
| 426 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL; | |
| 427 if (usingBindUniform) { | |
| 428 this->bindUniformLocations(programID); | |
| 429 } | |
| 430 fFS.bindFragmentShaderLocations(programID); | |
| 431 GL_CALL(LinkProgram(programID)); | |
| 247 | 432 |
| 248 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. | 433 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. |
| 249 bool checkLinked = !fGpu->ctxInfo().isChromium(); | 434 bool checkLinked = !fGpu->ctxInfo().isChromium(); |
| 250 #ifdef SK_DEBUG | 435 #ifdef SK_DEBUG |
| 251 checkLinked = true; | 436 checkLinked = true; |
| 252 #endif | 437 #endif |
| 253 if (checkLinked) { | 438 if (checkLinked) { |
| 254 GrGLint linked = GR_GL_INIT_ZERO; | 439 checkLinkStatus(programID); |
| 255 GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked)); | 440 } |
| 256 if (!linked) { | 441 if (!usingBindUniform) { |
| 257 GrGLint infoLen = GR_GL_INIT_ZERO; | 442 this->resolveUniformLocations(programID); |
| 258 GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen)); | |
| 259 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debug ger | |
| 260 if (infoLen > 0) { | |
| 261 // retrieve length even though we don't need it to workaround | |
| 262 // bug in chrome cmd buffer param validation. | |
| 263 GrGLsizei length = GR_GL_INIT_ZERO; | |
| 264 GL_CALL(GetProgramInfoLog(fProgramID, | |
| 265 infoLen+1, | |
| 266 &length, | |
| 267 (char*)log.get())); | |
| 268 GrPrintf((char*)log.get()); | |
| 269 } | |
| 270 SkDEBUGFAIL("Error linking program"); | |
| 271 GL_CALL(DeleteProgram(fProgramID)); | |
| 272 fProgramID = 0; | |
| 273 return false; | |
| 274 } | |
| 275 } | 443 } |
| 276 | 444 |
| 277 this->resolveProgramLocations(fProgramID); | 445 this->cleanupShaders(shadersToDelete); |
| 278 | 446 |
| 279 for (int i = 0; i < shadersToDelete.count(); ++i) { | 447 return this->createProgram(programID); |
| 280 GL_CALL(DeleteShader(shadersToDelete[i])); | |
| 281 } | |
| 282 | |
| 283 return true; | |
| 284 } | 448 } |
| 285 | 449 |
| 286 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId, | 450 void GrGLProgramBuilder::bindUniformLocations(GrGLuint programID) { |
| 287 SkTDArray<GrGLuint>* shaderIds) const { | 451 int count = fUniforms.count(); |
| 288 return fFS.compileAndAttachShaders(programId, shaderIds); | 452 for (int i = 0; i < count; ++i) { |
| 289 } | 453 GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str() )); |
| 290 | 454 fUniforms[i].fLocation = i; |
| 291 void GrGLProgramBuilder::bindProgramLocations(GrGLuint programId) { | |
| 292 fFS.bindProgramLocations(programId); | |
| 293 | |
| 294 // skbug.com/2056 | |
| 295 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL; | |
| 296 if (usingBindUniform) { | |
| 297 int count = fUniforms.count(); | |
| 298 for (int i = 0; i < count; ++i) { | |
| 299 GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_s tr())); | |
| 300 fUniforms[i].fLocation = i; | |
| 301 } | |
| 302 } | 455 } |
| 303 } | 456 } |
| 304 | 457 |
| 305 void GrGLProgramBuilder::resolveProgramLocations(GrGLuint programId) { | 458 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) { |
| 306 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL; | 459 GrGLint linked = GR_GL_INIT_ZERO; |
| 307 if (!usingBindUniform) { | 460 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked)); |
| 308 int count = fUniforms.count(); | 461 if (!linked) { |
| 309 for (int i = 0; i < count; ++i) { | 462 GrGLint infoLen = GR_GL_INIT_ZERO; |
| 310 GrGLint location; | 463 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen)); |
| 311 GL_CALL_RET(location, | 464 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger |
| 312 GetUniformLocation(programId, fUniforms[i].fVariable.c_s tr())); | 465 if (infoLen > 0) { |
| 313 fUniforms[i].fLocation = location; | 466 // retrieve length even though we don't need it to workaround |
| 467 // bug in chrome cmd buffer param validation. | |
| 468 GrGLsizei length = GR_GL_INIT_ZERO; | |
| 469 GL_CALL(GetProgramInfoLog(programID, | |
| 470 infoLen+1, | |
| 471 &length, | |
| 472 (char*)log.get())); | |
| 473 GrPrintf((char*)log.get()); | |
| 314 } | 474 } |
| 475 SkDEBUGFAIL("Error linking program"); | |
| 476 GL_CALL(DeleteProgram(programID)); | |
| 477 programID = 0; | |
| 315 } | 478 } |
| 479 return SkToBool(linked); | |
| 480 } | |
| 316 | 481 |
| 317 int count = fSeparableVaryingInfos.count(); | 482 void GrGLProgramBuilder::resolveUniformLocations(GrGLuint programID) { |
| 483 int count = fUniforms.count(); | |
| 318 for (int i = 0; i < count; ++i) { | 484 for (int i = 0; i < count; ++i) { |
| 319 GrGLint location; | 485 GrGLint location; |
| 320 GL_CALL_RET(location, | 486 GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariab le.c_str())); |
| 321 GetProgramResourceLocation(programId, | 487 fUniforms[i].fLocation = location; |
| 322 GR_GL_FRAGMENT_INPUT, | |
| 323 fSeparableVaryingInfos[i].fVariab le.c_str())); | |
| 324 fSeparableVaryingInfos[i].fLocation = location; | |
| 325 } | 488 } |
| 326 } | 489 } |
| 327 | 490 |
| 328 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const { | 491 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGL uint>& shaderIDs) { |
| 329 return fGpu->ctxInfo(); | 492 GL_CALL(DeleteProgram(programID)); |
| 493 cleanupShaders(shaderIDs); | |
| 330 } | 494 } |
| 495 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { | |
| 496 for (int i = 0; i < shaderIDs.count(); ++i) { | |
| 497 GL_CALL(DeleteShader(shaderIDs[i])); | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { | |
| 502 return SkNEW_ARGS(GrGLProgram, (fGpu, fDesc, fUniformHandles, programID, fUn iforms, | |
| 503 fGeometryProcessor, fColorEffects, fCoverage Effects)); | |
| 504 } | |
| 505 | |
| 506 //////////////////////////////////////////////////////////////////////////////// | |
| 507 | |
| 508 GrGLInstalledProcessors::~GrGLInstalledProcessors() { | |
| 509 int numEffects = fGLProcessors.count(); | |
| 510 for (int e = 0; e < numEffects; ++e) { | |
| 511 SkDELETE(fGLProcessors[e]); | |
| 512 } | |
| 513 } | |
| OLD | NEW |