1 //
2 // Copyright (c) 2002-2016 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
11 #include <algorithm>
12
13 namespace sh
14 {
15
16 namespace
17 {
18
19 // GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout
20 // declarations.
21 // GLSL ES 3.10 Revision 4, 4.10 Order of Qualification
AreTypeQualifierChecksRelaxed(int shaderVersion)22 bool AreTypeQualifierChecksRelaxed(int shaderVersion)
23 {
24 return shaderVersion >= 310;
25 }
26
IsScopeQualifier(TQualifier qualifier)27 bool IsScopeQualifier(TQualifier qualifier)
28 {
29 return qualifier == EvqGlobal || qualifier == EvqTemporary;
30 }
31
IsScopeQualifierWrapper(const TQualifierWrapperBase * qualifier)32 bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier)
33 {
34 if (qualifier->getType() != QtStorage)
35 return false;
36 const TStorageQualifierWrapper *storageQualifier =
37 static_cast<const TStorageQualifierWrapper *>(qualifier);
38 TQualifier q = storageQualifier->getQualifier();
39 return IsScopeQualifier(q);
40 }
41
42 // Returns true if the invariant for the qualifier sequence holds
IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence & qualifiers)43 bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers)
44 {
45 // We should have at least one qualifier.
46 // The first qualifier always tells the scope.
47 return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]);
48 }
49
50 // Returns true if there are qualifiers which have been specified multiple times
51 // If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed.
HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence & qualifiers,bool areQualifierChecksRelaxed,std::string * errorMessage)52 bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
53 bool areQualifierChecksRelaxed,
54 std::string *errorMessage)
55 {
56 bool invariantFound = false;
57 bool precisionFound = false;
58 bool layoutFound = false;
59 bool interpolationFound = false;
60
61 unsigned int locationsSpecified = 0;
62 bool isOut = false;
63
64 // The iteration starts from one since the first qualifier only reveals the scope of the
65 // expression. It is inserted first whenever the sequence gets created.
66 for (size_t i = 1; i < qualifiers.size(); ++i)
67 {
68 switch (qualifiers[i]->getType())
69 {
70 case QtInvariant:
71 {
72 if (invariantFound)
73 {
74 *errorMessage = "The invariant qualifier specified multiple times.";
75 return true;
76 }
77 invariantFound = true;
78 break;
79 }
80 case QtPrecision:
81 {
82 if (precisionFound)
83 {
84 *errorMessage = "The precision qualifier specified multiple times.";
85 return true;
86 }
87 precisionFound = true;
88 break;
89 }
90 case QtLayout:
91 {
92 if (layoutFound && !areQualifierChecksRelaxed)
93 {
94 *errorMessage = "The layout qualifier specified multiple times.";
95 return true;
96 }
97 if (invariantFound && !areQualifierChecksRelaxed)
98 {
99 // This combination is not correct according to the syntax specified in the
100 // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have
101 // a similar restriction.
102 *errorMessage =
103 "The layout qualifier and invariant qualifier cannot coexist in the same "
104 "declaration according to the grammar.";
105 return true;
106 }
107 layoutFound = true;
108 const TLayoutQualifier ¤tQualifier =
109 static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier();
110 locationsSpecified += currentQualifier.locationsSpecified;
111 break;
112 }
113 case QtInterpolation:
114 {
115 // 'centroid' is treated as a storage qualifier
116 // 'flat centroid' will be squashed to 'flat'
117 // 'smooth centroid' will be squashed to 'centroid'
118 if (interpolationFound)
119 {
120 *errorMessage = "The interpolation qualifier specified multiple times.";
121 return true;
122 }
123 interpolationFound = true;
124 break;
125 }
126 case QtStorage:
127 {
128 // Go over all of the storage qualifiers up until the current one and check for
129 // repetitions.
130 TQualifier currentQualifier =
131 static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier();
132 if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut)
133 {
134 isOut = true;
135 }
136 for (size_t j = 1; j < i; ++j)
137 {
138 if (qualifiers[j]->getType() == QtStorage)
139 {
140 const TStorageQualifierWrapper *previousQualifierWrapper =
141 static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
142 TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
143 if (currentQualifier == previousQualifier)
144 {
145 *errorMessage = previousQualifierWrapper->getQualifierString().c_str();
146 *errorMessage += " specified multiple times";
147 return true;
148 }
149 }
150 }
151 break;
152 }
153 case QtMemory:
154 {
155 // Go over all of the memory qualifiers up until the current one and check for
156 // repetitions.
157 // Having both readonly and writeonly in a sequence is valid.
158 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
159 TQualifier currentQualifier =
160 static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
161 for (size_t j = 1; j < i; ++j)
162 {
163 if (qualifiers[j]->getType() == QtMemory)
164 {
165 const TMemoryQualifierWrapper *previousQualifierWrapper =
166 static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
167 TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
168 if (currentQualifier == previousQualifier)
169 {
170 *errorMessage = previousQualifierWrapper->getQualifierString().c_str();
171 *errorMessage += " specified multiple times";
172 return true;
173 }
174 }
175 }
176 break;
177 }
178 default:
179 UNREACHABLE();
180 }
181 }
182
183 if (locationsSpecified > 1 && isOut)
184 {
185 // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
186 // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
187 // "The qualifier may appear at most once within a declaration."
188 *errorMessage = "Output layout location specified multiple times.";
189 return true;
190 }
191
192 return false;
193 }
194
195 // GLSL ES 3.00_6, 4.7 Order of Qualification
196 // The correct order of qualifiers is:
197 // invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
198 // layout-qualifier has to be before storage-qualifier.
AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence & qualifiers,std::string * errorMessage)199 bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
200 std::string *errorMessage)
201 {
202 bool foundInterpolation = false;
203 bool foundStorage = false;
204 bool foundPrecision = false;
205 for (size_t i = 1; i < qualifiers.size(); ++i)
206 {
207 switch (qualifiers[i]->getType())
208 {
209 case QtInvariant:
210 if (foundInterpolation || foundStorage || foundPrecision)
211 {
212 *errorMessage = "The invariant qualifier has to be first in the expression.";
213 return false;
214 }
215 break;
216 case QtInterpolation:
217 if (foundStorage)
218 {
219 *errorMessage = "Storage qualifiers have to be after interpolation qualifiers.";
220 return false;
221 }
222 else if (foundPrecision)
223 {
224 *errorMessage =
225 "Precision qualifiers have to be after interpolation qualifiers.";
226 return false;
227 }
228 foundInterpolation = true;
229 break;
230 case QtLayout:
231 if (foundStorage)
232 {
233 *errorMessage = "Storage qualifiers have to be after layout qualifiers.";
234 return false;
235 }
236 else if (foundPrecision)
237 {
238 *errorMessage = "Precision qualifiers have to be after layout qualifiers.";
239 return false;
240 }
241 break;
242 case QtStorage:
243 if (foundPrecision)
244 {
245 *errorMessage = "Precision qualifiers have to be after storage qualifiers.";
246 return false;
247 }
248 foundStorage = true;
249 break;
250 case QtMemory:
251 if (foundPrecision)
252 {
253 *errorMessage = "Precision qualifiers have to be after memory qualifiers.";
254 return false;
255 }
256 break;
257 case QtPrecision:
258 foundPrecision = true;
259 break;
260 default:
261 UNREACHABLE();
262 }
263 }
264 return true;
265 }
266
267 struct QualifierComparator
268 {
operator ()sh::__anon268cebfe0111::QualifierComparator269 bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
270 {
271 return q1->getRank() < q2->getRank();
272 }
273 };
274
SortSequence(TTypeQualifierBuilder::QualifierSequence & qualifiers)275 void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
276 {
277 // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
278 // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
279 // and we always want it to be first.
280 std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
281 }
282
283 // Handles the joining of storage qualifiers for variables.
JoinVariableStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)284 bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
285 {
286 switch (*joinedQualifier)
287 {
288 case EvqGlobal:
289 *joinedQualifier = storageQualifier;
290 break;
291 case EvqTemporary:
292 {
293 switch (storageQualifier)
294 {
295 case EvqConst:
296 *joinedQualifier = storageQualifier;
297 break;
298 default:
299 return false;
300 }
301 break;
302 }
303 case EvqSmooth:
304 {
305 switch (storageQualifier)
306 {
307 case EvqCentroid:
308 *joinedQualifier = EvqCentroid;
309 break;
310 case EvqVertexOut:
311 case EvqGeometryOut:
312 *joinedQualifier = EvqSmoothOut;
313 break;
314 case EvqFragmentIn:
315 case EvqGeometryIn:
316 *joinedQualifier = EvqSmoothIn;
317 break;
318 default:
319 return false;
320 }
321 break;
322 }
323 case EvqFlat:
324 {
325 switch (storageQualifier)
326 {
327 case EvqCentroid:
328 *joinedQualifier = EvqFlat;
329 break;
330 case EvqVertexOut:
331 case EvqGeometryOut:
332 *joinedQualifier = EvqFlatOut;
333 break;
334 case EvqFragmentIn:
335 case EvqGeometryIn:
336 *joinedQualifier = EvqFlatIn;
337 break;
338 default:
339 return false;
340 }
341 break;
342 }
343 case EvqCentroid:
344 {
345 switch (storageQualifier)
346 {
347 case EvqVertexOut:
348 case EvqGeometryOut:
349 *joinedQualifier = EvqCentroidOut;
350 break;
351 case EvqFragmentIn:
352 case EvqGeometryIn:
353 *joinedQualifier = EvqCentroidIn;
354 break;
355 default:
356 return false;
357 }
358 break;
359 }
360 default:
361 return false;
362 }
363 return true;
364 }
365
366 // Handles the joining of storage qualifiers for a parameter in a function.
JoinParameterStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)367 bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
368 {
369 switch (*joinedQualifier)
370 {
371 case EvqTemporary:
372 *joinedQualifier = storageQualifier;
373 break;
374 case EvqConst:
375 {
376 switch (storageQualifier)
377 {
378 case EvqIn:
379 *joinedQualifier = EvqConstReadOnly;
380 break;
381 default:
382 return false;
383 }
384 break;
385 }
386 default:
387 return false;
388 }
389 return true;
390 }
391
JoinMemoryQualifier(TMemoryQualifier * joinedMemoryQualifier,TQualifier memoryQualifier)392 bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
393 {
394 switch (memoryQualifier)
395 {
396 case EvqReadOnly:
397 joinedMemoryQualifier->readonly = true;
398 break;
399 case EvqWriteOnly:
400 joinedMemoryQualifier->writeonly = true;
401 break;
402 case EvqCoherent:
403 joinedMemoryQualifier->coherent = true;
404 break;
405 case EvqRestrict:
406 joinedMemoryQualifier->restrictQualifier = true;
407 break;
408 case EvqVolatile:
409 // Variables having the volatile qualifier are automatcally treated as coherent as well.
410 // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
411 joinedMemoryQualifier->volatileQualifier = true;
412 joinedMemoryQualifier->coherent = true;
413 break;
414 default:
415 UNREACHABLE();
416 }
417 return true;
418 }
419
GetVariableTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)420 TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
421 const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
422 TDiagnostics *diagnostics)
423 {
424 TTypeQualifier typeQualifier(
425 static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
426 sortedSequence[0]->getLine());
427 for (size_t i = 1; i < sortedSequence.size(); ++i)
428 {
429 const TQualifierWrapperBase *qualifier = sortedSequence[i];
430 bool isQualifierValid = false;
431 switch (qualifier->getType())
432 {
433 case QtInvariant:
434 isQualifierValid = true;
435 typeQualifier.invariant = true;
436 break;
437 case QtInterpolation:
438 {
439 switch (typeQualifier.qualifier)
440 {
441 case EvqGlobal:
442 isQualifierValid = true;
443 typeQualifier.qualifier =
444 static_cast<const TInterpolationQualifierWrapper *>(qualifier)
445 ->getQualifier();
446 break;
447 default:
448 isQualifierValid = false;
449 }
450 break;
451 }
452 case QtLayout:
453 {
454 const TLayoutQualifierWrapper *layoutQualifierWrapper =
455 static_cast<const TLayoutQualifierWrapper *>(qualifier);
456 isQualifierValid = true;
457 typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
458 typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
459 layoutQualifierWrapper->getLine(), diagnostics);
460 break;
461 }
462 case QtStorage:
463 isQualifierValid = JoinVariableStorageQualifier(
464 &typeQualifier.qualifier,
465 static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
466 break;
467 case QtPrecision:
468 isQualifierValid = true;
469 typeQualifier.precision =
470 static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
471 ASSERT(typeQualifier.precision != EbpUndefined);
472 break;
473 case QtMemory:
474 isQualifierValid = JoinMemoryQualifier(
475 &typeQualifier.memoryQualifier,
476 static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
477 break;
478 default:
479 UNREACHABLE();
480 }
481 if (!isQualifierValid)
482 {
483 const TString &qualifierString = qualifier->getQualifierString();
484 diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
485 qualifierString.c_str());
486 break;
487 }
488 }
489 return typeQualifier;
490 }
491
GetParameterTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)492 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
493 const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
494 TDiagnostics *diagnostics)
495 {
496 TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
497 for (size_t i = 1; i < sortedSequence.size(); ++i)
498 {
499 const TQualifierWrapperBase *qualifier = sortedSequence[i];
500 bool isQualifierValid = false;
501 switch (qualifier->getType())
502 {
503 case QtInvariant:
504 case QtInterpolation:
505 case QtLayout:
506 break;
507 case QtMemory:
508 isQualifierValid = JoinMemoryQualifier(
509 &typeQualifier.memoryQualifier,
510 static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
511 break;
512 case QtStorage:
513 isQualifierValid = JoinParameterStorageQualifier(
514 &typeQualifier.qualifier,
515 static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
516 break;
517 case QtPrecision:
518 isQualifierValid = true;
519 typeQualifier.precision =
520 static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
521 ASSERT(typeQualifier.precision != EbpUndefined);
522 break;
523 default:
524 UNREACHABLE();
525 }
526 if (!isQualifierValid)
527 {
528 const TString &qualifierString = qualifier->getQualifierString();
529 diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
530 qualifierString.c_str());
531 break;
532 }
533 }
534
535 switch (typeQualifier.qualifier)
536 {
537 case EvqIn:
538 case EvqConstReadOnly: // const in
539 case EvqOut:
540 case EvqInOut:
541 break;
542 case EvqConst:
543 typeQualifier.qualifier = EvqConstReadOnly;
544 break;
545 case EvqTemporary:
546 // no qualifier has been specified, set it to EvqIn which is the default
547 typeQualifier.qualifier = EvqIn;
548 break;
549 default:
550 diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
551 getQualifierString(typeQualifier.qualifier));
552 }
553 return typeQualifier;
554 }
555 } // namespace
556
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)557 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
558 TLayoutQualifier rightQualifier,
559 const TSourceLoc &rightQualifierLocation,
560 TDiagnostics *diagnostics)
561 {
562 TLayoutQualifier joinedQualifier = leftQualifier;
563
564 if (rightQualifier.location != -1)
565 {
566 joinedQualifier.location = rightQualifier.location;
567 ++joinedQualifier.locationsSpecified;
568 }
569 if (rightQualifier.yuv != false)
570 {
571 joinedQualifier.yuv = rightQualifier.yuv;
572 }
573 if (rightQualifier.binding != -1)
574 {
575 joinedQualifier.binding = rightQualifier.binding;
576 }
577 if (rightQualifier.offset != -1)
578 {
579 joinedQualifier.offset = rightQualifier.offset;
580 }
581 if (rightQualifier.matrixPacking != EmpUnspecified)
582 {
583 joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
584 }
585 if (rightQualifier.blockStorage != EbsUnspecified)
586 {
587 joinedQualifier.blockStorage = rightQualifier.blockStorage;
588 }
589
590 for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
591 {
592 if (rightQualifier.localSize[i] != -1)
593 {
594 if (joinedQualifier.localSize[i] != -1 &&
595 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
596 {
597 diagnostics->error(rightQualifierLocation,
598 "Cannot have multiple different work group size specifiers",
599 getWorkGroupSizeString(i));
600 }
601 joinedQualifier.localSize[i] = rightQualifier.localSize[i];
602 }
603 }
604
605 if (rightQualifier.numViews != -1)
606 {
607 joinedQualifier.numViews = rightQualifier.numViews;
608 }
609
610 if (rightQualifier.imageInternalFormat != EiifUnspecified)
611 {
612 joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
613 }
614
615 if (rightQualifier.primitiveType != EptUndefined)
616 {
617 if (joinedQualifier.primitiveType != EptUndefined &&
618 joinedQualifier.primitiveType != rightQualifier.primitiveType)
619 {
620 diagnostics->error(rightQualifierLocation,
621 "Cannot have multiple different primitive specifiers",
622 getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
623 }
624 joinedQualifier.primitiveType = rightQualifier.primitiveType;
625 }
626
627 if (rightQualifier.invocations != 0)
628 {
629 if (joinedQualifier.invocations != 0 &&
630 joinedQualifier.invocations != rightQualifier.invocations)
631 {
632 diagnostics->error(rightQualifierLocation,
633 "Cannot have multiple different invocations specifiers",
634 "invocations");
635 }
636 joinedQualifier.invocations = rightQualifier.invocations;
637 }
638
639 if (rightQualifier.maxVertices != -1)
640 {
641 if (joinedQualifier.maxVertices != -1 &&
642 joinedQualifier.maxVertices != rightQualifier.maxVertices)
643 {
644 diagnostics->error(rightQualifierLocation,
645 "Cannot have multiple different max_vertices specifiers",
646 "max_vertices");
647 }
648 joinedQualifier.maxVertices = rightQualifier.maxVertices;
649 }
650
651 return joinedQualifier;
652 }
653
getRank() const654 unsigned int TInvariantQualifierWrapper::getRank() const
655 {
656 return 0u;
657 }
658
getRank() const659 unsigned int TInterpolationQualifierWrapper::getRank() const
660 {
661 return 1u;
662 }
663
getRank() const664 unsigned int TLayoutQualifierWrapper::getRank() const
665 {
666 return 2u;
667 }
668
getRank() const669 unsigned int TStorageQualifierWrapper::getRank() const
670 {
671 // Force the 'centroid' auxilary storage qualifier to be always first among all storage
672 // qualifiers.
673 if (mStorageQualifier == EvqCentroid)
674 {
675 return 3u;
676 }
677 else
678 {
679 return 4u;
680 }
681 }
682
getRank() const683 unsigned int TMemoryQualifierWrapper::getRank() const
684 {
685 return 4u;
686 }
687
getRank() const688 unsigned int TPrecisionQualifierWrapper::getRank() const
689 {
690 return 5u;
691 }
692
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)693 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
694 : layoutQualifier(TLayoutQualifier::Create()),
695 memoryQualifier(TMemoryQualifier::Create()),
696 precision(EbpUndefined),
697 qualifier(scope),
698 invariant(false),
699 line(loc)
700 {
701 ASSERT(IsScopeQualifier(qualifier));
702 }
703
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)704 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
705 int shaderVersion)
706 : mShaderVersion(shaderVersion)
707 {
708 ASSERT(IsScopeQualifier(scope->getQualifier()));
709 mQualifiers.push_back(scope);
710 }
711
appendQualifier(const TQualifierWrapperBase * qualifier)712 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
713 {
714 mQualifiers.push_back(qualifier);
715 }
716
checkSequenceIsValid(TDiagnostics * diagnostics) const717 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
718 {
719 bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
720 std::string errorMessage;
721 if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
722 {
723 diagnostics->error(mQualifiers[0]->getLine(), errorMessage.c_str(), "qualifier sequence");
724 return false;
725 }
726
727 if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage))
728 {
729 diagnostics->error(mQualifiers[0]->getLine(), errorMessage.c_str(), "qualifier sequence");
730 return false;
731 }
732
733 return true;
734 }
735
getParameterTypeQualifier(TDiagnostics * diagnostics) const736 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const
737 {
738 ASSERT(IsInvariantCorrect(mQualifiers));
739 ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
740 EvqTemporary);
741
742 if (!checkSequenceIsValid(diagnostics))
743 {
744 return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
745 }
746
747 // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
748 // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
749 // combine the qualifiers.
750 if (AreTypeQualifierChecksRelaxed(mShaderVersion))
751 {
752 // Copy the qualifier sequence so that we can sort them.
753 QualifierSequence sortedQualifierSequence = mQualifiers;
754 SortSequence(sortedQualifierSequence);
755 return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
756 }
757 return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
758 }
759
getVariableTypeQualifier(TDiagnostics * diagnostics) const760 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
761 {
762 ASSERT(IsInvariantCorrect(mQualifiers));
763
764 if (!checkSequenceIsValid(diagnostics))
765 {
766 return TTypeQualifier(
767 static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
768 mQualifiers[0]->getLine());
769 }
770
771 // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
772 // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
773 // combine the qualifiers.
774 if (AreTypeQualifierChecksRelaxed(mShaderVersion))
775 {
776 // Copy the qualifier sequence so that we can sort them.
777 QualifierSequence sortedQualifierSequence = mQualifiers;
778 SortSequence(sortedQualifierSequence);
779 return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
780 }
781 return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
782 }
783
784 } // namespace sh
785