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