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' 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