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