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