xref: /aosp_15_r20/external/angle/src/compiler/translator/ValidateVaryingLocations.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // The ValidateVaryingLocations function checks if there exists location conflicts on shader
7*8975f5c5SAndroid Build Coastguard Worker // varyings.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "ValidateVaryingLocations.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/Diagnostics.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/SymbolTable.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/tree_util/IntermTraverse.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/util.h"
16*8975f5c5SAndroid Build Coastguard Worker 
17*8975f5c5SAndroid Build Coastguard Worker namespace sh
18*8975f5c5SAndroid Build Coastguard Worker {
19*8975f5c5SAndroid Build Coastguard Worker 
20*8975f5c5SAndroid Build Coastguard Worker namespace
21*8975f5c5SAndroid Build Coastguard Worker {
22*8975f5c5SAndroid Build Coastguard Worker 
error(const TIntermSymbol & symbol,const char * reason,TDiagnostics * diagnostics)23*8975f5c5SAndroid Build Coastguard Worker void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
24*8975f5c5SAndroid Build Coastguard Worker {
25*8975f5c5SAndroid Build Coastguard Worker     diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
26*8975f5c5SAndroid Build Coastguard Worker }
27*8975f5c5SAndroid Build Coastguard Worker 
28*8975f5c5SAndroid Build Coastguard Worker int GetStructLocationCount(const TStructure *structure);
29*8975f5c5SAndroid Build Coastguard Worker 
GetFieldLocationCount(const TField * field)30*8975f5c5SAndroid Build Coastguard Worker int GetFieldLocationCount(const TField *field)
31*8975f5c5SAndroid Build Coastguard Worker {
32*8975f5c5SAndroid Build Coastguard Worker     int field_size         = 0;
33*8975f5c5SAndroid Build Coastguard Worker     const TType *fieldType = field->type();
34*8975f5c5SAndroid Build Coastguard Worker 
35*8975f5c5SAndroid Build Coastguard Worker     if (fieldType->getStruct() != nullptr)
36*8975f5c5SAndroid Build Coastguard Worker     {
37*8975f5c5SAndroid Build Coastguard Worker         field_size = GetStructLocationCount(fieldType->getStruct());
38*8975f5c5SAndroid Build Coastguard Worker     }
39*8975f5c5SAndroid Build Coastguard Worker     else if (fieldType->isMatrix())
40*8975f5c5SAndroid Build Coastguard Worker     {
41*8975f5c5SAndroid Build Coastguard Worker         field_size = fieldType->getNominalSize();
42*8975f5c5SAndroid Build Coastguard Worker     }
43*8975f5c5SAndroid Build Coastguard Worker     else
44*8975f5c5SAndroid Build Coastguard Worker     {
45*8975f5c5SAndroid Build Coastguard Worker         ASSERT(fieldType->getSecondarySize() == 1);
46*8975f5c5SAndroid Build Coastguard Worker         field_size = 1;
47*8975f5c5SAndroid Build Coastguard Worker     }
48*8975f5c5SAndroid Build Coastguard Worker 
49*8975f5c5SAndroid Build Coastguard Worker     if (fieldType->isArray())
50*8975f5c5SAndroid Build Coastguard Worker     {
51*8975f5c5SAndroid Build Coastguard Worker         field_size *= fieldType->getArraySizeProduct();
52*8975f5c5SAndroid Build Coastguard Worker     }
53*8975f5c5SAndroid Build Coastguard Worker 
54*8975f5c5SAndroid Build Coastguard Worker     return field_size;
55*8975f5c5SAndroid Build Coastguard Worker }
56*8975f5c5SAndroid Build Coastguard Worker 
GetStructLocationCount(const TStructure * structure)57*8975f5c5SAndroid Build Coastguard Worker int GetStructLocationCount(const TStructure *structure)
58*8975f5c5SAndroid Build Coastguard Worker {
59*8975f5c5SAndroid Build Coastguard Worker     int totalLocation = 0;
60*8975f5c5SAndroid Build Coastguard Worker     for (const TField *field : structure->fields())
61*8975f5c5SAndroid Build Coastguard Worker     {
62*8975f5c5SAndroid Build Coastguard Worker         totalLocation += GetFieldLocationCount(field);
63*8975f5c5SAndroid Build Coastguard Worker     }
64*8975f5c5SAndroid Build Coastguard Worker     return totalLocation;
65*8975f5c5SAndroid Build Coastguard Worker }
66*8975f5c5SAndroid Build Coastguard Worker 
GetInterfaceBlockLocationCount(const TType & varyingType,bool ignoreVaryingArraySize)67*8975f5c5SAndroid Build Coastguard Worker int GetInterfaceBlockLocationCount(const TType &varyingType, bool ignoreVaryingArraySize)
68*8975f5c5SAndroid Build Coastguard Worker {
69*8975f5c5SAndroid Build Coastguard Worker     int totalLocation = 0;
70*8975f5c5SAndroid Build Coastguard Worker     for (const TField *field : varyingType.getInterfaceBlock()->fields())
71*8975f5c5SAndroid Build Coastguard Worker     {
72*8975f5c5SAndroid Build Coastguard Worker         totalLocation += GetFieldLocationCount(field);
73*8975f5c5SAndroid Build Coastguard Worker     }
74*8975f5c5SAndroid Build Coastguard Worker 
75*8975f5c5SAndroid Build Coastguard Worker     if (!ignoreVaryingArraySize && varyingType.isArray())
76*8975f5c5SAndroid Build Coastguard Worker     {
77*8975f5c5SAndroid Build Coastguard Worker         totalLocation *= varyingType.getArraySizeProduct();
78*8975f5c5SAndroid Build Coastguard Worker     }
79*8975f5c5SAndroid Build Coastguard Worker     return totalLocation;
80*8975f5c5SAndroid Build Coastguard Worker }
81*8975f5c5SAndroid Build Coastguard Worker 
GetLocationCount(const TType & varyingType,bool ignoreVaryingArraySize)82*8975f5c5SAndroid Build Coastguard Worker int GetLocationCount(const TType &varyingType, bool ignoreVaryingArraySize)
83*8975f5c5SAndroid Build Coastguard Worker {
84*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!varyingType.isInterfaceBlock());
85*8975f5c5SAndroid Build Coastguard Worker 
86*8975f5c5SAndroid Build Coastguard Worker     if (varyingType.getStruct() != nullptr)
87*8975f5c5SAndroid Build Coastguard Worker     {
88*8975f5c5SAndroid Build Coastguard Worker         int totalLocation = 0;
89*8975f5c5SAndroid Build Coastguard Worker         for (const TField *field : varyingType.getStruct()->fields())
90*8975f5c5SAndroid Build Coastguard Worker         {
91*8975f5c5SAndroid Build Coastguard Worker             const TType *fieldType = field->type();
92*8975f5c5SAndroid Build Coastguard Worker             ASSERT(fieldType->getStruct() == nullptr && !fieldType->isArray());
93*8975f5c5SAndroid Build Coastguard Worker 
94*8975f5c5SAndroid Build Coastguard Worker             totalLocation += GetFieldLocationCount(field);
95*8975f5c5SAndroid Build Coastguard Worker         }
96*8975f5c5SAndroid Build Coastguard Worker         return totalLocation;
97*8975f5c5SAndroid Build Coastguard Worker     }
98*8975f5c5SAndroid Build Coastguard Worker 
99*8975f5c5SAndroid Build Coastguard Worker     ASSERT(varyingType.isMatrix() || varyingType.getSecondarySize() == 1);
100*8975f5c5SAndroid Build Coastguard Worker     int elementLocationCount = varyingType.isMatrix() ? varyingType.getNominalSize() : 1;
101*8975f5c5SAndroid Build Coastguard Worker 
102*8975f5c5SAndroid Build Coastguard Worker     // [GL_EXT_shader_io_blocks SPEC Chapter 4.4.1]
103*8975f5c5SAndroid Build Coastguard Worker     // Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation
104*8975f5c5SAndroid Build Coastguard Worker     // evaluation inputs all have an additional level of arrayness relative to other shader inputs
105*8975f5c5SAndroid Build Coastguard Worker     // and outputs. This outer array level is removed from the type before considering how many
106*8975f5c5SAndroid Build Coastguard Worker     // locations the type consumes.
107*8975f5c5SAndroid Build Coastguard Worker     if (ignoreVaryingArraySize)
108*8975f5c5SAndroid Build Coastguard Worker     {
109*8975f5c5SAndroid Build Coastguard Worker         // Array-of-arrays cannot be inputs or outputs of a geometry shader.
110*8975f5c5SAndroid Build Coastguard Worker         // (GL_EXT_geometry_shader SPEC issues(5))
111*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!varyingType.isArrayOfArrays());
112*8975f5c5SAndroid Build Coastguard Worker         return elementLocationCount;
113*8975f5c5SAndroid Build Coastguard Worker     }
114*8975f5c5SAndroid Build Coastguard Worker 
115*8975f5c5SAndroid Build Coastguard Worker     return elementLocationCount * varyingType.getArraySizeProduct();
116*8975f5c5SAndroid Build Coastguard Worker }
117*8975f5c5SAndroid Build Coastguard Worker 
ShouldIgnoreVaryingArraySize(TQualifier qualifier,GLenum shaderType)118*8975f5c5SAndroid Build Coastguard Worker bool ShouldIgnoreVaryingArraySize(TQualifier qualifier, GLenum shaderType)
119*8975f5c5SAndroid Build Coastguard Worker {
120*8975f5c5SAndroid Build Coastguard Worker     bool isVaryingIn = IsShaderIn(qualifier) && qualifier != EvqPatchIn;
121*8975f5c5SAndroid Build Coastguard Worker 
122*8975f5c5SAndroid Build Coastguard Worker     switch (shaderType)
123*8975f5c5SAndroid Build Coastguard Worker     {
124*8975f5c5SAndroid Build Coastguard Worker         case GL_GEOMETRY_SHADER:
125*8975f5c5SAndroid Build Coastguard Worker         case GL_TESS_EVALUATION_SHADER:
126*8975f5c5SAndroid Build Coastguard Worker             return isVaryingIn;
127*8975f5c5SAndroid Build Coastguard Worker         case GL_TESS_CONTROL_SHADER:
128*8975f5c5SAndroid Build Coastguard Worker             return (IsShaderOut(qualifier) && qualifier != EvqPatchOut) || isVaryingIn;
129*8975f5c5SAndroid Build Coastguard Worker         default:
130*8975f5c5SAndroid Build Coastguard Worker             return false;
131*8975f5c5SAndroid Build Coastguard Worker     }
132*8975f5c5SAndroid Build Coastguard Worker }
133*8975f5c5SAndroid Build Coastguard Worker 
134*8975f5c5SAndroid Build Coastguard Worker struct SymbolAndField
135*8975f5c5SAndroid Build Coastguard Worker {
136*8975f5c5SAndroid Build Coastguard Worker     const TIntermSymbol *symbol;
137*8975f5c5SAndroid Build Coastguard Worker     const TField *field;
138*8975f5c5SAndroid Build Coastguard Worker };
139*8975f5c5SAndroid Build Coastguard Worker using LocationMap = std::map<int, SymbolAndField>;
140*8975f5c5SAndroid Build Coastguard Worker 
MarkVaryingLocations(TDiagnostics * diagnostics,const TIntermSymbol * varying,const TField * field,int location,int elementCount,LocationMap * locationMap)141*8975f5c5SAndroid Build Coastguard Worker void MarkVaryingLocations(TDiagnostics *diagnostics,
142*8975f5c5SAndroid Build Coastguard Worker                           const TIntermSymbol *varying,
143*8975f5c5SAndroid Build Coastguard Worker                           const TField *field,
144*8975f5c5SAndroid Build Coastguard Worker                           int location,
145*8975f5c5SAndroid Build Coastguard Worker                           int elementCount,
146*8975f5c5SAndroid Build Coastguard Worker                           LocationMap *locationMap)
147*8975f5c5SAndroid Build Coastguard Worker {
148*8975f5c5SAndroid Build Coastguard Worker     for (int elementIndex = 0; elementIndex < elementCount; ++elementIndex)
149*8975f5c5SAndroid Build Coastguard Worker     {
150*8975f5c5SAndroid Build Coastguard Worker         const int offsetLocation = location + elementIndex;
151*8975f5c5SAndroid Build Coastguard Worker         auto conflict            = locationMap->find(offsetLocation);
152*8975f5c5SAndroid Build Coastguard Worker         if (conflict != locationMap->end())
153*8975f5c5SAndroid Build Coastguard Worker         {
154*8975f5c5SAndroid Build Coastguard Worker             std::stringstream strstr = sh::InitializeStream<std::stringstream>();
155*8975f5c5SAndroid Build Coastguard Worker             strstr << "'" << varying->getName();
156*8975f5c5SAndroid Build Coastguard Worker             if (field)
157*8975f5c5SAndroid Build Coastguard Worker             {
158*8975f5c5SAndroid Build Coastguard Worker                 strstr << "." << field->name();
159*8975f5c5SAndroid Build Coastguard Worker             }
160*8975f5c5SAndroid Build Coastguard Worker             strstr << "' conflicting location with '" << conflict->second.symbol->getName();
161*8975f5c5SAndroid Build Coastguard Worker             if (conflict->second.field)
162*8975f5c5SAndroid Build Coastguard Worker             {
163*8975f5c5SAndroid Build Coastguard Worker                 strstr << "." << conflict->second.field->name();
164*8975f5c5SAndroid Build Coastguard Worker             }
165*8975f5c5SAndroid Build Coastguard Worker             strstr << "'";
166*8975f5c5SAndroid Build Coastguard Worker             error(*varying, strstr.str().c_str(), diagnostics);
167*8975f5c5SAndroid Build Coastguard Worker         }
168*8975f5c5SAndroid Build Coastguard Worker         else
169*8975f5c5SAndroid Build Coastguard Worker         {
170*8975f5c5SAndroid Build Coastguard Worker             (*locationMap)[offsetLocation] = {varying, field};
171*8975f5c5SAndroid Build Coastguard Worker         }
172*8975f5c5SAndroid Build Coastguard Worker     }
173*8975f5c5SAndroid Build Coastguard Worker }
174*8975f5c5SAndroid Build Coastguard Worker 
175*8975f5c5SAndroid Build Coastguard Worker using VaryingVector = std::vector<const TIntermSymbol *>;
176*8975f5c5SAndroid Build Coastguard Worker 
ValidateShaderInterfaceAndAssignLocations(TDiagnostics * diagnostics,const VaryingVector & varyingVector,GLenum shaderType)177*8975f5c5SAndroid Build Coastguard Worker void ValidateShaderInterfaceAndAssignLocations(TDiagnostics *diagnostics,
178*8975f5c5SAndroid Build Coastguard Worker                                                const VaryingVector &varyingVector,
179*8975f5c5SAndroid Build Coastguard Worker                                                GLenum shaderType)
180*8975f5c5SAndroid Build Coastguard Worker {
181*8975f5c5SAndroid Build Coastguard Worker     // Location conflicts can only happen when there are two or more varyings in varyingVector.
182*8975f5c5SAndroid Build Coastguard Worker     if (varyingVector.size() <= 1)
183*8975f5c5SAndroid Build Coastguard Worker     {
184*8975f5c5SAndroid Build Coastguard Worker         return;
185*8975f5c5SAndroid Build Coastguard Worker     }
186*8975f5c5SAndroid Build Coastguard Worker 
187*8975f5c5SAndroid Build Coastguard Worker     LocationMap locationMap;
188*8975f5c5SAndroid Build Coastguard Worker     for (const TIntermSymbol *varying : varyingVector)
189*8975f5c5SAndroid Build Coastguard Worker     {
190*8975f5c5SAndroid Build Coastguard Worker         const TType &varyingType = varying->getType();
191*8975f5c5SAndroid Build Coastguard Worker         const int location       = varyingType.getLayoutQualifier().location;
192*8975f5c5SAndroid Build Coastguard Worker         ASSERT(location >= 0);
193*8975f5c5SAndroid Build Coastguard Worker 
194*8975f5c5SAndroid Build Coastguard Worker         bool ignoreVaryingArraySize =
195*8975f5c5SAndroid Build Coastguard Worker             ShouldIgnoreVaryingArraySize(varying->getQualifier(), shaderType);
196*8975f5c5SAndroid Build Coastguard Worker 
197*8975f5c5SAndroid Build Coastguard Worker         // A varying is either:
198*8975f5c5SAndroid Build Coastguard Worker         //
199*8975f5c5SAndroid Build Coastguard Worker         // - A vector or matrix, which can take a number of contiguous locations
200*8975f5c5SAndroid Build Coastguard Worker         // - A struct, which also takes a number of contiguous locations
201*8975f5c5SAndroid Build Coastguard Worker         // - An interface block.
202*8975f5c5SAndroid Build Coastguard Worker         //
203*8975f5c5SAndroid Build Coastguard Worker         // Interface blocks can assign arbitrary locations to their fields, for example:
204*8975f5c5SAndroid Build Coastguard Worker         //
205*8975f5c5SAndroid Build Coastguard Worker         //     layout(location = 4) in block {
206*8975f5c5SAndroid Build Coastguard Worker         //         vec4 a;                         // gets location 4
207*8975f5c5SAndroid Build Coastguard Worker         //         vec4 b;                         // gets location 5
208*8975f5c5SAndroid Build Coastguard Worker         //         layout(location = 7) vec4 c;    // gets location 7
209*8975f5c5SAndroid Build Coastguard Worker         //         vec4 d;                         // gets location 8
210*8975f5c5SAndroid Build Coastguard Worker         //         layout (location = 1) vec4 e;   // gets location 1
211*8975f5c5SAndroid Build Coastguard Worker         //         vec4 f;                         // gets location 2
212*8975f5c5SAndroid Build Coastguard Worker         //     };
213*8975f5c5SAndroid Build Coastguard Worker         //
214*8975f5c5SAndroid Build Coastguard Worker         // The following code therefore takes two paths.  For non-interface-block types, the number
215*8975f5c5SAndroid Build Coastguard Worker         // of locations for the varying is calculated (elementCount), and all locations in
216*8975f5c5SAndroid Build Coastguard Worker         // [location, location + elementCount) are marked as occupied.
217*8975f5c5SAndroid Build Coastguard Worker         //
218*8975f5c5SAndroid Build Coastguard Worker         // For interface blocks, a similar algorithm is implemented except each field is
219*8975f5c5SAndroid Build Coastguard Worker         // individually marked with the location either advancing automatically or taking its value
220*8975f5c5SAndroid Build Coastguard Worker         // from the field's layout qualifier.
221*8975f5c5SAndroid Build Coastguard Worker 
222*8975f5c5SAndroid Build Coastguard Worker         if (varyingType.isInterfaceBlock())
223*8975f5c5SAndroid Build Coastguard Worker         {
224*8975f5c5SAndroid Build Coastguard Worker             int currentLocation       = location;
225*8975f5c5SAndroid Build Coastguard Worker             bool anyFieldWithLocation = false;
226*8975f5c5SAndroid Build Coastguard Worker 
227*8975f5c5SAndroid Build Coastguard Worker             for (const TField *field : varyingType.getInterfaceBlock()->fields())
228*8975f5c5SAndroid Build Coastguard Worker             {
229*8975f5c5SAndroid Build Coastguard Worker                 const int fieldLocation = field->type()->getLayoutQualifier().location;
230*8975f5c5SAndroid Build Coastguard Worker                 if (fieldLocation >= 0)
231*8975f5c5SAndroid Build Coastguard Worker                 {
232*8975f5c5SAndroid Build Coastguard Worker                     currentLocation      = fieldLocation;
233*8975f5c5SAndroid Build Coastguard Worker                     anyFieldWithLocation = true;
234*8975f5c5SAndroid Build Coastguard Worker                 }
235*8975f5c5SAndroid Build Coastguard Worker 
236*8975f5c5SAndroid Build Coastguard Worker                 const int fieldLocationCount = GetFieldLocationCount(field);
237*8975f5c5SAndroid Build Coastguard Worker                 MarkVaryingLocations(diagnostics, varying, field, currentLocation,
238*8975f5c5SAndroid Build Coastguard Worker                                      fieldLocationCount, &locationMap);
239*8975f5c5SAndroid Build Coastguard Worker 
240*8975f5c5SAndroid Build Coastguard Worker                 currentLocation += fieldLocationCount;
241*8975f5c5SAndroid Build Coastguard Worker             }
242*8975f5c5SAndroid Build Coastguard Worker 
243*8975f5c5SAndroid Build Coastguard Worker             // Array interface blocks can't have location qualifiers on fields.
244*8975f5c5SAndroid Build Coastguard Worker             ASSERT(ignoreVaryingArraySize || !anyFieldWithLocation || !varyingType.isArray());
245*8975f5c5SAndroid Build Coastguard Worker 
246*8975f5c5SAndroid Build Coastguard Worker             if (!ignoreVaryingArraySize && varyingType.isArray())
247*8975f5c5SAndroid Build Coastguard Worker             {
248*8975f5c5SAndroid Build Coastguard Worker                 // This is only reached if the varying is an array of interface blocks, with only a
249*8975f5c5SAndroid Build Coastguard Worker                 // layout qualifier on the block itself, for example:
250*8975f5c5SAndroid Build Coastguard Worker                 //
251*8975f5c5SAndroid Build Coastguard Worker                 //     layout(location = 4) in block {
252*8975f5c5SAndroid Build Coastguard Worker                 //         vec4 a;
253*8975f5c5SAndroid Build Coastguard Worker                 //         vec4 b;
254*8975f5c5SAndroid Build Coastguard Worker                 //         vec4 c;
255*8975f5c5SAndroid Build Coastguard Worker                 //         vec4 d;
256*8975f5c5SAndroid Build Coastguard Worker                 //     } instance[N];
257*8975f5c5SAndroid Build Coastguard Worker                 //
258*8975f5c5SAndroid Build Coastguard Worker                 // The locations for instance[0] are already marked by the above code, so we need to
259*8975f5c5SAndroid Build Coastguard Worker                 // further mark locations occupied by instances [1, N).  |currentLocation| is
260*8975f5c5SAndroid Build Coastguard Worker                 // already just past the end of instance[0], which is the beginning of instance[1].
261*8975f5c5SAndroid Build Coastguard Worker                 //
262*8975f5c5SAndroid Build Coastguard Worker                 int remainingLocations = currentLocation * (varyingType.getArraySizeProduct() - 1);
263*8975f5c5SAndroid Build Coastguard Worker                 MarkVaryingLocations(diagnostics, varying, nullptr, currentLocation,
264*8975f5c5SAndroid Build Coastguard Worker                                      remainingLocations, &locationMap);
265*8975f5c5SAndroid Build Coastguard Worker             }
266*8975f5c5SAndroid Build Coastguard Worker         }
267*8975f5c5SAndroid Build Coastguard Worker         else
268*8975f5c5SAndroid Build Coastguard Worker         {
269*8975f5c5SAndroid Build Coastguard Worker             const int elementCount = GetLocationCount(varying->getType(), ignoreVaryingArraySize);
270*8975f5c5SAndroid Build Coastguard Worker             MarkVaryingLocations(diagnostics, varying, nullptr, location, elementCount,
271*8975f5c5SAndroid Build Coastguard Worker                                  &locationMap);
272*8975f5c5SAndroid Build Coastguard Worker         }
273*8975f5c5SAndroid Build Coastguard Worker     }
274*8975f5c5SAndroid Build Coastguard Worker }
275*8975f5c5SAndroid Build Coastguard Worker 
276*8975f5c5SAndroid Build Coastguard Worker class ValidateVaryingLocationsTraverser : public TIntermTraverser
277*8975f5c5SAndroid Build Coastguard Worker {
278*8975f5c5SAndroid Build Coastguard Worker   public:
279*8975f5c5SAndroid Build Coastguard Worker     ValidateVaryingLocationsTraverser(GLenum shaderType);
280*8975f5c5SAndroid Build Coastguard Worker     void validate(TDiagnostics *diagnostics);
281*8975f5c5SAndroid Build Coastguard Worker 
282*8975f5c5SAndroid Build Coastguard Worker   private:
283*8975f5c5SAndroid Build Coastguard Worker     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
284*8975f5c5SAndroid Build Coastguard Worker     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
285*8975f5c5SAndroid Build Coastguard Worker 
286*8975f5c5SAndroid Build Coastguard Worker     VaryingVector mInputVaryingsWithLocation;
287*8975f5c5SAndroid Build Coastguard Worker     VaryingVector mOutputVaryingsWithLocation;
288*8975f5c5SAndroid Build Coastguard Worker     GLenum mShaderType;
289*8975f5c5SAndroid Build Coastguard Worker };
290*8975f5c5SAndroid Build Coastguard Worker 
ValidateVaryingLocationsTraverser(GLenum shaderType)291*8975f5c5SAndroid Build Coastguard Worker ValidateVaryingLocationsTraverser::ValidateVaryingLocationsTraverser(GLenum shaderType)
292*8975f5c5SAndroid Build Coastguard Worker     : TIntermTraverser(true, false, false), mShaderType(shaderType)
293*8975f5c5SAndroid Build Coastguard Worker {}
294*8975f5c5SAndroid Build Coastguard Worker 
visitDeclaration(Visit visit,TIntermDeclaration * node)295*8975f5c5SAndroid Build Coastguard Worker bool ValidateVaryingLocationsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
296*8975f5c5SAndroid Build Coastguard Worker {
297*8975f5c5SAndroid Build Coastguard Worker     const TIntermSequence &sequence = *(node->getSequence());
298*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!sequence.empty());
299*8975f5c5SAndroid Build Coastguard Worker 
300*8975f5c5SAndroid Build Coastguard Worker     const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
301*8975f5c5SAndroid Build Coastguard Worker     if (symbol == nullptr)
302*8975f5c5SAndroid Build Coastguard Worker     {
303*8975f5c5SAndroid Build Coastguard Worker         return false;
304*8975f5c5SAndroid Build Coastguard Worker     }
305*8975f5c5SAndroid Build Coastguard Worker 
306*8975f5c5SAndroid Build Coastguard Worker     if (symbol->variable().symbolType() == SymbolType::Empty)
307*8975f5c5SAndroid Build Coastguard Worker     {
308*8975f5c5SAndroid Build Coastguard Worker         return false;
309*8975f5c5SAndroid Build Coastguard Worker     }
310*8975f5c5SAndroid Build Coastguard Worker 
311*8975f5c5SAndroid Build Coastguard Worker     // Collect varyings that have explicit 'location' qualifiers.
312*8975f5c5SAndroid Build Coastguard Worker     const TQualifier qualifier = symbol->getQualifier();
313*8975f5c5SAndroid Build Coastguard Worker     if (symbol->getType().getLayoutQualifier().location != -1)
314*8975f5c5SAndroid Build Coastguard Worker     {
315*8975f5c5SAndroid Build Coastguard Worker         if (IsVaryingIn(qualifier))
316*8975f5c5SAndroid Build Coastguard Worker         {
317*8975f5c5SAndroid Build Coastguard Worker             mInputVaryingsWithLocation.push_back(symbol);
318*8975f5c5SAndroid Build Coastguard Worker         }
319*8975f5c5SAndroid Build Coastguard Worker         else if (IsVaryingOut(qualifier))
320*8975f5c5SAndroid Build Coastguard Worker         {
321*8975f5c5SAndroid Build Coastguard Worker             mOutputVaryingsWithLocation.push_back(symbol);
322*8975f5c5SAndroid Build Coastguard Worker         }
323*8975f5c5SAndroid Build Coastguard Worker     }
324*8975f5c5SAndroid Build Coastguard Worker 
325*8975f5c5SAndroid Build Coastguard Worker     return false;
326*8975f5c5SAndroid Build Coastguard Worker }
327*8975f5c5SAndroid Build Coastguard Worker 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)328*8975f5c5SAndroid Build Coastguard Worker bool ValidateVaryingLocationsTraverser::visitFunctionDefinition(Visit visit,
329*8975f5c5SAndroid Build Coastguard Worker                                                                 TIntermFunctionDefinition *node)
330*8975f5c5SAndroid Build Coastguard Worker {
331*8975f5c5SAndroid Build Coastguard Worker     // We stop traversing function definitions because varyings cannot be defined in a function.
332*8975f5c5SAndroid Build Coastguard Worker     return false;
333*8975f5c5SAndroid Build Coastguard Worker }
334*8975f5c5SAndroid Build Coastguard Worker 
validate(TDiagnostics * diagnostics)335*8975f5c5SAndroid Build Coastguard Worker void ValidateVaryingLocationsTraverser::validate(TDiagnostics *diagnostics)
336*8975f5c5SAndroid Build Coastguard Worker {
337*8975f5c5SAndroid Build Coastguard Worker     ASSERT(diagnostics);
338*8975f5c5SAndroid Build Coastguard Worker 
339*8975f5c5SAndroid Build Coastguard Worker     ValidateShaderInterfaceAndAssignLocations(diagnostics, mInputVaryingsWithLocation, mShaderType);
340*8975f5c5SAndroid Build Coastguard Worker     ValidateShaderInterfaceAndAssignLocations(diagnostics, mOutputVaryingsWithLocation,
341*8975f5c5SAndroid Build Coastguard Worker                                               mShaderType);
342*8975f5c5SAndroid Build Coastguard Worker }
343*8975f5c5SAndroid Build Coastguard Worker 
344*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
345*8975f5c5SAndroid Build Coastguard Worker 
CalculateVaryingLocationCount(const TType & varyingType,GLenum shaderType)346*8975f5c5SAndroid Build Coastguard Worker unsigned int CalculateVaryingLocationCount(const TType &varyingType, GLenum shaderType)
347*8975f5c5SAndroid Build Coastguard Worker {
348*8975f5c5SAndroid Build Coastguard Worker     const TQualifier qualifier        = varyingType.getQualifier();
349*8975f5c5SAndroid Build Coastguard Worker     const bool ignoreVaryingArraySize = ShouldIgnoreVaryingArraySize(qualifier, shaderType);
350*8975f5c5SAndroid Build Coastguard Worker 
351*8975f5c5SAndroid Build Coastguard Worker     if (varyingType.isInterfaceBlock())
352*8975f5c5SAndroid Build Coastguard Worker     {
353*8975f5c5SAndroid Build Coastguard Worker         return GetInterfaceBlockLocationCount(varyingType, ignoreVaryingArraySize);
354*8975f5c5SAndroid Build Coastguard Worker     }
355*8975f5c5SAndroid Build Coastguard Worker 
356*8975f5c5SAndroid Build Coastguard Worker     return GetLocationCount(varyingType, ignoreVaryingArraySize);
357*8975f5c5SAndroid Build Coastguard Worker }
358*8975f5c5SAndroid Build Coastguard Worker 
ValidateVaryingLocations(TIntermBlock * root,TDiagnostics * diagnostics,GLenum shaderType)359*8975f5c5SAndroid Build Coastguard Worker bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics, GLenum shaderType)
360*8975f5c5SAndroid Build Coastguard Worker {
361*8975f5c5SAndroid Build Coastguard Worker     ValidateVaryingLocationsTraverser varyingValidator(shaderType);
362*8975f5c5SAndroid Build Coastguard Worker     root->traverse(&varyingValidator);
363*8975f5c5SAndroid Build Coastguard Worker     int numErrorsBefore = diagnostics->numErrors();
364*8975f5c5SAndroid Build Coastguard Worker     varyingValidator.validate(diagnostics);
365*8975f5c5SAndroid Build Coastguard Worker     return (diagnostics->numErrors() == numErrorsBefore);
366*8975f5c5SAndroid Build Coastguard Worker }
367*8975f5c5SAndroid Build Coastguard Worker 
368*8975f5c5SAndroid Build Coastguard Worker }  // namespace sh
369