blob: 73048e77e769d94b33687d255f2cfedaf0c4352c [file] [log] [blame]
egdaniel0eafe792015-11-20 14:01:22 -08001/*
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"
Brian Salomon99938a82016-11-21 13:41:08 -050013#include "GrShaderVar.h"
egdaniel0eafe792015-11-20 14:01:22 -080014#include "GrTypesPriv.h"
15#include "glsl/GrGLSLProgramDataManager.h"
egdaniel0eafe792015-11-20 14:01:22 -080016
17class GrGLSLProgramBuilder;
18
Ethan Nicholas56b4e3d2019-01-08 09:34:40 -050019#ifdef SK_DEBUG
20static bool is_matrix(GrSLType type) {
21 switch (type) {
22 case kFloat2x2_GrSLType:
23 case kFloat3x3_GrSLType:
24 case kFloat4x4_GrSLType:
25 case kHalf2x2_GrSLType:
26 case kHalf3x3_GrSLType:
27 case kHalf4x4_GrSLType:
28 return true;
29 default:
30 return false;
31 }
32}
33#endif
34
egdaniel0eafe792015-11-20 14:01:22 -080035class GrGLSLVarying {
36public:
Chris Dalton27372882017-12-08 13:34:21 -070037 enum class Scope {
38 kVertToFrag,
39 kVertToGeo,
40 kGeoToFrag
egdaniel0eafe792015-11-20 14:01:22 -080041 };
42
Chris Dalton90e8fb12017-12-22 02:24:53 -070043 GrGLSLVarying() = default;
Ethan Nicholas56b4e3d2019-01-08 09:34:40 -050044 GrGLSLVarying(GrSLType type, Scope scope = Scope::kVertToFrag)
45 : fType(type)
46 , fScope(scope) {
47 // Metal doesn't support varying matrices, so we disallow them everywhere for consistency
48 SkASSERT(!is_matrix(type));
49 }
egdaniel0eafe792015-11-20 14:01:22 -080050
Chris Dalton90e8fb12017-12-22 02:24:53 -070051 void reset(GrSLType type, Scope scope = Scope::kVertToFrag) {
Ethan Nicholas56b4e3d2019-01-08 09:34:40 -050052 // Metal doesn't support varying matrices, so we disallow them everywhere for consistency
53 SkASSERT(!is_matrix(type));
Chris Dalton90e8fb12017-12-22 02:24:53 -070054 *this = GrGLSLVarying();
55 fType = type;
56 fScope = scope;
57 }
58
Chris Dalton27372882017-12-08 13:34:21 -070059 GrSLType type() const { return fType; }
60 Scope scope() const { return fScope; }
61 bool isInVertexShader() const { return Scope::kGeoToFrag != fScope; }
62 bool isInFragmentShader() const { return Scope::kVertToGeo != fScope; }
63
64 const char* vsOut() const { SkASSERT(this->isInVertexShader()); return fVsOut; }
65 const char* gsIn() const { return fGsIn; }
66 const char* gsOut() const { return fGsOut; }
67 const char* fsIn() const { SkASSERT(this->isInFragmentShader()); return fFsIn; }
egdaniel0eafe792015-11-20 14:01:22 -080068
69private:
Chris Dalton90e8fb12017-12-22 02:24:53 -070070 GrSLType fType = kVoid_GrSLType;
71 Scope fScope = Scope::kVertToFrag;
Chris Dalton27372882017-12-08 13:34:21 -070072 const char* fVsOut = nullptr;
73 const char* fGsIn = nullptr;
74 const char* fGsOut = nullptr;
75 const char* fFsIn = nullptr;
egdaniel0eafe792015-11-20 14:01:22 -080076
77 friend class GrGLSLVaryingHandler;
78};
79
egdaniel0eafe792015-11-20 14:01:22 -080080static const int kVaryingsPerBlock = 8;
81
82class GrGLSLVaryingHandler {
83public:
84 explicit GrGLSLVaryingHandler(GrGLSLProgramBuilder* program)
cdaltonc08f1962016-02-12 12:14:06 -080085 : fVaryings(kVaryingsPerBlock)
86 , fVertexInputs(kVaryingsPerBlock)
egdaniel0eafe792015-11-20 14:01:22 -080087 , fVertexOutputs(kVaryingsPerBlock)
88 , fGeomInputs(kVaryingsPerBlock)
89 , fGeomOutputs(kVaryingsPerBlock)
90 , fFragInputs(kVaryingsPerBlock)
91 , fFragOutputs(kVaryingsPerBlock)
cdaltonc08f1962016-02-12 12:14:06 -080092 , fProgramBuilder(program)
93 , fDefaultInterpolationModifier(nullptr) {}
egdaniel0eafe792015-11-20 14:01:22 -080094
egdanielb80ec8b2016-02-09 09:54:43 -080095 virtual ~GrGLSLVaryingHandler() {}
96
cdaltonc08f1962016-02-12 12:14:06 -080097 /*
98 * Notifies the varying handler that this shader will never emit geometry in perspective and
99 * therefore does not require perspective-correct interpolation. When supported, this allows
100 * varyings to use the "noperspective" keyword, which means the GPU can use cheaper math for
101 * interpolation.
102 */
103 void setNoPerspective();
egdaniel0eafe792015-11-20 14:01:22 -0800104
Chris Dalton7b046312018-02-02 11:06:30 -0700105 enum class Interpolation {
106 kInterpolated,
107 kCanBeFlat, // Use "flat" if it will be faster.
108 kMustBeFlat // Use "flat" even if it is known to be slow.
109 };
110
egdaniel0eafe792015-11-20 14:01:22 -0800111 /*
112 * addVarying allows fine grained control for setting up varyings between stages. Calling this
Robert Phillipsf95b1752017-08-31 08:56:07 -0400113 * function will make sure all necessary decls are setup for the client. The client however is
egdaniel0eafe792015-11-20 14:01:22 -0800114 * responsible for setting up all shader code (e.g "vOut = vIn;") If you just need to take an
115 * attribute and pass it through to an output value in a fragment shader, use
116 * addPassThroughAttribute.
117 * TODO convert most uses of addVarying to addPassThroughAttribute
118 */
Chris Dalton7b046312018-02-02 11:06:30 -0700119 void addVarying(const char* name, GrGLSLVarying* varying,
120 Interpolation = Interpolation::kInterpolated);
cdaltonc08f1962016-02-12 12:14:06 -0800121
122 /*
123 * The GP can use these calls to pass an attribute through all shaders directly to 'output' in
124 * the fragment shader. Though these calls affect both the vertex shader and fragment shader,
125 * they expect 'output' to be defined in the fragment shader before the call is made. If there
egdaniel0eafe792015-11-20 14:01:22 -0800126 * is a geometry shader, we will simply take the value of the varying from the first vertex and
127 * that will be set as the output varying for all emitted vertices.
cdaltonc08f1962016-02-12 12:14:06 -0800128 * TODO it might be nicer behavior to have a flag to declare output inside these calls
egdaniel0eafe792015-11-20 14:01:22 -0800129 */
Brian Salomon92be2f72018-06-19 14:33:47 -0400130 void addPassThroughAttribute(const GrGeometryProcessor::Attribute&, const char* output,
Chris Dalton7b046312018-02-02 11:06:30 -0700131 Interpolation = Interpolation::kInterpolated);
egdaniel0eafe792015-11-20 14:01:22 -0800132
133 void emitAttributes(const GrGeometryProcessor& gp);
134
egdanielb80ec8b2016-02-09 09:54:43 -0800135 // This should be called once all attributes and varyings have been added to the
136 // GrGLSLVaryingHanlder and before getting/adding any of the declarations to the shaders.
137 void finalize();
138
egdaniel0eafe792015-11-20 14:01:22 -0800139 void getVertexDecls(SkString* inputDecls, SkString* outputDecls) const;
140 void getGeomDecls(SkString* inputDecls, SkString* outputDecls) const;
141 void getFragDecls(SkString* inputDecls, SkString* outputDecls) const;
cdaltonc08f1962016-02-12 12:14:06 -0800142
egdaniel0eafe792015-11-20 14:01:22 -0800143protected:
cdaltonc08f1962016-02-12 12:14:06 -0800144 struct VaryingInfo {
145 GrSLType fType;
cdaltonc08f1962016-02-12 12:14:06 -0800146 bool fIsFlat;
147 SkString fVsOut;
148 SkString fGsOut;
149 GrShaderFlags fVisibility;
150 };
151
152 typedef GrTAllocator<VaryingInfo> VaryingList;
Brian Salomon99938a82016-11-21 13:41:08 -0500153 typedef GrTAllocator<GrShaderVar> VarArray;
cdaltonc08f1962016-02-12 12:14:06 -0800154 typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle;
155
156 VaryingList fVaryings;
157 VarArray fVertexInputs;
158 VarArray fVertexOutputs;
159 VarArray fGeomInputs;
160 VarArray fGeomOutputs;
161 VarArray fFragInputs;
162 VarArray fFragOutputs;
egdaniel0eafe792015-11-20 14:01:22 -0800163
164 // This is not owned by the class
165 GrGLSLProgramBuilder* fProgramBuilder;
166
167private:
egdaniel0eafe792015-11-20 14:01:22 -0800168 void addAttribute(const GrShaderVar& var);
169
egdanielb80ec8b2016-02-09 09:54:43 -0800170 virtual void onFinalize() = 0;
171
egdaniel0eafe792015-11-20 14:01:22 -0800172 // helper function for get*Decls
173 void appendDecls(const VarArray& vars, SkString* out) const;
174
cdaltonc08f1962016-02-12 12:14:06 -0800175 const char* fDefaultInterpolationModifier;
176
egdaniel0eafe792015-11-20 14:01:22 -0800177 friend class GrGLSLProgramBuilder;
178};
179
180#endif