• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 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/msl/Pipeline.h"
8 #include "compiler/translator/tree_util/BuiltIn.h"
9 
10 using namespace sh;
11 
12 ////////////////////////////////////////////////////////////////////////////////
13 
14 #define VARIANT_NAME(variant, base) (variant == Variant::Modified ? base "Mod" : base)
15 
uses(const TVariable & var) const16 bool Pipeline::uses(const TVariable &var) const
17 {
18     if (var.symbolType() == SymbolType::Empty)
19     {
20         return false;
21     }
22 
23     if (globalInstanceVar)
24     {
25         return &var == globalInstanceVar;
26     }
27 
28     const TType &nodeType      = var.getType();
29     const TQualifier qualifier = nodeType.getQualifier();
30 
31     switch (type)
32     {
33         case Type::VertexIn:
34             switch (qualifier)
35             {
36                 case TQualifier::EvqAttribute:
37                 case TQualifier::EvqVertexIn:
38                     return true;
39                 default:
40                     return false;
41             }
42 
43         case Type::VertexOut:
44             switch (qualifier)
45             {
46                 case TQualifier::EvqVaryingOut:
47                 case TQualifier::EvqVertexOut:
48                 case TQualifier::EvqPosition:
49                 case TQualifier::EvqPointSize:
50                 case TQualifier::EvqClipDistance:
51                 case TQualifier::EvqSmoothOut:
52                 case TQualifier::EvqFlatOut:
53                 case TQualifier::EvqNoPerspectiveOut:
54                 case TQualifier::EvqCentroidOut:
55                 case TQualifier::EvqSampleOut:
56                 case TQualifier::EvqNoPerspectiveCentroidOut:
57                 case TQualifier::EvqNoPerspectiveSampleOut:
58                     return true;
59                 default:
60                     return false;
61             }
62 
63         case Type::FragmentIn:
64             switch (qualifier)
65             {
66                 case TQualifier::EvqVaryingIn:
67                 case TQualifier::EvqFragmentIn:
68                 case TQualifier::EvqSmoothIn:
69                 case TQualifier::EvqFlatIn:
70                 case TQualifier::EvqNoPerspectiveIn:
71                 case TQualifier::EvqCentroidIn:
72                 case TQualifier::EvqSampleIn:
73                 case TQualifier::EvqNoPerspectiveCentroidIn:
74                 case TQualifier::EvqNoPerspectiveSampleIn:
75                     return true;
76                 default:
77                     return false;
78             }
79 
80         case Type::FragmentOut:
81             switch (qualifier)
82             {
83                 case TQualifier::EvqFragmentOut:
84                 case TQualifier::EvqFragmentInOut:
85                 case TQualifier::EvqFragColor:
86                 case TQualifier::EvqFragData:
87                 case TQualifier::EvqFragDepth:
88                 case TQualifier::EvqSecondaryFragColorEXT:
89                 case TQualifier::EvqSecondaryFragDataEXT:
90                     return true;
91                 case TQualifier::EvqSampleMask:
92                     return var.symbolType() == SymbolType::AngleInternal;
93                 default:
94                     return false;
95             }
96 
97         case Type::UserUniforms:
98             switch (qualifier)
99             {
100                 case TQualifier::EvqUniform:
101                     return true;
102                 default:
103                     return false;
104             }
105 
106         case Type::NonConstantGlobals:
107             switch (qualifier)
108             {
109                 case TQualifier::EvqGlobal:
110                 case TQualifier::EvqSamplePosition:
111                     return true;
112                 case TQualifier::EvqSampleMaskIn:
113                 case TQualifier::EvqSampleMask:
114                     return var.symbolType() == SymbolType::BuiltIn;
115                 case TQualifier::EvqUniform:
116                     return var.name() == "gl_NumSamples";
117                 default:
118                     return false;
119             }
120 
121         case Type::InvocationVertexGlobals:
122             switch (qualifier)
123             {
124                 case TQualifier::EvqVertexID:
125                     return true;
126                 default:
127                     return false;
128             }
129 
130         case Type::InvocationFragmentGlobals:
131             switch (qualifier)
132             {
133                 case TQualifier::EvqFragCoord:
134                 case TQualifier::EvqPointCoord:
135                 case TQualifier::EvqFrontFacing:
136                 case TQualifier::EvqSampleID:
137                     return true;
138                 case TQualifier::EvqSampleMaskIn:
139                     return var.symbolType() == SymbolType::AngleInternal;
140                 default:
141                     return false;
142             }
143 
144         case Type::UniformBuffer:
145             switch (qualifier)
146             {
147                 case TQualifier::EvqBuffer:
148                     return true;
149                 default:
150                     return false;
151             }
152         case Type::AngleUniforms:
153             UNREACHABLE();  // globalInstanceVar should be non-null and thus never reach here.
154             return false;
155 
156         case Type::Texture:
157             return IsSampler(nodeType.getBasicType());
158 
159         case Type::Image:
160             return IsImage(nodeType.getBasicType());
161 
162         case Type::InstanceId:
163             return Name(var) == Name(*BuiltInVariable::gl_InstanceID());
164     }
165 }
166 
getStructTypeName(Variant variant) const167 Name Pipeline::getStructTypeName(Variant variant) const
168 {
169     const char *name;
170     switch (type)
171     {
172         case Type::VertexIn:
173             name = VARIANT_NAME(variant, "VertexIn");
174             break;
175         case Type::VertexOut:
176             name = VARIANT_NAME(variant, "VertexOut");
177             break;
178         case Type::FragmentIn:
179             name = VARIANT_NAME(variant, "FragmentIn");
180             break;
181         case Type::FragmentOut:
182             name = VARIANT_NAME(variant, "FragmentOut");
183             break;
184         case Type::UserUniforms:
185             name = VARIANT_NAME(variant, "UserUniforms");
186             break;
187         case Type::AngleUniforms:
188             name = VARIANT_NAME(variant, "AngleUniforms");
189             break;
190         case Type::NonConstantGlobals:
191             name = VARIANT_NAME(variant, "NonConstGlobals");
192             break;
193         case Type::InvocationVertexGlobals:
194             name = VARIANT_NAME(variant, "InvocationVertexGlobals");
195             break;
196         case Type::InvocationFragmentGlobals:
197             name = VARIANT_NAME(variant, "InvocationFragmentGlobals");
198             break;
199         case Type::Texture:
200             name = VARIANT_NAME(variant, "TextureEnvs");
201             break;
202         case Type::Image:
203             name = VARIANT_NAME(variant, "Images");
204             break;
205         case Type::InstanceId:
206             name = VARIANT_NAME(variant, "InstanceId");
207             break;
208         case Type::UniformBuffer:
209             name = VARIANT_NAME(variant, "UniformBuffer");
210     }
211     return Name(name);
212 }
213 
getStructInstanceName(Variant variant) const214 Name Pipeline::getStructInstanceName(Variant variant) const
215 {
216     const char *name;
217     switch (type)
218     {
219         case Type::VertexIn:
220             name = VARIANT_NAME(variant, "vertexIn");
221             break;
222         case Type::VertexOut:
223             name = VARIANT_NAME(variant, "vertexOut");
224             break;
225         case Type::FragmentIn:
226             name = VARIANT_NAME(variant, "fragmentIn");
227             break;
228         case Type::FragmentOut:
229             name = VARIANT_NAME(variant, "fragmentOut");
230             break;
231         case Type::UserUniforms:
232             name = VARIANT_NAME(variant, "userUniforms");
233             break;
234         case Type::AngleUniforms:
235             name = VARIANT_NAME(variant, "angleUniforms");
236             break;
237         case Type::NonConstantGlobals:
238             name = VARIANT_NAME(variant, "nonConstGlobals");
239             break;
240         case Type::InvocationVertexGlobals:
241             name = VARIANT_NAME(variant, "invocationVertexGlobals");
242             break;
243         case Type::InvocationFragmentGlobals:
244             name = VARIANT_NAME(variant, "invocationFragmentGlobals");
245             break;
246         case Type::Texture:
247             name = VARIANT_NAME(variant, "textureEnvs");
248             break;
249         case Type::Image:
250             name = VARIANT_NAME(variant, "images");
251             break;
252         case Type::InstanceId:
253             name = VARIANT_NAME(variant, "instanceId");
254             break;
255         case Type::UniformBuffer:
256             name = VARIANT_NAME(variant, "uniformBuffer");
257     }
258     return Name(name);
259 }
260 
AllowPacking(Pipeline::Type type)261 static bool AllowPacking(Pipeline::Type type)
262 {
263     return false;
264 }
265 
AllowPadding(Pipeline::Type type)266 static bool AllowPadding(Pipeline::Type type)
267 {
268     using Type = Pipeline::Type;
269 
270     switch (type)
271     {
272         case Type::VertexIn:
273         case Type::VertexOut:
274         case Type::FragmentIn:
275         case Type::FragmentOut:
276         case Type::AngleUniforms:
277         case Type::NonConstantGlobals:
278         case Type::InvocationVertexGlobals:
279         case Type::InvocationFragmentGlobals:
280             return true;
281 
282         case Type::UserUniforms:
283         case Type::Texture:
284         case Type::Image:
285         case Type::InstanceId:
286         case Type::UniformBuffer:
287             return false;
288     }
289 }
290 enum Compare
291 {
292     LT,
293     LTE,
294     EQ,
295     GTE,
296     GT,
297 };
298 
299 template <typename T>
CompareBy(Compare op,const T & x,const T & y)300 static bool CompareBy(Compare op, const T &x, const T &y)
301 {
302     switch (op)
303     {
304         case LT:
305             return x < y;
306         case LTE:
307             return x <= y;
308         case EQ:
309             return x == y;
310         case GTE:
311             return x >= y;
312         case GT:
313             return x > y;
314     }
315 }
316 
317 template <TBasicType BT, Compare Cmp, uint8_t MatchDim, uint8_t NewDim>
SaturateVectorOf(const TField & field)318 static uint8_t SaturateVectorOf(const TField &field)
319 {
320     static_assert(NewDim >= MatchDim, "");
321 
322     const TType &type = *field.type();
323     ASSERT(type.isScalar() || type.isVector());
324 
325     const bool cond = type.getBasicType() == BT && !type.isArray() &&
326                       CompareBy(Cmp, type.getNominalSize(), MatchDim) &&
327                       type.getQualifier() != TQualifier::EvqFragDepth;
328 
329     if (cond)
330     {
331         return NewDim;
332     }
333     return 0;
334 }
335 
externalStructModifyConfig() const336 ModifyStructConfig Pipeline::externalStructModifyConfig() const
337 {
338     using Pred   = ModifyStructConfig::Predicate;
339     using SatVec = ModifyStructConfig::SaturateVector;
340 
341     ModifyStructConfig config(
342         isPipelineOut() ? ConvertType::OriginalToModified : ConvertType::ModifiedToOriginal,
343         AllowPacking(type), AllowPadding(type));
344 
345     config.externalAddressSpace = externalAddressSpace();
346 
347     switch (type)
348     {
349         case Type::VertexIn:
350             config.inlineArray        = Pred::True;
351             config.splitMatrixColumns = Pred::True;
352             config.inlineStruct       = Pred::True;
353             break;
354 
355         case Type::VertexOut:
356             config.inlineArray = [](const TField &field) -> bool {
357                 // Clip distance output uses float[n] type instead of metal::array.
358                 return field.type()->getQualifier() != TQualifier::EvqClipDistance;
359             };
360             config.splitMatrixColumns = Pred::True;
361             config.inlineStruct       = Pred::True;
362             break;
363 
364         case Type::FragmentIn:
365             config.inlineArray        = Pred::True;
366             config.splitMatrixColumns = Pred::True;
367             config.inlineStruct       = Pred::True;
368             break;
369 
370         case Type::FragmentOut:
371             config.inlineArray            = Pred::True;
372             config.splitMatrixColumns     = Pred::True;
373             config.inlineStruct           = Pred::True;
374             config.saturateScalarOrVector = [](const TField &field) -> uint8_t {
375                 if (field.type()->getQualifier() == TQualifier::EvqSampleMask)
376                 {
377                     return 1;
378                 }
379                 if (uint8_t s = SaturateVectorOf<TBasicType::EbtInt, LT, 4, 4>(field))
380                 {
381                     return s;
382                 }
383                 if (uint8_t s = SaturateVectorOf<TBasicType::EbtUInt, LT, 4, 4>(field))
384                 {
385                     return s;
386                 }
387                 if (uint8_t s = SaturateVectorOf<TBasicType::EbtFloat, LT, 4, 4>(field))
388                 {
389                     return s;
390                 }
391                 return 0;
392             };
393             break;
394         case Type::UserUniforms:
395             config.promoteBoolToUint            = Pred::False;
396             config.saturateMatrixRows           = SatVec::DontSaturate;
397             config.saturateScalarOrVectorArrays = SatVec::DontSaturate;
398             config.recurseStruct                = Pred::True;
399             break;
400 
401         case Type::AngleUniforms:
402             config.initialBlockStorage = TLayoutBlockStorage::EbsStd430;  // XXX: Correct?
403             break;
404 
405         case Type::NonConstantGlobals:
406             break;
407         case Type::UniformBuffer:
408             config.promoteBoolToUint            = Pred::False;
409             config.saturateMatrixRows           = SatVec::DontSaturate;
410             config.saturateScalarOrVectorArrays = SatVec::DontSaturate;
411             config.recurseStruct                = Pred::True;
412             break;
413         case Type::InvocationVertexGlobals:
414         case Type::InvocationFragmentGlobals:
415         case Type::Texture:
416         case Type::Image:
417         case Type::InstanceId:
418             break;
419     }
420 
421     return config;
422 }
423 
alwaysRequiresLocalVariableDeclarationInMain() const424 bool Pipeline::alwaysRequiresLocalVariableDeclarationInMain() const
425 {
426     switch (type)
427     {
428         case Type::VertexIn:
429         case Type::FragmentIn:
430         case Type::UserUniforms:
431         case Type::AngleUniforms:
432         case Type::UniformBuffer:
433         case Type::Image:
434             return false;
435 
436         case Type::VertexOut:
437         case Type::FragmentOut:
438         case Type::NonConstantGlobals:
439         case Type::InvocationVertexGlobals:
440         case Type::InvocationFragmentGlobals:
441         case Type::Texture:
442         case Type::InstanceId:
443             return true;
444     }
445 }
446 
isPipelineOut() const447 bool Pipeline::isPipelineOut() const
448 {
449     switch (type)
450     {
451         case Type::VertexIn:
452         case Type::FragmentIn:
453         case Type::UserUniforms:
454         case Type::AngleUniforms:
455         case Type::NonConstantGlobals:
456         case Type::InvocationVertexGlobals:
457         case Type::InvocationFragmentGlobals:
458         case Type::Texture:
459         case Type::Image:
460         case Type::InstanceId:
461         case Type::UniformBuffer:
462             return false;
463 
464         case Type::VertexOut:
465         case Type::FragmentOut:
466             return true;
467     }
468 }
469 
externalAddressSpace() const470 AddressSpace Pipeline::externalAddressSpace() const
471 {
472     switch (type)
473     {
474         case Type::VertexIn:
475         case Type::FragmentIn:
476         case Type::NonConstantGlobals:
477         case Type::InvocationVertexGlobals:
478         case Type::InvocationFragmentGlobals:
479         case Type::Texture:
480         case Type::Image:
481         case Type::InstanceId:
482         case Type::FragmentOut:
483         case Type::VertexOut:
484             return AddressSpace::Thread;
485 
486         case Type::UserUniforms:
487         case Type::AngleUniforms:
488         case Type::UniformBuffer:
489             return AddressSpace::Constant;
490     }
491 }
492 
matches(const TStructure & s,bool internal,bool external) const493 bool PipelineStructs::matches(const TStructure &s, bool internal, bool external) const
494 {
495     PipelineScoped<TStructure> ps[] = {
496         fragmentIn,
497         fragmentOut,
498         vertexIn,
499         vertexOut,
500         userUniforms,
501         /* angleUniforms, */
502         nonConstantGlobals,
503         invocationVertexGlobals,
504         invocationFragmentGlobals,
505         uniformBuffers,
506         texture,
507         instanceId,
508     };
509     for (const auto &p : ps)
510     {
511         if (internal && p.internal == &s)
512         {
513             return true;
514         }
515         if (external && p.external == &s)
516         {
517             return true;
518         }
519     }
520     return false;
521 }
522