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::__anonb34714300111::QualifierComparator333 bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
334 {
335 return q1->getRank() < q2->getRank();
336 }
337 };
338
SortSequence(TTypeQualifierBuilder::QualifierSequence & qualifiers)339 void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
340 {
341 // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
342 // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
343 // and we always want it to be first.
344 std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
345 }
346
347 // Handles the joining of storage qualifiers for variables.
JoinVariableStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)348 bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
349 {
350 switch (*joinedQualifier)
351 {
352 case EvqGlobal:
353 *joinedQualifier = storageQualifier;
354 break;
355 case EvqTemporary:
356 {
357 switch (storageQualifier)
358 {
359 case EvqConst:
360 *joinedQualifier = storageQualifier;
361 break;
362 default:
363 return false;
364 }
365 break;
366 }
367 case EvqSmooth:
368 {
369 switch (storageQualifier)
370 {
371 case EvqCentroid:
372 *joinedQualifier = EvqCentroid;
373 break;
374 case EvqVertexOut:
375 case EvqGeometryOut:
376 case EvqTessControlOut:
377 case EvqTessEvaluationOut:
378 *joinedQualifier = EvqSmoothOut;
379 break;
380 case EvqFragmentIn:
381 case EvqGeometryIn:
382 case EvqTessControlIn:
383 case EvqTessEvaluationIn:
384 *joinedQualifier = EvqSmoothIn;
385 break;
386 default:
387 return false;
388 }
389 break;
390 }
391 case EvqFlat:
392 {
393 switch (storageQualifier)
394 {
395 case EvqCentroid:
396 *joinedQualifier = EvqFlat;
397 break;
398 case EvqVertexOut:
399 case EvqGeometryOut:
400 case EvqTessControlOut:
401 case EvqTessEvaluationOut:
402 *joinedQualifier = EvqFlatOut;
403 break;
404 case EvqFragmentIn:
405 case EvqGeometryIn:
406 case EvqTessControlIn:
407 case EvqTessEvaluationIn:
408 *joinedQualifier = EvqFlatIn;
409 break;
410 default:
411 return false;
412 }
413 break;
414 }
415 case EvqNoPerspective:
416 {
417 switch (storageQualifier)
418 {
419 case EvqCentroid:
420 *joinedQualifier = EvqNoPerspective;
421 break;
422 case EvqVertexOut:
423 case EvqGeometryOut:
424 case EvqTessControlOut:
425 case EvqTessEvaluationOut:
426 *joinedQualifier = EvqNoPerspectiveOut;
427 break;
428 case EvqFragmentIn:
429 case EvqGeometryIn:
430 case EvqTessControlIn:
431 case EvqTessEvaluationIn:
432 *joinedQualifier = EvqNoPerspectiveIn;
433 break;
434 default:
435 return false;
436 }
437 break;
438 }
439 case EvqCentroid:
440 {
441 switch (storageQualifier)
442 {
443 case EvqVertexOut:
444 case EvqGeometryOut:
445 case EvqTessControlOut:
446 case EvqTessEvaluationOut:
447 *joinedQualifier = EvqCentroidOut;
448 break;
449 case EvqFragmentIn:
450 case EvqGeometryIn:
451 case EvqTessControlIn:
452 case EvqTessEvaluationIn:
453 *joinedQualifier = EvqCentroidIn;
454 break;
455 default:
456 return false;
457 }
458 break;
459 }
460 case EvqSample:
461 {
462 switch (storageQualifier)
463 {
464 case EvqVertexOut:
465 case EvqGeometryOut:
466 case EvqTessControlOut:
467 case EvqTessEvaluationOut:
468 *joinedQualifier = EvqSampleOut;
469 break;
470 case EvqFragmentIn:
471 case EvqGeometryIn:
472 case EvqTessControlIn:
473 case EvqTessEvaluationIn:
474 *joinedQualifier = EvqSampleIn;
475 break;
476 default:
477 return false;
478 }
479 break;
480 }
481 case EvqPatch:
482 {
483 switch (storageQualifier)
484 {
485 case EvqTessControlOut:
486 *joinedQualifier = EvqPatchOut;
487 break;
488 case EvqTessEvaluationIn:
489 *joinedQualifier = EvqPatchIn;
490 break;
491 default:
492 return false;
493 }
494 break;
495 }
496 default:
497 return false;
498 }
499 return true;
500 }
501
502 // Handles the joining of storage qualifiers for a parameter in a function.
JoinParameterStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)503 bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
504 {
505 switch (*joinedQualifier)
506 {
507 case EvqTemporary:
508 *joinedQualifier = storageQualifier;
509 break;
510 case EvqConst:
511 {
512 switch (storageQualifier)
513 {
514 case EvqIn:
515 *joinedQualifier = EvqConstReadOnly;
516 break;
517 default:
518 return false;
519 }
520 break;
521 }
522 default:
523 return false;
524 }
525 return true;
526 }
527
JoinMemoryQualifier(TMemoryQualifier * joinedMemoryQualifier,TQualifier memoryQualifier)528 bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
529 {
530 switch (memoryQualifier)
531 {
532 case EvqReadOnly:
533 joinedMemoryQualifier->readonly = true;
534 break;
535 case EvqWriteOnly:
536 joinedMemoryQualifier->writeonly = true;
537 break;
538 case EvqCoherent:
539 joinedMemoryQualifier->coherent = true;
540 break;
541 case EvqRestrict:
542 joinedMemoryQualifier->restrictQualifier = true;
543 break;
544 case EvqVolatile:
545 // Variables having the volatile qualifier are automatcally treated as coherent as well.
546 // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
547 joinedMemoryQualifier->volatileQualifier = true;
548 joinedMemoryQualifier->coherent = true;
549 break;
550 default:
551 UNREACHABLE();
552 }
553 return true;
554 }
555
GetVariableTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)556 TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
557 const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
558 TDiagnostics *diagnostics)
559 {
560 TTypeQualifier typeQualifier(
561 static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
562 sortedSequence[0]->getLine());
563 for (size_t i = 1; i < sortedSequence.size(); ++i)
564 {
565 const TQualifierWrapperBase *qualifier = sortedSequence[i];
566 bool isQualifierValid = false;
567 switch (qualifier->getType())
568 {
569 case QtInvariant:
570 isQualifierValid = true;
571 typeQualifier.invariant = true;
572 break;
573 case QtPrecise:
574 isQualifierValid = true;
575 typeQualifier.precise = true;
576 break;
577 case QtInterpolation:
578 {
579 switch (typeQualifier.qualifier)
580 {
581 case EvqGlobal:
582 isQualifierValid = true;
583 typeQualifier.qualifier =
584 static_cast<const TInterpolationQualifierWrapper *>(qualifier)
585 ->getQualifier();
586 break;
587 default:
588 isQualifierValid = false;
589 }
590 break;
591 }
592 case QtLayout:
593 {
594 const TLayoutQualifierWrapper *layoutQualifierWrapper =
595 static_cast<const TLayoutQualifierWrapper *>(qualifier);
596 isQualifierValid = true;
597 typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
598 typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
599 layoutQualifierWrapper->getLine(), diagnostics);
600 break;
601 }
602 case QtStorage:
603 isQualifierValid = JoinVariableStorageQualifier(
604 &typeQualifier.qualifier,
605 static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
606 break;
607 case QtPrecision:
608 isQualifierValid = true;
609 typeQualifier.precision =
610 static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
611 ASSERT(typeQualifier.precision != EbpUndefined);
612 break;
613 case QtMemory:
614 isQualifierValid = JoinMemoryQualifier(
615 &typeQualifier.memoryQualifier,
616 static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
617 break;
618 default:
619 UNREACHABLE();
620 }
621 if (!isQualifierValid)
622 {
623 const ImmutableString &qualifierString = qualifier->getQualifierString();
624 diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
625 qualifierString.data());
626 break;
627 }
628 }
629 return typeQualifier;
630 }
631
GetParameterTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)632 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
633 const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
634 TDiagnostics *diagnostics)
635 {
636 TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
637 for (size_t i = 1; i < sortedSequence.size(); ++i)
638 {
639 const TQualifierWrapperBase *qualifier = sortedSequence[i];
640 bool isQualifierValid = false;
641 switch (qualifier->getType())
642 {
643 case QtInvariant:
644 case QtPrecise:
645 case QtInterpolation:
646 case QtLayout:
647 break;
648 case QtMemory:
649 isQualifierValid = JoinMemoryQualifier(
650 &typeQualifier.memoryQualifier,
651 static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
652 break;
653 case QtStorage:
654 isQualifierValid = JoinParameterStorageQualifier(
655 &typeQualifier.qualifier,
656 static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
657 break;
658 case QtPrecision:
659 isQualifierValid = true;
660 typeQualifier.precision =
661 static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
662 ASSERT(typeQualifier.precision != EbpUndefined);
663 break;
664 default:
665 UNREACHABLE();
666 }
667 if (!isQualifierValid)
668 {
669 const ImmutableString &qualifierString = qualifier->getQualifierString();
670 diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
671 qualifierString.data());
672 break;
673 }
674 }
675
676 switch (typeQualifier.qualifier)
677 {
678 case EvqIn:
679 case EvqConstReadOnly: // const in
680 case EvqOut:
681 case EvqInOut:
682 break;
683 case EvqConst:
684 typeQualifier.qualifier = EvqConstReadOnly;
685 break;
686 case EvqTemporary:
687 // no qualifier has been specified, set it to EvqIn which is the default
688 typeQualifier.qualifier = EvqIn;
689 break;
690 default:
691 diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
692 getQualifierString(typeQualifier.qualifier));
693 }
694 return typeQualifier;
695 }
696 } // namespace
697
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)698 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
699 TLayoutQualifier rightQualifier,
700 const TSourceLoc &rightQualifierLocation,
701 TDiagnostics *diagnostics)
702 {
703 TLayoutQualifier joinedQualifier = leftQualifier;
704
705 if (rightQualifier.location != -1)
706 {
707 joinedQualifier.location = rightQualifier.location;
708 ++joinedQualifier.locationsSpecified;
709 }
710 if (rightQualifier.yuv != false)
711 {
712 joinedQualifier.yuv = rightQualifier.yuv;
713 }
714 if (rightQualifier.earlyFragmentTests != false)
715 {
716 joinedQualifier.earlyFragmentTests = rightQualifier.earlyFragmentTests;
717 }
718 if (rightQualifier.binding != -1)
719 {
720 joinedQualifier.binding = rightQualifier.binding;
721 }
722 if (rightQualifier.offset != -1)
723 {
724 joinedQualifier.offset = rightQualifier.offset;
725 }
726 if (rightQualifier.matrixPacking != EmpUnspecified)
727 {
728 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
729 }
730 if (rightQualifier.blockStorage != EbsUnspecified)
731 {
732 joinedQualifier.blockStorage = rightQualifier.blockStorage;
733 }
734 if (rightQualifier.noncoherent != false)
735 {
736 joinedQualifier.noncoherent = rightQualifier.noncoherent;
737 }
738
739 for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
740 {
741 if (rightQualifier.localSize[i] != -1)
742 {
743 if (joinedQualifier.localSize[i] != -1 &&
744 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
745 {
746 diagnostics->error(rightQualifierLocation,
747 "Cannot have multiple different work group size specifiers",
748 getWorkGroupSizeString(i));
749 }
750 joinedQualifier.localSize[i] = rightQualifier.localSize[i];
751 }
752 }
753
754 if (rightQualifier.numViews != -1)
755 {
756 joinedQualifier.numViews = rightQualifier.numViews;
757 }
758
759 if (rightQualifier.imageInternalFormat != EiifUnspecified)
760 {
761 joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
762 }
763
764 if (rightQualifier.primitiveType != EptUndefined)
765 {
766 if (joinedQualifier.primitiveType != EptUndefined &&
767 joinedQualifier.primitiveType != rightQualifier.primitiveType)
768 {
769 diagnostics->error(rightQualifierLocation,
770 "Cannot have multiple different primitive specifiers",
771 getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
772 }
773 joinedQualifier.primitiveType = rightQualifier.primitiveType;
774 }
775
776 if (rightQualifier.invocations != 0)
777 {
778 if (joinedQualifier.invocations != 0 &&
779 joinedQualifier.invocations != rightQualifier.invocations)
780 {
781 diagnostics->error(rightQualifierLocation,
782 "Cannot have multiple different invocations specifiers",
783 "invocations");
784 }
785 joinedQualifier.invocations = rightQualifier.invocations;
786 }
787
788 if (rightQualifier.maxVertices != -1)
789 {
790 if (joinedQualifier.maxVertices != -1 &&
791 joinedQualifier.maxVertices != rightQualifier.maxVertices)
792 {
793 diagnostics->error(rightQualifierLocation,
794 "Cannot have multiple different max_vertices specifiers",
795 "max_vertices");
796 }
797 joinedQualifier.maxVertices = rightQualifier.maxVertices;
798 }
799
800 if (rightQualifier.tesPrimitiveType != EtetUndefined)
801 {
802 if (joinedQualifier.tesPrimitiveType == EtetUndefined)
803 {
804 joinedQualifier.tesPrimitiveType = rightQualifier.tesPrimitiveType;
805 }
806 }
807
808 if (rightQualifier.tesVertexSpacingType != EtetUndefined)
809 {
810 if (joinedQualifier.tesVertexSpacingType == EtetUndefined)
811 {
812 joinedQualifier.tesVertexSpacingType = rightQualifier.tesVertexSpacingType;
813 }
814 }
815
816 if (rightQualifier.tesOrderingType != EtetUndefined)
817 {
818 if (joinedQualifier.tesOrderingType == EtetUndefined)
819 {
820 joinedQualifier.tesOrderingType = rightQualifier.tesOrderingType;
821 }
822 }
823
824 if (rightQualifier.tesPointType != EtetUndefined)
825 {
826 if (joinedQualifier.tesPointType == EtetUndefined)
827 {
828 joinedQualifier.tesPointType = rightQualifier.tesPointType;
829 }
830 }
831
832 if (rightQualifier.vertices != 0)
833 {
834 if (joinedQualifier.vertices != 0 && joinedQualifier.vertices != rightQualifier.vertices)
835 {
836 diagnostics->error(rightQualifierLocation,
837 "Cannot have multiple different vertices specifiers", "vertices");
838 }
839 joinedQualifier.vertices = rightQualifier.vertices;
840 }
841
842 if (rightQualifier.index != -1)
843 {
844 if (joinedQualifier.index != -1)
845 {
846 // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
847 diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
848 "index");
849 }
850 joinedQualifier.index = rightQualifier.index;
851 }
852
853 return joinedQualifier;
854 }
855
getRank() const856 unsigned int TInvariantQualifierWrapper::getRank() const
857 {
858 return 0u;
859 }
860
getRank() const861 unsigned int TPreciseQualifierWrapper::getRank() const
862 {
863 return 1u;
864 }
865
getRank() const866 unsigned int TInterpolationQualifierWrapper::getRank() const
867 {
868 return 2u;
869 }
870
getRank() const871 unsigned int TLayoutQualifierWrapper::getRank() const
872 {
873 return 3u;
874 }
875
getRank() const876 unsigned int TStorageQualifierWrapper::getRank() const
877 {
878 // Force the 'centroid' auxilary storage qualifier to be always first among all storage
879 // qualifiers.
880 if (mStorageQualifier == EvqCentroid)
881 {
882 return 4u;
883 }
884 else
885 {
886 return 5u;
887 }
888 }
889
getRank() const890 unsigned int TMemoryQualifierWrapper::getRank() const
891 {
892 return 5u;
893 }
894
getRank() const895 unsigned int TPrecisionQualifierWrapper::getRank() const
896 {
897 return 6u;
898 }
899
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)900 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
901 : layoutQualifier(TLayoutQualifier::Create()),
902 memoryQualifier(TMemoryQualifier::Create()),
903 precision(EbpUndefined),
904 qualifier(scope),
905 invariant(false),
906 precise(false),
907 line(loc)
908 {
909 ASSERT(IsScopeQualifier(qualifier));
910 }
911
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)912 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
913 int shaderVersion)
914 : mShaderVersion(shaderVersion)
915 {
916 ASSERT(IsScopeQualifier(scope->getQualifier()));
917 mQualifiers.push_back(scope);
918 }
919
appendQualifier(const TQualifierWrapperBase * qualifier)920 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
921 {
922 mQualifiers.push_back(qualifier);
923 }
924
checkSequenceIsValid(TDiagnostics * diagnostics) const925 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
926 {
927 bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
928 ImmutableString errorMessage("");
929 if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
930 {
931 diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
932 return false;
933 }
934
935 if (!areQualifierChecksRelaxed &&
936 !AreQualifiersInOrder(mQualifiers, mShaderVersion, &errorMessage))
937 {
938 diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
939 return false;
940 }
941
942 return true;
943 }
944
getParameterTypeQualifier(TDiagnostics * diagnostics) const945 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const
946 {
947 ASSERT(IsInvariantCorrect(mQualifiers));
948 ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
949 EvqTemporary);
950
951 if (!checkSequenceIsValid(diagnostics))
952 {
953 return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
954 }
955
956 // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
957 // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
958 // combine the qualifiers.
959 if (AreTypeQualifierChecksRelaxed(mShaderVersion))
960 {
961 // Copy the qualifier sequence so that we can sort them.
962 QualifierSequence sortedQualifierSequence = mQualifiers;
963 SortSequence(sortedQualifierSequence);
964 return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
965 }
966 return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
967 }
968
getVariableTypeQualifier(TDiagnostics * diagnostics) const969 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
970 {
971 ASSERT(IsInvariantCorrect(mQualifiers));
972
973 if (!checkSequenceIsValid(diagnostics))
974 {
975 return TTypeQualifier(
976 static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
977 mQualifiers[0]->getLine());
978 }
979
980 // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
981 // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
982 // combine the qualifiers.
983 if (AreTypeQualifierChecksRelaxed(mShaderVersion))
984 {
985 // Copy the qualifier sequence so that we can sort them.
986 QualifierSequence sortedQualifierSequence = mQualifiers;
987 SortSequence(sortedQualifierSequence);
988 return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
989 }
990 return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
991 }
992
993 } // namespace sh
994