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