1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrGLFragmentShaderBuilder.h"
9#include "GrGLProgramBuilder.h"
10#include "../GrGLGpu.h"
11
12#define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X)
13#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(), R, X)
14
15const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor";
16static const char* declared_color_output_name() { return "fsColorOut"; }
17static const char* dual_source_output_name() { return "dualSourceOut"; }
18static void append_default_precision_qualifier(GrSLPrecision p,
19                                               GrGLStandard standard,
20                                               SkString* str) {
21    // Desktop GLSL has added precision qualifiers but they don't do anything.
22    if (kGLES_GrGLStandard == standard) {
23        switch (p) {
24            case kHigh_GrSLPrecision:
25                str->append("precision highp float;\n");
26                break;
27            case kMedium_GrSLPrecision:
28                str->append("precision mediump float;\n");
29                break;
30            case kLow_GrSLPrecision:
31                str->append("precision lowp float;\n");
32                break;
33            default:
34                SkFAIL("Unknown precision value.");
35        }
36    }
37}
38
39static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
40    SkASSERT(GrBlendEquationIsAdvanced(equation));
41
42    static const char* kLayoutQualifierNames[] = {
43        "blend_support_screen",
44        "blend_support_overlay",
45        "blend_support_darken",
46        "blend_support_lighten",
47        "blend_support_colordodge",
48        "blend_support_colorburn",
49        "blend_support_hardlight",
50        "blend_support_softlight",
51        "blend_support_difference",
52        "blend_support_exclusion",
53        "blend_support_multiply",
54        "blend_support_hsl_hue",
55        "blend_support_hsl_saturation",
56        "blend_support_hsl_color",
57        "blend_support_hsl_luminosity"
58    };
59    return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation];
60
61    GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation);
62    GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation);
63    GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation);
64    GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation);
65    GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation);
66    GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation);
67    GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
68    GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
69    GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation);
70    GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation);
71    GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation);
72    GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation);
73    GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation);
74    GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation);
75    GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation);
76    GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) ==
77                     kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation);
78}
79
80GrGLFragmentShaderBuilder::DstReadKey
81GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps& caps) {
82    uint32_t key = kYesDstRead_DstReadKeyBit;
83    if (caps.glslCaps()->fbFetchSupport()) {
84        return key;
85    }
86    SkASSERT(dstCopy);
87    if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
88        // The fact that the config is alpha-only must be considered when generating code.
89        key |= kUseAlphaConfig_DstReadKeyBit;
90    }
91    if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
92        key |= kTopLeftOrigin_DstReadKeyBit;
93    }
94    SkASSERT(static_cast<DstReadKey>(key) == key);
95    return static_cast<DstReadKey>(key);
96}
97
98GrGLFragmentShaderBuilder::FragPosKey
99GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&) {
100    if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
101        return kTopLeftFragPosRead_FragPosKey;
102    } else {
103        return kBottomLeftFragPosRead_FragPosKey;
104    }
105}
106
107GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
108                                                     uint8_t fragPosKey)
109    : INHERITED(program)
110    , fHasCustomColorOutput(false)
111    , fHasSecondaryOutput(false)
112    , fSetupFragPosition(false)
113    , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
114    , fCustomColorOutputIndex(-1)
115    , fHasReadDstColor(false)
116    , fHasReadFragmentPosition(false) {
117}
118
119bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
120    switch (feature) {
121        case kStandardDerivatives_GLSLFeature: {
122            GrGLGpu* gpu = fProgramBuilder->gpu();
123            if (!gpu->glCaps().shaderCaps()->shaderDerivativeSupport()) {
124                return false;
125            }
126            if (kGLES_GrGLStandard == gpu->glStandard() &&
127                k110_GrGLSLGeneration == gpu->glslGeneration()) {
128                this->addFeature(1 << kStandardDerivatives_GLSLFeature,
129                                 "GL_OES_standard_derivatives");
130            }
131            return true;
132        }
133        default:
134            SkFAIL("Unexpected GLSLFeature requested.");
135            return false;
136    }
137}
138
139SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
140        const GrGLProcessor::TransformedCoordsArray& coords, int index) {
141    if (kVec3f_GrSLType != coords[index].getType()) {
142        SkASSERT(kVec2f_GrSLType == coords[index].getType());
143        return coords[index].getName();
144    }
145
146    SkString coords2D("coords2D");
147    if (0 != index) {
148        coords2D.appendf("_%i", index);
149    }
150    this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
151                      coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
152    return coords2D;
153}
154
155const char* GrGLFragmentShaderBuilder::fragmentPosition() {
156    fHasReadFragmentPosition = true;
157
158    GrGLGpu* gpu = fProgramBuilder->gpu();
159    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
160    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
161    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
162    if (fTopLeftFragPosRead) {
163        fSetupFragPosition = true;
164        return "gl_FragCoord";
165    } else if (gpu->glCaps().fragCoordConventionsSupport()) {
166        if (!fSetupFragPosition) {
167            if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
168                this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
169                                 "GL_ARB_fragment_coord_conventions");
170            }
171            fInputs.push_back().set(kVec4f_GrSLType,
172                                    GrGLShaderVar::kIn_TypeModifier,
173                                    "gl_FragCoord",
174                                    kDefault_GrSLPrecision,
175                                    GrGLShaderVar::kUpperLeft_Origin);
176            fSetupFragPosition = true;
177        }
178        return "gl_FragCoord";
179    } else {
180        static const char* kCoordName = "fragCoordYDown";
181        if (!fSetupFragPosition) {
182            // temporarily change the stage index because we're inserting non-stage code.
183            GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
184            SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
185            const char* rtHeightName;
186
187            fProgramBuilder->fUniformHandles.fRTHeightUni =
188                    fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
189                                                kFloat_GrSLType,
190                                                kDefault_GrSLPrecision,
191                                                "RTHeight",
192                                                &rtHeightName);
193
194            // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
195            // causes programs to fail to link. Making this function return a vec2() didn't fix the
196            // problem but using 1.0 for the last two components does.
197            this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
198                               "1.0);\n", kCoordName, rtHeightName);
199            fSetupFragPosition = true;
200        }
201        SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
202        return kCoordName;
203    }
204}
205
206const char* GrGLFragmentShaderBuilder::dstColor() {
207    fHasReadDstColor = true;
208
209    GrGLGpu* gpu = fProgramBuilder->gpu();
210    if (gpu->glCaps().glslCaps()->fbFetchSupport()) {
211        this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
212                         gpu->glCaps().glslCaps()->fbFetchExtensionString());
213
214        // Some versions of this extension string require declaring custom color output on ES 3.0+
215        const char* fbFetchColorName = gpu->glCaps().glslCaps()->fbFetchColorName();
216        if (gpu->glCaps().glslCaps()->fbFetchNeedsCustomOutput()) {
217            this->enableCustomOutput();
218            fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
219            fbFetchColorName = declared_color_output_name();
220        }
221        return fbFetchColorName;
222    } else {
223        return kDstCopyColorName;
224    }
225}
226
227void GrGLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) {
228    SkASSERT(GrBlendEquationIsAdvanced(equation));
229
230    const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
231    if (!caps.mustEnableAdvBlendEqs()) {
232        return;
233    }
234
235    this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature,
236                     "GL_KHR_blend_equation_advanced");
237    if (caps.mustEnableSpecificAdvBlendEqs()) {
238        this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier);
239    } else {
240        this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier);
241    }
242}
243
244void GrGLFragmentShaderBuilder::enableCustomOutput() {
245    if (!fHasCustomColorOutput) {
246        fHasCustomColorOutput = true;
247        fCustomColorOutputIndex = fOutputs.count();
248        fOutputs.push_back().set(kVec4f_GrSLType,
249                                 GrGLShaderVar::kOut_TypeModifier,
250                                 declared_color_output_name());
251    }
252}
253
254void GrGLFragmentShaderBuilder::enableSecondaryOutput() {
255    SkASSERT(!fHasSecondaryOutput);
256    fHasSecondaryOutput = true;
257    fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
258                             dual_source_output_name());
259}
260
261const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
262    return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
263}
264
265const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const {
266    return dual_source_output_name();
267}
268
269bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
270                                                        SkTDArray<GrGLuint>* shaderIds) {
271    GrGLGpu* gpu = fProgramBuilder->gpu();
272    this->versionDecl() = GrGetGLSLVersionDecl(gpu->ctxInfo());
273    append_default_precision_qualifier(kDefault_GrSLPrecision,
274                                       gpu->glStandard(),
275                                       &this->precisionQualifier());
276    this->compileAndAppendLayoutQualifiers();
277    fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility,
278                                        &this->uniforms());
279    this->appendDecls(fInputs, &this->inputs());
280    // We shouldn't have declared outputs on 1.10
281    SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
282    this->appendDecls(fOutputs, &this->outputs());
283    return this->finalize(programId, GR_GL_FRAGMENT_SHADER, shaderIds);
284}
285
286void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
287    // ES 3.00 requires custom color output but doesn't support bindFragDataLocation
288    if (fHasCustomColorOutput &&
289        kGLES_GrGLStandard != fProgramBuilder->gpu()->ctxInfo().standard()) {
290        GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
291    }
292    if (fHasSecondaryOutput) {
293        GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_name()));
294    }
295}
296
297void GrGLFragmentShaderBuilder::addVarying(GrGLVarying* v, GrSLPrecision fsPrec) {
298    v->fFsIn = v->fVsOut;
299    if (v->fGsOut) {
300        v->fFsIn = v->fGsOut;
301    }
302    fInputs.push_back().set(v->fType, GrGLShaderVar::kVaryingIn_TypeModifier, v->fFsIn, fsPrec);
303}
304