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