void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder, const GrEffectStage* effectStages[], int effectCnt, const GrGLProgramDesc::EffectKeyProvider& keyProvider, GrGLSLExpr4* fsInOutColor) { bool effectEmitted = false; GrGLSLExpr4 inColor = *fsInOutColor; GrGLSLExpr4 outColor; for (int e = 0; e < effectCnt; ++e) { SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect()); const GrEffectStage& stage = *effectStages[e]; CodeStage::AutoStageRestore csar(&fCodeStage, &stage); if (inColor.isZeros()) { SkString inColorName; // Effects have no way to communicate zeros, they treat an empty string as ones. this->nameVariable(&inColorName, '\0', "input"); this->fsCodeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor.c_str()); inColor = inColorName; } // create var to hold stage result SkString outColorName; this->nameVariable(&outColorName, '\0', "output"); this->fsCodeAppendf("\tvec4 %s;\n", outColorName.c_str()); outColor = outColorName; programEffectsBuilder->emitEffect(stage, keyProvider.get(e), outColor.c_str(), inColor.isOnes() ? NULL : inColor.c_str(), fCodeStage.stageIndex()); inColor = outColor; effectEmitted = true; } if (effectEmitted) { *fsInOutColor = outColor; } }
void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, const GrGLSLExpr4& colorIn, const GrGLSLExpr4& coverageIn) { // Program builders have a bit of state we need to clear with each effect AutoStageAdvance adv(this); SkASSERT(!fXferProcessor); fXferProcessor = new GrGLInstalledXferProc; fXferProcessor->fGLProc.reset(xp.createGLSLInstance()); // Enable dual source secondary output if we have one if (xp.hasSecondaryOutput()) { fFS.enableSecondaryOutput(); } if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { fFS.enableCustomOutput(); } SkString openBrace; openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); fFS.codeAppend(openBrace.c_str()); SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); this->emitSamplers(xp, &samplers, fXferProcessor); GrGLSLXferProcessor::EmitArgs args(this, &fFS, this->glslCaps(), xp, colorIn.c_str(), coverageIn.c_str(), fFS.getPrimaryColorOutputName(), fFS.getSecondaryColorOutputName(), samplers); fXferProcessor->fGLProc->emitCode(args); // We have to check that effects and the code they emit are consistent, ie if an effect // asks for dst color, then the emit code needs to follow suit verify(xp); fFS.codeAppend("}"); }
// TODO Processors cannot output zeros because an empty string is all 1s // the fix is to allow effects to take the GrGLSLExpr4 directly void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, int index, const GrGLSLExpr4& input, GrGLSLExpr4* output) { // Program builders have a bit of state we need to clear with each effect AutoStageAdvance adv(this); this->nameExpression(output, "output"); // Enclose custom code in a block to avoid namespace conflicts SkString openBrace; openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); fFS.codeAppend(openBrace.c_str()); this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullptr : input.c_str()); fFS.codeAppend("}"); }
virtual void emitCode(EmitArgs& args) override { SkXfermode::Mode mode = args.fFp.cast<ModeColorFilterEffect>().mode(); SkASSERT(SkXfermode::kDst_Mode != mode); const char* colorFilterColorUniName = nullptr; if (args.fFp.cast<ModeColorFilterEffect>().willUseFilterColor()) { fFilterColorUni = args.fBuilder->addUniform( GrGLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "FilterColor", &colorFilterColorUniName); } GrGLSLExpr4 filter = color_filter_expression(mode, GrGLSLExpr4(colorFilterColorUniName), GrGLSLExpr4(args.fInputColor)); args.fBuilder->getFragmentShaderBuilder()-> codeAppendf("\t%s = %s;\n", args.fOutputColor, filter.c_str()); }
virtual void emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor& fp, const char* outputColor, const char* inputColor, const TransformedCoordsArray&, const TextureSamplerArray&) override { SkXfermode::Mode mode = fp.cast<ModeColorFilterEffect>().mode(); SkASSERT(SkXfermode::kDst_Mode != mode); const char* colorFilterColorUniName = NULL; if (fp.cast<ModeColorFilterEffect>().willUseFilterColor()) { fFilterColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "FilterColor", &colorFilterColorUniName); } GrGLSLExpr4 filter = color_filter_expression(mode, GrGLSLExpr4(colorFilterColorUniName), GrGLSLExpr4(inputColor)); builder->getFragmentShaderBuilder()-> codeAppendf("\t%s = %s;\n", outputColor, filter.c_str()); }
bool GrGLShaderBuilder::genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) { const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); /////////////////////////////////////////////////////////////////////////// // emit code to read the dst copy texture, if necessary if (kNoDstRead_DstReadKey != header.fDstReadKey && !fGpu->glCaps().fbFetchSupport()) { bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey); const char* dstCopyTopLeftName; const char* dstCopyCoordScaleName; const char* dstCopySamplerName; uint32_t configMask; if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { configMask = kA_GrColorComponentFlag; } else { configMask = kRGBA_GrColorComponentFlags; } fUniformHandles.fDstCopySamplerUni = this->addUniform(kFragment_Visibility, kSampler2D_GrSLType, "DstCopySampler", &dstCopySamplerName); fUniformHandles.fDstCopyTopLeftUni = this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyUpperLeft", &dstCopyTopLeftName); fUniformHandles.fDstCopyScaleUni = this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyCoordScale", &dstCopyCoordScaleName); const char* fragPos = this->fragmentPosition(); this->fsCodeAppend("\t// Read color from copy of the destination.\n"); this->fsCodeAppendf("\tvec2 _dstTexCoord = (%s.xy - %s) * %s;\n", fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); if (!topDown) { this->fsCodeAppend("\t_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n"); } this->fsCodeAppendf("\tvec4 %s = ", kDstCopyColorName); append_texture_lookup(&fFSCode, fGpu, dstCopySamplerName, "_dstTexCoord", configMask, "rgba"); this->fsCodeAppend(";\n\n"); } /////////////////////////////////////////////////////////////////////////// // get the initial color and coverage to feed into the first effect in each effect chain GrGLSLExpr4 inputColor; GrGLSLExpr4 inputCoverage; if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { const char* name; fUniformHandles.fColorUni = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Color", &name); inputColor = GrGLSLExpr4(name); } if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { const char* name; fUniformHandles.fCoverageUni = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Coverage", &name); inputCoverage = GrGLSLExpr4(name); } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) { inputCoverage = GrGLSLExpr4(1); } if (k110_GrGLSLGeneration != fGpu->glslGeneration()) { fFSOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier, declared_color_output_name()); fHasCustomColorOutput = true; } this->emitCodeBeforeEffects(&inputColor, &inputCoverage); /////////////////////////////////////////////////////////////////////////// // emit the per-effect code for both color and coverage effects GrGLProgramDesc::EffectKeyProvider colorKeyProvider( &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType); fColorEffects.reset(this->createAndEmitEffects(colorStages, this->desc().numColorEffects(), colorKeyProvider, &inputColor)); GrGLProgramDesc::EffectKeyProvider coverageKeyProvider( &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType); fCoverageEffects.reset(this->createAndEmitEffects(coverageStages, this->desc().numCoverageEffects(), coverageKeyProvider, &inputCoverage)); this->emitCodeAfterEffects(); /////////////////////////////////////////////////////////////////////////// // write the secondary color output if necessary if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) { const char* secondaryOutputName = this->enableSecondaryOutput(); // default coeff to ones for kCoverage_DualSrcOutput GrGLSLExpr4 coeff(1); if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) { // Get (1-A) into coeff coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput){ // Get (1-RGBA) into coeff coeff = GrGLSLExpr4(1) - inputColor; } // Get coeff * coverage into modulate and then write that to the dual source output. this->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str()); } /////////////////////////////////////////////////////////////////////////// // combine color and coverage as frag color // Get "color * coverage" into fragColor GrGLSLExpr4 fragColor = inputColor * inputCoverage; // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) { GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor()); fragColor = fragColor + dstContribution; } this->fsCodeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str()); if (!this->finish()) { return false; } return true; }
bool GrGLProgram::genProgram(GrGLShaderBuilder* builder, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) { SkASSERT(0 == fProgramID); const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); // incoming color to current stage being processed. GrGLSLExpr4 inColor = builder->getInputColor(); fColorEffects.reset( builder->createAndEmitEffects(colorStages, fDesc.effectKeys(), fDesc.numColorEffects(), &inColor)); /////////////////////////////////////////////////////////////////////////// // compute the partial coverage GrGLSLExpr4 inCoverage = builder->getInputCoverage(); fCoverageEffects.reset( builder->createAndEmitEffects(coverageStages, fDesc.getEffectKeys() + fDesc.numColorEffects(), fDesc.numCoverageEffects(), &inCoverage)); if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) { const char* secondaryOutputName = builder->enableSecondaryOutput(); // default coeff to ones for kCoverage_DualSrcOutput GrGLSLExpr4 coeff(1); if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) { // Get (1-A) into coeff coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inColor.a()); } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) { // Get (1-RGBA) into coeff coeff = GrGLSLExpr4(1) - inColor; } // Get coeff * coverage into modulate and then write that to the dual source output. builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inCoverage).c_str()); } /////////////////////////////////////////////////////////////////////////// // combine color and coverage as frag color // Get "color * coverage" into fragColor GrGLSLExpr4 fragColor = inColor * inCoverage; // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) { GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inCoverage; GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(builder->dstColor()); fragColor = fragColor + dstContribution; } builder->fsCodeAppendf("\t%s = %s;\n", builder->getColorOutputName(), fragColor.c_str()); if (!builder->finish(&fProgramID)) { return false; } fUniformHandles.fRTHeightUni = builder->getRTHeightUniform(); fUniformHandles.fDstCopyTopLeftUni = builder->getDstCopyTopLeftUniform(); fUniformHandles.fDstCopyScaleUni = builder->getDstCopyScaleUniform(); fUniformHandles.fColorUni = builder->getColorUniform(); fUniformHandles.fCoverageUni = builder->getCoverageUniform(); fUniformHandles.fDstCopySamplerUni = builder->getDstCopySamplerUniform(); // This must be called after we set fDstCopySamplerUni above. this->initSamplerUniforms(); return true; }