GrGLSLFragmentShaderBuilder.cpp revision 1cbb5ea0a07255bcc0b8351ddf1fc84f50887aef
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 "GrGLSLFragmentShaderBuilder.h"
9#include "GrRenderTarget.h"
10#include "glsl/GrGLSL.h"
11#include "glsl/GrGLSLCaps.h"
12#include "glsl/GrGLSLProgramBuilder.h"
13#include "glsl/GrGLSLUniformHandler.h"
14#include "glsl/GrGLSLVarying.h"
15
16const char* GrGLSLFragmentShaderBuilder::kDstTextureColorName = "_dstColor";
17
18static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
19    SkASSERT(GrBlendEquationIsAdvanced(equation));
20
21    static const char* kLayoutQualifierNames[] = {
22        "blend_support_screen",
23        "blend_support_overlay",
24        "blend_support_darken",
25        "blend_support_lighten",
26        "blend_support_colordodge",
27        "blend_support_colorburn",
28        "blend_support_hardlight",
29        "blend_support_softlight",
30        "blend_support_difference",
31        "blend_support_exclusion",
32        "blend_support_multiply",
33        "blend_support_hsl_hue",
34        "blend_support_hsl_saturation",
35        "blend_support_hsl_color",
36        "blend_support_hsl_luminosity"
37    };
38    return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation];
39
40    GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation);
41    GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation);
42    GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation);
43    GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation);
44    GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation);
45    GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation);
46    GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
47    GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
48    GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation);
49    GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation);
50    GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation);
51    GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation);
52    GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation);
53    GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation);
54    GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation);
55    GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) ==
56                     kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation);
57}
58
59GrGLSLFragmentShaderBuilder::FragPosKey
60GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst) {
61    if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
62        return kTopLeftFragPosRead_FragPosKey;
63    } else {
64        return kBottomLeftFragPosRead_FragPosKey;
65    }
66}
67
68GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program,
69                                                         uint8_t fragPosKey)
70    : INHERITED(program)
71    , fSetupFragPosition(false)
72    , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
73    , fCustomColorOutputIndex(-1)
74    , fHasReadDstColor(false)
75    , fHasReadFragmentPosition(false) {
76}
77
78bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
79    switch (feature) {
80        case kStandardDerivatives_GLSLFeature: {
81            if (!fProgramBuilder->glslCaps()->shaderDerivativeSupport()) {
82                return false;
83            }
84            const char* extension = fProgramBuilder->glslCaps()->shaderDerivativeExtensionString();
85            if (extension) {
86                this->addFeature(1 << kStandardDerivatives_GLSLFeature, extension);
87            }
88            return true;
89        }
90        default:
91            SkFAIL("Unexpected GLSLFeature requested.");
92            return false;
93    }
94}
95
96SkString GrGLSLFragmentShaderBuilder::ensureFSCoords2D(const GrGLSLTransformedCoordsArray& coords,
97                                                       int index) {
98    if (kVec3f_GrSLType != coords[index].getType()) {
99        SkASSERT(kVec2f_GrSLType == coords[index].getType());
100        return coords[index].getName();
101    }
102
103    SkString coords2D("coords2D");
104    if (0 != index) {
105        coords2D.appendf("_%i", index);
106    }
107    this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
108                      coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
109    return coords2D;
110}
111
112const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
113    fHasReadFragmentPosition = true;
114
115    const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
116    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
117    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
118    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
119    if (fTopLeftFragPosRead) {
120        fSetupFragPosition = true;
121        return "gl_FragCoord";
122    } else if (const char* extension = glslCaps->fragCoordConventionsExtensionString()) {
123        if (!fSetupFragPosition) {
124            if (glslCaps->generation() < k150_GrGLSLGeneration) {
125                this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
126                                 extension);
127            }
128            fInputs.push_back().set(kVec4f_GrSLType,
129                                    GrGLSLShaderVar::kIn_TypeModifier,
130                                    "gl_FragCoord",
131                                    kDefault_GrSLPrecision,
132                                    GrGLSLShaderVar::kUpperLeft_Origin);
133            fSetupFragPosition = true;
134        }
135        return "gl_FragCoord";
136    } else {
137        static const char* kTempName = "tmpXYFragCoord";
138        static const char* kCoordName = "fragCoordYDown";
139        if (!fSetupFragPosition) {
140            const char* rtHeightName;
141
142            fProgramBuilder->addRTHeightUniform("RTHeight", &rtHeightName);
143
144            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
145            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
146            // depending on the surrounding code, accessing .xy with a uniform involved can
147            // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
148            // (and only accessing .xy) seems to "fix" things.
149            const char* precision = glslCaps->usesPrecisionModifiers() ? "highp " : "";
150            this->codePrependf("\t%svec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n",
151                               precision, kCoordName, kTempName, rtHeightName, kTempName);
152            this->codePrependf("%svec2 %s = gl_FragCoord.xy;", precision, kTempName);
153            fSetupFragPosition = true;
154        }
155        SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
156        return kCoordName;
157    }
158}
159
160const char* GrGLSLFragmentShaderBuilder::dstColor() {
161    fHasReadDstColor = true;
162
163    const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
164    if (glslCaps->fbFetchSupport()) {
165        this->addFeature(1 << (GrGLSLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
166                         glslCaps->fbFetchExtensionString());
167
168        // Some versions of this extension string require declaring custom color output on ES 3.0+
169        const char* fbFetchColorName = glslCaps->fbFetchColorName();
170        if (glslCaps->fbFetchNeedsCustomOutput()) {
171            this->enableCustomOutput();
172            fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
173            fbFetchColorName = DeclaredColorOutputName();
174        }
175        return fbFetchColorName;
176    } else {
177        return kDstTextureColorName;
178    }
179}
180
181void GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) {
182    SkASSERT(GrBlendEquationIsAdvanced(equation));
183
184    const GrGLSLCaps& caps = *fProgramBuilder->glslCaps();
185    if (!caps.mustEnableAdvBlendEqs()) {
186        return;
187    }
188
189    this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature,
190                     "GL_KHR_blend_equation_advanced");
191    if (caps.mustEnableSpecificAdvBlendEqs()) {
192        this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier);
193    } else {
194        this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier);
195    }
196}
197
198void GrGLSLFragmentShaderBuilder::enableCustomOutput() {
199    if (!fHasCustomColorOutput) {
200        fHasCustomColorOutput = true;
201        fCustomColorOutputIndex = fOutputs.count();
202        fOutputs.push_back().set(kVec4f_GrSLType,
203                                 GrGLSLShaderVar::kOut_TypeModifier,
204                                 DeclaredColorOutputName());
205    }
206}
207
208void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() {
209    SkASSERT(!fHasSecondaryOutput);
210    fHasSecondaryOutput = true;
211    const GrGLSLCaps& caps = *fProgramBuilder->glslCaps();
212    if (const char* extension = caps.secondaryOutputExtensionString()) {
213        this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension);
214    }
215
216    // If the primary output is declared, we must declare also the secondary output
217    // and vice versa, since it is not allowed to use a built-in gl_FragColor and a custom
218    // output. The condition also co-incides with the condition in whici GLES SL 2.0
219    // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a custom output.
220    if (caps.mustDeclareFragmentShaderOutput()) {
221        fOutputs.push_back().set(kVec4f_GrSLType, GrGLSLShaderVar::kOut_TypeModifier,
222                                 DeclaredSecondaryColorOutputName());
223    }
224}
225
226const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const {
227    return fHasCustomColorOutput ? DeclaredColorOutputName() : "gl_FragColor";
228}
229
230const char* GrGLSLFragmentShaderBuilder::getSecondaryColorOutputName() const {
231    const GrGLSLCaps& caps = *fProgramBuilder->glslCaps();
232    return caps.mustDeclareFragmentShaderOutput() ? DeclaredSecondaryColorOutputName()
233                                                  : "gl_SecondaryFragColorEXT";
234}
235
236void GrGLSLFragmentShaderBuilder::onFinalize() {
237    fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs());
238    GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
239                                                 *fProgramBuilder->glslCaps(),
240                                                 &this->precisionQualifier());
241}
242
243void GrGLSLFragmentBuilder::onBeforeChildProcEmitCode() {
244    SkASSERT(fSubstageIndices.count() >= 1);
245    fSubstageIndices.push_back(0);
246    // second-to-last value in the fSubstageIndices stack is the index of the child proc
247    // at that level which is currently emitting code.
248    fMangleString.appendf("_c%d", fSubstageIndices[fSubstageIndices.count() - 2]);
249}
250
251void GrGLSLFragmentBuilder::onAfterChildProcEmitCode() {
252    SkASSERT(fSubstageIndices.count() >= 2);
253    fSubstageIndices.pop_back();
254    fSubstageIndices.back()++;
255    int removeAt = fMangleString.findLastOf('_');
256    fMangleString.remove(removeAt, fMangleString.size() - removeAt);
257}
258
259