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 ¤tQualifier =
157 static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier();
158 locationsSpecified += currentQualifier.locationsSpecified;
159 break;
160 }
161 case QtInterpolation:
162 {
163 // 'centroid' and 'sample' are treated as storage qualifiers
164 // 'flat centroid' and 'flat sample' will be squashed to 'flat'
165 // 'smooth centroid' will be squashed to 'centroid'
166 // 'smooth sample' will be squashed to 'sample'
167 if (interpolationFound)
168 {
169 *errorMessage = kInterpolationMultipleTimes;
170 return true;
171 }
172 interpolationFound = true;
173 break;
174 }
175 case QtStorage:
176 {
177 // Go over all of the storage qualifiers up until the current one and check for
178 // repetitions.
179 TQualifier currentQualifier =
180 static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier();
181 if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut ||
182 currentQualifier == EvqFragmentInOut)
183 {
184 isOut = true;
185 }
186 for (size_t j = 1; j < i; ++j)
187 {
188 if (qualifiers[j]->getType() == QtStorage)
189 {
190 const TStorageQualifierWrapper *previousQualifierWrapper =
191 static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
192 TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
193 if (currentQualifier == previousQualifier)
194 {
195 *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
196 previousQualifierWrapper->getQualifierString());
197 return true;
198 }
199 }
200 }
201 break;
202 }
203 case QtMemory:
204 {
205 // Go over all of the memory qualifiers up until the current one and check for
206 // repetitions.
207 // Having both readonly and writeonly in a sequence is valid.
208 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
209 TQualifier currentQualifier =
210 static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
211 for (size_t j = 1; j < i; ++j)
212 {
213 if (qualifiers[j]->getType() == QtMemory)
214 {
215 const TMemoryQualifierWrapper *previousQualifierWrapper =
216 static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
217 TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
218 if (currentQualifier == previousQualifier)
219 {
220 *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
221 previousQualifierWrapper->getQualifierString());
222 return true;
223 }
224 }
225 }
226 break;
227 }
228 default:
229 UNREACHABLE();
230 }
231 }
232
233 if (locationsSpecified > 1 && isOut)
234 {
235 // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
236 // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
237 // "The qualifier may appear at most once within a declaration."
238 *errorMessage = kOutputLayoutMultipleTimes;
239 return true;
240 }
241
242 return false;
243 }
244
245 // GLSL ES 3.00_6, 4.7 Order of Qualification
246 // The correct order of qualifiers is:
247 // invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
248 // layout-qualifier has to be before storage-qualifier.
249 //
250 // GLSL ES 3.1 relaxes the order of qualification:
251 // When multiple qualifiers are present in a declaration, they may appear in any order, but they
252 // must all appear before the type.
AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence & qualifiers,int shaderVersion,ImmutableString * errorMessage)253 bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
254 int shaderVersion,
255 ImmutableString *errorMessage)
256 {
257 if (shaderVersion >= 310)
258 {
259 return true;
260 }
261
262 bool foundInterpolation = false;
263 bool foundStorage = false;
264 bool foundPrecision = false;
265 for (size_t i = 1; i < qualifiers.size(); ++i)
266 {
267 switch (qualifiers[i]->getType())
268 {
269 case QtInvariant:
270 if (foundInterpolation || foundStorage || foundPrecision)
271 {
272 *errorMessage = kInvariantQualifierFirst;
273 return false;
274 }
275 break;
276 case QtInterpolation:
277 if (foundStorage)
278 {
279 *errorMessage = kStorageAfterInterpolation;
280 return false;
281 }
282 else if (foundPrecision)
283 {
284 *errorMessage = kPrecisionAfterInterpolation;
285 return false;
286 }
287 foundInterpolation = true;
288 break;
289 case QtLayout:
290 if (foundStorage)
291 {
292 *errorMessage = kStorageAfterLayout;
293 return false;
294 }
295 else if (foundPrecision)
296 {
297 *errorMessage = kPrecisionAfterLayout;
298 return false;
299 }
300 break;
301 case QtStorage:
302 if (foundPrecision)
303 {
304 *errorMessage = kPrecisionAfterStorage;
305 return false;
306 }
307 foundStorage = true;
308 break;
309 case QtMemory:
310 if (foundPrecision)
311 {
312 *errorMessage = kPrecisionAfterMemory;
313 return false;
314 }
315 break;
316 case QtPrecision:
317 foundPrecision = true;
318 break;
319 case QtPrecise:
320 // This keyword is available in ES3.1 (with extension) or in ES3.2, but the function
321 // should early-out in such a case as the spec doesn't require a particular order to
322 // the qualifiers.
323 UNREACHABLE();
324 break;
325 default:
326 UNREACHABLE();
327 }
328 }
329 return true;
330 }
331
332 struct QualifierComparator
333 {
operator ()sh::__anonc724bd5f0111::QualifierComparator334 bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
335 {
336 return q1->getRank() < q2->getRank();
337 }
338 };
339
SortSequence(TTypeQualifierBuilder::QualifierSequence & qualifiers)340 void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
341 {
342 // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
343 // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
344 // and we always want it to be first.
345 std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
346 }
347
348 // Handles the joining of storage qualifiers for variables.
JoinVariableStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)349 bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
350 {
351 switch (*joinedQualifier)
352 {
353 case EvqGlobal:
354 *joinedQualifier = storageQualifier;
355 break;
356 case EvqTemporary:
357 {
358 switch (storageQualifier)
359 {
360 case EvqConst:
361 *joinedQualifier = storageQualifier;
362 break;
363 default:
364 return false;
365 }
366 break;
367 }
368 case EvqSmooth:
369 {
370 switch (storageQualifier)
371 {
372 case EvqCentroid:
373 *joinedQualifier = EvqCentroid;
374 break;
375 case EvqSample:
376 *joinedQualifier = EvqSample;
377 break;
378 case EvqVertexOut:
379 case EvqGeometryOut:
380 case EvqTessControlOut:
381 case EvqTessEvaluationOut:
382 *joinedQualifier = EvqSmoothOut;
383 break;
384 case EvqFragmentIn:
385 case EvqGeometryIn:
386 case EvqTessControlIn:
387 case EvqTessEvaluationIn:
388 *joinedQualifier = EvqSmoothIn;
389 break;
390 default:
391 return false;
392 }
393 break;
394 }
395 case EvqFlat:
396 {
397 switch (storageQualifier)
398 {
399 case EvqCentroid:
400 case EvqSample:
401 *joinedQualifier = EvqFlat;
402 break;
403 case EvqVertexOut:
404 case EvqGeometryOut:
405 case EvqTessControlOut:
406 case EvqTessEvaluationOut:
407 *joinedQualifier = EvqFlatOut;
408 break;
409 case EvqFragmentIn:
410 case EvqGeometryIn:
411 case EvqTessControlIn:
412 case EvqTessEvaluationIn:
413 *joinedQualifier = EvqFlatIn;
414 break;
415 default:
416 return false;
417 }
418 break;
419 }
420 case EvqNoPerspective:
421 {
422 switch (storageQualifier)
423 {
424 case EvqCentroid:
425 *joinedQualifier = EvqNoPerspectiveCentroid;
426 break;
427 case EvqSample:
428 *joinedQualifier = EvqNoPerspectiveSample;
429 break;
430 case EvqVertexOut:
431 case EvqGeometryOut:
432 case EvqTessControlOut:
433 case EvqTessEvaluationOut:
434 *joinedQualifier = EvqNoPerspectiveOut;
435 break;
436 case EvqFragmentIn:
437 case EvqGeometryIn:
438 case EvqTessControlIn:
439 case EvqTessEvaluationIn:
440 *joinedQualifier = EvqNoPerspectiveIn;
441 break;
442 default:
443 return false;
444 }
445 break;
446 }
447 case EvqCentroid:
448 {
449 switch (storageQualifier)
450 {
451 case EvqVertexOut:
452 case EvqGeometryOut:
453 case EvqTessControlOut:
454 case EvqTessEvaluationOut:
455 *joinedQualifier = EvqCentroidOut;
456 break;
457 case EvqFragmentIn:
458 case EvqGeometryIn:
459 case EvqTessControlIn:
460 case EvqTessEvaluationIn:
461 *joinedQualifier = EvqCentroidIn;
462 break;
463 default:
464 return false;
465 }
466 break;
467 }
468 case EvqSample:
469 {
470 switch (storageQualifier)
471 {
472 case EvqVertexOut:
473 case EvqGeometryOut:
474 case EvqTessControlOut:
475 case EvqTessEvaluationOut:
476 *joinedQualifier = EvqSampleOut;
477 break;
478 case EvqFragmentIn:
479 case EvqGeometryIn:
480 case EvqTessControlIn:
481 case EvqTessEvaluationIn:
482 *joinedQualifier = EvqSampleIn;
483 break;
484 default:
485 return false;
486 }
487 break;
488 }
489 case EvqNoPerspectiveCentroid:
490 {
491 switch (storageQualifier)
492 {
493 case EvqVertexOut:
494 case EvqGeometryOut:
495 case EvqTessControlOut:
496 case EvqTessEvaluationOut:
497 *joinedQualifier = EvqNoPerspectiveCentroidOut;
498 break;
499 case EvqFragmentIn:
500 case EvqGeometryIn:
501 case EvqTessControlIn:
502 case EvqTessEvaluationIn:
503 *joinedQualifier = EvqNoPerspectiveCentroidIn;
504 break;
505 default:
506 return false;
507 }
508 break;
509 }
510 case EvqNoPerspectiveSample:
511 {
512 switch (storageQualifier)
513 {
514 case EvqVertexOut:
515 case EvqGeometryOut:
516 case EvqTessControlOut:
517 case EvqTessEvaluationOut:
518 *joinedQualifier = EvqNoPerspectiveSampleOut;
519 break;
520 case EvqFragmentIn:
521 case EvqGeometryIn:
522 case EvqTessControlIn:
523 case EvqTessEvaluationIn:
524 *joinedQualifier = EvqNoPerspectiveSampleIn;
525 break;
526 default:
527 return false;
528 }
529 break;
530 }
531 case EvqPatch:
532 {
533 switch (storageQualifier)
534 {
535 case EvqTessControlOut:
536 *joinedQualifier = EvqPatchOut;
537 break;
538 case EvqTessEvaluationIn:
539 *joinedQualifier = EvqPatchIn;
540 break;
541 default:
542 return false;
543 }
544 break;
545 }
546 default:
547 return false;
548 }
549 return true;
550 }
551
552 // Handles the joining of storage qualifiers for a parameter in a function.
JoinParameterStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)553 bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
554 {
555 switch (*joinedQualifier)
556 {
557 case EvqTemporary:
558 *joinedQualifier = storageQualifier;
559 break;
560 case EvqConst:
561 {
562 switch (storageQualifier)
563 {
564 case EvqParamIn:
565 *joinedQualifier = EvqParamConst;
566 break;
567 default:
568 return false;
569 }
570 break;
571 }
572 default:
573 return false;
574 }
575 return true;
576 }
577
JoinMemoryQualifier(TMemoryQualifier * joinedMemoryQualifier,TQualifier memoryQualifier)578 bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
579 {
580 switch (memoryQualifier)
581 {
582 case EvqReadOnly:
583 joinedMemoryQualifier->readonly = true;
584 break;
585 case EvqWriteOnly:
586 joinedMemoryQualifier->writeonly = true;
587 break;
588 case EvqCoherent:
589 joinedMemoryQualifier->coherent = true;
590 break;
591 case EvqRestrict:
592 joinedMemoryQualifier->restrictQualifier = true;
593 break;
594 case EvqVolatile:
595 // Variables having the volatile qualifier are automatcally treated as coherent as well.
596 // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
597 joinedMemoryQualifier->volatileQualifier = true;
598 joinedMemoryQualifier->coherent = true;
599 break;
600 default:
601 UNREACHABLE();
602 }
603 return true;
604 }
605
GetVariableTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)606 TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
607 const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
608 TDiagnostics *diagnostics)
609 {
610 TTypeQualifier typeQualifier(
611 static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
612 sortedSequence[0]->getLine());
613 for (size_t i = 1; i < sortedSequence.size(); ++i)
614 {
615 const TQualifierWrapperBase *qualifier = sortedSequence[i];
616 bool isQualifierValid = false;
617 switch (qualifier->getType())
618 {
619 case QtInvariant:
620 isQualifierValid = true;
621 typeQualifier.invariant = true;
622 break;
623 case QtPrecise:
624 isQualifierValid = true;
625 typeQualifier.precise = true;
626 break;
627 case QtInterpolation:
628 {
629 switch (typeQualifier.qualifier)
630 {
631 case EvqGlobal:
632 isQualifierValid = true;
633 typeQualifier.qualifier =
634 static_cast<const TInterpolationQualifierWrapper *>(qualifier)
635 ->getQualifier();
636 break;
637 default:
638 isQualifierValid = false;
639 }
640 break;
641 }
642 case QtLayout:
643 {
644 const TLayoutQualifierWrapper *layoutQualifierWrapper =
645 static_cast<const TLayoutQualifierWrapper *>(qualifier);
646 isQualifierValid = true;
647 typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
648 typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
649 layoutQualifierWrapper->getLine(), diagnostics);
650 break;
651 }
652 case QtStorage:
653 isQualifierValid = JoinVariableStorageQualifier(
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 QtMemory:
664 isQualifierValid = JoinMemoryQualifier(
665 &typeQualifier.memoryQualifier,
666 static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
667 break;
668 default:
669 UNREACHABLE();
670 }
671 if (!isQualifierValid)
672 {
673 const ImmutableString &qualifierString = qualifier->getQualifierString();
674 diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
675 qualifierString.data());
676 break;
677 }
678 }
679 return typeQualifier;
680 }
681
GetParameterTypeQualifierFromSortedSequence(TBasicType parameterBasicType,const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)682 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
683 TBasicType parameterBasicType,
684 const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
685 TDiagnostics *diagnostics)
686 {
687 TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
688 for (size_t i = 1; i < sortedSequence.size(); ++i)
689 {
690 const TQualifierWrapperBase *qualifier = sortedSequence[i];
691 bool isQualifierValid = false;
692 switch (qualifier->getType())
693 {
694 case QtInvariant:
695 case QtInterpolation:
696 case QtLayout:
697 break;
698 case QtMemory:
699 isQualifierValid = JoinMemoryQualifier(
700 &typeQualifier.memoryQualifier,
701 static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
702 break;
703 case QtStorage:
704 isQualifierValid = JoinParameterStorageQualifier(
705 &typeQualifier.qualifier,
706 static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
707 break;
708 case QtPrecision:
709 isQualifierValid = true;
710 typeQualifier.precision =
711 static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
712 ASSERT(typeQualifier.precision != EbpUndefined);
713 break;
714 case QtPrecise:
715 isQualifierValid = true;
716 typeQualifier.precise = true;
717 break;
718 default:
719 UNREACHABLE();
720 }
721 if (!isQualifierValid)
722 {
723 const ImmutableString &qualifierString = qualifier->getQualifierString();
724 diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
725 qualifierString.data());
726 break;
727 }
728 }
729
730 switch (typeQualifier.qualifier)
731 {
732 case EvqParamIn:
733 case EvqParamOut:
734 case EvqParamInOut:
735 break;
736 case EvqParamConst: // const in
737 case EvqConst:
738 // Opaque parameters can only be |in|. |const| is allowed, but is meaningless and is
739 // dropped.
740 typeQualifier.qualifier = IsOpaqueType(parameterBasicType) ? EvqParamIn : EvqParamConst;
741 break;
742 case EvqTemporary:
743 // no qualifier has been specified, set it to EvqParamIn which is the default
744 typeQualifier.qualifier = EvqParamIn;
745 break;
746 default:
747 diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
748 getQualifierString(typeQualifier.qualifier));
749 }
750 return typeQualifier;
751 }
752 } // namespace
753
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)754 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
755 TLayoutQualifier rightQualifier,
756 const TSourceLoc &rightQualifierLocation,
757 TDiagnostics *diagnostics)
758 {
759 TLayoutQualifier joinedQualifier = leftQualifier;
760
761 if (rightQualifier.location != -1)
762 {
763 joinedQualifier.location = rightQualifier.location;
764 ++joinedQualifier.locationsSpecified;
765 }
766 if (rightQualifier.depth != EdUnspecified)
767 {
768 if (joinedQualifier.depth != EdUnspecified)
769 {
770 diagnostics->error(rightQualifierLocation, "Cannot have multiple depth qualifiers",
771 getDepthString(rightQualifier.depth));
772 }
773 joinedQualifier.depth = rightQualifier.depth;
774 }
775 if (rightQualifier.yuv != false)
776 {
777 joinedQualifier.yuv = rightQualifier.yuv;
778 }
779 if (rightQualifier.earlyFragmentTests != false)
780 {
781 joinedQualifier.earlyFragmentTests = rightQualifier.earlyFragmentTests;
782 }
783 if (rightQualifier.binding != -1)
784 {
785 joinedQualifier.binding = rightQualifier.binding;
786 }
787 if (rightQualifier.offset != -1)
788 {
789 joinedQualifier.offset = rightQualifier.offset;
790 }
791 if (rightQualifier.matrixPacking != EmpUnspecified)
792 {
793 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
794 }
795 if (rightQualifier.blockStorage != EbsUnspecified)
796 {
797 joinedQualifier.blockStorage = rightQualifier.blockStorage;
798 }
799 if (rightQualifier.noncoherent != false)
800 {
801 joinedQualifier.noncoherent = rightQualifier.noncoherent;
802 }
803
804 for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
805 {
806 if (rightQualifier.localSize[i] != -1)
807 {
808 if (joinedQualifier.localSize[i] != -1 &&
809 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
810 {
811 diagnostics->error(rightQualifierLocation,
812 "Cannot have multiple different work group size specifiers",
813 getWorkGroupSizeString(i));
814 }
815 joinedQualifier.localSize[i] = rightQualifier.localSize[i];
816 }
817 }
818
819 if (rightQualifier.numViews != -1)
820 {
821 joinedQualifier.numViews = rightQualifier.numViews;
822 }
823
824 if (rightQualifier.imageInternalFormat != EiifUnspecified)
825 {
826 joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
827 }
828
829 if (rightQualifier.primitiveType != EptUndefined)
830 {
831 if (joinedQualifier.primitiveType != EptUndefined &&
832 joinedQualifier.primitiveType != rightQualifier.primitiveType)
833 {
834 diagnostics->error(rightQualifierLocation,
835 "Cannot have multiple different primitive specifiers",
836 getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
837 }
838 joinedQualifier.primitiveType = rightQualifier.primitiveType;
839 }
840
841 if (rightQualifier.invocations != 0)
842 {
843 if (joinedQualifier.invocations != 0 &&
844 joinedQualifier.invocations != rightQualifier.invocations)
845 {
846 diagnostics->error(rightQualifierLocation,
847 "Cannot have multiple different invocations specifiers",
848 "invocations");
849 }
850 joinedQualifier.invocations = rightQualifier.invocations;
851 }
852
853 if (rightQualifier.maxVertices != -1)
854 {
855 if (joinedQualifier.maxVertices != -1 &&
856 joinedQualifier.maxVertices != rightQualifier.maxVertices)
857 {
858 diagnostics->error(rightQualifierLocation,
859 "Cannot have multiple different max_vertices specifiers",
860 "max_vertices");
861 }
862 joinedQualifier.maxVertices = rightQualifier.maxVertices;
863 }
864
865 if (rightQualifier.tesPrimitiveType != EtetUndefined)
866 {
867 if (joinedQualifier.tesPrimitiveType == EtetUndefined)
868 {
869 joinedQualifier.tesPrimitiveType = rightQualifier.tesPrimitiveType;
870 }
871 }
872
873 if (rightQualifier.tesVertexSpacingType != EtetUndefined)
874 {
875 if (joinedQualifier.tesVertexSpacingType == EtetUndefined)
876 {
877 joinedQualifier.tesVertexSpacingType = rightQualifier.tesVertexSpacingType;
878 }
879 }
880
881 if (rightQualifier.tesOrderingType != EtetUndefined)
882 {
883 if (joinedQualifier.tesOrderingType == EtetUndefined)
884 {
885 joinedQualifier.tesOrderingType = rightQualifier.tesOrderingType;
886 }
887 }
888
889 if (rightQualifier.tesPointType != EtetUndefined)
890 {
891 if (joinedQualifier.tesPointType == EtetUndefined)
892 {
893 joinedQualifier.tesPointType = rightQualifier.tesPointType;
894 }
895 }
896
897 if (rightQualifier.vertices != 0)
898 {
899 if (joinedQualifier.vertices != 0 && joinedQualifier.vertices != rightQualifier.vertices)
900 {
901 diagnostics->error(rightQualifierLocation,
902 "Cannot have multiple different vertices specifiers", "vertices");
903 }
904 joinedQualifier.vertices = rightQualifier.vertices;
905 }
906
907 if (rightQualifier.index != -1)
908 {
909 if (joinedQualifier.index != -1)
910 {
911 // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
912 diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
913 "index");
914 }
915 joinedQualifier.index = rightQualifier.index;
916 }
917
918 if (rightQualifier.advancedBlendEquations.any())
919 {
920 joinedQualifier.advancedBlendEquations |= rightQualifier.advancedBlendEquations;
921 }
922
923 return joinedQualifier;
924 }
925
getRank() const926 unsigned int TInvariantQualifierWrapper::getRank() const
927 {
928 return 0u;
929 }
930
getRank() const931 unsigned int TPreciseQualifierWrapper::getRank() const
932 {
933 return 1u;
934 }
935
getRank() const936 unsigned int TInterpolationQualifierWrapper::getRank() const
937 {
938 return 2u;
939 }
940
getRank() const941 unsigned int TLayoutQualifierWrapper::getRank() const
942 {
943 return 3u;
944 }
945
getRank() const946 unsigned int TStorageQualifierWrapper::getRank() const
947 {
948 // Force the 'centroid' and 'sample' auxilary storage qualifiers
949 // to be always first among all storage qualifiers.
950 if (mStorageQualifier == EvqCentroid || mStorageQualifier == EvqSample)
951 {
952 return 4u;
953 }
954 else
955 {
956 return 5u;
957 }
958 }
959
getRank() const960 unsigned int TMemoryQualifierWrapper::getRank() const
961 {
962 return 5u;
963 }
964
getRank() const965 unsigned int TPrecisionQualifierWrapper::getRank() const
966 {
967 return 6u;
968 }
969
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)970 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
971 : layoutQualifier(TLayoutQualifier::Create()),
972 memoryQualifier(TMemoryQualifier::Create()),
973 precision(EbpUndefined),
974 qualifier(scope),
975 invariant(false),
976 precise(false),
977 line(loc)
978 {
979 ASSERT(IsScopeQualifier(qualifier));
980 }
981
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)982 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
983 int shaderVersion)
984 : mShaderVersion(shaderVersion)
985 {
986 ASSERT(IsScopeQualifier(scope->getQualifier()));
987 mQualifiers.push_back(scope);
988 }
989
appendQualifier(const TQualifierWrapperBase * qualifier)990 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
991 {
992 mQualifiers.push_back(qualifier);
993 }
994
checkSequenceIsValid(TDiagnostics * diagnostics) const995 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
996 {
997 bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
998 ImmutableString errorMessage("");
999 if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
1000 {
1001 diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
1002 return false;
1003 }
1004
1005 if (!areQualifierChecksRelaxed &&
1006 !AreQualifiersInOrder(mQualifiers, mShaderVersion, &errorMessage))
1007 {
1008 diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
1009 return false;
1010 }
1011
1012 return true;
1013 }
1014
getParameterTypeQualifier(TBasicType parameterBasicType,TDiagnostics * diagnostics) const1015 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TBasicType parameterBasicType,
1016 TDiagnostics *diagnostics) const
1017 {
1018 ASSERT(IsInvariantCorrect(mQualifiers));
1019 ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
1020 EvqTemporary);
1021
1022 if (!checkSequenceIsValid(diagnostics))
1023 {
1024 return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
1025 }
1026
1027 // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
1028 // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
1029 // combine the qualifiers.
1030 if (AreTypeQualifierChecksRelaxed(mShaderVersion))
1031 {
1032 // Copy the qualifier sequence so that we can sort them.
1033 QualifierSequence sortedQualifierSequence = mQualifiers;
1034 SortSequence(sortedQualifierSequence);
1035 return GetParameterTypeQualifierFromSortedSequence(parameterBasicType,
1036 sortedQualifierSequence, diagnostics);
1037 }
1038 return GetParameterTypeQualifierFromSortedSequence(parameterBasicType, mQualifiers,
1039 diagnostics);
1040 }
1041
getVariableTypeQualifier(TDiagnostics * diagnostics) const1042 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
1043 {
1044 ASSERT(IsInvariantCorrect(mQualifiers));
1045
1046 if (!checkSequenceIsValid(diagnostics))
1047 {
1048 return TTypeQualifier(
1049 static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
1050 mQualifiers[0]->getLine());
1051 }
1052
1053 // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
1054 // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
1055 // combine the qualifiers.
1056 if (AreTypeQualifierChecksRelaxed(mShaderVersion))
1057 {
1058 // Copy the qualifier sequence so that we can sort them.
1059 QualifierSequence sortedQualifierSequence = mQualifiers;
1060 SortSequence(sortedQualifierSequence);
1061 return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
1062 }
1063 return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
1064 }
1065
1066 } // namespace sh
1067