• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "compiler/translator/QualifierTypes.h"
8 
9 #include "compiler/translator/Diagnostics.h"
10 #include "compiler/translator/ImmutableStringBuilder.h"
11 
12 #include <algorithm>
13 
14 namespace sh
15 {
16 
17 namespace
18 {
19 
20 constexpr const ImmutableString kSpecifiedMultipleTimes(" specified multiple times");
21 constexpr const ImmutableString kInvariantMultipleTimes(
22     "The invariant qualifier specified multiple times.");
23 constexpr const ImmutableString kPreciseMultipleTimes(
24     "The precise qualifier specified multiple times.");
25 constexpr const ImmutableString kPrecisionMultipleTimes(
26     "The precision qualifier specified multiple times.");
27 constexpr const ImmutableString kLayoutMultipleTimes(
28     "The layout qualifier specified multiple times.");
29 constexpr const ImmutableString kLayoutAndInvariantDisallowed(
30     "The layout qualifier and invariant qualifier cannot coexist in the same "
31     "declaration according to the grammar.");
32 constexpr const ImmutableString kInterpolationMultipleTimes(
33     "The interpolation qualifier specified multiple times.");
34 constexpr const ImmutableString kOutputLayoutMultipleTimes(
35     "Output layout location specified multiple times.");
36 constexpr const ImmutableString kInvariantQualifierFirst(
37     "The invariant qualifier has to be first in the expression.");
38 constexpr const ImmutableString kStorageAfterInterpolation(
39     "Storage qualifiers have to be after interpolation qualifiers.");
40 constexpr const ImmutableString kPrecisionAfterInterpolation(
41     "Precision qualifiers have to be after interpolation qualifiers.");
42 constexpr const ImmutableString kStorageAfterLayout(
43     "Storage qualifiers have to be after layout qualifiers.");
44 constexpr const ImmutableString kPrecisionAfterLayout(
45     "Precision qualifiers have to be after layout qualifiers.");
46 constexpr const ImmutableString kPrecisionAfterStorage(
47     "Precision qualifiers have to be after storage qualifiers.");
48 constexpr const ImmutableString kPrecisionAfterMemory(
49     "Precision qualifiers have to be after memory qualifiers.");
50 
51 // GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout
52 // declarations.
53 // GLSL ES 3.10 Revision 4, 4.10 Order of Qualification
AreTypeQualifierChecksRelaxed(int shaderVersion)54 bool AreTypeQualifierChecksRelaxed(int shaderVersion)
55 {
56     return shaderVersion >= 310;
57 }
58 
IsScopeQualifier(TQualifier qualifier)59 bool IsScopeQualifier(TQualifier qualifier)
60 {
61     return qualifier == EvqGlobal || qualifier == EvqTemporary;
62 }
63 
IsScopeQualifierWrapper(const TQualifierWrapperBase * qualifier)64 bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier)
65 {
66     if (qualifier->getType() != QtStorage)
67         return false;
68     const TStorageQualifierWrapper *storageQualifier =
69         static_cast<const TStorageQualifierWrapper *>(qualifier);
70     TQualifier q = storageQualifier->getQualifier();
71     return IsScopeQualifier(q);
72 }
73 
74 // Returns true if the invariant/precise for the qualifier sequence holds
IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence & qualifiers)75 bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers)
76 {
77     // We should have at least one qualifier.
78     // The first qualifier always tells the scope.
79     return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]);
80 }
81 
QualifierSpecifiedMultipleTimesErrorMessage(const ImmutableString & qualifierString)82 ImmutableString QualifierSpecifiedMultipleTimesErrorMessage(const ImmutableString &qualifierString)
83 {
84     ImmutableStringBuilder errorMsg(qualifierString.length() + kSpecifiedMultipleTimes.length());
85     errorMsg << qualifierString << kSpecifiedMultipleTimes;
86     return errorMsg;
87 }
88 
89 // Returns true if there are qualifiers which have been specified multiple times
90 // If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed.
HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence & qualifiers,bool areQualifierChecksRelaxed,ImmutableString * errorMessage)91 bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
92                             bool areQualifierChecksRelaxed,
93                             ImmutableString *errorMessage)
94 {
95     bool invariantFound     = false;
96     bool preciseFound       = false;
97     bool precisionFound     = false;
98     bool layoutFound        = false;
99     bool interpolationFound = false;
100 
101     unsigned int locationsSpecified = 0;
102     bool isOut                      = false;
103 
104     // The iteration starts from one since the first qualifier only reveals the scope of the
105     // expression. It is inserted first whenever the sequence gets created.
106     for (size_t i = 1; i < qualifiers.size(); ++i)
107     {
108         switch (qualifiers[i]->getType())
109         {
110             case QtInvariant:
111             {
112                 if (invariantFound)
113                 {
114                     *errorMessage = kInvariantMultipleTimes;
115                     return true;
116                 }
117                 invariantFound = true;
118                 break;
119             }
120             case QtPrecise:
121             {
122                 if (preciseFound)
123                 {
124                     *errorMessage = kPreciseMultipleTimes;
125                     return true;
126                 }
127                 preciseFound = true;
128                 break;
129             }
130             case QtPrecision:
131             {
132                 if (precisionFound)
133                 {
134                     *errorMessage = kPrecisionMultipleTimes;
135                     return true;
136                 }
137                 precisionFound = true;
138                 break;
139             }
140             case QtLayout:
141             {
142                 if (layoutFound && !areQualifierChecksRelaxed)
143                 {
144                     *errorMessage = kLayoutMultipleTimes;
145                     return true;
146                 }
147                 if (invariantFound && !areQualifierChecksRelaxed)
148                 {
149                     // This combination is not correct according to the syntax specified in the
150                     // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have
151                     // a similar restriction.
152                     *errorMessage = kLayoutAndInvariantDisallowed;
153                     return true;
154                 }
155                 layoutFound = true;
156                 const TLayoutQualifier &currentQualifier =
157                     static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier();
158                 locationsSpecified += currentQualifier.locationsSpecified;
159                 break;
160             }
161             case QtInterpolation:
162             {
163                 // 'centroid' is treated as a storage qualifier
164                 // 'flat centroid' will be squashed to 'flat'
165                 // 'smooth centroid' will be squashed to 'centroid'
166                 if (interpolationFound)
167                 {
168                     *errorMessage = kInterpolationMultipleTimes;
169                     return true;
170                 }
171                 interpolationFound = true;
172                 break;
173             }
174             case QtStorage:
175             {
176                 // Go over all of the storage qualifiers up until the current one and check for
177                 // repetitions.
178                 TQualifier currentQualifier =
179                     static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier();
180                 if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut ||
181                     currentQualifier == EvqFragmentInOut)
182                 {
183                     isOut = true;
184                 }
185                 for (size_t j = 1; j < i; ++j)
186                 {
187                     if (qualifiers[j]->getType() == QtStorage)
188                     {
189                         const TStorageQualifierWrapper *previousQualifierWrapper =
190                             static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
191                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
192                         if (currentQualifier == previousQualifier)
193                         {
194                             *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
195                                 previousQualifierWrapper->getQualifierString());
196                             return true;
197                         }
198                     }
199                 }
200                 break;
201             }
202             case QtMemory:
203             {
204                 // Go over all of the memory qualifiers up until the current one and check for
205                 // repetitions.
206                 // Having both readonly and writeonly in a sequence is valid.
207                 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
208                 TQualifier currentQualifier =
209                     static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
210                 for (size_t j = 1; j < i; ++j)
211                 {
212                     if (qualifiers[j]->getType() == QtMemory)
213                     {
214                         const TMemoryQualifierWrapper *previousQualifierWrapper =
215                             static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
216                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
217                         if (currentQualifier == previousQualifier)
218                         {
219                             *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
220                                 previousQualifierWrapper->getQualifierString());
221                             return true;
222                         }
223                     }
224                 }
225                 break;
226             }
227             default:
228                 UNREACHABLE();
229         }
230     }
231 
232     if (locationsSpecified > 1 && isOut)
233     {
234         // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
235         // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
236         // "The qualifier may appear at most once within a declaration."
237         *errorMessage = kOutputLayoutMultipleTimes;
238         return true;
239     }
240 
241     return false;
242 }
243 
244 // GLSL ES 3.00_6, 4.7 Order of Qualification
245 // The correct order of qualifiers is:
246 // invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
247 // layout-qualifier has to be before storage-qualifier.
248 //
249 // GLSL ES 3.1 relaxes the order of qualification:
250 // When multiple qualifiers are present in a declaration, they may appear in any order, but they
251 // must all appear before the type.
AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence & qualifiers,int shaderVersion,ImmutableString * errorMessage)252 bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
253                           int shaderVersion,
254                           ImmutableString *errorMessage)
255 {
256     if (shaderVersion >= 310)
257     {
258         return true;
259     }
260 
261     bool foundInterpolation = false;
262     bool foundStorage       = false;
263     bool foundPrecision     = false;
264     for (size_t i = 1; i < qualifiers.size(); ++i)
265     {
266         switch (qualifiers[i]->getType())
267         {
268             case QtInvariant:
269                 if (foundInterpolation || foundStorage || foundPrecision)
270                 {
271                     *errorMessage = kInvariantQualifierFirst;
272                     return false;
273                 }
274                 break;
275             case QtInterpolation:
276                 if (foundStorage)
277                 {
278                     *errorMessage = kStorageAfterInterpolation;
279                     return false;
280                 }
281                 else if (foundPrecision)
282                 {
283                     *errorMessage = kPrecisionAfterInterpolation;
284                     return false;
285                 }
286                 foundInterpolation = true;
287                 break;
288             case QtLayout:
289                 if (foundStorage)
290                 {
291                     *errorMessage = kStorageAfterLayout;
292                     return false;
293                 }
294                 else if (foundPrecision)
295                 {
296                     *errorMessage = kPrecisionAfterLayout;
297                     return false;
298                 }
299                 break;
300             case QtStorage:
301                 if (foundPrecision)
302                 {
303                     *errorMessage = kPrecisionAfterStorage;
304                     return false;
305                 }
306                 foundStorage = true;
307                 break;
308             case QtMemory:
309                 if (foundPrecision)
310                 {
311                     *errorMessage = kPrecisionAfterMemory;
312                     return false;
313                 }
314                 break;
315             case QtPrecision:
316                 foundPrecision = true;
317                 break;
318             case QtPrecise:
319                 // This keyword is available in ES3.1 (with extension) or in ES3.2, but the function
320                 // should early-out in such a case as the spec doesn't require a particular order to
321                 // the qualifiers.
322                 UNREACHABLE();
323                 break;
324             default:
325                 UNREACHABLE();
326         }
327     }
328     return true;
329 }
330 
331 struct QualifierComparator
332 {
operator ()sh::__anoned6916150111::QualifierComparator333     bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
334     {
335         return q1->getRank() < q2->getRank();
336     }
337 };
338 
SortSequence(TTypeQualifierBuilder::QualifierSequence & qualifiers)339 void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
340 {
341     // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
342     // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
343     // and we always want it to be first.
344     std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
345 }
346 
347 // Handles the joining of storage qualifiers for variables.
JoinVariableStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)348 bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
349 {
350     switch (*joinedQualifier)
351     {
352         case EvqGlobal:
353             *joinedQualifier = storageQualifier;
354             break;
355         case EvqTemporary:
356         {
357             switch (storageQualifier)
358             {
359                 case EvqConst:
360                     *joinedQualifier = storageQualifier;
361                     break;
362                 default:
363                     return false;
364             }
365             break;
366         }
367         case EvqSmooth:
368         {
369             switch (storageQualifier)
370             {
371                 case EvqCentroid:
372                     *joinedQualifier = EvqCentroid;
373                     break;
374                 case EvqVertexOut:
375                 case EvqGeometryOut:
376                 case EvqTessControlOut:
377                 case EvqTessEvaluationOut:
378                     *joinedQualifier = EvqSmoothOut;
379                     break;
380                 case EvqFragmentIn:
381                 case EvqGeometryIn:
382                 case EvqTessControlIn:
383                 case EvqTessEvaluationIn:
384                     *joinedQualifier = EvqSmoothIn;
385                     break;
386                 default:
387                     return false;
388             }
389             break;
390         }
391         case EvqFlat:
392         {
393             switch (storageQualifier)
394             {
395                 case EvqCentroid:
396                     *joinedQualifier = EvqFlat;
397                     break;
398                 case EvqVertexOut:
399                 case EvqGeometryOut:
400                 case EvqTessControlOut:
401                 case EvqTessEvaluationOut:
402                     *joinedQualifier = EvqFlatOut;
403                     break;
404                 case EvqFragmentIn:
405                 case EvqGeometryIn:
406                 case EvqTessControlIn:
407                 case EvqTessEvaluationIn:
408                     *joinedQualifier = EvqFlatIn;
409                     break;
410                 default:
411                     return false;
412             }
413             break;
414         }
415         case EvqNoPerspective:
416         {
417             switch (storageQualifier)
418             {
419                 case EvqCentroid:
420                     *joinedQualifier = EvqNoPerspective;
421                     break;
422                 case EvqVertexOut:
423                 case EvqGeometryOut:
424                 case EvqTessControlOut:
425                 case EvqTessEvaluationOut:
426                     *joinedQualifier = EvqNoPerspectiveOut;
427                     break;
428                 case EvqFragmentIn:
429                 case EvqGeometryIn:
430                 case EvqTessControlIn:
431                 case EvqTessEvaluationIn:
432                     *joinedQualifier = EvqNoPerspectiveIn;
433                     break;
434                 default:
435                     return false;
436             }
437             break;
438         }
439         case EvqCentroid:
440         {
441             switch (storageQualifier)
442             {
443                 case EvqVertexOut:
444                 case EvqGeometryOut:
445                 case EvqTessControlOut:
446                 case EvqTessEvaluationOut:
447                     *joinedQualifier = EvqCentroidOut;
448                     break;
449                 case EvqFragmentIn:
450                 case EvqGeometryIn:
451                 case EvqTessControlIn:
452                 case EvqTessEvaluationIn:
453                     *joinedQualifier = EvqCentroidIn;
454                     break;
455                 default:
456                     return false;
457             }
458             break;
459         }
460         case EvqSample:
461         {
462             switch (storageQualifier)
463             {
464                 case EvqVertexOut:
465                 case EvqGeometryOut:
466                 case EvqTessControlOut:
467                 case EvqTessEvaluationOut:
468                     *joinedQualifier = EvqSampleOut;
469                     break;
470                 case EvqFragmentIn:
471                 case EvqGeometryIn:
472                 case EvqTessControlIn:
473                 case EvqTessEvaluationIn:
474                     *joinedQualifier = EvqSampleIn;
475                     break;
476                 default:
477                     return false;
478             }
479             break;
480         }
481         case EvqPatch:
482         {
483             switch (storageQualifier)
484             {
485                 case EvqTessControlOut:
486                     *joinedQualifier = EvqPatchOut;
487                     break;
488                 case EvqTessEvaluationIn:
489                     *joinedQualifier = EvqPatchIn;
490                     break;
491                 default:
492                     return false;
493             }
494             break;
495         }
496         default:
497             return false;
498     }
499     return true;
500 }
501 
502 // Handles the joining of storage qualifiers for a parameter in a function.
JoinParameterStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)503 bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
504 {
505     switch (*joinedQualifier)
506     {
507         case EvqTemporary:
508             *joinedQualifier = storageQualifier;
509             break;
510         case EvqConst:
511         {
512             switch (storageQualifier)
513             {
514                 case EvqParamIn:
515                     *joinedQualifier = EvqParamConst;
516                     break;
517                 default:
518                     return false;
519             }
520             break;
521         }
522         default:
523             return false;
524     }
525     return true;
526 }
527 
JoinMemoryQualifier(TMemoryQualifier * joinedMemoryQualifier,TQualifier memoryQualifier)528 bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
529 {
530     switch (memoryQualifier)
531     {
532         case EvqReadOnly:
533             joinedMemoryQualifier->readonly = true;
534             break;
535         case EvqWriteOnly:
536             joinedMemoryQualifier->writeonly = true;
537             break;
538         case EvqCoherent:
539             joinedMemoryQualifier->coherent = true;
540             break;
541         case EvqRestrict:
542             joinedMemoryQualifier->restrictQualifier = true;
543             break;
544         case EvqVolatile:
545             // Variables having the volatile qualifier are automatcally treated as coherent as well.
546             // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
547             joinedMemoryQualifier->volatileQualifier = true;
548             joinedMemoryQualifier->coherent          = true;
549             break;
550         default:
551             UNREACHABLE();
552     }
553     return true;
554 }
555 
GetVariableTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)556 TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
557     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
558     TDiagnostics *diagnostics)
559 {
560     TTypeQualifier typeQualifier(
561         static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
562         sortedSequence[0]->getLine());
563     for (size_t i = 1; i < sortedSequence.size(); ++i)
564     {
565         const TQualifierWrapperBase *qualifier = sortedSequence[i];
566         bool isQualifierValid                  = false;
567         switch (qualifier->getType())
568         {
569             case QtInvariant:
570                 isQualifierValid        = true;
571                 typeQualifier.invariant = true;
572                 break;
573             case QtPrecise:
574                 isQualifierValid      = true;
575                 typeQualifier.precise = true;
576                 break;
577             case QtInterpolation:
578             {
579                 switch (typeQualifier.qualifier)
580                 {
581                     case EvqGlobal:
582                         isQualifierValid = true;
583                         typeQualifier.qualifier =
584                             static_cast<const TInterpolationQualifierWrapper *>(qualifier)
585                                 ->getQualifier();
586                         break;
587                     default:
588                         isQualifierValid = false;
589                 }
590                 break;
591             }
592             case QtLayout:
593             {
594                 const TLayoutQualifierWrapper *layoutQualifierWrapper =
595                     static_cast<const TLayoutQualifierWrapper *>(qualifier);
596                 isQualifierValid              = true;
597                 typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
598                     typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
599                     layoutQualifierWrapper->getLine(), diagnostics);
600                 break;
601             }
602             case QtStorage:
603                 isQualifierValid = JoinVariableStorageQualifier(
604                     &typeQualifier.qualifier,
605                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
606                 break;
607             case QtPrecision:
608                 isQualifierValid = true;
609                 typeQualifier.precision =
610                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
611                 ASSERT(typeQualifier.precision != EbpUndefined);
612                 break;
613             case QtMemory:
614                 isQualifierValid = JoinMemoryQualifier(
615                     &typeQualifier.memoryQualifier,
616                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
617                 break;
618             default:
619                 UNREACHABLE();
620         }
621         if (!isQualifierValid)
622         {
623             const ImmutableString &qualifierString = qualifier->getQualifierString();
624             diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
625                                qualifierString.data());
626             break;
627         }
628     }
629     return typeQualifier;
630 }
631 
GetParameterTypeQualifierFromSortedSequence(TBasicType parameterBasicType,const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)632 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
633     TBasicType parameterBasicType,
634     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
635     TDiagnostics *diagnostics)
636 {
637     TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
638     for (size_t i = 1; i < sortedSequence.size(); ++i)
639     {
640         const TQualifierWrapperBase *qualifier = sortedSequence[i];
641         bool isQualifierValid                  = false;
642         switch (qualifier->getType())
643         {
644             case QtInvariant:
645             case QtInterpolation:
646             case QtLayout:
647                 break;
648             case QtMemory:
649                 isQualifierValid = JoinMemoryQualifier(
650                     &typeQualifier.memoryQualifier,
651                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
652                 break;
653             case QtStorage:
654                 isQualifierValid = JoinParameterStorageQualifier(
655                     &typeQualifier.qualifier,
656                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
657                 break;
658             case QtPrecision:
659                 isQualifierValid = true;
660                 typeQualifier.precision =
661                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
662                 ASSERT(typeQualifier.precision != EbpUndefined);
663                 break;
664             case QtPrecise:
665                 isQualifierValid      = true;
666                 typeQualifier.precise = true;
667                 break;
668             default:
669                 UNREACHABLE();
670         }
671         if (!isQualifierValid)
672         {
673             const ImmutableString &qualifierString = qualifier->getQualifierString();
674             diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
675                                qualifierString.data());
676             break;
677         }
678     }
679 
680     switch (typeQualifier.qualifier)
681     {
682         case EvqParamIn:
683         case EvqParamConst:  // const in
684         case EvqParamOut:
685         case EvqParamInOut:
686             break;
687         case EvqConst:
688             // Opaque parameters can only be |in|.  |const| is allowed, but is meaningless and is
689             // dropped.
690             typeQualifier.qualifier = IsOpaqueType(parameterBasicType) ? EvqParamIn : EvqParamConst;
691             break;
692         case EvqTemporary:
693             // no qualifier has been specified, set it to EvqParamIn which is the default
694             typeQualifier.qualifier = EvqParamIn;
695             break;
696         default:
697             diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
698                                getQualifierString(typeQualifier.qualifier));
699     }
700     return typeQualifier;
701 }
702 }  // namespace
703 
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)704 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
705                                       TLayoutQualifier rightQualifier,
706                                       const TSourceLoc &rightQualifierLocation,
707                                       TDiagnostics *diagnostics)
708 {
709     TLayoutQualifier joinedQualifier = leftQualifier;
710 
711     if (rightQualifier.location != -1)
712     {
713         joinedQualifier.location = rightQualifier.location;
714         ++joinedQualifier.locationsSpecified;
715     }
716     if (rightQualifier.yuv != false)
717     {
718         joinedQualifier.yuv = rightQualifier.yuv;
719     }
720     if (rightQualifier.earlyFragmentTests != false)
721     {
722         joinedQualifier.earlyFragmentTests = rightQualifier.earlyFragmentTests;
723     }
724     if (rightQualifier.binding != -1)
725     {
726         joinedQualifier.binding = rightQualifier.binding;
727     }
728     if (rightQualifier.offset != -1)
729     {
730         joinedQualifier.offset = rightQualifier.offset;
731     }
732     if (rightQualifier.matrixPacking != EmpUnspecified)
733     {
734         joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
735     }
736     if (rightQualifier.blockStorage != EbsUnspecified)
737     {
738         joinedQualifier.blockStorage = rightQualifier.blockStorage;
739     }
740     if (rightQualifier.noncoherent != false)
741     {
742         joinedQualifier.noncoherent = rightQualifier.noncoherent;
743     }
744 
745     for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
746     {
747         if (rightQualifier.localSize[i] != -1)
748         {
749             if (joinedQualifier.localSize[i] != -1 &&
750                 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
751             {
752                 diagnostics->error(rightQualifierLocation,
753                                    "Cannot have multiple different work group size specifiers",
754                                    getWorkGroupSizeString(i));
755             }
756             joinedQualifier.localSize[i] = rightQualifier.localSize[i];
757         }
758     }
759 
760     if (rightQualifier.numViews != -1)
761     {
762         joinedQualifier.numViews = rightQualifier.numViews;
763     }
764 
765     if (rightQualifier.imageInternalFormat != EiifUnspecified)
766     {
767         joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
768     }
769 
770     if (rightQualifier.primitiveType != EptUndefined)
771     {
772         if (joinedQualifier.primitiveType != EptUndefined &&
773             joinedQualifier.primitiveType != rightQualifier.primitiveType)
774         {
775             diagnostics->error(rightQualifierLocation,
776                                "Cannot have multiple different primitive specifiers",
777                                getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
778         }
779         joinedQualifier.primitiveType = rightQualifier.primitiveType;
780     }
781 
782     if (rightQualifier.invocations != 0)
783     {
784         if (joinedQualifier.invocations != 0 &&
785             joinedQualifier.invocations != rightQualifier.invocations)
786         {
787             diagnostics->error(rightQualifierLocation,
788                                "Cannot have multiple different invocations specifiers",
789                                "invocations");
790         }
791         joinedQualifier.invocations = rightQualifier.invocations;
792     }
793 
794     if (rightQualifier.maxVertices != -1)
795     {
796         if (joinedQualifier.maxVertices != -1 &&
797             joinedQualifier.maxVertices != rightQualifier.maxVertices)
798         {
799             diagnostics->error(rightQualifierLocation,
800                                "Cannot have multiple different max_vertices specifiers",
801                                "max_vertices");
802         }
803         joinedQualifier.maxVertices = rightQualifier.maxVertices;
804     }
805 
806     if (rightQualifier.tesPrimitiveType != EtetUndefined)
807     {
808         if (joinedQualifier.tesPrimitiveType == EtetUndefined)
809         {
810             joinedQualifier.tesPrimitiveType = rightQualifier.tesPrimitiveType;
811         }
812     }
813 
814     if (rightQualifier.tesVertexSpacingType != EtetUndefined)
815     {
816         if (joinedQualifier.tesVertexSpacingType == EtetUndefined)
817         {
818             joinedQualifier.tesVertexSpacingType = rightQualifier.tesVertexSpacingType;
819         }
820     }
821 
822     if (rightQualifier.tesOrderingType != EtetUndefined)
823     {
824         if (joinedQualifier.tesOrderingType == EtetUndefined)
825         {
826             joinedQualifier.tesOrderingType = rightQualifier.tesOrderingType;
827         }
828     }
829 
830     if (rightQualifier.tesPointType != EtetUndefined)
831     {
832         if (joinedQualifier.tesPointType == EtetUndefined)
833         {
834             joinedQualifier.tesPointType = rightQualifier.tesPointType;
835         }
836     }
837 
838     if (rightQualifier.vertices != 0)
839     {
840         if (joinedQualifier.vertices != 0 && joinedQualifier.vertices != rightQualifier.vertices)
841         {
842             diagnostics->error(rightQualifierLocation,
843                                "Cannot have multiple different vertices specifiers", "vertices");
844         }
845         joinedQualifier.vertices = rightQualifier.vertices;
846     }
847 
848     if (rightQualifier.index != -1)
849     {
850         if (joinedQualifier.index != -1)
851         {
852             // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
853             diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
854                                "index");
855         }
856         joinedQualifier.index = rightQualifier.index;
857     }
858 
859     if (rightQualifier.advancedBlendEquations.any())
860     {
861         joinedQualifier.advancedBlendEquations |= rightQualifier.advancedBlendEquations;
862     }
863 
864     return joinedQualifier;
865 }
866 
getRank() const867 unsigned int TInvariantQualifierWrapper::getRank() const
868 {
869     return 0u;
870 }
871 
getRank() const872 unsigned int TPreciseQualifierWrapper::getRank() const
873 {
874     return 1u;
875 }
876 
getRank() const877 unsigned int TInterpolationQualifierWrapper::getRank() const
878 {
879     return 2u;
880 }
881 
getRank() const882 unsigned int TLayoutQualifierWrapper::getRank() const
883 {
884     return 3u;
885 }
886 
getRank() const887 unsigned int TStorageQualifierWrapper::getRank() const
888 {
889     // Force the 'centroid' auxilary storage qualifier to be always first among all storage
890     // qualifiers.
891     if (mStorageQualifier == EvqCentroid)
892     {
893         return 4u;
894     }
895     else
896     {
897         return 5u;
898     }
899 }
900 
getRank() const901 unsigned int TMemoryQualifierWrapper::getRank() const
902 {
903     return 5u;
904 }
905 
getRank() const906 unsigned int TPrecisionQualifierWrapper::getRank() const
907 {
908     return 6u;
909 }
910 
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)911 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
912     : layoutQualifier(TLayoutQualifier::Create()),
913       memoryQualifier(TMemoryQualifier::Create()),
914       precision(EbpUndefined),
915       qualifier(scope),
916       invariant(false),
917       precise(false),
918       line(loc)
919 {
920     ASSERT(IsScopeQualifier(qualifier));
921 }
922 
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)923 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
924                                              int shaderVersion)
925     : mShaderVersion(shaderVersion)
926 {
927     ASSERT(IsScopeQualifier(scope->getQualifier()));
928     mQualifiers.push_back(scope);
929 }
930 
appendQualifier(const TQualifierWrapperBase * qualifier)931 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
932 {
933     mQualifiers.push_back(qualifier);
934 }
935 
checkSequenceIsValid(TDiagnostics * diagnostics) const936 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
937 {
938     bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
939     ImmutableString errorMessage("");
940     if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
941     {
942         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
943         return false;
944     }
945 
946     if (!areQualifierChecksRelaxed &&
947         !AreQualifiersInOrder(mQualifiers, mShaderVersion, &errorMessage))
948     {
949         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
950         return false;
951     }
952 
953     return true;
954 }
955 
getParameterTypeQualifier(TBasicType parameterBasicType,TDiagnostics * diagnostics) const956 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TBasicType parameterBasicType,
957                                                                 TDiagnostics *diagnostics) const
958 {
959     ASSERT(IsInvariantCorrect(mQualifiers));
960     ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
961            EvqTemporary);
962 
963     if (!checkSequenceIsValid(diagnostics))
964     {
965         return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
966     }
967 
968     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
969     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
970     // combine the qualifiers.
971     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
972     {
973         // Copy the qualifier sequence so that we can sort them.
974         QualifierSequence sortedQualifierSequence = mQualifiers;
975         SortSequence(sortedQualifierSequence);
976         return GetParameterTypeQualifierFromSortedSequence(parameterBasicType,
977                                                            sortedQualifierSequence, diagnostics);
978     }
979     return GetParameterTypeQualifierFromSortedSequence(parameterBasicType, mQualifiers,
980                                                        diagnostics);
981 }
982 
getVariableTypeQualifier(TDiagnostics * diagnostics) const983 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
984 {
985     ASSERT(IsInvariantCorrect(mQualifiers));
986 
987     if (!checkSequenceIsValid(diagnostics))
988     {
989         return TTypeQualifier(
990             static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
991             mQualifiers[0]->getLine());
992     }
993 
994     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
995     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
996     // combine the qualifiers.
997     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
998     {
999         // Copy the qualifier sequence so that we can sort them.
1000         QualifierSequence sortedQualifierSequence = mQualifiers;
1001         SortSequence(sortedQualifierSequence);
1002         return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
1003     }
1004     return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
1005 }
1006 
1007 }  // namespace sh
1008