xref: /aosp_15_r20/external/swiftshader/src/Pipeline/SpirvShaderGLSLstd450.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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