• 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::__anonb34714300111::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 EvqIn:
515                     *joinedQualifier = EvqConstReadOnly;
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(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)632 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
633     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
634     TDiagnostics *diagnostics)
635 {
636     TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
637     for (size_t i = 1; i < sortedSequence.size(); ++i)
638     {
639         const TQualifierWrapperBase *qualifier = sortedSequence[i];
640         bool isQualifierValid                  = false;
641         switch (qualifier->getType())
642         {
643             case QtInvariant:
644             case QtPrecise:
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             default:
665                 UNREACHABLE();
666         }
667         if (!isQualifierValid)
668         {
669             const ImmutableString &qualifierString = qualifier->getQualifierString();
670             diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
671                                qualifierString.data());
672             break;
673         }
674     }
675 
676     switch (typeQualifier.qualifier)
677     {
678         case EvqIn:
679         case EvqConstReadOnly:  // const in
680         case EvqOut:
681         case EvqInOut:
682             break;
683         case EvqConst:
684             typeQualifier.qualifier = EvqConstReadOnly;
685             break;
686         case EvqTemporary:
687             // no qualifier has been specified, set it to EvqIn which is the default
688             typeQualifier.qualifier = EvqIn;
689             break;
690         default:
691             diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
692                                getQualifierString(typeQualifier.qualifier));
693     }
694     return typeQualifier;
695 }
696 }  // namespace
697 
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)698 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
699                                       TLayoutQualifier rightQualifier,
700                                       const TSourceLoc &rightQualifierLocation,
701                                       TDiagnostics *diagnostics)
702 {
703     TLayoutQualifier joinedQualifier = leftQualifier;
704 
705     if (rightQualifier.location != -1)
706     {
707         joinedQualifier.location = rightQualifier.location;
708         ++joinedQualifier.locationsSpecified;
709     }
710     if (rightQualifier.yuv != false)
711     {
712         joinedQualifier.yuv = rightQualifier.yuv;
713     }
714     if (rightQualifier.earlyFragmentTests != false)
715     {
716         joinedQualifier.earlyFragmentTests = rightQualifier.earlyFragmentTests;
717     }
718     if (rightQualifier.binding != -1)
719     {
720         joinedQualifier.binding = rightQualifier.binding;
721     }
722     if (rightQualifier.offset != -1)
723     {
724         joinedQualifier.offset = rightQualifier.offset;
725     }
726     if (rightQualifier.matrixPacking != EmpUnspecified)
727     {
728         joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
729     }
730     if (rightQualifier.blockStorage != EbsUnspecified)
731     {
732         joinedQualifier.blockStorage = rightQualifier.blockStorage;
733     }
734     if (rightQualifier.noncoherent != false)
735     {
736         joinedQualifier.noncoherent = rightQualifier.noncoherent;
737     }
738 
739     for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
740     {
741         if (rightQualifier.localSize[i] != -1)
742         {
743             if (joinedQualifier.localSize[i] != -1 &&
744                 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
745             {
746                 diagnostics->error(rightQualifierLocation,
747                                    "Cannot have multiple different work group size specifiers",
748                                    getWorkGroupSizeString(i));
749             }
750             joinedQualifier.localSize[i] = rightQualifier.localSize[i];
751         }
752     }
753 
754     if (rightQualifier.numViews != -1)
755     {
756         joinedQualifier.numViews = rightQualifier.numViews;
757     }
758 
759     if (rightQualifier.imageInternalFormat != EiifUnspecified)
760     {
761         joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
762     }
763 
764     if (rightQualifier.primitiveType != EptUndefined)
765     {
766         if (joinedQualifier.primitiveType != EptUndefined &&
767             joinedQualifier.primitiveType != rightQualifier.primitiveType)
768         {
769             diagnostics->error(rightQualifierLocation,
770                                "Cannot have multiple different primitive specifiers",
771                                getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
772         }
773         joinedQualifier.primitiveType = rightQualifier.primitiveType;
774     }
775 
776     if (rightQualifier.invocations != 0)
777     {
778         if (joinedQualifier.invocations != 0 &&
779             joinedQualifier.invocations != rightQualifier.invocations)
780         {
781             diagnostics->error(rightQualifierLocation,
782                                "Cannot have multiple different invocations specifiers",
783                                "invocations");
784         }
785         joinedQualifier.invocations = rightQualifier.invocations;
786     }
787 
788     if (rightQualifier.maxVertices != -1)
789     {
790         if (joinedQualifier.maxVertices != -1 &&
791             joinedQualifier.maxVertices != rightQualifier.maxVertices)
792         {
793             diagnostics->error(rightQualifierLocation,
794                                "Cannot have multiple different max_vertices specifiers",
795                                "max_vertices");
796         }
797         joinedQualifier.maxVertices = rightQualifier.maxVertices;
798     }
799 
800     if (rightQualifier.tesPrimitiveType != EtetUndefined)
801     {
802         if (joinedQualifier.tesPrimitiveType == EtetUndefined)
803         {
804             joinedQualifier.tesPrimitiveType = rightQualifier.tesPrimitiveType;
805         }
806     }
807 
808     if (rightQualifier.tesVertexSpacingType != EtetUndefined)
809     {
810         if (joinedQualifier.tesVertexSpacingType == EtetUndefined)
811         {
812             joinedQualifier.tesVertexSpacingType = rightQualifier.tesVertexSpacingType;
813         }
814     }
815 
816     if (rightQualifier.tesOrderingType != EtetUndefined)
817     {
818         if (joinedQualifier.tesOrderingType == EtetUndefined)
819         {
820             joinedQualifier.tesOrderingType = rightQualifier.tesOrderingType;
821         }
822     }
823 
824     if (rightQualifier.tesPointType != EtetUndefined)
825     {
826         if (joinedQualifier.tesPointType == EtetUndefined)
827         {
828             joinedQualifier.tesPointType = rightQualifier.tesPointType;
829         }
830     }
831 
832     if (rightQualifier.vertices != 0)
833     {
834         if (joinedQualifier.vertices != 0 && joinedQualifier.vertices != rightQualifier.vertices)
835         {
836             diagnostics->error(rightQualifierLocation,
837                                "Cannot have multiple different vertices specifiers", "vertices");
838         }
839         joinedQualifier.vertices = rightQualifier.vertices;
840     }
841 
842     if (rightQualifier.index != -1)
843     {
844         if (joinedQualifier.index != -1)
845         {
846             // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
847             diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
848                                "index");
849         }
850         joinedQualifier.index = rightQualifier.index;
851     }
852 
853     return joinedQualifier;
854 }
855 
getRank() const856 unsigned int TInvariantQualifierWrapper::getRank() const
857 {
858     return 0u;
859 }
860 
getRank() const861 unsigned int TPreciseQualifierWrapper::getRank() const
862 {
863     return 1u;
864 }
865 
getRank() const866 unsigned int TInterpolationQualifierWrapper::getRank() const
867 {
868     return 2u;
869 }
870 
getRank() const871 unsigned int TLayoutQualifierWrapper::getRank() const
872 {
873     return 3u;
874 }
875 
getRank() const876 unsigned int TStorageQualifierWrapper::getRank() const
877 {
878     // Force the 'centroid' auxilary storage qualifier to be always first among all storage
879     // qualifiers.
880     if (mStorageQualifier == EvqCentroid)
881     {
882         return 4u;
883     }
884     else
885     {
886         return 5u;
887     }
888 }
889 
getRank() const890 unsigned int TMemoryQualifierWrapper::getRank() const
891 {
892     return 5u;
893 }
894 
getRank() const895 unsigned int TPrecisionQualifierWrapper::getRank() const
896 {
897     return 6u;
898 }
899 
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)900 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
901     : layoutQualifier(TLayoutQualifier::Create()),
902       memoryQualifier(TMemoryQualifier::Create()),
903       precision(EbpUndefined),
904       qualifier(scope),
905       invariant(false),
906       precise(false),
907       line(loc)
908 {
909     ASSERT(IsScopeQualifier(qualifier));
910 }
911 
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)912 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
913                                              int shaderVersion)
914     : mShaderVersion(shaderVersion)
915 {
916     ASSERT(IsScopeQualifier(scope->getQualifier()));
917     mQualifiers.push_back(scope);
918 }
919 
appendQualifier(const TQualifierWrapperBase * qualifier)920 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
921 {
922     mQualifiers.push_back(qualifier);
923 }
924 
checkSequenceIsValid(TDiagnostics * diagnostics) const925 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
926 {
927     bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
928     ImmutableString errorMessage("");
929     if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
930     {
931         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
932         return false;
933     }
934 
935     if (!areQualifierChecksRelaxed &&
936         !AreQualifiersInOrder(mQualifiers, mShaderVersion, &errorMessage))
937     {
938         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
939         return false;
940     }
941 
942     return true;
943 }
944 
getParameterTypeQualifier(TDiagnostics * diagnostics) const945 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const
946 {
947     ASSERT(IsInvariantCorrect(mQualifiers));
948     ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
949            EvqTemporary);
950 
951     if (!checkSequenceIsValid(diagnostics))
952     {
953         return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
954     }
955 
956     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
957     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
958     // combine the qualifiers.
959     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
960     {
961         // Copy the qualifier sequence so that we can sort them.
962         QualifierSequence sortedQualifierSequence = mQualifiers;
963         SortSequence(sortedQualifierSequence);
964         return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
965     }
966     return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
967 }
968 
getVariableTypeQualifier(TDiagnostics * diagnostics) const969 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
970 {
971     ASSERT(IsInvariantCorrect(mQualifiers));
972 
973     if (!checkSequenceIsValid(diagnostics))
974     {
975         return TTypeQualifier(
976             static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
977             mQualifiers[0]->getLine());
978     }
979 
980     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
981     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
982     // combine the qualifiers.
983     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
984     {
985         // Copy the qualifier sequence so that we can sort them.
986         QualifierSequence sortedQualifierSequence = mQualifiers;
987         SortSequence(sortedQualifierSequence);
988         return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
989     }
990     return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
991 }
992 
993 }  // namespace sh
994