1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "SpirvShader.hpp"
16
17 #include "ShaderCore.hpp"
18 #include "Device/Primitive.hpp"
19 #include "Pipeline/Constants.hpp"
20
21 #include <spirv/unified1/GLSL.std.450.h>
22 #include <spirv/unified1/spirv.hpp>
23
24 namespace sw {
25
26 static constexpr float PI = 3.141592653589793f;
27
EmitExtGLSLstd450(Spirv::InsnIterator insn)28 void SpirvEmitter::EmitExtGLSLstd450(Spirv::InsnIterator insn)
29 {
30 auto &type = shader.getType(insn.resultTypeId());
31 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
32 auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
33
34 switch(extInstIndex)
35 {
36 case GLSLstd450FAbs:
37 {
38 auto src = Operand(shader, *this, insn.word(5));
39 for(auto i = 0u; i < type.componentCount; i++)
40 {
41 dst.move(i, Abs(src.Float(i)));
42 }
43 }
44 break;
45 case GLSLstd450SAbs:
46 {
47 auto src = Operand(shader, *this, insn.word(5));
48 for(auto i = 0u; i < type.componentCount; i++)
49 {
50 dst.move(i, Abs(src.Int(i)));
51 }
52 }
53 break;
54 case GLSLstd450Cross:
55 {
56 auto lhs = Operand(shader, *this, insn.word(5));
57 auto rhs = Operand(shader, *this, insn.word(6));
58 dst.move(0, lhs.Float(1) * rhs.Float(2) - rhs.Float(1) * lhs.Float(2));
59 dst.move(1, lhs.Float(2) * rhs.Float(0) - rhs.Float(2) * lhs.Float(0));
60 dst.move(2, lhs.Float(0) * rhs.Float(1) - rhs.Float(0) * lhs.Float(1));
61 }
62 break;
63 case GLSLstd450Floor:
64 {
65 auto src = Operand(shader, *this, insn.word(5));
66 for(auto i = 0u; i < type.componentCount; i++)
67 {
68 dst.move(i, Floor(src.Float(i)));
69 }
70 }
71 break;
72 case GLSLstd450Trunc:
73 {
74 auto src = Operand(shader, *this, insn.word(5));
75 for(auto i = 0u; i < type.componentCount; i++)
76 {
77 dst.move(i, Trunc(src.Float(i)));
78 }
79 }
80 break;
81 case GLSLstd450Ceil:
82 {
83 auto src = Operand(shader, *this, insn.word(5));
84 for(auto i = 0u; i < type.componentCount; i++)
85 {
86 dst.move(i, Ceil(src.Float(i)));
87 }
88 }
89 break;
90 case GLSLstd450Fract:
91 {
92 auto src = Operand(shader, *this, insn.word(5));
93 for(auto i = 0u; i < type.componentCount; i++)
94 {
95 dst.move(i, Frac(src.Float(i)));
96 }
97 }
98 break;
99 case GLSLstd450Round:
100 {
101 auto src = Operand(shader, *this, insn.word(5));
102 for(auto i = 0u; i < type.componentCount; i++)
103 {
104 dst.move(i, Round(src.Float(i)));
105 }
106 }
107 break;
108 case GLSLstd450RoundEven:
109 {
110 auto src = Operand(shader, *this, insn.word(5));
111 for(auto i = 0u; i < type.componentCount; i++)
112 {
113 auto x = Round(src.Float(i));
114 // dst = round(src) + ((round(src) < src) * 2 - 1) * (fract(src) == 0.5) * isOdd(round(src));
115 dst.move(i, x + ((SIMD::Float(CmpLT(x, src.Float(i)) & SIMD::Int(1)) * SIMD::Float(2.0f)) - SIMD::Float(1.0f)) *
116 SIMD::Float(CmpEQ(Frac(src.Float(i)), SIMD::Float(0.5f)) & SIMD::Int(1)) * SIMD::Float(SIMD::Int(x) & SIMD::Int(1)));
117 }
118 }
119 break;
120 case GLSLstd450FMin:
121 {
122 auto lhs = Operand(shader, *this, insn.word(5));
123 auto rhs = Operand(shader, *this, insn.word(6));
124 for(auto i = 0u; i < type.componentCount; i++)
125 {
126 dst.move(i, Min(lhs.Float(i), rhs.Float(i)));
127 }
128 }
129 break;
130 case GLSLstd450FMax:
131 {
132 auto lhs = Operand(shader, *this, insn.word(5));
133 auto rhs = Operand(shader, *this, insn.word(6));
134 for(auto i = 0u; i < type.componentCount; i++)
135 {
136 dst.move(i, Max(lhs.Float(i), rhs.Float(i)));
137 }
138 }
139 break;
140 case GLSLstd450SMin:
141 {
142 auto lhs = Operand(shader, *this, insn.word(5));
143 auto rhs = Operand(shader, *this, insn.word(6));
144 for(auto i = 0u; i < type.componentCount; i++)
145 {
146 dst.move(i, Min(lhs.Int(i), rhs.Int(i)));
147 }
148 }
149 break;
150 case GLSLstd450SMax:
151 {
152 auto lhs = Operand(shader, *this, insn.word(5));
153 auto rhs = Operand(shader, *this, insn.word(6));
154 for(auto i = 0u; i < type.componentCount; i++)
155 {
156 dst.move(i, Max(lhs.Int(i), rhs.Int(i)));
157 }
158 }
159 break;
160 case GLSLstd450UMin:
161 {
162 auto lhs = Operand(shader, *this, insn.word(5));
163 auto rhs = Operand(shader, *this, insn.word(6));
164 for(auto i = 0u; i < type.componentCount; i++)
165 {
166 dst.move(i, Min(lhs.UInt(i), rhs.UInt(i)));
167 }
168 }
169 break;
170 case GLSLstd450UMax:
171 {
172 auto lhs = Operand(shader, *this, insn.word(5));
173 auto rhs = Operand(shader, *this, insn.word(6));
174 for(auto i = 0u; i < type.componentCount; i++)
175 {
176 dst.move(i, Max(lhs.UInt(i), rhs.UInt(i)));
177 }
178 }
179 break;
180 case GLSLstd450Step:
181 {
182 auto edge = Operand(shader, *this, insn.word(5));
183 auto x = Operand(shader, *this, insn.word(6));
184 for(auto i = 0u; i < type.componentCount; i++)
185 {
186 dst.move(i, CmpNLT(x.Float(i), edge.Float(i)) & As<SIMD::Int>(SIMD::Float(1.0f)));
187 }
188 }
189 break;
190 case GLSLstd450SmoothStep:
191 {
192 auto edge0 = Operand(shader, *this, insn.word(5));
193 auto edge1 = Operand(shader, *this, insn.word(6));
194 auto x = Operand(shader, *this, insn.word(7));
195 for(auto i = 0u; i < type.componentCount; i++)
196 {
197 auto tx = Min(Max((x.Float(i) - edge0.Float(i)) / (edge1.Float(i) - edge0.Float(i)), 0.0f), 1.0f);
198 dst.move(i, tx * tx * (3.0f - 2.0f * tx));
199 }
200 }
201 break;
202 case GLSLstd450FMix:
203 {
204 auto x = Operand(shader, *this, insn.word(5));
205 auto y = Operand(shader, *this, insn.word(6));
206 auto a = Operand(shader, *this, insn.word(7));
207 for(auto i = 0u; i < type.componentCount; i++)
208 {
209 dst.move(i, a.Float(i) * (y.Float(i) - x.Float(i)) + x.Float(i));
210 }
211 }
212 break;
213 case GLSLstd450FClamp:
214 {
215 auto x = Operand(shader, *this, insn.word(5));
216 auto minVal = Operand(shader, *this, insn.word(6));
217 auto maxVal = Operand(shader, *this, insn.word(7));
218 for(auto i = 0u; i < type.componentCount; i++)
219 {
220 dst.move(i, Min(Max(x.Float(i), minVal.Float(i)), maxVal.Float(i)));
221 }
222 }
223 break;
224 case GLSLstd450SClamp:
225 {
226 auto x = Operand(shader, *this, insn.word(5));
227 auto minVal = Operand(shader, *this, insn.word(6));
228 auto maxVal = Operand(shader, *this, insn.word(7));
229 for(auto i = 0u; i < type.componentCount; i++)
230 {
231 dst.move(i, Min(Max(x.Int(i), minVal.Int(i)), maxVal.Int(i)));
232 }
233 }
234 break;
235 case GLSLstd450UClamp:
236 {
237 auto x = Operand(shader, *this, insn.word(5));
238 auto minVal = Operand(shader, *this, insn.word(6));
239 auto maxVal = Operand(shader, *this, insn.word(7));
240 for(auto i = 0u; i < type.componentCount; i++)
241 {
242 dst.move(i, Min(Max(x.UInt(i), minVal.UInt(i)), maxVal.UInt(i)));
243 }
244 }
245 break;
246 case GLSLstd450FSign:
247 {
248 auto src = Operand(shader, *this, insn.word(5));
249 for(auto i = 0u; i < type.componentCount; i++)
250 {
251 auto neg = As<SIMD::Int>(CmpLT(src.Float(i), SIMD::Float(-0.0f))) & As<SIMD::Int>(SIMD::Float(-1.0f));
252 auto pos = As<SIMD::Int>(CmpNLE(src.Float(i), SIMD::Float(+0.0f))) & As<SIMD::Int>(SIMD::Float(1.0f));
253 dst.move(i, neg | pos);
254 }
255 }
256 break;
257 case GLSLstd450SSign:
258 {
259 auto src = Operand(shader, *this, insn.word(5));
260 for(auto i = 0u; i < type.componentCount; i++)
261 {
262 auto neg = CmpLT(src.Int(i), SIMD::Int(0)) & SIMD::Int(-1);
263 auto pos = CmpNLE(src.Int(i), SIMD::Int(0)) & SIMD::Int(1);
264 dst.move(i, neg | pos);
265 }
266 }
267 break;
268 case GLSLstd450Reflect:
269 {
270 auto I = Operand(shader, *this, insn.word(5));
271 auto N = Operand(shader, *this, insn.word(6));
272
273 SIMD::Float d = FDot(type.componentCount, I, N);
274
275 for(auto i = 0u; i < type.componentCount; i++)
276 {
277 dst.move(i, I.Float(i) - SIMD::Float(2.0f) * d * N.Float(i));
278 }
279 }
280 break;
281 case GLSLstd450Refract:
282 {
283 auto I = Operand(shader, *this, insn.word(5));
284 auto N = Operand(shader, *this, insn.word(6));
285 auto eta = Operand(shader, *this, insn.word(7));
286 Spirv::Decorations r = shader.GetDecorationsForId(insn.resultId());
287
288 SIMD::Float d = FDot(type.componentCount, I, N);
289 SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d);
290 SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
291 SIMD::Float t = (eta.Float(0) * d + Sqrt(k, r.RelaxedPrecision));
292
293 for(auto i = 0u; i < type.componentCount; i++)
294 {
295 dst.move(i, pos & As<SIMD::Int>(eta.Float(0) * I.Float(i) - t * N.Float(i)));
296 }
297 }
298 break;
299 case GLSLstd450FaceForward:
300 {
301 auto N = Operand(shader, *this, insn.word(5));
302 auto I = Operand(shader, *this, insn.word(6));
303 auto Nref = Operand(shader, *this, insn.word(7));
304
305 SIMD::Float d = FDot(type.componentCount, I, Nref);
306 SIMD::Int neg = CmpLT(d, SIMD::Float(0.0f));
307
308 for(auto i = 0u; i < type.componentCount; i++)
309 {
310 auto n = N.Float(i);
311 dst.move(i, (neg & As<SIMD::Int>(n)) | (~neg & As<SIMD::Int>(-n)));
312 }
313 }
314 break;
315 case GLSLstd450Length:
316 {
317 auto x = Operand(shader, *this, insn.word(5));
318 SIMD::Float d = FDot(shader.getObjectType(insn.word(5)).componentCount, x, x);
319 Spirv::Decorations r = shader.GetDecorationsForId(insn.resultId());
320
321 dst.move(0, Sqrt(d, r.RelaxedPrecision));
322 }
323 break;
324 case GLSLstd450Normalize:
325 {
326 auto x = Operand(shader, *this, insn.word(5));
327 Spirv::Decorations r = shader.GetDecorationsForId(insn.resultId());
328
329 SIMD::Float d = FDot(shader.getObjectType(insn.word(5)).componentCount, x, x);
330 SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d, r.RelaxedPrecision);
331
332 for(auto i = 0u; i < type.componentCount; i++)
333 {
334 dst.move(i, invLength * x.Float(i));
335 }
336 }
337 break;
338 case GLSLstd450Distance:
339 {
340 auto p0 = Operand(shader, *this, insn.word(5));
341 auto p1 = Operand(shader, *this, insn.word(6));
342 Spirv::Decorations r = shader.GetDecorationsForId(insn.resultId());
343
344 // sqrt(dot(p0-p1, p0-p1))
345 SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0));
346
347 for(auto i = 1u; i < p0.componentCount; i++)
348 {
349 d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i));
350 }
351
352 dst.move(0, Sqrt(d, r.RelaxedPrecision));
353 }
354 break;
355 case GLSLstd450Modf:
356 {
357 auto val = Operand(shader, *this, insn.word(5));
358 auto ptrId = Spirv::Object::ID(insn.word(6));
359
360 Intermediate whole(type.componentCount);
361
362 for(auto i = 0u; i < type.componentCount; i++)
363 {
364 auto wholeAndFrac = Modf(val.Float(i));
365 dst.move(i, wholeAndFrac.second);
366 whole.move(i, wholeAndFrac.first);
367 }
368
369 Store(ptrId, whole, false, std::memory_order_relaxed);
370 }
371 break;
372 case GLSLstd450ModfStruct:
373 {
374 auto val = Operand(shader, *this, insn.word(5));
375
376 for(auto i = 0u; i < val.componentCount; i++)
377 {
378 auto wholeAndFrac = Modf(val.Float(i));
379 dst.move(i, wholeAndFrac.second);
380 dst.move(val.componentCount + i, wholeAndFrac.first);
381 }
382 }
383 break;
384 case GLSLstd450PackSnorm4x8:
385 {
386 auto val = Operand(shader, *this, insn.word(5));
387 dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
388 SIMD::Int(0xFF)) |
389 ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
390 SIMD::Int(0xFF))
391 << 8) |
392 ((SIMD::Int(Round(Min(Max(val.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
393 SIMD::Int(0xFF))
394 << 16) |
395 ((SIMD::Int(Round(Min(Max(val.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
396 SIMD::Int(0xFF))
397 << 24));
398 }
399 break;
400 case GLSLstd450PackUnorm4x8:
401 {
402 auto val = Operand(shader, *this, insn.word(5));
403 dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
404 ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
405 ((SIMD::UInt(Round(Min(Max(val.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
406 ((SIMD::UInt(Round(Min(Max(val.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24));
407 }
408 break;
409 case GLSLstd450PackSnorm2x16:
410 {
411 auto val = Operand(shader, *this, insn.word(5));
412 dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) &
413 SIMD::Int(0xFFFF)) |
414 ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) &
415 SIMD::Int(0xFFFF))
416 << 16));
417 }
418 break;
419 case GLSLstd450PackUnorm2x16:
420 {
421 auto val = Operand(shader, *this, insn.word(5));
422 dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) &
423 SIMD::UInt(0xFFFF)) |
424 ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) &
425 SIMD::UInt(0xFFFF))
426 << 16));
427 }
428 break;
429 case GLSLstd450PackHalf2x16:
430 {
431 auto val = Operand(shader, *this, insn.word(5));
432 dst.move(0, floatToHalfBits(val.UInt(0), false) | floatToHalfBits(val.UInt(1), true));
433 }
434 break;
435 case GLSLstd450UnpackSnorm4x8:
436 {
437 auto val = Operand(shader, *this, insn.word(5));
438 dst.move(0, Min(Max(SIMD::Float(((val.Int(0) << 24) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
439 dst.move(1, Min(Max(SIMD::Float(((val.Int(0) << 16) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
440 dst.move(2, Min(Max(SIMD::Float(((val.Int(0) << 8) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
441 dst.move(3, Min(Max(SIMD::Float(((val.Int(0)) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f)));
442 }
443 break;
444 case GLSLstd450UnpackUnorm4x8:
445 {
446 auto val = Operand(shader, *this, insn.word(5));
447 dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
448 dst.move(1, SIMD::Float(((val.UInt(0) >> 8) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
449 dst.move(2, SIMD::Float(((val.UInt(0) >> 16) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
450 dst.move(3, SIMD::Float(((val.UInt(0) >> 24) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f));
451 }
452 break;
453 case GLSLstd450UnpackSnorm2x16:
454 {
455 auto val = Operand(shader, *this, insn.word(5));
456 // clamp(f / 32767.0, -1.0, 1.0)
457 dst.move(0, Min(Max(SIMD::Float(As<SIMD::Int>((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16)) *
458 SIMD::Float(1.0f / float(0x7FFF0000)),
459 SIMD::Float(-1.0f)),
460 SIMD::Float(1.0f)));
461 dst.move(1, Min(Max(SIMD::Float(As<SIMD::Int>(val.UInt(0) & SIMD::UInt(0xFFFF0000))) * SIMD::Float(1.0f / float(0x7FFF0000)),
462 SIMD::Float(-1.0f)),
463 SIMD::Float(1.0f)));
464 }
465 break;
466 case GLSLstd450UnpackUnorm2x16:
467 {
468 auto val = Operand(shader, *this, insn.word(5));
469 // f / 65535.0
470 dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16) * SIMD::Float(1.0f / float(0xFFFF0000)));
471 dst.move(1, SIMD::Float(val.UInt(0) & SIMD::UInt(0xFFFF0000)) * SIMD::Float(1.0f / float(0xFFFF0000)));
472 }
473 break;
474 case GLSLstd450UnpackHalf2x16:
475 {
476 auto val = Operand(shader, *this, insn.word(5));
477 dst.move(0, halfToFloatBits(val.UInt(0) & SIMD::UInt(0x0000FFFF)));
478 dst.move(1, halfToFloatBits((val.UInt(0) & SIMD::UInt(0xFFFF0000)) >> 16));
479 }
480 break;
481 case GLSLstd450Fma:
482 {
483 auto a = Operand(shader, *this, insn.word(5));
484 auto b = Operand(shader, *this, insn.word(6));
485 auto c = Operand(shader, *this, insn.word(7));
486 for(auto i = 0u; i < type.componentCount; i++)
487 {
488 dst.move(i, MulAdd(a.Float(i), b.Float(i), c.Float(i)));
489 }
490 }
491 break;
492 case GLSLstd450Frexp:
493 {
494 auto val = Operand(shader, *this, insn.word(5));
495 auto ptrId = Spirv::Object::ID(insn.word(6));
496
497 Intermediate exp(type.componentCount);
498
499 for(auto i = 0u; i < type.componentCount; i++)
500 {
501 auto significandAndExponent = Frexp(val.Float(i));
502 dst.move(i, significandAndExponent.first);
503 exp.move(i, significandAndExponent.second);
504 }
505
506 Store(ptrId, exp, false, std::memory_order_relaxed);
507 }
508 break;
509 case GLSLstd450FrexpStruct:
510 {
511 auto val = Operand(shader, *this, insn.word(5));
512
513 for(auto i = 0u; i < val.componentCount; i++)
514 {
515 auto significandAndExponent = Frexp(val.Float(i));
516 dst.move(i, significandAndExponent.first);
517 dst.move(val.componentCount + i, significandAndExponent.second);
518 }
519 }
520 break;
521 case GLSLstd450Ldexp:
522 {
523 auto x = Operand(shader, *this, insn.word(5));
524 auto exp = Operand(shader, *this, insn.word(6));
525
526 for(auto i = 0u; i < type.componentCount; i++)
527 {
528 dst.move(i, Ldexp(x.Float(i), exp.Int(i)));
529 }
530 }
531 break;
532 case GLSLstd450Radians:
533 {
534 auto degrees = Operand(shader, *this, insn.word(5));
535 for(auto i = 0u; i < type.componentCount; i++)
536 {
537 dst.move(i, degrees.Float(i) * SIMD::Float(PI / 180.0f));
538 }
539 }
540 break;
541 case GLSLstd450Degrees:
542 {
543 auto radians = Operand(shader, *this, insn.word(5));
544 for(auto i = 0u; i < type.componentCount; i++)
545 {
546 dst.move(i, radians.Float(i) * SIMD::Float(180.0f / PI));
547 }
548 }
549 break;
550 case GLSLstd450Sin:
551 {
552 auto radians = Operand(shader, *this, insn.word(5));
553 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
554
555 for(auto i = 0u; i < type.componentCount; i++)
556 {
557 dst.move(i, Sin(radians.Float(i), d.RelaxedPrecision));
558 }
559 }
560 break;
561 case GLSLstd450Cos:
562 {
563 auto radians = Operand(shader, *this, insn.word(5));
564 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
565
566 for(auto i = 0u; i < type.componentCount; i++)
567 {
568 dst.move(i, Cos(radians.Float(i), d.RelaxedPrecision));
569 }
570 }
571 break;
572 case GLSLstd450Tan:
573 {
574 auto radians = Operand(shader, *this, insn.word(5));
575 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
576
577 for(auto i = 0u; i < type.componentCount; i++)
578 {
579 dst.move(i, Tan(radians.Float(i), d.RelaxedPrecision));
580 }
581 }
582 break;
583 case GLSLstd450Asin:
584 {
585 auto val = Operand(shader, *this, insn.word(5));
586 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
587
588 for(auto i = 0u; i < type.componentCount; i++)
589 {
590 dst.move(i, Asin(val.Float(i), d.RelaxedPrecision));
591 }
592 }
593 break;
594 case GLSLstd450Acos:
595 {
596 auto val = Operand(shader, *this, insn.word(5));
597 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
598
599 for(auto i = 0u; i < type.componentCount; i++)
600 {
601 dst.move(i, Acos(val.Float(i), d.RelaxedPrecision));
602 }
603 }
604 break;
605 case GLSLstd450Atan:
606 {
607 auto val = Operand(shader, *this, insn.word(5));
608 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
609
610 for(auto i = 0u; i < type.componentCount; i++)
611 {
612 dst.move(i, Atan(val.Float(i), d.RelaxedPrecision));
613 }
614 }
615 break;
616 case GLSLstd450Sinh:
617 {
618 auto val = Operand(shader, *this, insn.word(5));
619 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
620
621 for(auto i = 0u; i < type.componentCount; i++)
622 {
623 dst.move(i, Sinh(val.Float(i), d.RelaxedPrecision));
624 }
625 }
626 break;
627 case GLSLstd450Cosh:
628 {
629 auto val = Operand(shader, *this, insn.word(5));
630 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
631
632 for(auto i = 0u; i < type.componentCount; i++)
633 {
634 dst.move(i, Cosh(val.Float(i), d.RelaxedPrecision));
635 }
636 }
637 break;
638 case GLSLstd450Tanh:
639 {
640 auto val = Operand(shader, *this, insn.word(5));
641 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
642
643 for(auto i = 0u; i < type.componentCount; i++)
644 {
645 dst.move(i, Tanh(val.Float(i), d.RelaxedPrecision));
646 }
647 }
648 break;
649 case GLSLstd450Asinh:
650 {
651 auto val = Operand(shader, *this, insn.word(5));
652 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
653
654 for(auto i = 0u; i < type.componentCount; i++)
655 {
656 dst.move(i, Asinh(val.Float(i), d.RelaxedPrecision));
657 }
658 }
659 break;
660 case GLSLstd450Acosh:
661 {
662 auto val = Operand(shader, *this, insn.word(5));
663 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
664
665 for(auto i = 0u; i < type.componentCount; i++)
666 {
667 dst.move(i, Acosh(val.Float(i), d.RelaxedPrecision));
668 }
669 }
670 break;
671 case GLSLstd450Atanh:
672 {
673 auto val = Operand(shader, *this, insn.word(5));
674 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
675
676 for(auto i = 0u; i < type.componentCount; i++)
677 {
678 dst.move(i, Atanh(val.Float(i), d.RelaxedPrecision));
679 }
680 }
681 break;
682 case GLSLstd450Atan2:
683 {
684 auto x = Operand(shader, *this, insn.word(5));
685 auto y = Operand(shader, *this, insn.word(6));
686 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
687
688 for(auto i = 0u; i < type.componentCount; i++)
689 {
690 dst.move(i, Atan2(x.Float(i), y.Float(i), d.RelaxedPrecision));
691 }
692 }
693 break;
694 case GLSLstd450Pow:
695 {
696 auto x = Operand(shader, *this, insn.word(5));
697 auto y = Operand(shader, *this, insn.word(6));
698 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
699
700 for(auto i = 0u; i < type.componentCount; i++)
701 {
702 dst.move(i, Pow(x.Float(i), y.Float(i), d.RelaxedPrecision));
703 }
704 }
705 break;
706 case GLSLstd450Exp:
707 {
708 auto val = Operand(shader, *this, insn.word(5));
709 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
710
711 for(auto i = 0u; i < type.componentCount; i++)
712 {
713 dst.move(i, Exp(val.Float(i), d.RelaxedPrecision));
714 }
715 }
716 break;
717 case GLSLstd450Log:
718 {
719 auto val = Operand(shader, *this, insn.word(5));
720 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
721
722 for(auto i = 0u; i < type.componentCount; i++)
723 {
724 dst.move(i, Log(val.Float(i), d.RelaxedPrecision));
725 }
726 }
727 break;
728 case GLSLstd450Exp2:
729 {
730 auto val = Operand(shader, *this, insn.word(5));
731 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
732
733 for(auto i = 0u; i < type.componentCount; i++)
734 {
735 dst.move(i, Exp2(val.Float(i), d.RelaxedPrecision));
736 }
737 }
738 break;
739 case GLSLstd450Log2:
740 {
741 auto val = Operand(shader, *this, insn.word(5));
742 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
743
744 for(auto i = 0u; i < type.componentCount; i++)
745 {
746 dst.move(i, Log2(val.Float(i), d.RelaxedPrecision));
747 }
748 }
749 break;
750 case GLSLstd450Sqrt:
751 {
752 auto val = Operand(shader, *this, insn.word(5));
753 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
754
755 for(auto i = 0u; i < type.componentCount; i++)
756 {
757 dst.move(i, Sqrt(val.Float(i), d.RelaxedPrecision));
758 }
759 }
760 break;
761 case GLSLstd450InverseSqrt:
762 {
763 auto val = Operand(shader, *this, insn.word(5));
764 Spirv::Decorations d = shader.GetDecorationsForId(insn.resultId());
765
766 for(auto i = 0u; i < type.componentCount; i++)
767 {
768 dst.move(i, RcpSqrt(val.Float(i), d.RelaxedPrecision));
769 }
770 }
771 break;
772 case GLSLstd450Determinant:
773 {
774 auto mat = Operand(shader, *this, insn.word(5));
775
776 switch(mat.componentCount)
777 {
778 case 4: // 2x2
779 dst.move(0, Determinant(
780 mat.Float(0), mat.Float(1),
781 mat.Float(2), mat.Float(3)));
782 break;
783 case 9: // 3x3
784 dst.move(0, Determinant(
785 mat.Float(0), mat.Float(1), mat.Float(2),
786 mat.Float(3), mat.Float(4), mat.Float(5),
787 mat.Float(6), mat.Float(7), mat.Float(8)));
788 break;
789 case 16: // 4x4
790 dst.move(0, Determinant(
791 mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3),
792 mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7),
793 mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11),
794 mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15)));
795 break;
796 default:
797 UNREACHABLE("GLSLstd450Determinant can only operate with square matrices. Got %d elements", int(mat.componentCount));
798 }
799 }
800 break;
801 case GLSLstd450MatrixInverse:
802 {
803 auto mat = Operand(shader, *this, insn.word(5));
804
805 switch(mat.componentCount)
806 {
807 case 4: // 2x2
808 {
809 auto inv = MatrixInverse(
810 mat.Float(0), mat.Float(1),
811 mat.Float(2), mat.Float(3));
812 for(uint32_t i = 0; i < inv.size(); i++)
813 {
814 dst.move(i, inv[i]);
815 }
816 }
817 break;
818 case 9: // 3x3
819 {
820 auto inv = MatrixInverse(
821 mat.Float(0), mat.Float(1), mat.Float(2),
822 mat.Float(3), mat.Float(4), mat.Float(5),
823 mat.Float(6), mat.Float(7), mat.Float(8));
824 for(uint32_t i = 0; i < inv.size(); i++)
825 {
826 dst.move(i, inv[i]);
827 }
828 }
829 break;
830 case 16: // 4x4
831 {
832 auto inv = MatrixInverse(
833 mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3),
834 mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7),
835 mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11),
836 mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15));
837 for(uint32_t i = 0; i < inv.size(); i++)
838 {
839 dst.move(i, inv[i]);
840 }
841 }
842 break;
843 default:
844 UNREACHABLE("GLSLstd450MatrixInverse can only operate with square matrices. Got %d elements", int(mat.componentCount));
845 }
846 }
847 break;
848 case GLSLstd450IMix:
849 {
850 UNREACHABLE("GLSLstd450IMix has been removed from the specification");
851 }
852 break;
853 case GLSLstd450PackDouble2x32:
854 {
855 UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450PackDouble2x32)");
856 }
857 break;
858 case GLSLstd450UnpackDouble2x32:
859 {
860 UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450UnpackDouble2x32)");
861 }
862 break;
863 case GLSLstd450FindILsb:
864 {
865 auto val = Operand(shader, *this, insn.word(5));
866 for(auto i = 0u; i < type.componentCount; i++)
867 {
868 auto v = val.UInt(i);
869 dst.move(i, Cttz(v, false) | CmpEQ(v, SIMD::UInt(0)));
870 }
871 }
872 break;
873 case GLSLstd450FindSMsb:
874 {
875 auto val = Operand(shader, *this, insn.word(5));
876 for(auto i = 0u; i < type.componentCount; i++)
877 {
878 auto v = val.UInt(i) ^ As<SIMD::UInt>(CmpLT(val.Int(i), SIMD::Int(0)));
879 dst.move(i, SIMD::UInt(31) - Ctlz(v, false));
880 }
881 }
882 break;
883 case GLSLstd450FindUMsb:
884 {
885 auto val = Operand(shader, *this, insn.word(5));
886 for(auto i = 0u; i < type.componentCount; i++)
887 {
888 dst.move(i, SIMD::UInt(31) - Ctlz(val.UInt(i), false));
889 }
890 }
891 break;
892 case GLSLstd450InterpolateAtCentroid:
893 {
894 Spirv::Decorations d = shader.GetDecorationsForId(insn.word(5));
895 auto ptr = getPointer(insn.word(5));
896 for(auto i = 0u; i < type.componentCount; i++)
897 {
898 dst.move(i, EmitInterpolate(ptr, d.Location, 0, i, Centroid));
899 }
900 }
901 break;
902 case GLSLstd450InterpolateAtSample:
903 {
904 Spirv::Decorations d = shader.GetDecorationsForId(insn.word(5));
905 auto ptr = getPointer(insn.word(5));
906 for(auto i = 0u; i < type.componentCount; i++)
907 {
908 dst.move(i, EmitInterpolate(ptr, d.Location, insn.word(6), i, AtSample));
909 }
910 }
911 break;
912 case GLSLstd450InterpolateAtOffset:
913 {
914 Spirv::Decorations d = shader.GetDecorationsForId(insn.word(5));
915 auto ptr = getPointer(insn.word(5));
916 for(auto i = 0u; i < type.componentCount; i++)
917 {
918 dst.move(i, EmitInterpolate(ptr, d.Location, insn.word(6), i, AtOffset));
919 }
920 }
921 break;
922 case GLSLstd450NMin:
923 {
924 auto x = Operand(shader, *this, insn.word(5));
925 auto y = Operand(shader, *this, insn.word(6));
926 for(auto i = 0u; i < type.componentCount; i++)
927 {
928 dst.move(i, NMin(x.Float(i), y.Float(i)));
929 }
930 }
931 break;
932 case GLSLstd450NMax:
933 {
934 auto x = Operand(shader, *this, insn.word(5));
935 auto y = Operand(shader, *this, insn.word(6));
936 for(auto i = 0u; i < type.componentCount; i++)
937 {
938 dst.move(i, NMax(x.Float(i), y.Float(i)));
939 }
940 }
941 break;
942 case GLSLstd450NClamp:
943 {
944 auto x = Operand(shader, *this, insn.word(5));
945 auto minVal = Operand(shader, *this, insn.word(6));
946 auto maxVal = Operand(shader, *this, insn.word(7));
947 for(auto i = 0u; i < type.componentCount; i++)
948 {
949 auto clamp = NMin(NMax(x.Float(i), minVal.Float(i)), maxVal.Float(i));
950 dst.move(i, clamp);
951 }
952 }
953 break;
954 default:
955 UNREACHABLE("ExtInst %d", int(extInstIndex));
956 break;
957 }
958 }
959
Interpolate(const SIMD::Float & x,const SIMD::Float & y,const SIMD::Float & rhw,const SIMD::Float & A,const SIMD::Float & B,const SIMD::Float & C,SpirvRoutine::Interpolation interpolation)960 static SIMD::Float Interpolate(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw,
961 const SIMD::Float &A, const SIMD::Float &B, const SIMD::Float &C,
962 SpirvRoutine::Interpolation interpolation)
963 {
964 SIMD::Float interpolant = C;
965
966 if(interpolation != SpirvRoutine::Flat)
967 {
968 interpolant += x * A + y * B;
969
970 if(interpolation == SpirvRoutine::Perspective)
971 {
972 interpolant *= rhw;
973 }
974 }
975
976 return interpolant;
977 }
978
EmitInterpolate(const SIMD::Pointer & ptr,int32_t location,Spirv::Object::ID paramId,uint32_t component,InterpolationType type) const979 SIMD::Float SpirvEmitter::EmitInterpolate(const SIMD::Pointer &ptr, int32_t location, Spirv::Object::ID paramId,
980 uint32_t component, InterpolationType type) const
981 {
982 uint32_t interpolant = (location * 4);
983 uint32_t components_per_row = shader.GetNumInputComponents(location);
984 if((location < 0) || (interpolant >= shader.inputs.size()) || (components_per_row == 0))
985 {
986 return SIMD::Float(0.0f);
987 }
988
989 const auto &interpolationData = routine->interpolationData;
990
991 SIMD::Float x;
992 SIMD::Float y;
993 SIMD::Float rhw;
994
995 bool multisample = (multiSampleCount > 1);
996 switch(type)
997 {
998 case Centroid:
999 if(multisample)
1000 {
1001 x = interpolationData.xCentroid;
1002 y = interpolationData.yCentroid;
1003 rhw = interpolationData.rhwCentroid;
1004 }
1005 else
1006 {
1007 x = interpolationData.x;
1008 y = interpolationData.y;
1009 rhw = interpolationData.rhw;
1010 }
1011 break;
1012 case AtSample:
1013 x = SIMD::Float(0.0f);
1014 y = SIMD::Float(0.0f);
1015
1016 if(multisample)
1017 {
1018 static constexpr int NUM_SAMPLES = 4;
1019 ASSERT(multiSampleCount == NUM_SAMPLES);
1020
1021 auto sampleOperand = Operand(shader, *this, paramId);
1022 ASSERT(sampleOperand.componentCount == 1);
1023
1024 // If sample does not exist, the position used to interpolate the
1025 // input variable is undefined, so we just clamp to avoid OOB accesses.
1026 SIMD::Int samples = sampleOperand.Int(0) & SIMD::Int(NUM_SAMPLES - 1);
1027
1028 for(int i = 0; i < SIMD::Width; i++)
1029 {
1030 Int sample = Extract(samples, i);
1031 x = Insert(x, *Pointer<Float>(routine->constants + OFFSET(Constants, SampleLocationsX) + sample * sizeof(float)), i);
1032 y = Insert(y, *Pointer<Float>(routine->constants + OFFSET(Constants, SampleLocationsY) + sample * sizeof(float)), i);
1033 }
1034 }
1035
1036 x += interpolationData.x;
1037 y += interpolationData.y;
1038 rhw = interpolationData.rhw;
1039 break;
1040 case AtOffset:
1041 {
1042 // An offset of (0, 0) identifies the center of the pixel.
1043 auto offset = Operand(shader, *this, paramId);
1044 ASSERT(offset.componentCount == 2);
1045
1046 x = interpolationData.x + offset.Float(0);
1047 y = interpolationData.y + offset.Float(1);
1048 rhw = interpolationData.rhw;
1049 }
1050 break;
1051 default:
1052 UNREACHABLE("Unknown interpolation type: %d", (int)type);
1053 return SIMD::Float(0.0f);
1054 }
1055
1056 uint32_t packedInterpolant = shader.GetPackedInterpolant(location);
1057 Pointer<Byte> planeEquation = interpolationData.primitive + OFFSET(Primitive, V[packedInterpolant]);
1058
1059 // The pointer's offsets index into the input variable array, which are SIMD::Float vectors.
1060 // To obtain the index into the interpolant's plane equation we must unscale by the vector size.
1061 const int offsetShift = log2i(sizeof(float) * SIMD::Width);
1062
1063 if(ptr.hasDynamicOffsets)
1064 {
1065 // Combine plane equations into one
1066 SIMD::Float A;
1067 SIMD::Float B;
1068 SIMD::Float C;
1069
1070 for(int i = 0; i < SIMD::Width; i++)
1071 {
1072 Int offset = ((Extract(ptr.dynamicOffsets, i) + ptr.staticOffsets[i]) >> offsetShift) + component;
1073 Pointer<Byte> planeEquationI = planeEquation + (offset * sizeof(PlaneEquation));
1074 A = Insert(A, *Pointer<Float>(planeEquationI + OFFSET(PlaneEquation, A)), i);
1075 B = Insert(B, *Pointer<Float>(planeEquationI + OFFSET(PlaneEquation, B)), i);
1076 C = Insert(C, *Pointer<Float>(planeEquationI + OFFSET(PlaneEquation, C)), i);
1077 }
1078
1079 return Interpolate(x, y, rhw, A, B, C, routine->inputsInterpolation[packedInterpolant]);
1080 }
1081 else
1082 {
1083 ASSERT(ptr.hasStaticEqualOffsets());
1084
1085 uint32_t offset = (ptr.staticOffsets[0] >> offsetShift) + component;
1086 if((interpolant + offset) >= shader.inputs.size())
1087 {
1088 return SIMD::Float(0.0f);
1089 }
1090 planeEquation += offset * sizeof(PlaneEquation);
1091 }
1092
1093 return SpirvRoutine::interpolateAtXY(x, y, rhw, planeEquation, routine->inputsInterpolation[packedInterpolant]);
1094 }
1095
interpolateAtXY(const SIMD::Float & x,const SIMD::Float & y,const SIMD::Float & rhw,Pointer<Byte> planeEquation,Interpolation interpolation)1096 SIMD::Float SpirvRoutine::interpolateAtXY(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw, Pointer<Byte> planeEquation, Interpolation interpolation)
1097 {
1098 SIMD::Float A;
1099 SIMD::Float B;
1100 SIMD::Float C = *Pointer<Float>(planeEquation + OFFSET(PlaneEquation, C));
1101
1102 if(interpolation != SpirvRoutine::Flat)
1103 {
1104 A = *Pointer<Float>(planeEquation + OFFSET(PlaneEquation, A));
1105 B = *Pointer<Float>(planeEquation + OFFSET(PlaneEquation, B));
1106 }
1107
1108 return Interpolate(x, y, rhw, A, B, C, interpolation);
1109 }
1110
1111 } // namespace sw
1112