// 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("}");
}
示例#2
0
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("}");
}
示例#3
0
        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());
        }
示例#4
0
        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());
        }
示例#5
0
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;
    }
}
示例#6
0
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;
}
示例#7
0
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;
}