1/*
2 * Copyright 2015 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#ifndef GrGLSLVarying_DEFINED
9#define GrGLSLVarying_DEFINED
10
11#include "GrAllocator.h"
12#include "GrGeometryProcessor.h"
13#include "GrTypesPriv.h"
14#include "glsl/GrGLSLProgramDataManager.h"
15#include "glsl/GrGLSLShaderVar.h"
16
17class GrGLSLProgramBuilder;
18
19class GrGLSLVarying {
20public:
21    bool vsVarying() const { return kVertToFrag_Varying == fVarying ||
22                                    kVertToGeo_Varying == fVarying; }
23    bool fsVarying() const { return kVertToFrag_Varying == fVarying ||
24                                    kGeoToFrag_Varying == fVarying; }
25    const char* vsOut() const { return fVsOut; }
26    const char* gsIn() const { return fGsIn; }
27    const char* gsOut() const { return fGsOut; }
28    const char* fsIn() const { return fFsIn; }
29    GrSLType type() const { return fType; }
30
31protected:
32    enum Varying {
33        kVertToFrag_Varying,
34        kVertToGeo_Varying,
35        kGeoToFrag_Varying,
36    };
37
38    GrGLSLVarying(GrSLType type, Varying varying)
39        : fVarying(varying), fType(type), fVsOut(nullptr), fGsIn(nullptr), fGsOut(nullptr),
40          fFsIn(nullptr) {}
41
42    Varying fVarying;
43
44private:
45    GrSLType fType;
46    const char* fVsOut;
47    const char* fGsIn;
48    const char* fGsOut;
49    const char* fFsIn;
50
51    friend class GrGLSLVaryingHandler;
52};
53
54struct GrGLSLVertToFrag : public GrGLSLVarying {
55    GrGLSLVertToFrag(GrSLType type)
56        : GrGLSLVarying(type, kVertToFrag_Varying) {}
57};
58
59struct GrGLSLVertToGeo : public GrGLSLVarying {
60    GrGLSLVertToGeo(GrSLType type)
61        : GrGLSLVarying(type, kVertToGeo_Varying) {}
62};
63
64struct GrGLSLGeoToFrag : public GrGLSLVarying {
65    GrGLSLGeoToFrag(GrSLType type)
66        : GrGLSLVarying(type, kGeoToFrag_Varying) {}
67};
68
69static const int kVaryingsPerBlock = 8;
70
71class GrGLSLVaryingHandler {
72public:
73    explicit GrGLSLVaryingHandler(GrGLSLProgramBuilder* program)
74        : fVaryings(kVaryingsPerBlock)
75        , fVertexInputs(kVaryingsPerBlock)
76        , fVertexOutputs(kVaryingsPerBlock)
77        , fGeomInputs(kVaryingsPerBlock)
78        , fGeomOutputs(kVaryingsPerBlock)
79        , fFragInputs(kVaryingsPerBlock)
80        , fFragOutputs(kVaryingsPerBlock)
81        , fProgramBuilder(program)
82        , fDefaultInterpolationModifier(nullptr) {}
83
84    virtual ~GrGLSLVaryingHandler() {}
85
86    /*
87     * Notifies the varying handler that this shader will never emit geometry in perspective and
88     * therefore does not require perspective-correct interpolation. When supported, this allows
89     * varyings to use the "noperspective" keyword, which means the GPU can use cheaper math for
90     * interpolation.
91     */
92    void setNoPerspective();
93
94    /*
95     * addVarying allows fine grained control for setting up varyings between stages. Calling this
96     * functions will make sure all necessary decls are setup for the client. The client however is
97     * responsible for setting up all shader code (e.g "vOut = vIn;") If you just need to take an
98     * attribute and pass it through to an output value in a fragment shader, use
99     * addPassThroughAttribute.
100     * TODO convert most uses of addVarying to addPassThroughAttribute
101     */
102    void addVarying(const char* name,
103                    GrGLSLVarying* varying,
104                    GrSLPrecision precision = kDefault_GrSLPrecision) {
105        SkASSERT(GrSLTypeIsFloatType(varying->type())); // Integers must use addFlatVarying.
106        this->internalAddVarying(name, varying, precision, false /*flat*/);
107    }
108
109    /*
110     * addFlatVarying sets up a varying whose value is constant across every fragment. The graphics
111     * pipeline will pull its value from the final vertex of the draw primitive (provoking vertex).
112     * Flat interpolation is not always supported and the user must check the caps before using.
113     * TODO: Some platforms can change the provoking vertex. Should we be resetting this knob?
114     */
115    void addFlatVarying(const char* name,
116                        GrGLSLVarying* varying,
117                        GrSLPrecision precision = kDefault_GrSLPrecision) {
118        this->internalAddVarying(name, varying, precision, true /*flat*/);
119    }
120
121    /*
122     * The GP can use these calls to pass an attribute through all shaders directly to 'output' in
123     * the fragment shader.  Though these calls affect both the vertex shader and fragment shader,
124     * they expect 'output' to be defined in the fragment shader before the call is made. If there
125     * is a geometry shader, we will simply take the value of the varying from the first vertex and
126     * that will be set as the output varying for all emitted vertices.
127     * TODO it might be nicer behavior to have a flag to declare output inside these calls
128     */
129    void addPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output,
130                                 GrSLPrecision = kDefault_GrSLPrecision);
131    void addFlatPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output,
132                                     GrSLPrecision = kDefault_GrSLPrecision);
133
134    void emitAttributes(const GrGeometryProcessor& gp);
135
136    // This should be called once all attributes and varyings have been added to the
137    // GrGLSLVaryingHanlder and before getting/adding any of the declarations to the shaders.
138    void finalize();
139
140    void getVertexDecls(SkString* inputDecls, SkString* outputDecls) const;
141    void getGeomDecls(SkString* inputDecls, SkString* outputDecls) const;
142    void getFragDecls(SkString* inputDecls, SkString* outputDecls) const;
143
144protected:
145    struct VaryingInfo {
146        GrSLType         fType;
147        GrSLPrecision    fPrecision;
148        bool             fIsFlat;
149        SkString         fVsOut;
150        SkString         fGsOut;
151        GrShaderFlags    fVisibility;
152    };
153
154    typedef GrTAllocator<VaryingInfo> VaryingList;
155    typedef GrTAllocator<GrGLSLShaderVar> VarArray;
156    typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle;
157
158    VaryingList    fVaryings;
159    VarArray       fVertexInputs;
160    VarArray       fVertexOutputs;
161    VarArray       fGeomInputs;
162    VarArray       fGeomOutputs;
163    VarArray       fFragInputs;
164    VarArray       fFragOutputs;
165
166    // This is not owned by the class
167    GrGLSLProgramBuilder* fProgramBuilder;
168
169private:
170    void internalAddVarying(const char* name, GrGLSLVarying*, GrSLPrecision, bool flat);
171    void writePassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output,
172                                   const GrGLSLVarying&);
173
174    void addAttribute(const GrShaderVar& var);
175
176    virtual void onFinalize() = 0;
177
178    // helper function for get*Decls
179    void appendDecls(const VarArray& vars, SkString* out) const;
180
181    const char* fDefaultInterpolationModifier;
182
183    friend class GrGLSLProgramBuilder;
184};
185
186#endif
187