• 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                 {
182                     isOut = true;
183                 }
184                 for (size_t j = 1; j < i; ++j)
185                 {
186                     if (qualifiers[j]->getType() == QtStorage)
187                     {
188                         const TStorageQualifierWrapper *previousQualifierWrapper =
189                             static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
190                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
191                         if (currentQualifier == previousQualifier)
192                         {
193                             *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
194                                 previousQualifierWrapper->getQualifierString());
195                             return true;
196                         }
197                     }
198                 }
199                 break;
200             }
201             case QtMemory:
202             {
203                 // Go over all of the memory qualifiers up until the current one and check for
204                 // repetitions.
205                 // Having both readonly and writeonly in a sequence is valid.
206                 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
207                 TQualifier currentQualifier =
208                     static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
209                 for (size_t j = 1; j < i; ++j)
210                 {
211                     if (qualifiers[j]->getType() == QtMemory)
212                     {
213                         const TMemoryQualifierWrapper *previousQualifierWrapper =
214                             static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
215                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
216                         if (currentQualifier == previousQualifier)
217                         {
218                             *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
219                                 previousQualifierWrapper->getQualifierString());
220                             return true;
221                         }
222                     }
223                 }
224                 break;
225             }
226             default:
227                 UNREACHABLE();
228         }
229     }
230 
231     if (locationsSpecified > 1 && isOut)
232     {
233         // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
234         // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
235         // "The qualifier may appear at most once within a declaration."
236         *errorMessage = kOutputLayoutMultipleTimes;
237         return true;
238     }
239 
240     return false;
241 }
242 
243 // GLSL ES 3.00_6, 4.7 Order of Qualification
244 // The correct order of qualifiers is:
245 // invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
246 // layout-qualifier has to be before storage-qualifier.
247 //
248 // GLSL ES 3.1 relaxes the order of qualification:
249 // When multiple qualifiers are present in a declaration, they may appear in any order, but they
250 // must all appear before the type.
AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence & qualifiers,int shaderVersion,ImmutableString * errorMessage)251 bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
252                           int shaderVersion,
253                           ImmutableString *errorMessage)
254 {
255     if (shaderVersion >= 310)
256     {
257         return true;
258     }
259 
260     bool foundInterpolation = false;
261     bool foundStorage       = false;
262     bool foundPrecision     = false;
263     for (size_t i = 1; i < qualifiers.size(); ++i)
264     {
265         switch (qualifiers[i]->getType())
266         {
267             case QtInvariant:
268                 if (foundInterpolation || foundStorage || foundPrecision)
269                 {
270                     *errorMessage = kInvariantQualifierFirst;
271                     return false;
272                 }
273                 break;
274             case QtInterpolation:
275                 if (foundStorage)
276                 {
277                     *errorMessage = kStorageAfterInterpolation;
278                     return false;
279                 }
280                 else if (foundPrecision)
281                 {
282                     *errorMessage = kPrecisionAfterInterpolation;
283                     return false;
284                 }
285                 foundInterpolation = true;
286                 break;
287             case QtLayout:
288                 if (foundStorage)
289                 {
290                     *errorMessage = kStorageAfterLayout;
291                     return false;
292                 }
293                 else if (foundPrecision)
294                 {
295                     *errorMessage = kPrecisionAfterLayout;
296                     return false;
297                 }
298                 break;
299             case QtStorage:
300                 if (foundPrecision)
301                 {
302                     *errorMessage = kPrecisionAfterStorage;
303                     return false;
304                 }
305                 foundStorage = true;
306                 break;
307             case QtMemory:
308                 if (foundPrecision)
309                 {
310                     *errorMessage = kPrecisionAfterMemory;
311                     return false;
312                 }
313                 break;
314             case QtPrecision:
315                 foundPrecision = true;
316                 break;
317             case QtPrecise:
318                 // This keyword is available in ES3.1 (with extension) or in ES3.2, but the function
319                 // should early-out in such a case as the spec doesn't require a particular order to
320                 // the qualifiers.
321                 UNREACHABLE();
322                 break;
323             default:
324                 UNREACHABLE();
325         }
326     }
327     return true;
328 }
329 
330 struct QualifierComparator
331 {
operator ()sh::__anon4ab638540111::QualifierComparator332     bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
333     {
334         return q1->getRank() < q2->getRank();
335     }
336 };
337 
SortSequence(TTypeQualifierBuilder::QualifierSequence & qualifiers)338 void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
339 {
340     // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
341     // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
342     // and we always want it to be first.
343     std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
344 }
345 
346 // Handles the joining of storage qualifiers for variables.
JoinVariableStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)347 bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
348 {
349     switch (*joinedQualifier)
350     {
351         case EvqGlobal:
352             *joinedQualifier = storageQualifier;
353             break;
354         case EvqTemporary:
355         {
356             switch (storageQualifier)
357             {
358                 case EvqConst:
359                     *joinedQualifier = storageQualifier;
360                     break;
361                 default:
362                     return false;
363             }
364             break;
365         }
366         case EvqSmooth:
367         {
368             switch (storageQualifier)
369             {
370                 case EvqCentroid:
371                     *joinedQualifier = EvqCentroid;
372                     break;
373                 case EvqVertexOut:
374                 case EvqGeometryOut:
375                     *joinedQualifier = EvqSmoothOut;
376                     break;
377                 case EvqFragmentIn:
378                 case EvqGeometryIn:
379                     *joinedQualifier = EvqSmoothIn;
380                     break;
381                 default:
382                     return false;
383             }
384             break;
385         }
386         case EvqFlat:
387         {
388             switch (storageQualifier)
389             {
390                 case EvqCentroid:
391                     *joinedQualifier = EvqFlat;
392                     break;
393                 case EvqVertexOut:
394                 case EvqGeometryOut:
395                     *joinedQualifier = EvqFlatOut;
396                     break;
397                 case EvqFragmentIn:
398                 case EvqGeometryIn:
399                     *joinedQualifier = EvqFlatIn;
400                     break;
401                 default:
402                     return false;
403             }
404             break;
405         }
406         case EvqNoPerspective:
407         {
408             switch (storageQualifier)
409             {
410                 case EvqCentroid:
411                     *joinedQualifier = EvqNoPerspective;
412                     break;
413                 case EvqVertexOut:
414                 case EvqGeometryOut:
415                     *joinedQualifier = EvqNoPerspectiveOut;
416                     break;
417                 case EvqFragmentIn:
418                 case EvqGeometryIn:
419                     *joinedQualifier = EvqNoPerspectiveIn;
420                     break;
421                 default:
422                     return false;
423             }
424             break;
425         }
426         case EvqCentroid:
427         {
428             switch (storageQualifier)
429             {
430                 case EvqVertexOut:
431                 case EvqGeometryOut:
432                     *joinedQualifier = EvqCentroidOut;
433                     break;
434                 case EvqFragmentIn:
435                 case EvqGeometryIn:
436                     *joinedQualifier = EvqCentroidIn;
437                     break;
438                 default:
439                     return false;
440             }
441             break;
442         }
443         default:
444             return false;
445     }
446     return true;
447 }
448 
449 // Handles the joining of storage qualifiers for a parameter in a function.
JoinParameterStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)450 bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
451 {
452     switch (*joinedQualifier)
453     {
454         case EvqTemporary:
455             *joinedQualifier = storageQualifier;
456             break;
457         case EvqConst:
458         {
459             switch (storageQualifier)
460             {
461                 case EvqIn:
462                     *joinedQualifier = EvqConstReadOnly;
463                     break;
464                 default:
465                     return false;
466             }
467             break;
468         }
469         default:
470             return false;
471     }
472     return true;
473 }
474 
JoinMemoryQualifier(TMemoryQualifier * joinedMemoryQualifier,TQualifier memoryQualifier)475 bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
476 {
477     switch (memoryQualifier)
478     {
479         case EvqReadOnly:
480             joinedMemoryQualifier->readonly = true;
481             break;
482         case EvqWriteOnly:
483             joinedMemoryQualifier->writeonly = true;
484             break;
485         case EvqCoherent:
486             joinedMemoryQualifier->coherent = true;
487             break;
488         case EvqRestrict:
489             joinedMemoryQualifier->restrictQualifier = true;
490             break;
491         case EvqVolatile:
492             // Variables having the volatile qualifier are automatcally treated as coherent as well.
493             // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
494             joinedMemoryQualifier->volatileQualifier = true;
495             joinedMemoryQualifier->coherent          = true;
496             break;
497         default:
498             UNREACHABLE();
499     }
500     return true;
501 }
502 
GetVariableTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)503 TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
504     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
505     TDiagnostics *diagnostics)
506 {
507     TTypeQualifier typeQualifier(
508         static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
509         sortedSequence[0]->getLine());
510     for (size_t i = 1; i < sortedSequence.size(); ++i)
511     {
512         const TQualifierWrapperBase *qualifier = sortedSequence[i];
513         bool isQualifierValid                  = false;
514         switch (qualifier->getType())
515         {
516             case QtInvariant:
517                 isQualifierValid        = true;
518                 typeQualifier.invariant = true;
519                 break;
520             case QtPrecise:
521                 isQualifierValid      = true;
522                 typeQualifier.precise = true;
523                 break;
524             case QtInterpolation:
525             {
526                 switch (typeQualifier.qualifier)
527                 {
528                     case EvqGlobal:
529                         isQualifierValid = true;
530                         typeQualifier.qualifier =
531                             static_cast<const TInterpolationQualifierWrapper *>(qualifier)
532                                 ->getQualifier();
533                         break;
534                     default:
535                         isQualifierValid = false;
536                 }
537                 break;
538             }
539             case QtLayout:
540             {
541                 const TLayoutQualifierWrapper *layoutQualifierWrapper =
542                     static_cast<const TLayoutQualifierWrapper *>(qualifier);
543                 isQualifierValid              = true;
544                 typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
545                     typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
546                     layoutQualifierWrapper->getLine(), diagnostics);
547                 break;
548             }
549             case QtStorage:
550                 isQualifierValid = JoinVariableStorageQualifier(
551                     &typeQualifier.qualifier,
552                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
553                 break;
554             case QtPrecision:
555                 isQualifierValid = true;
556                 typeQualifier.precision =
557                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
558                 ASSERT(typeQualifier.precision != EbpUndefined);
559                 break;
560             case QtMemory:
561                 isQualifierValid = JoinMemoryQualifier(
562                     &typeQualifier.memoryQualifier,
563                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
564                 break;
565             default:
566                 UNREACHABLE();
567         }
568         if (!isQualifierValid)
569         {
570             const ImmutableString &qualifierString = qualifier->getQualifierString();
571             diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
572                                qualifierString.data());
573             break;
574         }
575     }
576     return typeQualifier;
577 }
578 
GetParameterTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)579 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
580     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
581     TDiagnostics *diagnostics)
582 {
583     TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
584     for (size_t i = 1; i < sortedSequence.size(); ++i)
585     {
586         const TQualifierWrapperBase *qualifier = sortedSequence[i];
587         bool isQualifierValid                  = false;
588         switch (qualifier->getType())
589         {
590             case QtInvariant:
591             case QtPrecise:
592             case QtInterpolation:
593             case QtLayout:
594                 break;
595             case QtMemory:
596                 isQualifierValid = JoinMemoryQualifier(
597                     &typeQualifier.memoryQualifier,
598                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
599                 break;
600             case QtStorage:
601                 isQualifierValid = JoinParameterStorageQualifier(
602                     &typeQualifier.qualifier,
603                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
604                 break;
605             case QtPrecision:
606                 isQualifierValid = true;
607                 typeQualifier.precision =
608                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
609                 ASSERT(typeQualifier.precision != EbpUndefined);
610                 break;
611             default:
612                 UNREACHABLE();
613         }
614         if (!isQualifierValid)
615         {
616             const ImmutableString &qualifierString = qualifier->getQualifierString();
617             diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
618                                qualifierString.data());
619             break;
620         }
621     }
622 
623     switch (typeQualifier.qualifier)
624     {
625         case EvqIn:
626         case EvqConstReadOnly:  // const in
627         case EvqOut:
628         case EvqInOut:
629             break;
630         case EvqConst:
631             typeQualifier.qualifier = EvqConstReadOnly;
632             break;
633         case EvqTemporary:
634             // no qualifier has been specified, set it to EvqIn which is the default
635             typeQualifier.qualifier = EvqIn;
636             break;
637         default:
638             diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
639                                getQualifierString(typeQualifier.qualifier));
640     }
641     return typeQualifier;
642 }
643 }  // namespace
644 
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)645 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
646                                       TLayoutQualifier rightQualifier,
647                                       const TSourceLoc &rightQualifierLocation,
648                                       TDiagnostics *diagnostics)
649 {
650     TLayoutQualifier joinedQualifier = leftQualifier;
651 
652     if (rightQualifier.location != -1)
653     {
654         joinedQualifier.location = rightQualifier.location;
655         ++joinedQualifier.locationsSpecified;
656     }
657     if (rightQualifier.yuv != false)
658     {
659         joinedQualifier.yuv = rightQualifier.yuv;
660     }
661     if (rightQualifier.earlyFragmentTests != false)
662     {
663         joinedQualifier.earlyFragmentTests = rightQualifier.earlyFragmentTests;
664     }
665     if (rightQualifier.binding != -1)
666     {
667         joinedQualifier.binding = rightQualifier.binding;
668     }
669     if (rightQualifier.offset != -1)
670     {
671         joinedQualifier.offset = rightQualifier.offset;
672     }
673     if (rightQualifier.matrixPacking != EmpUnspecified)
674     {
675         joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
676     }
677     if (rightQualifier.blockStorage != EbsUnspecified)
678     {
679         joinedQualifier.blockStorage = rightQualifier.blockStorage;
680     }
681 
682     for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
683     {
684         if (rightQualifier.localSize[i] != -1)
685         {
686             if (joinedQualifier.localSize[i] != -1 &&
687                 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
688             {
689                 diagnostics->error(rightQualifierLocation,
690                                    "Cannot have multiple different work group size specifiers",
691                                    getWorkGroupSizeString(i));
692             }
693             joinedQualifier.localSize[i] = rightQualifier.localSize[i];
694         }
695     }
696 
697     if (rightQualifier.numViews != -1)
698     {
699         joinedQualifier.numViews = rightQualifier.numViews;
700     }
701 
702     if (rightQualifier.imageInternalFormat != EiifUnspecified)
703     {
704         joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
705     }
706 
707     if (rightQualifier.primitiveType != EptUndefined)
708     {
709         if (joinedQualifier.primitiveType != EptUndefined &&
710             joinedQualifier.primitiveType != rightQualifier.primitiveType)
711         {
712             diagnostics->error(rightQualifierLocation,
713                                "Cannot have multiple different primitive specifiers",
714                                getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
715         }
716         joinedQualifier.primitiveType = rightQualifier.primitiveType;
717     }
718 
719     if (rightQualifier.invocations != 0)
720     {
721         if (joinedQualifier.invocations != 0 &&
722             joinedQualifier.invocations != rightQualifier.invocations)
723         {
724             diagnostics->error(rightQualifierLocation,
725                                "Cannot have multiple different invocations specifiers",
726                                "invocations");
727         }
728         joinedQualifier.invocations = rightQualifier.invocations;
729     }
730 
731     if (rightQualifier.maxVertices != -1)
732     {
733         if (joinedQualifier.maxVertices != -1 &&
734             joinedQualifier.maxVertices != rightQualifier.maxVertices)
735         {
736             diagnostics->error(rightQualifierLocation,
737                                "Cannot have multiple different max_vertices specifiers",
738                                "max_vertices");
739         }
740         joinedQualifier.maxVertices = rightQualifier.maxVertices;
741     }
742 
743     if (rightQualifier.index != -1)
744     {
745         if (joinedQualifier.index != -1)
746         {
747             // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
748             diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
749                                "index");
750         }
751         joinedQualifier.index = rightQualifier.index;
752     }
753 
754     return joinedQualifier;
755 }
756 
getRank() const757 unsigned int TInvariantQualifierWrapper::getRank() const
758 {
759     return 0u;
760 }
761 
getRank() const762 unsigned int TPreciseQualifierWrapper::getRank() const
763 {
764     return 1u;
765 }
766 
getRank() const767 unsigned int TInterpolationQualifierWrapper::getRank() const
768 {
769     return 2u;
770 }
771 
getRank() const772 unsigned int TLayoutQualifierWrapper::getRank() const
773 {
774     return 3u;
775 }
776 
getRank() const777 unsigned int TStorageQualifierWrapper::getRank() const
778 {
779     // Force the 'centroid' auxilary storage qualifier to be always first among all storage
780     // qualifiers.
781     if (mStorageQualifier == EvqCentroid)
782     {
783         return 4u;
784     }
785     else
786     {
787         return 5u;
788     }
789 }
790 
getRank() const791 unsigned int TMemoryQualifierWrapper::getRank() const
792 {
793     return 5u;
794 }
795 
getRank() const796 unsigned int TPrecisionQualifierWrapper::getRank() const
797 {
798     return 6u;
799 }
800 
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)801 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
802     : layoutQualifier(TLayoutQualifier::Create()),
803       memoryQualifier(TMemoryQualifier::Create()),
804       precision(EbpUndefined),
805       qualifier(scope),
806       invariant(false),
807       precise(false),
808       line(loc)
809 {
810     ASSERT(IsScopeQualifier(qualifier));
811 }
812 
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)813 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
814                                              int shaderVersion)
815     : mShaderVersion(shaderVersion)
816 {
817     ASSERT(IsScopeQualifier(scope->getQualifier()));
818     mQualifiers.push_back(scope);
819 }
820 
appendQualifier(const TQualifierWrapperBase * qualifier)821 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
822 {
823     mQualifiers.push_back(qualifier);
824 }
825 
checkSequenceIsValid(TDiagnostics * diagnostics) const826 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
827 {
828     bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
829     ImmutableString errorMessage("");
830     if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
831     {
832         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
833         return false;
834     }
835 
836     if (!areQualifierChecksRelaxed &&
837         !AreQualifiersInOrder(mQualifiers, mShaderVersion, &errorMessage))
838     {
839         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
840         return false;
841     }
842 
843     return true;
844 }
845 
getParameterTypeQualifier(TDiagnostics * diagnostics) const846 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const
847 {
848     ASSERT(IsInvariantCorrect(mQualifiers));
849     ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
850            EvqTemporary);
851 
852     if (!checkSequenceIsValid(diagnostics))
853     {
854         return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
855     }
856 
857     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
858     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
859     // combine the qualifiers.
860     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
861     {
862         // Copy the qualifier sequence so that we can sort them.
863         QualifierSequence sortedQualifierSequence = mQualifiers;
864         SortSequence(sortedQualifierSequence);
865         return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
866     }
867     return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
868 }
869 
getVariableTypeQualifier(TDiagnostics * diagnostics) const870 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
871 {
872     ASSERT(IsInvariantCorrect(mQualifiers));
873 
874     if (!checkSequenceIsValid(diagnostics))
875     {
876         return TTypeQualifier(
877             static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
878             mQualifiers[0]->getLine());
879     }
880 
881     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
882     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
883     // combine the qualifiers.
884     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
885     {
886         // Copy the qualifier sequence so that we can sort them.
887         QualifierSequence sortedQualifierSequence = mQualifiers;
888         SortSequence(sortedQualifierSequence);
889         return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
890     }
891     return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
892 }
893 
894 }  // namespace sh
895