bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
                                                        SkTDArray<GrGLuint>* shaderIds) const {
    GrGLGpu* gpu = fProgramBuilder->gpu();
    SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo()));
    fragShaderSrc.append(fExtensions);
    append_default_precision_qualifier(kDefault_GrSLPrecision,
                                       gpu->glStandard(),
                                       &fragShaderSrc);
    fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &fragShaderSrc);
    this->appendDecls(fInputs, &fragShaderSrc);
    // We shouldn't have declared outputs on 1.10
    SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
    this->appendDecls(fOutputs, &fragShaderSrc);
    fragShaderSrc.append(fFunctions);
    fragShaderSrc.append("void main() {\n");
    fragShaderSrc.append(fCode);
    fragShaderSrc.append("}\n");

    GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), programId,
                                                       GR_GL_FRAGMENT_SHADER, fragShaderSrc,
                                                       gpu->gpuStats());
    if (!fragShaderId) {
        return false;
    }

    *shaderIds->append() = fragShaderId;

    return true;
}
const char* GrGLFragmentShaderBuilder::fragmentPosition() {
    fHasReadFragmentPosition = true;

    GrGLGpu* gpu = fProgramBuilder->gpu();
    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
    if (fTopLeftFragPosRead) {
        fSetupFragPosition = true;
        return "gl_FragCoord";
    } else if (gpu->glCaps().fragCoordConventionsSupport()) {
        if (!fSetupFragPosition) {
            if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
                this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
                                 "GL_ARB_fragment_coord_conventions");
            }
            fInputs.push_back().set(kVec4f_GrSLType,
                                    GrGLShaderVar::kIn_TypeModifier,
                                    "gl_FragCoord",
                                    kDefault_GrSLPrecision,
                                    GrGLShaderVar::kUpperLeft_Origin);
            fSetupFragPosition = true;
        }
        return "gl_FragCoord";
    } else {
        static const char* kTempName = "tmpXYFragCoord";
        static const char* kCoordName = "fragCoordYDown";
        if (!fSetupFragPosition) {
            // temporarily change the stage index because we're inserting non-stage code.
            GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
            SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
            const char* rtHeightName;

            fProgramBuilder->fUniformHandles.fRTHeightUni =
                    fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                kFloat_GrSLType,
                                                kDefault_GrSLPrecision,
                                                "RTHeight",
                                                &rtHeightName);

            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
            // depending on the surrounding code, accessing .xy with a uniform involved can
            // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand 
            // (and only accessing .xy) seems to "fix" things.
            this->codePrependf("\tvec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n",
                               kCoordName, kTempName, rtHeightName, kTempName);
            this->codePrependf("vec2 %s = gl_FragCoord.xy;", kTempName);
            fSetupFragPosition = true;
        }
        SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
        return kCoordName;
    }
}
const char* GrGLFragmentShaderBuilder::fragmentPosition() {
    fHasReadFragmentPosition = true;

    GrGLGpu* gpu = fProgramBuilder->gpu();
    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
    if (fTopLeftFragPosRead) {
        fSetupFragPosition = true;
        return "gl_FragCoord";
    } else if (gpu->glCaps().fragCoordConventionsSupport()) {
        if (!fSetupFragPosition) {
            if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
                this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
                                 "GL_ARB_fragment_coord_conventions");
            }
            fInputs.push_back().set(kVec4f_GrSLType,
                                    GrGLShaderVar::kIn_TypeModifier,
                                    "gl_FragCoord",
                                    kDefault_GrSLPrecision,
                                    GrGLShaderVar::kUpperLeft_Origin);
            fSetupFragPosition = true;
        }
        return "gl_FragCoord";
    } else {
        static const char* kCoordName = "fragCoordYDown";
        if (!fSetupFragPosition) {
            // temporarily change the stage index because we're inserting non-stage code.
            GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
            SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
            const char* rtHeightName;

            fProgramBuilder->fUniformHandles.fRTHeightUni =
                    fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                kFloat_GrSLType,
                                                kDefault_GrSLPrecision,
                                                "RTHeight",
                                                &rtHeightName);

            // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
            // causes programs to fail to link. Making this function return a vec2() didn't fix the
            // problem but using 1.0 for the last two components does.
            this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
                               "1.0);\n", kCoordName, rtHeightName);
            fSetupFragPosition = true;
        }
        SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
        return kCoordName;
    }
}
bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
                                                        SkTDArray<GrGLuint>* shaderIds) {
    GrGLGpu* gpu = fProgramBuilder->gpu();
    this->versionDecl() = GrGLGetGLSLVersionDecl(gpu->ctxInfo());
    GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
                                                   gpu->glStandard(),
                                                   &this->precisionQualifier());
    this->compileAndAppendLayoutQualifiers();
    fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility,
                                        &this->uniforms());
    this->appendDecls(fInputs, &this->inputs());
    // We shouldn't have declared outputs on 1.10
    SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
    this->appendDecls(fOutputs, &this->outputs());
    return this->finalize(programId, GR_GL_FRAGMENT_SHADER, shaderIds);
}
bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
    switch (feature) {
        case kStandardDerivatives_GLSLFeature: {
            GrGLGpu* gpu = fProgramBuilder->gpu();
            if (!gpu->glCaps().shaderCaps()->shaderDerivativeSupport()) {
                return false;
            }
            if (kGLES_GrGLStandard == gpu->glStandard() &&
                k110_GrGLSLGeneration == gpu->glslGeneration()) {
                this->addFeature(1 << kStandardDerivatives_GLSLFeature,
                                 "GL_OES_standard_derivatives");
            }
            return true;
        }
        default:
            SkFAIL("Unexpected GLSLFeature requested.");
            return false;
    }
}
const char* GrGLFragmentShaderBuilder::dstColor() {
    fHasReadDstColor = true;

    GrGLGpu* gpu = fProgramBuilder->gpu();
    if (gpu->glCaps().fbFetchSupport()) {
        this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
                         gpu->glCaps().fbFetchExtensionString());

        // On ES 3.0 we have to declare this, and use the custom color output name
        const char* fbFetchColorName = gpu->glCaps().fbFetchColorName();
        if (gpu->glslGeneration() >= k330_GrGLSLGeneration) {
            this->enableCustomOutput();
            fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
            fbFetchColorName = declared_color_output_name();
        }
        return fbFetchColorName;
    } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) {
        return kDstCopyColorName;
    } else {
        return "";
    }
}