xref: /aosp_15_r20/external/angle/src/compiler/translator/msl/Pipeline.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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             // Used by name in compiler/translator/tree_ops/msl/RewriteOutArgs.cpp
224             name = VARIANT_NAME(variant, "vertexOut");
225             break;
226         case Type::FragmentIn:
227             name = VARIANT_NAME(variant, "fragmentIn");
228             break;
229         case Type::FragmentOut:
230             // Used by name in compiler/translator/tree_ops/msl/RewriteOutArgs.cpp
231             name = VARIANT_NAME(variant, "fragmentOut");
232             break;
233         case Type::UserUniforms:
234             name = VARIANT_NAME(variant, "userUniforms");
235             break;
236         case Type::AngleUniforms:
237             name = VARIANT_NAME(variant, "angleUniforms");
238             break;
239         case Type::NonConstantGlobals:
240             // Used by name in compiler/translator/tree_ops/msl/RewriteOutArgs.cpp
241             name = VARIANT_NAME(variant, "nonConstGlobals");
242             break;
243         case Type::InvocationVertexGlobals:
244             name = VARIANT_NAME(variant, "invocationVertexGlobals");
245             break;
246         case Type::InvocationFragmentGlobals:
247             name = VARIANT_NAME(variant, "invocationFragmentGlobals");
248             break;
249         case Type::Texture:
250             name = VARIANT_NAME(variant, "textureEnvs");
251             break;
252         case Type::Image:
253             name = VARIANT_NAME(variant, "images");
254             break;
255         case Type::InstanceId:
256             name = VARIANT_NAME(variant, "instanceId");
257             break;
258         case Type::UniformBuffer:
259             name = VARIANT_NAME(variant, "uniformBuffer");
260     }
261     return Name(name);
262 }
263 
AllowPacking(Pipeline::Type type)264 static bool AllowPacking(Pipeline::Type type)
265 {
266     return false;
267 }
268 
AllowPadding(Pipeline::Type type)269 static bool AllowPadding(Pipeline::Type type)
270 {
271     using Type = Pipeline::Type;
272 
273     switch (type)
274     {
275         case Type::VertexIn:
276         case Type::VertexOut:
277         case Type::FragmentIn:
278         case Type::FragmentOut:
279         case Type::AngleUniforms:
280         case Type::NonConstantGlobals:
281         case Type::InvocationVertexGlobals:
282         case Type::InvocationFragmentGlobals:
283             return true;
284 
285         case Type::UserUniforms:
286         case Type::Texture:
287         case Type::Image:
288         case Type::InstanceId:
289         case Type::UniformBuffer:
290             return false;
291     }
292 }
293 enum Compare
294 {
295     LT,
296     LTE,
297     EQ,
298     GTE,
299     GT,
300 };
301 
302 template <typename T>
CompareBy(Compare op,const T & x,const T & y)303 static bool CompareBy(Compare op, const T &x, const T &y)
304 {
305     switch (op)
306     {
307         case LT:
308             return x < y;
309         case LTE:
310             return x <= y;
311         case EQ:
312             return x == y;
313         case GTE:
314             return x >= y;
315         case GT:
316             return x > y;
317     }
318 }
319 
320 template <TBasicType BT, Compare Cmp, uint8_t MatchDim, uint8_t NewDim>
SaturateVectorOf(const TField & field)321 static uint8_t SaturateVectorOf(const TField &field)
322 {
323     static_assert(NewDim >= MatchDim, "");
324 
325     const TType &type = *field.type();
326     ASSERT(type.isScalar() || type.isVector());
327 
328     const bool cond = type.getBasicType() == BT && !type.isArray() &&
329                       CompareBy(Cmp, type.getNominalSize(), MatchDim) &&
330                       type.getQualifier() != TQualifier::EvqFragDepth;
331 
332     if (cond)
333     {
334         return NewDim;
335     }
336     return 0;
337 }
338 
externalStructModifyConfig() const339 ModifyStructConfig Pipeline::externalStructModifyConfig() const
340 {
341     using Pred   = ModifyStructConfig::Predicate;
342     using SatVec = ModifyStructConfig::SaturateVector;
343 
344     ModifyStructConfig config(
345         isPipelineOut() ? ConvertType::OriginalToModified : ConvertType::ModifiedToOriginal,
346         AllowPacking(type), AllowPadding(type));
347 
348     config.externalAddressSpace = externalAddressSpace();
349 
350     switch (type)
351     {
352         case Type::VertexIn:
353             config.inlineArray        = Pred::True;
354             config.splitMatrixColumns = Pred::True;
355             config.inlineStruct       = Pred::True;
356             break;
357 
358         case Type::VertexOut:
359             config.inlineArray = [](const TField &field) -> bool {
360                 // Clip distance output uses float[n] type instead of metal::array.
361                 return field.type()->getQualifier() != TQualifier::EvqClipDistance;
362             };
363             config.splitMatrixColumns = Pred::True;
364             config.inlineStruct       = Pred::True;
365             break;
366 
367         case Type::FragmentIn:
368             config.inlineArray        = Pred::True;
369             config.splitMatrixColumns = Pred::True;
370             config.inlineStruct       = Pred::True;
371             break;
372 
373         case Type::FragmentOut:
374             config.inlineArray            = Pred::True;
375             config.splitMatrixColumns     = Pred::True;
376             config.inlineStruct           = Pred::True;
377             config.saturateScalarOrVector = [](const TField &field) -> uint8_t {
378                 if (field.type()->getQualifier() == TQualifier::EvqSampleMask)
379                 {
380                     return 1;
381                 }
382                 if (uint8_t s = SaturateVectorOf<TBasicType::EbtInt, LT, 4, 4>(field))
383                 {
384                     return s;
385                 }
386                 if (uint8_t s = SaturateVectorOf<TBasicType::EbtUInt, LT, 4, 4>(field))
387                 {
388                     return s;
389                 }
390                 if (uint8_t s = SaturateVectorOf<TBasicType::EbtFloat, LT, 4, 4>(field))
391                 {
392                     return s;
393                 }
394                 return 0;
395             };
396             break;
397         case Type::UserUniforms:
398             config.promoteBoolToUint            = Pred::False;
399             config.saturateMatrixRows           = SatVec::DontSaturate;
400             config.saturateScalarOrVectorArrays = SatVec::DontSaturate;
401             config.recurseStruct                = Pred::True;
402             break;
403 
404         case Type::AngleUniforms:
405             config.initialBlockStorage = TLayoutBlockStorage::EbsStd430;  // XXX: Correct?
406             break;
407 
408         case Type::NonConstantGlobals:
409             break;
410         case Type::UniformBuffer:
411             config.promoteBoolToUint            = Pred::False;
412             config.saturateMatrixRows           = SatVec::DontSaturate;
413             config.saturateScalarOrVectorArrays = SatVec::DontSaturate;
414             config.recurseStruct                = Pred::True;
415             break;
416         case Type::InvocationVertexGlobals:
417         case Type::InvocationFragmentGlobals:
418         case Type::Texture:
419         case Type::Image:
420         case Type::InstanceId:
421             break;
422     }
423 
424     return config;
425 }
426 
alwaysRequiresLocalVariableDeclarationInMain() const427 bool Pipeline::alwaysRequiresLocalVariableDeclarationInMain() const
428 {
429     switch (type)
430     {
431         case Type::VertexIn:
432         case Type::FragmentIn:
433         case Type::UserUniforms:
434         case Type::AngleUniforms:
435         case Type::UniformBuffer:
436         case Type::Image:
437             return false;
438 
439         case Type::VertexOut:
440         case Type::FragmentOut:
441         case Type::NonConstantGlobals:
442         case Type::InvocationVertexGlobals:
443         case Type::InvocationFragmentGlobals:
444         case Type::Texture:
445         case Type::InstanceId:
446             return true;
447     }
448 }
449 
isPipelineOut() const450 bool Pipeline::isPipelineOut() const
451 {
452     switch (type)
453     {
454         case Type::VertexIn:
455         case Type::FragmentIn:
456         case Type::UserUniforms:
457         case Type::AngleUniforms:
458         case Type::NonConstantGlobals:
459         case Type::InvocationVertexGlobals:
460         case Type::InvocationFragmentGlobals:
461         case Type::Texture:
462         case Type::Image:
463         case Type::InstanceId:
464         case Type::UniformBuffer:
465             return false;
466 
467         case Type::VertexOut:
468         case Type::FragmentOut:
469             return true;
470     }
471 }
472 
externalAddressSpace() const473 AddressSpace Pipeline::externalAddressSpace() const
474 {
475     switch (type)
476     {
477         case Type::VertexIn:
478         case Type::FragmentIn:
479         case Type::NonConstantGlobals:
480         case Type::InvocationVertexGlobals:
481         case Type::InvocationFragmentGlobals:
482         case Type::Texture:
483         case Type::Image:
484         case Type::InstanceId:
485         case Type::FragmentOut:
486         case Type::VertexOut:
487             return AddressSpace::Thread;
488 
489         case Type::UserUniforms:
490         case Type::AngleUniforms:
491         case Type::UniformBuffer:
492             return AddressSpace::Constant;
493     }
494 }
495 
matches(const TStructure & s,bool internal,bool external) const496 bool PipelineStructs::matches(const TStructure &s, bool internal, bool external) const
497 {
498     PipelineScoped<TStructure> ps[] = {
499         fragmentIn,
500         fragmentOut,
501         vertexIn,
502         vertexOut,
503         userUniforms,
504         /* angleUniforms, */
505         nonConstantGlobals,
506         invocationVertexGlobals,
507         invocationFragmentGlobals,
508         uniformBuffers,
509         texture,
510         instanceId,
511     };
512     for (const auto &p : ps)
513     {
514         if (internal && p.internal == &s)
515         {
516             return true;
517         }
518         if (external && p.external == &s)
519         {
520             return true;
521         }
522     }
523     return false;
524 }
525