blob: 4926f41eb6a35fba647be1b1ac9a0fac1e47a7cf [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzenf9818f02020-01-16 15:24:37 +01002 * Copyright 2015-2020 Arm Limited
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020017#include "spirv_glsl.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010018#include "GLSL.std.450.h"
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +020019#include "spirv_common.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010020#include <algorithm>
21#include <assert.h>
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010022#include <cmath>
Hans-Kristian Arntzencc7679e2018-07-17 00:10:12 +020023#include <limits>
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +010024#include <locale.h>
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +010025#include <utility>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010026
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +010027#ifndef _WIN32
28#include <langinfo.h>
29#endif
30#include <locale.h>
31
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010032using namespace spv;
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010033using namespace SPIRV_CROSS_NAMESPACE;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010034using namespace std;
35
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020036static bool is_unsigned_opcode(Op op)
37{
38 // Don't have to be exhaustive, only relevant for legacy target checking ...
39 switch (op)
40 {
41 case OpShiftRightLogical:
42 case OpUGreaterThan:
43 case OpUGreaterThanEqual:
44 case OpULessThan:
45 case OpULessThanEqual:
46 case OpUConvert:
47 case OpUDiv:
48 case OpUMod:
49 case OpUMulExtended:
50 case OpConvertUToF:
51 case OpConvertFToU:
52 return true;
53
54 default:
55 return false;
56 }
57}
58
59static bool is_unsigned_glsl_opcode(GLSLstd450 op)
60{
61 // Don't have to be exhaustive, only relevant for legacy target checking ...
62 switch (op)
63 {
64 case GLSLstd450UClamp:
65 case GLSLstd450UMin:
66 case GLSLstd450UMax:
67 case GLSLstd450FindUMsb:
68 return true;
69
70 default:
71 return false;
72 }
73}
74
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +020075static bool packing_is_vec4_padded(BufferPackingStandard packing)
76{
77 switch (packing)
78 {
79 case BufferPackingHLSLCbuffer:
80 case BufferPackingHLSLCbufferPackOffset:
81 case BufferPackingStd140:
82 case BufferPackingStd140EnhancedLayout:
83 return true;
84
85 default:
86 return false;
87 }
88}
89
90static bool packing_is_hlsl(BufferPackingStandard packing)
91{
92 switch (packing)
93 {
94 case BufferPackingHLSLCbuffer:
95 case BufferPackingHLSLCbufferPackOffset:
96 return true;
97
98 default:
99 return false;
100 }
101}
102
103static bool packing_has_flexible_offset(BufferPackingStandard packing)
104{
105 switch (packing)
106 {
107 case BufferPackingStd140:
108 case BufferPackingStd430:
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200109 case BufferPackingScalar:
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200110 case BufferPackingHLSLCbuffer:
111 return false;
112
113 default:
114 return true;
115 }
116}
117
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200118static bool packing_is_scalar(BufferPackingStandard packing)
119{
120 switch (packing)
121 {
122 case BufferPackingScalar:
123 case BufferPackingScalarEnhancedLayout:
124 return true;
125
126 default:
127 return false;
128 }
129}
130
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200131static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard packing)
132{
133 switch (packing)
134 {
135 case BufferPackingStd140EnhancedLayout:
136 return BufferPackingStd140;
137 case BufferPackingStd430EnhancedLayout:
138 return BufferPackingStd430;
139 case BufferPackingHLSLCbufferPackOffset:
140 return BufferPackingHLSLCbuffer;
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200141 case BufferPackingScalarEnhancedLayout:
142 return BufferPackingScalar;
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200143 default:
144 return packing;
145 }
146}
147
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +0100148// Sanitizes underscores for GLSL where multiple underscores in a row are not allowed.
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +0200149string CompilerGLSL::sanitize_underscores(const string &str)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +0100150{
151 string res;
152 res.reserve(str.size());
153
154 bool last_underscore = false;
155 for (auto c : str)
156 {
157 if (c == '_')
158 {
159 if (last_underscore)
160 continue;
161
162 res += c;
163 last_underscore = true;
164 }
165 else
166 {
167 res += c;
168 last_underscore = false;
169 }
170 }
171 return res;
172}
173
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100174void CompilerGLSL::init()
175{
176 if (ir.source.known)
177 {
178 options.es = ir.source.es;
179 options.version = ir.source.version;
180 }
181
182 // Query the locale to see what the decimal point is.
183 // We'll rely on fixing it up ourselves in the rare case we have a comma-as-decimal locale
184 // rather than setting locales ourselves. Settings locales in a safe and isolated way is rather
185 // tricky.
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100186#ifdef _WIN32
187 // On Windows, localeconv uses thread-local storage, so it should be fine.
188 const struct lconv *conv = localeconv();
189 if (conv && conv->decimal_point)
190 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen73102742019-03-18 10:13:33 +0100191#elif defined(__ANDROID__) && __ANDROID_API__ < 26
192 // nl_langinfo is not supported on this platform, fall back to the worse alternative.
193 const struct lconv *conv = localeconv();
194 if (conv && conv->decimal_point)
195 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100196#else
197 // localeconv, the portable function is not MT safe ...
Hans-Kristian Arntzen40965522019-02-28 12:32:52 +0100198 const char *decimal_point = nl_langinfo(RADIXCHAR);
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100199 if (decimal_point && *decimal_point != '\0')
200 current_locale_radix_character = *decimal_point;
201#endif
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100202}
203
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200204static const char *to_pls_layout(PlsFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100205{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200206 switch (format)
207 {
208 case PlsR11FG11FB10F:
209 return "layout(r11f_g11f_b10f) ";
210 case PlsR32F:
211 return "layout(r32f) ";
212 case PlsRG16F:
213 return "layout(rg16f) ";
214 case PlsRGB10A2:
215 return "layout(rgb10_a2) ";
216 case PlsRGBA8:
217 return "layout(rgba8) ";
218 case PlsRG16:
219 return "layout(rg16) ";
220 case PlsRGBA8I:
221 return "layout(rgba8i)";
222 case PlsRG16I:
223 return "layout(rg16i) ";
224 case PlsRGB10A2UI:
225 return "layout(rgb10_a2ui) ";
226 case PlsRGBA8UI:
227 return "layout(rgba8ui) ";
228 case PlsRG16UI:
229 return "layout(rg16ui) ";
230 case PlsR32UI:
231 return "layout(r32ui) ";
232 default:
233 return "";
234 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100235}
236
237static SPIRType::BaseType pls_format_to_basetype(PlsFormat format)
238{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200239 switch (format)
240 {
241 default:
242 case PlsR11FG11FB10F:
243 case PlsR32F:
244 case PlsRG16F:
245 case PlsRGB10A2:
246 case PlsRGBA8:
247 case PlsRG16:
248 return SPIRType::Float;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200250 case PlsRGBA8I:
251 case PlsRG16I:
252 return SPIRType::Int;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200254 case PlsRGB10A2UI:
255 case PlsRGBA8UI:
256 case PlsRG16UI:
257 case PlsR32UI:
258 return SPIRType::UInt;
259 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100260}
261
262static uint32_t pls_format_to_components(PlsFormat format)
263{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200264 switch (format)
265 {
266 default:
267 case PlsR32F:
268 case PlsR32UI:
269 return 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100270
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200271 case PlsRG16F:
272 case PlsRG16:
273 case PlsRG16UI:
274 case PlsRG16I:
275 return 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100276
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200277 case PlsR11FG11FB10F:
278 return 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100279
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200280 case PlsRGB10A2:
281 case PlsRGBA8:
282 case PlsRGBA8I:
283 case PlsRGB10A2UI:
284 case PlsRGBA8UI:
285 return 4;
286 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100287}
288
Hans-Kristian Arntzen93f32652020-01-07 14:05:55 +0100289const char *CompilerGLSL::vector_swizzle(int vecsize, int index)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800290{
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +0200291 static const char *const swizzle[4][4] = {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +0200292 { ".x", ".y", ".z", ".w" },
293 { ".xy", ".yz", ".zw", nullptr },
294 { ".xyz", ".yzw", nullptr, nullptr },
Hans-Kristian Arntzen7557ff52019-06-24 10:17:25 +0200295#if defined(__GNUC__) && (__GNUC__ == 9)
296 // This works around a GCC 9 bug, see details in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90947.
297 // This array ends up being compiled as all nullptrs, tripping the assertions below.
298 { "", nullptr, nullptr, "$" },
299#else
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +0200300 { "", nullptr, nullptr, nullptr },
Hans-Kristian Arntzen7557ff52019-06-24 10:17:25 +0200301#endif
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800302 };
303
304 assert(vecsize >= 1 && vecsize <= 4);
305 assert(index >= 0 && index < 4);
306 assert(swizzle[vecsize - 1][index]);
307
308 return swizzle[vecsize - 1][index];
309}
310
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100311void CompilerGLSL::reset()
312{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200313 // We do some speculative optimizations which should pretty much always work out,
314 // but just in case the SPIR-V is rather weird, recompile until it's happy.
315 // This typically only means one extra pass.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200316 clear_force_recompile();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200318 // Clear invalid expression tracking.
319 invalid_expressions.clear();
320 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100321
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200322 // Clear temporary usage tracking.
323 expression_usage_counts.clear();
324 forwarded_temporaries.clear();
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +0200325 suppressed_usage_tracking.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100326
Lukas Hermanns50ac6862019-09-18 14:03:54 -0400327 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -0400328 flushed_phi_variables.clear();
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400329
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +0100330 reset_name_caches();
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200331
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100332 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, SPIRFunction &func) {
333 func.active = false;
334 func.flush_undeclared = true;
335 });
336
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +0100337 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) { var.dependees.clear(); });
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100338
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400339 ir.reset_all_of_type<SPIRExpression>();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100340 ir.reset_all_of_type<SPIRAccessChain>();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100341
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200342 statement_count = 0;
343 indent = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100344}
345
346void CompilerGLSL::remap_pls_variables()
347{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200348 for (auto &input : pls_inputs)
349 {
350 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200352 bool input_is_target = false;
353 if (var.storage == StorageClassUniformConstant)
354 {
355 auto &type = get<SPIRType>(var.basetype);
356 input_is_target = type.image.dim == DimSubpassData;
357 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100358
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200359 if (var.storage != StorageClassInput && !input_is_target)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100360 SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200361 var.remapped_variable = true;
362 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200364 for (auto &output : pls_outputs)
365 {
366 auto &var = get<SPIRVariable>(output.id);
367 if (var.storage != StorageClassOutput)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100368 SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200369 var.remapped_variable = true;
370 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100371}
372
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100373void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location)
374{
375 subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
376 inout_color_attachments.insert(color_location);
377}
378
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200379void CompilerGLSL::find_static_extensions()
380{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100381 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
382 if (type.basetype == SPIRType::Double)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200383 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100384 if (options.es)
385 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
386 if (!options.es && options.version < 400)
387 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200388 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100389 else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100390 {
391 if (options.es)
392 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
393 if (!options.es)
394 require_extension_internal("GL_ARB_gpu_shader_int64");
395 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100396 else if (type.basetype == SPIRType::Half)
397 {
398 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_float16");
399 if (options.vulkan_semantics)
400 require_extension_internal("GL_EXT_shader_16bit_storage");
401 }
402 else if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
403 {
404 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int8");
405 if (options.vulkan_semantics)
406 require_extension_internal("GL_EXT_shader_8bit_storage");
407 }
408 else if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
409 {
410 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int16");
411 if (options.vulkan_semantics)
412 require_extension_internal("GL_EXT_shader_16bit_storage");
413 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100414 });
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200415
416 auto &execution = get_entry_point();
417 switch (execution.model)
418 {
419 case ExecutionModelGLCompute:
420 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200421 require_extension_internal("GL_ARB_compute_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200422 if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100423 SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200424 break;
425
426 case ExecutionModelGeometry:
427 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200428 require_extension_internal("GL_EXT_geometry_shader");
robfb1820e2017-06-17 10:06:46 +0900429 if (!options.es && options.version < 150)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200430 require_extension_internal("GL_ARB_geometry_shader4");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200431
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100432 if (execution.flags.get(ExecutionModeInvocations) && execution.invocations != 1)
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200433 {
434 // Instanced GS is part of 400 core or this extension.
435 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200436 require_extension_internal("GL_ARB_gpu_shader5");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200437 }
438 break;
439
440 case ExecutionModelTessellationEvaluation:
441 case ExecutionModelTessellationControl:
442 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200443 require_extension_internal("GL_EXT_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200444 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200445 require_extension_internal("GL_ARB_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200446 break;
447
Patrick Moursc74d7a42019-03-25 15:06:01 +0100448 case ExecutionModelRayGenerationNV:
449 case ExecutionModelIntersectionNV:
450 case ExecutionModelAnyHitNV:
451 case ExecutionModelClosestHitNV:
452 case ExecutionModelMissNV:
453 case ExecutionModelCallableNV:
454 if (options.es || options.version < 460)
455 SPIRV_CROSS_THROW("Ray tracing shaders require non-es profile with version 460 or above.");
Patrick Moursc96bab02019-03-26 14:04:39 +0100456 require_extension_internal("GL_NV_ray_tracing");
Patrick Moursc74d7a42019-03-25 15:06:01 +0100457 break;
458
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200459 default:
460 break;
461 }
462
463 if (!pls_inputs.empty() || !pls_outputs.empty())
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100464 {
465 if (execution.model != ExecutionModelFragment)
466 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_pixel_local_storage in fragment shaders.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200467 require_extension_internal("GL_EXT_shader_pixel_local_storage");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100468 }
469
470 if (!inout_color_attachments.empty())
471 {
472 if (execution.model != ExecutionModelFragment)
473 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
474 if (options.vulkan_semantics)
475 SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
476 require_extension_internal("GL_EXT_shader_framebuffer_fetch");
477 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +0200478
479 if (options.separate_shader_objects && !options.es && options.version < 410)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200480 require_extension_internal("GL_ARB_separate_shader_objects");
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200481
482 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
483 {
484 if (!options.vulkan_semantics)
485 SPIRV_CROSS_THROW("GL_EXT_buffer_reference is only supported in Vulkan GLSL.");
486 if (options.es && options.version < 320)
487 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires ESSL 320.");
488 else if (!options.es && options.version < 450)
489 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires GLSL 450.");
490 require_extension_internal("GL_EXT_buffer_reference");
491 }
492 else if (ir.addressing_model != AddressingModelLogical)
493 {
494 SPIRV_CROSS_THROW("Only Logical and PhysicalStorageBuffer64EXT addressing models are supported.");
495 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200496
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100497 // Check for nonuniform qualifier and passthrough.
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200498 // Instead of looping over all decorations to find this, just look at capabilities.
499 for (auto &cap : ir.declared_capabilities)
500 {
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200501 switch (cap)
502 {
503 case CapabilityShaderNonUniformEXT:
Mateusz Kielan127224d2020-04-18 21:21:43 +0200504 if (!options.vulkan_semantics)
505 require_extension_internal("GL_NV_gpu_shader5");
506 else
507 require_extension_internal("GL_EXT_nonuniform_qualifier");
508 break;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200509 case CapabilityRuntimeDescriptorArrayEXT:
510 if (!options.vulkan_semantics)
511 SPIRV_CROSS_THROW("GL_EXT_nonuniform_qualifier is only supported in Vulkan GLSL.");
512 require_extension_internal("GL_EXT_nonuniform_qualifier");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100513 break;
514
515 case CapabilityGeometryShaderPassthroughNV:
516 if (execution.model == ExecutionModelGeometry)
517 {
518 require_extension_internal("GL_NV_geometry_shader_passthrough");
519 execution.geometry_passthrough = true;
520 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200521 break;
522
523 default:
524 break;
525 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200526 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200527}
528
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100529string CompilerGLSL::compile()
530{
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100531 if (options.vulkan_semantics)
532 backend.allow_precision_qualifiers = true;
Mateusz Kielan127224d2020-04-18 21:21:43 +0200533 else
534 {
535 // only NV_gpu_shader5 supports divergent indexing on OpenGL, and it does so without extra qualifiers
536 backend.nonuniform_qualifier = "";
537 }
Hans-Kristian Arntzenf708b492018-01-09 09:16:33 +0100538 backend.force_gl_in_out_block = true;
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +0100539 backend.supports_extensions = true;
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +0200540 backend.use_array_constructor = true;
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100541
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200542 // Scan the SPIR-V to find trivial uses of extensions.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200543 fixup_type_alias();
544 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200545 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200546 find_static_extensions();
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +0100547 fixup_image_load_store_access();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100548 update_active_builtins();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +0100549 analyze_image_and_sampler_usage();
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200550 analyze_interlocked_resource_usage();
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100551 if (!inout_color_attachments.empty())
552 emit_inout_fragment_outputs_copy_to_subpass_inputs();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200553
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200554 // Shaders might cast unrelated data to pointers of non-block types.
555 // Find all such instances and make sure we can cast the pointers to a synthesized block type.
556 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
557 analyze_non_block_pointer_types();
558
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200559 uint32_t pass_count = 0;
560 do
561 {
562 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100563 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200565 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100566
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200567 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100568
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200569 emit_header();
570 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100571
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200572 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200574 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200575 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100576
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200577 // Implement the interlocked wrapper function at the end.
578 // The body was implemented in lieu of main().
579 if (interlocked_is_complex)
580 {
581 statement("void main()");
582 begin_scope();
583 statement("// Interlocks were used in a way not compatible with GLSL, this is very slow.");
584 if (options.es)
585 statement("beginInvocationInterlockNV();");
586 else
587 statement("beginInvocationInterlockARB();");
588 statement("spvMainInterlockedBody();");
589 if (options.es)
590 statement("endInvocationInterlockNV();");
591 else
592 statement("endInvocationInterlockARB();");
593 end_scope();
594 }
595
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100596 // Entry point in GLSL is always main().
597 get_entry_point().name = "main";
598
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200599 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100600}
601
Bill Hollingsc5c07362016-11-27 12:34:04 -0500602std::string CompilerGLSL::get_partial_source()
603{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200604 return buffer.str();
Bill Hollingsc5c07362016-11-27 12:34:04 -0500605}
606
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200607void CompilerGLSL::build_workgroup_size(SmallVector<string> &arguments, const SpecializationConstant &wg_x,
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +0100608 const SpecializationConstant &wg_y, const SpecializationConstant &wg_z)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100609{
610 auto &execution = get_entry_point();
611
612 if (wg_x.id)
613 {
614 if (options.vulkan_semantics)
615 arguments.push_back(join("local_size_x_id = ", wg_x.constant_id));
616 else
617 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(wg_x.id).specialization_constant_macro_name));
618 }
619 else
620 arguments.push_back(join("local_size_x = ", execution.workgroup_size.x));
621
622 if (wg_y.id)
623 {
624 if (options.vulkan_semantics)
625 arguments.push_back(join("local_size_y_id = ", wg_y.constant_id));
626 else
627 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(wg_y.id).specialization_constant_macro_name));
628 }
629 else
630 arguments.push_back(join("local_size_y = ", execution.workgroup_size.y));
631
632 if (wg_z.id)
633 {
634 if (options.vulkan_semantics)
635 arguments.push_back(join("local_size_z_id = ", wg_z.constant_id));
636 else
637 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(wg_z.id).specialization_constant_macro_name));
638 }
639 else
640 arguments.push_back(join("local_size_z = ", execution.workgroup_size.z));
641}
642
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100643void CompilerGLSL::emit_header()
644{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200645 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200646 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100647
Ben Claytone9621822017-10-09 10:33:42 +0100648 if (!options.es && options.version < 420)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200649 {
Ben Claytone9621822017-10-09 10:33:42 +0100650 // Needed for binding = # on UBOs, etc.
651 if (options.enable_420pack_extension)
652 {
653 statement("#ifdef GL_ARB_shading_language_420pack");
654 statement("#extension GL_ARB_shading_language_420pack : require");
655 statement("#endif");
656 }
657 // Needed for: layout(early_fragment_tests) in;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100658 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200659 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200660 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100661
Chip Davis1df47db2019-07-10 22:42:39 -0500662 // Needed for: layout(post_depth_coverage) in;
663 if (execution.flags.get(ExecutionModePostDepthCoverage))
664 require_extension_internal("GL_ARB_post_depth_coverage");
665
Chip Davis2eff4202019-08-04 00:07:20 -0500666 // Needed for: layout({pixel,sample}_interlock_[un]ordered) in;
667 if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT) ||
668 execution.flags.get(ExecutionModePixelInterlockUnorderedEXT) ||
669 execution.flags.get(ExecutionModeSampleInterlockOrderedEXT) ||
670 execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT))
671 {
672 if (options.es)
673 {
674 if (options.version < 310)
675 SPIRV_CROSS_THROW("At least ESSL 3.10 required for fragment shader interlock.");
676 require_extension_internal("GL_NV_fragment_shader_interlock");
677 }
678 else
679 {
680 if (options.version < 420)
681 require_extension_internal("GL_ARB_shader_image_load_store");
682 require_extension_internal("GL_ARB_fragment_shader_interlock");
683 }
684 }
685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200686 for (auto &ext : forced_extensions)
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200687 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100688 if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16")
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200689 {
690 // Special case, this extension has a potential fallback to another vendor extension in normal GLSL.
691 // GL_AMD_gpu_shader_half_float is a superset, so try that first.
692 statement("#if defined(GL_AMD_gpu_shader_half_float)");
693 statement("#extension GL_AMD_gpu_shader_half_float : require");
Chip Davis1fb27b42018-10-31 09:43:03 -0500694 if (!options.vulkan_semantics)
695 {
696 statement("#elif defined(GL_NV_gpu_shader5)");
697 statement("#extension GL_NV_gpu_shader5 : require");
698 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100699 else
700 {
701 statement("#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)");
702 statement("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
703 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200704 statement("#else");
705 statement("#error No extension available for FP16.");
706 statement("#endif");
707 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100708 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16")
Chip Davis1fb27b42018-10-31 09:43:03 -0500709 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100710 if (options.vulkan_semantics)
711 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
712 else
713 {
714 statement("#if defined(GL_AMD_gpu_shader_int16)");
715 statement("#extension GL_AMD_gpu_shader_int16 : require");
716 statement("#else");
717 statement("#error No extension available for Int16.");
718 statement("#endif");
719 }
Chip Davis1fb27b42018-10-31 09:43:03 -0500720 }
Chip Davis5fe1ecc2019-08-02 21:02:05 -0500721 else if (ext == "GL_ARB_post_depth_coverage")
722 {
723 if (options.es)
724 statement("#extension GL_EXT_post_depth_coverage : require");
725 else
726 {
727 statement("#if defined(GL_ARB_post_depth_coverge)");
728 statement("#extension GL_ARB_post_depth_coverage : require");
729 statement("#else");
730 statement("#extension GL_EXT_post_depth_coverage : require");
731 statement("#endif");
732 }
733 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +0200734 else if (!options.vulkan_semantics && ext == "GL_ARB_shader_draw_parameters")
735 {
736 // Soft-enable this extension on plain GLSL.
737 statement("#ifdef ", ext);
738 statement("#extension ", ext, " : enable");
739 statement("#endif");
740 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200741 else
742 statement("#extension ", ext, " : require");
743 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100744
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200745 for (auto &header : header_lines)
746 statement(header);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100747
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200748 SmallVector<string> inputs;
749 SmallVector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100750
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200751 switch (execution.model)
752 {
753 case ExecutionModelGeometry:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100754 if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200755 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100756 if (execution.flags.get(ExecutionModeInputPoints))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200757 inputs.push_back("points");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100758 if (execution.flags.get(ExecutionModeInputLines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200759 inputs.push_back("lines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100760 if (execution.flags.get(ExecutionModeInputLinesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200761 inputs.push_back("lines_adjacency");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100762 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200763 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100764 if (execution.flags.get(ExecutionModeInputTrianglesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200765 inputs.push_back("triangles_adjacency");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100766
767 if (!execution.geometry_passthrough)
768 {
769 // For passthrough, these are implies and cannot be declared in shader.
770 outputs.push_back(join("max_vertices = ", execution.output_vertices));
771 if (execution.flags.get(ExecutionModeOutputTriangleStrip))
772 outputs.push_back("triangle_strip");
773 if (execution.flags.get(ExecutionModeOutputPoints))
774 outputs.push_back("points");
775 if (execution.flags.get(ExecutionModeOutputLineStrip))
776 outputs.push_back("line_strip");
777 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200778 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200780 case ExecutionModelTessellationControl:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100781 if (execution.flags.get(ExecutionModeOutputVertices))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200782 outputs.push_back(join("vertices = ", execution.output_vertices));
783 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100784
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200785 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100786 if (execution.flags.get(ExecutionModeQuads))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200787 inputs.push_back("quads");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100788 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200789 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100790 if (execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200791 inputs.push_back("isolines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100792 if (execution.flags.get(ExecutionModePointMode))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200793 inputs.push_back("point_mode");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200794
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100795 if (!execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200796 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100797 if (execution.flags.get(ExecutionModeVertexOrderCw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200798 inputs.push_back("cw");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100799 if (execution.flags.get(ExecutionModeVertexOrderCcw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200800 inputs.push_back("ccw");
801 }
802
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100803 if (execution.flags.get(ExecutionModeSpacingFractionalEven))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200804 inputs.push_back("fractional_even_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100805 if (execution.flags.get(ExecutionModeSpacingFractionalOdd))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200806 inputs.push_back("fractional_odd_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100807 if (execution.flags.get(ExecutionModeSpacingEqual))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200808 inputs.push_back("equal_spacing");
809 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100810
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200811 case ExecutionModelGLCompute:
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200812 {
813 if (execution.workgroup_size.constant != 0)
814 {
815 SpecializationConstant wg_x, wg_y, wg_z;
816 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
817
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100818 // If there are any spec constants on legacy GLSL, defer declaration, we need to set up macro
819 // declarations before we can emit the work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200820 if (options.vulkan_semantics ||
821 ((wg_x.id == ConstantID(0)) && (wg_y.id == ConstantID(0)) && (wg_z.id == ConstantID(0))))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100822 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200823 }
824 else
825 {
826 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
827 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
828 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
829 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200830 break;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200831 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100832
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200833 case ExecutionModelFragment:
834 if (options.es)
835 {
836 switch (options.fragment.default_float_precision)
837 {
838 case Options::Lowp:
839 statement("precision lowp float;");
840 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100841
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200842 case Options::Mediump:
843 statement("precision mediump float;");
844 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100845
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200846 case Options::Highp:
847 statement("precision highp float;");
848 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100849
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200850 default:
851 break;
852 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100853
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200854 switch (options.fragment.default_int_precision)
855 {
856 case Options::Lowp:
857 statement("precision lowp int;");
858 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100859
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200860 case Options::Mediump:
861 statement("precision mediump int;");
862 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100863
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200864 case Options::Highp:
865 statement("precision highp int;");
866 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100867
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200868 default:
869 break;
870 }
871 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100872
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100873 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200874 inputs.push_back("early_fragment_tests");
Chip Davis1df47db2019-07-10 22:42:39 -0500875 if (execution.flags.get(ExecutionModePostDepthCoverage))
876 inputs.push_back("post_depth_coverage");
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +0100877
Chip Davis2eff4202019-08-04 00:07:20 -0500878 if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT))
879 inputs.push_back("pixel_interlock_ordered");
880 else if (execution.flags.get(ExecutionModePixelInterlockUnorderedEXT))
881 inputs.push_back("pixel_interlock_unordered");
882 else if (execution.flags.get(ExecutionModeSampleInterlockOrderedEXT))
883 inputs.push_back("sample_interlock_ordered");
884 else if (execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT))
885 inputs.push_back("sample_interlock_unordered");
886
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +0100887 if (!options.es && execution.flags.get(ExecutionModeDepthGreater))
888 statement("layout(depth_greater) out float gl_FragDepth;");
889 else if (!options.es && execution.flags.get(ExecutionModeDepthLess))
890 statement("layout(depth_less) out float gl_FragDepth;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100891
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200892 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100893
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200894 default:
895 break;
896 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100897
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200898 if (!inputs.empty())
899 statement("layout(", merge(inputs), ") in;");
900 if (!outputs.empty())
901 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100902
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200903 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100904}
905
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +0100906bool CompilerGLSL::type_is_empty(const SPIRType &type)
907{
908 return type.basetype == SPIRType::Struct && type.member_types.empty();
909}
910
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200911void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100912{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200913 // Struct types can be stamped out multiple times
914 // with just different offsets, matrix layouts, etc ...
915 // Type-punning with these types is legal, which complicates things
916 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzen294259e2018-03-05 16:27:04 +0100917 // If the type master is packed however, we can no longer assume that the struct declaration will be redundant.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200918 if (type.type_alias != TypeID(0) &&
919 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200920 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200921
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200922 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200923 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100924
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200925 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200926 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100927
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200928 type.member_name_cache.clear();
929
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200930 uint32_t i = 0;
931 bool emitted = false;
932 for (auto &member : type.member_types)
933 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200934 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -0500935 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200936 i++;
937 emitted = true;
938 }
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +0200939
940 // Don't declare empty structs in GLSL, this is not allowed.
941 if (type_is_empty(type) && !backend.supports_empty_struct)
942 {
943 statement("int empty_struct_member;");
944 emitted = true;
945 }
946
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +0200947 if (has_extended_decoration(type.self, SPIRVCrossDecorationPaddingTarget))
948 emit_struct_padding_target(type);
949
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200950 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100951
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200952 if (emitted)
953 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100954}
955
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100956string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200957{
958 string res;
959 //if (flags & (1ull << DecorationSmooth))
960 // res += "smooth ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100961 if (flags.get(DecorationFlat))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200962 res += "flat ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100963 if (flags.get(DecorationNoPerspective))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200964 res += "noperspective ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100965 if (flags.get(DecorationCentroid))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200966 res += "centroid ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100967 if (flags.get(DecorationPatch))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200968 res += "patch ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100969 if (flags.get(DecorationSample))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200970 res += "sample ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100971 if (flags.get(DecorationInvariant))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200972 res += "invariant ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100973 if (flags.get(DecorationExplicitInterpAMD))
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +0100974 res += "__explicitInterpAMD ";
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200975
976 return res;
977}
978
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100979string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
980{
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +0100981 if (is_legacy())
982 return "";
983
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200984 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
985 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200986 if (!is_block)
987 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100988
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200989 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200990 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +0200991 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200992 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100993
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200994 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100995
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100996 if (has_member_decoration(type.self, index, DecorationPassthroughNV))
997 attr.push_back("passthrough");
998
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200999 // We can only apply layouts on members in block interfaces.
1000 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
1001 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
1002 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
1003 //
1004 // We would like to go from (SPIR-V style):
1005 //
1006 // struct Foo { layout(row_major) mat4 matrix; };
1007 // buffer UBO { Foo foo; };
1008 //
1009 // to
1010 //
1011 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
1012 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
1013 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001014
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001015 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001016 attr.push_back("row_major");
1017 // We don't emit any global layouts, so column_major is default.
1018 //if (flags & (1ull << DecorationColMajor))
1019 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001020
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001021 if (dec.decoration_flags.get(DecorationLocation) && can_use_io_location(type.storage, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001022 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001023
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001024 // Can only declare component if we can declare location.
1025 if (dec.decoration_flags.get(DecorationComponent) && can_use_io_location(type.storage, true))
1026 {
1027 if (!options.es)
1028 {
1029 if (options.version < 440 && options.version >= 140)
1030 require_extension_internal("GL_ARB_enhanced_layouts");
1031 else if (options.version < 140)
1032 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
1033 attr.push_back(join("component = ", dec.component));
1034 }
1035 else
1036 SPIRV_CROSS_THROW("Component decoration is not supported in ES targets.");
1037 }
1038
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001039 // SPIRVCrossDecorationPacked is set by layout_for_variable earlier to mark that we need to emit offset qualifiers.
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001040 // This is only done selectively in GLSL as needed.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02001041 if (has_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset) &&
1042 dec.decoration_flags.get(DecorationOffset))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001043 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001044 else if (type.storage == StorageClassOutput && dec.decoration_flags.get(DecorationOffset))
1045 attr.push_back(join("xfb_offset = ", dec.offset));
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001046
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001047 if (attr.empty())
1048 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001049
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001050 string res = "layout(";
1051 res += merge(attr);
1052 res += ") ";
1053 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001054}
1055
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001056const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001057{
Brad Davis76204002018-06-20 10:25:38 -07001058 if (options.es && is_desktop_only_format(format))
1059 SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001061 switch (format)
1062 {
1063 case ImageFormatRgba32f:
1064 return "rgba32f";
1065 case ImageFormatRgba16f:
1066 return "rgba16f";
1067 case ImageFormatR32f:
1068 return "r32f";
1069 case ImageFormatRgba8:
1070 return "rgba8";
1071 case ImageFormatRgba8Snorm:
1072 return "rgba8_snorm";
1073 case ImageFormatRg32f:
1074 return "rg32f";
1075 case ImageFormatRg16f:
1076 return "rg16f";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001077 case ImageFormatRgba32i:
1078 return "rgba32i";
1079 case ImageFormatRgba16i:
1080 return "rgba16i";
1081 case ImageFormatR32i:
1082 return "r32i";
1083 case ImageFormatRgba8i:
1084 return "rgba8i";
1085 case ImageFormatRg32i:
1086 return "rg32i";
1087 case ImageFormatRg16i:
1088 return "rg16i";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001089 case ImageFormatRgba32ui:
1090 return "rgba32ui";
1091 case ImageFormatRgba16ui:
1092 return "rgba16ui";
1093 case ImageFormatR32ui:
1094 return "r32ui";
1095 case ImageFormatRgba8ui:
1096 return "rgba8ui";
1097 case ImageFormatRg32ui:
1098 return "rg32ui";
1099 case ImageFormatRg16ui:
1100 return "rg16ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001101 case ImageFormatR11fG11fB10f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001102 return "r11f_g11f_b10f";
1103 case ImageFormatR16f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001104 return "r16f";
1105 case ImageFormatRgb10A2:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001106 return "rgb10_a2";
1107 case ImageFormatR8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001108 return "r8";
1109 case ImageFormatRg8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001110 return "rg8";
1111 case ImageFormatR16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001112 return "r16";
1113 case ImageFormatRg16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001114 return "rg16";
1115 case ImageFormatRgba16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001116 return "rgba16";
1117 case ImageFormatR16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001118 return "r16_snorm";
1119 case ImageFormatRg16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001120 return "rg16_snorm";
1121 case ImageFormatRgba16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001122 return "rgba16_snorm";
1123 case ImageFormatR8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001124 return "r8_snorm";
1125 case ImageFormatRg8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001126 return "rg8_snorm";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001127 case ImageFormatR8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001128 return "r8ui";
1129 case ImageFormatRg8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001130 return "rg8ui";
1131 case ImageFormatR16ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001132 return "r16ui";
1133 case ImageFormatRgb10a2ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001134 return "rgb10_a2ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001135 case ImageFormatR8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001136 return "r8i";
1137 case ImageFormatRg8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001138 return "rg8i";
1139 case ImageFormatR16i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001140 return "r16i";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001141 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001142 case ImageFormatUnknown:
1143 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001144 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001145}
1146
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001147uint32_t CompilerGLSL::type_to_packed_base_size(const SPIRType &type, BufferPackingStandard)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001148{
1149 switch (type.basetype)
1150 {
1151 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02001152 case SPIRType::Int64:
1153 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001154 return 8;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001155 case SPIRType::Float:
1156 case SPIRType::Int:
1157 case SPIRType::UInt:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001158 return 4;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001159 case SPIRType::Half:
Chip Davis117ccf42018-11-01 17:20:07 -05001160 case SPIRType::Short:
1161 case SPIRType::UShort:
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001162 return 2;
Chip Davis117ccf42018-11-01 17:20:07 -05001163 case SPIRType::SByte:
1164 case SPIRType::UByte:
1165 return 1;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001166
1167 default:
1168 SPIRV_CROSS_THROW("Unrecognized type in type_to_packed_base_size.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001169 }
1170}
1171
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001172uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bitset &flags,
1173 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001174{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001175 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1176 // and is 64-bit.
1177 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1178 {
1179 if (!type.pointer)
1180 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1181
1182 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1183 {
1184 if (packing_is_vec4_padded(packing) && type_is_array_of_pointers(type))
1185 return 16;
1186 else
1187 return 8;
1188 }
1189 else
1190 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1191 }
1192
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001193 if (!type.array.empty())
1194 {
1195 uint32_t minimum_alignment = 1;
1196 if (packing_is_vec4_padded(packing))
1197 minimum_alignment = 16;
1198
1199 auto *tmp = &get<SPIRType>(type.parent_type);
1200 while (!tmp->array.empty())
1201 tmp = &get<SPIRType>(tmp->parent_type);
1202
1203 // Get the alignment of the base type, then maybe round up.
1204 return max(minimum_alignment, type_to_packed_alignment(*tmp, flags, packing));
1205 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001207 if (type.basetype == SPIRType::Struct)
1208 {
1209 // Rule 9. Structs alignments are maximum alignment of its members.
Hans-Kristian Arntzen8c632da2019-01-28 11:02:28 +01001210 uint32_t alignment = 1;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001211 for (uint32_t i = 0; i < type.member_types.size(); i++)
1212 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001213 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +02001214 alignment =
1215 max(alignment, type_to_packed_alignment(get<SPIRType>(type.member_types[i]), member_flags, packing));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001216 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001217
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001218 // In std140, struct alignment is rounded up to 16.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001219 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001220 alignment = max(alignment, 16u);
1221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001222 return alignment;
1223 }
1224 else
1225 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001226 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1227
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001228 // Alignment requirement for scalar block layout is always the alignment for the most basic component.
1229 if (packing_is_scalar(packing))
1230 return base_alignment;
1231
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001232 // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle
1233 // a vec4, this is handled outside since that part knows our current offset.
1234 if (type.columns == 1 && packing_is_hlsl(packing))
1235 return base_alignment;
1236
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001237 // From 7.6.2.2 in GL 4.5 core spec.
1238 // Rule 1
1239 if (type.vecsize == 1 && type.columns == 1)
1240 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001241
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001242 // Rule 2
1243 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
1244 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001245
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001246 // Rule 3
1247 if (type.vecsize == 3 && type.columns == 1)
1248 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001250 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001252 // Rule 5. Column-major matrices are stored as arrays of
1253 // vectors.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001254 if (flags.get(DecorationColMajor) && type.columns > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001255 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001256 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001257 return 4 * base_alignment;
1258 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001259 return 4 * base_alignment;
1260 else
1261 return type.vecsize * base_alignment;
1262 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001263
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001264 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001266 // Rule 7.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001267 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001268 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001269 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001270 return 4 * base_alignment;
1271 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001272 return 4 * base_alignment;
1273 else
1274 return type.columns * base_alignment;
1275 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001276
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001277 // Rule 8 implied.
1278 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001279
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001280 SPIRV_CROSS_THROW("Did not find suitable rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001281}
1282
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001283uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, const Bitset &flags,
1284 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001285{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001286 // Array stride is equal to aligned size of the underlying type.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001287 uint32_t parent = type.parent_type;
1288 assert(parent);
1289
1290 auto &tmp = get<SPIRType>(parent);
1291
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001292 uint32_t size = type_to_packed_size(tmp, flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001293 if (tmp.array.empty())
1294 {
1295 uint32_t alignment = type_to_packed_alignment(type, flags, packing);
1296 return (size + alignment - 1) & ~(alignment - 1);
1297 }
1298 else
1299 {
1300 // For multidimensional arrays, array stride always matches size of subtype.
1301 // The alignment cannot change because multidimensional arrays are basically N * M array elements.
1302 return size;
1303 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001304}
1305
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001306uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001307{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001308 if (!type.array.empty())
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001309 {
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001310 return to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001311 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001312
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001313 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1314 // and is 64-bit.
1315 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1316 {
1317 if (!type.pointer)
1318 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1319
1320 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1321 return 8;
1322 else
1323 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1324 }
1325
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001326 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001327
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001328 if (type.basetype == SPIRType::Struct)
1329 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001330 uint32_t pad_alignment = 1;
1331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001332 for (uint32_t i = 0; i < type.member_types.size(); i++)
1333 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001334 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001335 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001336
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001337 uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
1338 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001339
1340 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1341 // GL 4.5 spec, 7.6.2.2.
1342 if (member_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001343 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001344 else
1345 pad_alignment = 1;
1346
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001347 size = (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001348 size += type_to_packed_size(member_type, member_flags, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001349 }
1350 }
1351 else
1352 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001353 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1354
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001355 if (packing_is_scalar(packing))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001356 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001357 size = type.vecsize * type.columns * base_alignment;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001358 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001359 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001360 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001361 if (type.columns == 1)
1362 size = type.vecsize * base_alignment;
1363
1364 if (flags.get(DecorationColMajor) && type.columns > 1)
1365 {
1366 if (packing_is_vec4_padded(packing))
1367 size = type.columns * 4 * base_alignment;
1368 else if (type.vecsize == 3)
1369 size = type.columns * 4 * base_alignment;
1370 else
1371 size = type.columns * type.vecsize * base_alignment;
1372 }
1373
1374 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
1375 {
1376 if (packing_is_vec4_padded(packing))
1377 size = type.vecsize * 4 * base_alignment;
1378 else if (type.columns == 3)
1379 size = type.vecsize * 4 * base_alignment;
1380 else
1381 size = type.vecsize * type.columns * base_alignment;
1382 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001383 }
1384 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001385
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001386 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001387}
1388
msiglreithd096f5c2017-11-27 16:00:56 +01001389bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001390 uint32_t *failed_validation_index, uint32_t start_offset,
1391 uint32_t end_offset)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001392{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001393 // This is very tricky and error prone, but try to be exhaustive and correct here.
1394 // SPIR-V doesn't directly say if we're using std430 or std140.
1395 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
1396 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
1397 // We do not have to consider shared or packed since these layouts are not allowed in Vulkan SPIR-V (they are useless anyways, and custom offsets would do the same thing).
1398 //
1399 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
1400 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
1401 //
1402 // The only two differences between std140 and std430 are related to padding alignment/array stride
1403 // in arrays and structs. In std140 they take minimum vec4 alignment.
1404 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001405
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001406 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001407 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001408
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001409 bool is_top_level_block =
1410 has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
1411
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001412 for (uint32_t i = 0; i < type.member_types.size(); i++)
1413 {
1414 auto &memb_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001415 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001417 // Verify alignment rules.
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001418 uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001419
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001420 // This is a rather dirty workaround to deal with some cases of OpSpecConstantOp used as array size, e.g:
1421 // layout(constant_id = 0) const int s = 10;
1422 // const int S = s + 5; // SpecConstantOp
1423 // buffer Foo { int data[S]; }; // <-- Very hard for us to deduce a fixed value here,
1424 // we would need full implementation of compile-time constant folding. :(
1425 // If we are the last member of a struct, there might be cases where the actual size of that member is irrelevant
1426 // for our analysis (e.g. unsized arrays).
1427 // This lets us simply ignore that there are spec constant op sized arrays in our buffers.
1428 // Querying size of this member will fail, so just don't call it unless we have to.
1429 //
1430 // This is likely "best effort" we can support without going into unacceptably complicated workarounds.
1431 bool member_can_be_unsized =
1432 is_top_level_block && size_t(i + 1) == type.member_types.size() && !memb_type.array.empty();
1433
1434 uint32_t packed_size = 0;
1435 if (!member_can_be_unsized)
1436 packed_size = type_to_packed_size(memb_type, member_flags, packing);
1437
1438 // We only need to care about this if we have non-array types which can straddle the vec4 boundary.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001439 if (packing_is_hlsl(packing))
1440 {
1441 // If a member straddles across a vec4 boundary, alignment is actually vec4.
1442 uint32_t begin_word = offset / 16;
1443 uint32_t end_word = (offset + packed_size - 1) / 16;
1444 if (begin_word != end_word)
1445 packed_alignment = max(packed_alignment, 16u);
1446 }
1447
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001448 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001449 offset = (offset + alignment - 1) & ~(alignment - 1);
1450
msiglreithd096f5c2017-11-27 16:00:56 +01001451 // Field is not in the specified range anymore and we can ignore any further fields.
1452 if (offset >= end_offset)
1453 break;
1454
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001455 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1456 // GL 4.5 spec, 7.6.2.2.
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001457 if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001458 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001459 else
1460 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001461
msiglreithd096f5c2017-11-27 16:00:56 +01001462 // Only care about packing if we are in the given range
1463 if (offset >= start_offset)
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001464 {
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001465 uint32_t actual_offset = type_struct_member_offset(type, i);
1466
msiglreithd096f5c2017-11-27 16:00:56 +01001467 // We only care about offsets in std140, std430, etc ...
1468 // For EnhancedLayout variants, we have the flexibility to choose our own offsets.
1469 if (!packing_has_flexible_offset(packing))
1470 {
msiglreithd096f5c2017-11-27 16:00:56 +01001471 if (actual_offset != offset) // This cannot be the packing we're looking for.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001472 {
1473 if (failed_validation_index)
1474 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001475 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001476 }
msiglreithd096f5c2017-11-27 16:00:56 +01001477 }
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001478 else if ((actual_offset & (alignment - 1)) != 0)
1479 {
1480 // We still need to verify that alignment rules are observed, even if we have explicit offset.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001481 if (failed_validation_index)
1482 *failed_validation_index = i;
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001483 return false;
1484 }
msiglreithd096f5c2017-11-27 16:00:56 +01001485
1486 // Verify array stride rules.
1487 if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
1488 type_struct_member_array_stride(type, i))
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001489 {
1490 if (failed_validation_index)
1491 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001492 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001493 }
msiglreithd096f5c2017-11-27 16:00:56 +01001494
1495 // Verify that sub-structs also follow packing rules.
1496 // We cannot use enhanced layouts on substructs, so they better be up to spec.
1497 auto substruct_packing = packing_to_substruct_packing(packing);
1498
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001499 if (!memb_type.pointer && !memb_type.member_types.empty() &&
1500 !buffer_is_packing_standard(memb_type, substruct_packing))
1501 {
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001502 if (failed_validation_index)
1503 *failed_validation_index = i;
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001504 return false;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001505 }
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001506 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001507
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001508 // Bump size.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001509 offset += packed_size;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001510 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001512 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001513}
1514
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001515bool CompilerGLSL::can_use_io_location(StorageClass storage, bool block)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001516{
1517 // Location specifiers are must have in SPIR-V, but they aren't really supported in earlier versions of GLSL.
1518 // Be very explicit here about how to solve the issue.
1519 if ((get_execution_model() != ExecutionModelVertex && storage == StorageClassInput) ||
1520 (get_execution_model() != ExecutionModelFragment && storage == StorageClassOutput))
1521 {
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001522 uint32_t minimum_desktop_version = block ? 440 : 410;
1523 // ARB_enhanced_layouts vs ARB_separate_shader_objects ...
1524
1525 if (!options.es && options.version < minimum_desktop_version && !options.separate_shader_objects)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001526 return false;
1527 else if (options.es && options.version < 310)
1528 return false;
1529 }
1530
1531 if ((get_execution_model() == ExecutionModelVertex && storage == StorageClassInput) ||
1532 (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput))
1533 {
1534 if (options.es && options.version < 300)
1535 return false;
1536 else if (!options.es && options.version < 330)
1537 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001538 }
1539
Hans-Kristian Arntzen1389aa32019-03-19 11:20:25 +01001540 if (storage == StorageClassUniform || storage == StorageClassUniformConstant || storage == StorageClassPushConstant)
Andrei Alexeyev4a430242018-04-07 22:14:35 +03001541 {
1542 if (options.es && options.version < 310)
1543 return false;
1544 else if (!options.es && options.version < 430)
1545 return false;
1546 }
1547
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001548 return true;
1549}
1550
1551string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
1552{
Hans-Kristian Arntzen62d223a2016-09-21 08:20:04 +02001553 // FIXME: Come up with a better solution for when to disable layouts.
1554 // Having layouts depend on extensions as well as which types
1555 // of layouts are used. For now, the simple solution is to just disable
1556 // layouts for legacy versions.
1557 if (is_legacy())
rob42fe8c32016-09-18 13:18:33 +09001558 return "";
1559
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01001560 if (subpass_input_is_framebuffer_fetch(var.self))
1561 return "";
1562
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001563 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001565 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001566 auto &flags = get_decoration_bitset(var.self);
1567 auto &typeflags = get_decoration_bitset(type.self);
1568
1569 if (flags.get(DecorationPassthroughNV))
1570 attr.push_back("passthrough");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001571
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001572 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
1573 attr.push_back("push_constant");
Patrick Mours78917862019-06-03 15:25:21 +02001574 else if (var.storage == StorageClassShaderRecordBufferNV)
1575 attr.push_back("shaderRecordNV");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001576
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001577 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001578 attr.push_back("row_major");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001579 if (flags.get(DecorationColMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001580 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001581
1582 if (options.vulkan_semantics)
1583 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001584 if (flags.get(DecorationInputAttachmentIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001585 attr.push_back(join("input_attachment_index = ", get_decoration(var.self, DecorationInputAttachmentIndex)));
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001586 }
1587
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001588 bool is_block = has_decoration(type.self, DecorationBlock);
1589 if (flags.get(DecorationLocation) && can_use_io_location(var.storage, is_block))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001590 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001591 Bitset combined_decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001592 for (uint32_t i = 0; i < ir.meta[type.self].members.size(); i++)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001593 combined_decoration.merge_or(combined_decoration_for_member(type, i));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001594
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001595 // If our members have location decorations, we don't need to
1596 // emit location decorations at the top as well (looks weird).
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001597 if (!combined_decoration.get(DecorationLocation))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001598 attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation)));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001599 }
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001600
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001601 // Transform feedback
1602 bool uses_enhanced_layouts = false;
1603 if (is_block && var.storage == StorageClassOutput)
1604 {
1605 // For blocks, there is a restriction where xfb_stride/xfb_buffer must only be declared on the block itself,
1606 // since all members must match the same xfb_buffer. The only thing we will declare for members of the block
1607 // is the xfb_offset.
1608 uint32_t member_count = uint32_t(type.member_types.size());
1609 bool have_xfb_buffer_stride = false;
1610 bool have_any_xfb_offset = false;
1611 uint32_t xfb_stride = 0, xfb_buffer = 0;
1612
1613 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride))
1614 {
1615 have_xfb_buffer_stride = true;
1616 xfb_buffer = get_decoration(var.self, DecorationXfbBuffer);
1617 xfb_stride = get_decoration(var.self, DecorationXfbStride);
1618 }
1619
1620 // Verify that none of the members violate our assumption.
1621 for (uint32_t i = 0; i < member_count; i++)
1622 {
1623 // Only members with an Offset decoration participate in XFB.
1624 if (!has_member_decoration(type.self, i, DecorationOffset))
1625 continue;
1626 have_any_xfb_offset = true;
1627
1628 if (has_member_decoration(type.self, i, DecorationXfbBuffer))
1629 {
1630 uint32_t buffer_index = get_member_decoration(type.self, i, DecorationXfbBuffer);
1631 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
1632 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
1633 have_xfb_buffer_stride = true;
1634 xfb_buffer = buffer_index;
1635 }
1636
1637 if (has_member_decoration(type.self, i, DecorationXfbStride))
1638 {
1639 uint32_t stride = get_member_decoration(type.self, i, DecorationXfbStride);
1640 if (have_xfb_buffer_stride && stride != xfb_stride)
1641 SPIRV_CROSS_THROW("IO block member XfbStride mismatch.");
1642 have_xfb_buffer_stride = true;
1643 xfb_stride = stride;
1644 }
1645 }
1646
1647 if (have_xfb_buffer_stride && have_any_xfb_offset)
1648 {
1649 attr.push_back(join("xfb_buffer = ", xfb_buffer));
1650 attr.push_back(join("xfb_stride = ", xfb_stride));
1651 uses_enhanced_layouts = true;
1652 }
1653 }
1654 else if (var.storage == StorageClassOutput && flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) &&
1655 flags.get(DecorationOffset))
1656 {
1657 // XFB for standalone variables, we can emit all decorations.
1658 attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer)));
1659 attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride)));
1660 attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset)));
1661 uses_enhanced_layouts = true;
1662 }
1663
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001664 // Can only declare Component if we can declare location.
1665 if (flags.get(DecorationComponent) && can_use_io_location(var.storage, is_block))
1666 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001667 uses_enhanced_layouts = true;
1668 attr.push_back(join("component = ", get_decoration(var.self, DecorationComponent)));
1669 }
1670
1671 if (uses_enhanced_layouts)
1672 {
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001673 if (!options.es)
1674 {
1675 if (options.version < 440 && options.version >= 140)
1676 require_extension_internal("GL_ARB_enhanced_layouts");
1677 else if (options.version < 140)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001678 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in targets below GLSL 1.40.");
1679 if (!options.es && options.version < 440)
1680 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001681 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001682 else if (options.es)
1683 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in ESSL.");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001684 }
1685
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001686 if (flags.get(DecorationIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001687 attr.push_back(join("index = ", get_decoration(var.self, DecorationIndex)));
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001688
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001689 // Do not emit set = decoration in regular GLSL output, but
1690 // we need to preserve it in Vulkan GLSL mode.
Patrick Mours8d64d5e2019-06-05 13:29:01 +02001691 if (var.storage != StorageClassPushConstant && var.storage != StorageClassShaderRecordBufferNV)
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001692 {
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001693 if (flags.get(DecorationDescriptorSet) && options.vulkan_semantics)
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001694 attr.push_back(join("set = ", get_decoration(var.self, DecorationDescriptorSet)));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001695 }
1696
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001697 bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
Patrick Mours8d64d5e2019-06-05 13:29:01 +02001698 bool ssbo_block = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferNV ||
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001699 (var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
1700 bool emulated_ubo = var.storage == StorageClassPushConstant && options.emit_push_constant_as_uniform_buffer;
1701 bool ubo_block = var.storage == StorageClassUniform && typeflags.get(DecorationBlock);
1702
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001703 // GL 3.0/GLSL 1.30 is not considered legacy, but it doesn't have UBOs ...
1704 bool can_use_buffer_blocks = (options.es && options.version >= 300) || (!options.es && options.version >= 140);
1705
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001706 // pretend no UBOs when options say so
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001707 if (ubo_block && options.emit_uniform_buffer_as_plain_uniforms)
1708 can_use_buffer_blocks = false;
1709
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001710 bool can_use_binding;
1711 if (options.es)
1712 can_use_binding = options.version >= 310;
1713 else
1714 can_use_binding = options.enable_420pack_extension || (options.version >= 420);
1715
Hans-Kristian Arntzen938040b2018-04-03 16:58:05 +02001716 // Make sure we don't emit binding layout for a classic uniform on GLSL 1.30.
1717 if (!can_use_buffer_blocks && var.storage == StorageClassUniform)
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001718 can_use_binding = false;
1719
Patrick Mours8d64d5e2019-06-05 13:29:01 +02001720 if (var.storage == StorageClassShaderRecordBufferNV)
1721 can_use_binding = false;
1722
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001723 if (can_use_binding && flags.get(DecorationBinding))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001724 attr.push_back(join("binding = ", get_decoration(var.self, DecorationBinding)));
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001725
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001726 if (var.storage != StorageClassOutput && flags.get(DecorationOffset))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001727 attr.push_back(join("offset = ", get_decoration(var.self, DecorationOffset)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001728
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001729 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
1730 // If SPIR-V does not comply with either layout, we cannot really work around it.
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001731 if (can_use_buffer_blocks && (ubo_block || emulated_ubo))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001732 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001733 attr.push_back(buffer_to_packing_standard(type, false));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001734 }
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001735 else if (can_use_buffer_blocks && (push_constant_block || ssbo_block))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001736 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001737 attr.push_back(buffer_to_packing_standard(type, true));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001738 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001740 // For images, the type itself adds a layout qualifer.
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02001741 // Only emit the format for storage images.
1742 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001743 {
1744 const char *fmt = format_to_glsl(type.image.format);
1745 if (fmt)
1746 attr.push_back(fmt);
1747 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001748
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001749 if (attr.empty())
1750 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001751
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001752 string res = "layout(";
1753 res += merge(attr);
1754 res += ") ";
1755 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001756}
1757
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001758string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type, bool support_std430_without_scalar_layout)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001759{
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001760 if (support_std430_without_scalar_layout && buffer_is_packing_standard(type, BufferPackingStd430))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001761 return "std430";
1762 else if (buffer_is_packing_standard(type, BufferPackingStd140))
1763 return "std140";
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001764 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalar))
1765 {
1766 require_extension_internal("GL_EXT_scalar_block_layout");
1767 return "scalar";
1768 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001769 else if (support_std430_without_scalar_layout &&
1770 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001771 {
1772 if (options.es && !options.vulkan_semantics)
1773 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1774 "not support GL_ARB_enhanced_layouts.");
1775 if (!options.es && !options.vulkan_semantics && options.version < 440)
1776 require_extension_internal("GL_ARB_enhanced_layouts");
1777
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001778 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001779 return "std430";
1780 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001781 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
1782 {
1783 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
1784 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
1785 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
1786 if (options.es && !options.vulkan_semantics)
1787 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1788 "not support GL_ARB_enhanced_layouts.");
1789 if (!options.es && !options.vulkan_semantics && options.version < 440)
1790 require_extension_internal("GL_ARB_enhanced_layouts");
1791
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001792 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001793 return "std140";
1794 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001795 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalarEnhancedLayout))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001796 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001797 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001798 require_extension_internal("GL_EXT_scalar_block_layout");
1799 return "scalar";
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001800 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001801 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
1802 buffer_is_packing_standard(type, BufferPackingStd430))
1803 {
1804 // UBOs can support std430 with GL_EXT_scalar_block_layout.
1805 require_extension_internal("GL_EXT_scalar_block_layout");
1806 return "std430";
1807 }
1808 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
1809 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
1810 {
1811 // UBOs can support std430 with GL_EXT_scalar_block_layout.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001812 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001813 require_extension_internal("GL_EXT_scalar_block_layout");
1814 return "std430";
1815 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001816 else
1817 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001818 SPIRV_CROSS_THROW("Buffer block cannot be expressed as any of std430, std140, scalar, even with enhanced "
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001819 "layouts. You can try flattening this block to support a more flexible layout.");
1820 }
1821}
1822
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001823void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
1824{
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01001825 if (flattened_buffer_blocks.count(var.self))
1826 emit_buffer_block_flattened(var);
1827 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001828 emit_push_constant_block_vulkan(var);
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001829 else if (options.emit_push_constant_as_uniform_buffer)
1830 emit_buffer_block_native(var);
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001831 else
1832 emit_push_constant_block_glsl(var);
1833}
1834
1835void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
1836{
1837 emit_buffer_block(var);
1838}
1839
1840void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
1841{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001842 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
1843 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001844
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001845 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001846 flags.clear(DecorationBinding);
1847 flags.clear(DecorationDescriptorSet);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001848
1849#if 0
1850 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001851 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001852 "Remap to location with reflection API first or disable these decorations.");
1853#endif
1854
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001855 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1856 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001857 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001858 bool block_flag = block_flags.get(DecorationBlock);
1859 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001861 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001862
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001863 if (block_flag)
1864 block_flags.set(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001866 emit_uniform(var);
1867 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001868}
1869
1870void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
1871{
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001872 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001873 bool ubo_block = var.storage == StorageClassUniform && has_decoration(type.self, DecorationBlock);
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001874
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001875 if (flattened_buffer_blocks.count(var.self))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001876 emit_buffer_block_flattened(var);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001877 else if (is_legacy() || (!options.es && options.version == 130) ||
1878 (ubo_block && options.emit_uniform_buffer_as_plain_uniforms))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001879 emit_buffer_block_legacy(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001880 else
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001881 emit_buffer_block_native(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001882}
1883
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001884void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
1885{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001886 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001887 bool ssbo = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001888 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001889 if (ssbo)
1890 SPIRV_CROSS_THROW("SSBOs not supported in legacy targets.");
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001891
1892 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1893 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001894 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001895 bool block_flag = block_flags.get(DecorationBlock);
1896 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001897 emit_struct(type);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001898 if (block_flag)
1899 block_flags.set(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001900 emit_uniform(var);
1901 statement("");
1902}
1903
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001904void CompilerGLSL::emit_buffer_reference_block(SPIRType &type, bool forward_declaration)
1905{
1906 string buffer_name;
1907
1908 if (forward_declaration)
1909 {
1910 // Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
1911 // Allow aliased name since we might be declaring the block twice. Once with buffer reference (forward declared) and one proper declaration.
1912 // The names must match up.
1913 buffer_name = to_name(type.self, false);
1914
1915 // Shaders never use the block by interface name, so we don't
1916 // have to track this other than updating name caches.
1917 // If we have a collision for any reason, just fallback immediately.
1918 if (ir.meta[type.self].decoration.alias.empty() ||
1919 block_ssbo_names.find(buffer_name) != end(block_ssbo_names) ||
1920 resource_names.find(buffer_name) != end(resource_names))
1921 {
1922 buffer_name = join("_", type.self);
1923 }
1924
1925 // Make sure we get something unique for both global name scope and block name scope.
1926 // See GLSL 4.5 spec: section 4.3.9 for details.
1927 add_variable(block_ssbo_names, resource_names, buffer_name);
1928
1929 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
1930 // This cannot conflict with anything else, so we're safe now.
1931 // We cannot reuse this fallback name in neither global scope (blocked by block_names) nor block name scope.
1932 if (buffer_name.empty())
1933 buffer_name = join("_", type.self);
1934
1935 block_names.insert(buffer_name);
1936 block_ssbo_names.insert(buffer_name);
1937 }
1938 else if (type.basetype != SPIRType::Struct)
1939 buffer_name = type_to_glsl(type);
1940 else
1941 buffer_name = to_name(type.self, false);
1942
1943 if (!forward_declaration)
1944 {
1945 if (type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001946 statement("layout(buffer_reference, ", buffer_to_packing_standard(type, true), ") buffer ", buffer_name);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001947 else
1948 statement("layout(buffer_reference) buffer ", buffer_name);
1949
1950 begin_scope();
1951
1952 if (type.basetype == SPIRType::Struct)
1953 {
1954 type.member_name_cache.clear();
1955
1956 uint32_t i = 0;
1957 for (auto &member : type.member_types)
1958 {
1959 add_member_name(type, i);
1960 emit_struct_member(type, member, i);
1961 i++;
1962 }
1963 }
1964 else
1965 {
1966 auto &pointee_type = get_pointee_type(type);
1967 statement(type_to_glsl(pointee_type), " value", type_to_array_glsl(pointee_type), ";");
1968 }
1969
1970 end_scope_decl();
1971 statement("");
1972 }
1973 else
1974 {
1975 statement("layout(buffer_reference) buffer ", buffer_name, ";");
1976 }
1977}
1978
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001979void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001980{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001981 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01001982
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001983 Bitset flags = ir.get_buffer_block_flags(var);
Patrick Mours78917862019-06-03 15:25:21 +02001984 bool ssbo = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferNV ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001985 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001986 bool is_restrict = ssbo && flags.get(DecorationRestrict);
1987 bool is_writeonly = ssbo && flags.get(DecorationNonReadable);
1988 bool is_readonly = ssbo && flags.get(DecorationNonWritable);
1989 bool is_coherent = ssbo && flags.get(DecorationCoherent);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001990
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001991 // Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001992 auto buffer_name = to_name(type.self, false);
1993
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02001994 auto &block_namespace = ssbo ? block_ssbo_names : block_ubo_names;
1995
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001996 // Shaders never use the block by interface name, so we don't
1997 // have to track this other than updating name caches.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01001998 // If we have a collision for any reason, just fallback immediately.
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01001999 if (ir.meta[type.self].decoration.alias.empty() || block_namespace.find(buffer_name) != end(block_namespace) ||
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002000 resource_names.find(buffer_name) != end(resource_names))
2001 {
Hans-Kristian Arntzenaab31072017-09-29 12:16:53 +02002002 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002003 }
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002004
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002005 // Make sure we get something unique for both global name scope and block name scope.
2006 // See GLSL 4.5 spec: section 4.3.9 for details.
2007 add_variable(block_namespace, resource_names, buffer_name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002008
2009 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2010 // This cannot conflict with anything else, so we're safe now.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002011 // We cannot reuse this fallback name in neither global scope (blocked by block_names) nor block name scope.
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002012 if (buffer_name.empty())
2013 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2014
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002015 block_names.insert(buffer_name);
2016 block_namespace.insert(buffer_name);
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002017
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002018 // Save for post-reflection later.
2019 declared_block_names[var.self] = buffer_name;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002020
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02002021 statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
2022 is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
2023 buffer_name);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002025 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002026
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002027 type.member_name_cache.clear();
2028
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002029 uint32_t i = 0;
2030 for (auto &member : type.member_types)
2031 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002032 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002033 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002034 i++;
2035 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002036
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +01002037 // var.self can be used as a backup name for the block name,
2038 // so we need to make sure we don't disturb the name here on a recompile.
2039 // It will need to be reset if we have to recompile.
2040 preserve_alias_on_reset(var.self);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002041 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002042 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
2043 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002044}
2045
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002046void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002047{
2048 auto &type = get<SPIRType>(var.basetype);
2049
2050 // Block names should never alias.
2051 auto buffer_name = to_name(type.self, false);
2052 size_t buffer_size = (get_declared_struct_size(type) + 15) / 16;
2053
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002054 SPIRType::BaseType basic_type;
2055 if (get_common_basic_type(type, basic_type))
2056 {
2057 SPIRType tmp;
2058 tmp.basetype = basic_type;
Hans-Kristian Arntzenefba6102017-01-22 08:53:52 +01002059 tmp.vecsize = 4;
2060 if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt)
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002061 SPIRV_CROSS_THROW("Basic types in a flattened UBO must be float, int or uint.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002062
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002063 auto flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002064 statement("uniform ", flags_to_qualifiers_glsl(tmp, flags), type_to_glsl(tmp), " ", buffer_name, "[",
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01002065 buffer_size, "];");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002066 }
2067 else
2068 SPIRV_CROSS_THROW("All basic types in a flattened block must be the same.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002069}
2070
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002071const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002072{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002073 auto &execution = get_entry_point();
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002074
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002075 if (subpass_input_is_framebuffer_fetch(var.self))
2076 return "";
2077
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002078 if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
2079 {
2080 if (is_legacy() && execution.model == ExecutionModelVertex)
2081 return var.storage == StorageClassInput ? "attribute " : "varying ";
2082 else if (is_legacy() && execution.model == ExecutionModelFragment)
2083 return "varying "; // Fragment outputs are renamed so they never hit this case.
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002084 else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
2085 {
2086 if (inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
2087 return "inout ";
2088 else
2089 return "out ";
2090 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002091 else
2092 return var.storage == StorageClassInput ? "in " : "out ";
2093 }
2094 else if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
2095 var.storage == StorageClassPushConstant)
2096 {
2097 return "uniform ";
2098 }
Patrick Moursda39a7b2019-02-26 15:43:03 +01002099 else if (var.storage == StorageClassRayPayloadNV)
2100 {
2101 return "rayPayloadNV ";
2102 }
2103 else if (var.storage == StorageClassIncomingRayPayloadNV)
2104 {
2105 return "rayPayloadInNV ";
2106 }
2107 else if (var.storage == StorageClassHitAttributeNV)
2108 {
2109 return "hitAttributeNV ";
2110 }
Patrick Mours78917862019-06-03 15:25:21 +02002111 else if (var.storage == StorageClassCallableDataNV)
2112 {
Patrick Moursbe3035d2019-06-05 13:19:41 +02002113 return "callableDataNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002114 }
2115 else if (var.storage == StorageClassIncomingCallableDataNV)
2116 {
Patrick Moursbe3035d2019-06-05 13:19:41 +02002117 return "callableDataInNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002118 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002119
2120 return "";
2121}
2122
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002123void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual)
2124{
2125 auto &type = get<SPIRType>(var.basetype);
2126 if (!type.array.empty())
2127 SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings.");
2128
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002129 auto old_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002130 // Emit the members as if they are part of a block to get all qualifiers.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002131 ir.meta[type.self].decoration.decoration_flags.set(DecorationBlock);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002132
Hans-Kristian Arntzena8df0802017-11-22 11:19:54 +01002133 type.member_name_cache.clear();
2134
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002135 uint32_t i = 0;
2136 for (auto &member : type.member_types)
2137 {
2138 add_member_name(type, i);
2139 auto &membertype = get<SPIRType>(member);
2140
2141 if (membertype.basetype == SPIRType::Struct)
2142 SPIRV_CROSS_THROW("Cannot flatten struct inside structs in I/O variables.");
2143
2144 // Pass in the varying qualifier here so it will appear in the correct declaration order.
2145 // Replace member name while emitting it so it encodes both struct name and member name.
2146 // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row,
2147 // which is not allowed.
Hans-Kristian Arntzen94ff3552017-10-10 17:32:26 +02002148 auto backup_name = get_member_name(type.self, i);
2149 auto member_name = to_member_name(type, i);
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01002150 set_member_name(type.self, i, sanitize_underscores(join(to_name(var.self), "_", member_name)));
Bill Hollingsdc694272017-03-11 12:17:22 -05002151 emit_struct_member(type, member, i, qual);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002152 // Restore member name.
2153 set_member_name(type.self, i, member_name);
2154 i++;
2155 }
2156
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002157 ir.meta[type.self].decoration.decoration_flags = old_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002158
2159 // Treat this variable as flattened from now on.
2160 flattened_structs.insert(var.self);
2161}
2162
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002163void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
2164{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002165 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002166
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002167 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002168 bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002169 const char *qual = to_storage_qualifiers_glsl(var);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002170
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002171 if (block)
2172 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002173 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2174 // I/O variables which are struct types.
2175 // To support this, flatten the struct into separate varyings instead.
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002176 if ((options.es && options.version < 310) || (!options.es && options.version < 150))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002177 {
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002178 // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320.
2179 // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150).
2180 emit_flattened_io_block(var, qual);
2181 }
2182 else
2183 {
2184 if (options.es && options.version < 320)
2185 {
2186 // Geometry and tessellation extensions imply this extension.
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01002187 if (!has_extension("GL_EXT_geometry_shader") && !has_extension("GL_EXT_tessellation_shader"))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002188 require_extension_internal("GL_EXT_shader_io_blocks");
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002189 }
2190
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002191 // Block names should never alias.
2192 auto block_name = to_name(type.self, false);
2193
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002194 // The namespace for I/O blocks is separate from other variables in GLSL.
2195 auto &block_namespace = type.storage == StorageClassInput ? block_input_names : block_output_names;
2196
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002197 // Shaders never use the block by interface name, so we don't
2198 // have to track this other than updating name caches.
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002199 if (block_name.empty() || block_namespace.find(block_name) != end(block_namespace))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002200 block_name = get_fallback_name(type.self);
2201 else
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002202 block_namespace.insert(block_name);
2203
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002204 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2205 // This cannot conflict with anything else, so we're safe now.
2206 if (block_name.empty())
2207 block_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2208
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002209 // Instance names cannot alias block names.
2210 resource_names.insert(block_name);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002211
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002212 statement(layout_for_variable(var), qual, block_name);
2213 begin_scope();
2214
2215 type.member_name_cache.clear();
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002216
2217 uint32_t i = 0;
2218 for (auto &member : type.member_types)
2219 {
2220 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002221 emit_struct_member(type, member, i);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002222 i++;
2223 }
2224
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002225 add_resource_name(var.self);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002226 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
2227 statement("");
2228 }
2229 }
2230 else
2231 {
2232 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2233 // I/O variables which are struct types.
2234 // To support this, flatten the struct into separate varyings instead.
2235 if (type.basetype == SPIRType::Struct &&
2236 ((options.es && options.version < 310) || (!options.es && options.version < 150)))
2237 {
2238 emit_flattened_io_block(var, qual);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002239 }
2240 else
2241 {
2242 add_resource_name(var.self);
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002243
2244 // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays.
2245 // Opt for unsized as it's the more "correct" variant to use.
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +01002246 bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() &&
2247 !has_decoration(var.self, DecorationPatch) &&
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002248 (get_entry_point().model == ExecutionModelTessellationControl ||
2249 get_entry_point().model == ExecutionModelTessellationEvaluation);
2250
2251 uint32_t old_array_size = 0;
2252 bool old_array_size_literal = true;
2253
2254 if (control_point_input_array)
2255 {
2256 swap(type.array.back(), old_array_size);
2257 swap(type.array_size_literal.back(), old_array_size_literal);
2258 }
2259
Chip Davis3bfb2f92018-12-03 02:06:33 -06002260 statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
2261 variable_decl(type, to_name(var.self), var.self), ";");
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002262
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002263 if (control_point_input_array)
2264 {
2265 swap(type.array.back(), old_array_size);
2266 swap(type.array_size_literal.back(), old_array_size_literal);
2267 }
2268
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002269 // If a StorageClassOutput variable has an initializer, we need to initialize it in main().
2270 if (var.storage == StorageClassOutput && var.initializer)
2271 {
2272 auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
Hans-Kristian Arntzen2edee352019-01-30 13:42:50 +01002273 entry_func.fixup_hooks_in.push_back(
2274 [&]() { statement(to_name(var.self), " = ", to_expression(var.initializer), ";"); });
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002275 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002276 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002277 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002278}
2279
2280void CompilerGLSL::emit_uniform(const SPIRVariable &var)
2281{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002282 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002283 if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002284 {
2285 if (!options.es && options.version < 420)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002286 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002287 else if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002288 SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002289 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002290
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002291 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002292 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002293}
2294
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002295string CompilerGLSL::constant_value_macro_name(uint32_t id)
2296{
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002297 return join("SPIRV_CROSS_CONSTANT_ID_", id);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002298}
2299
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002300void CompilerGLSL::emit_specialization_constant_op(const SPIRConstantOp &constant)
2301{
2302 auto &type = get<SPIRType>(constant.basetype);
2303 auto name = to_name(constant.self);
2304 statement("const ", variable_decl(type, name), " = ", constant_op_expression(constant), ";");
2305}
2306
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002307void CompilerGLSL::emit_constant(const SPIRConstant &constant)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002308{
2309 auto &type = get<SPIRType>(constant.constant_type);
2310 auto name = to_name(constant.self);
2311
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002312 SpecializationConstant wg_x, wg_y, wg_z;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002313 ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002314
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002315 // This specialization constant is implicitly declared by emitting layout() in;
2316 if (constant.self == workgroup_size_id)
2317 return;
2318
2319 // These specialization constants are implicitly declared by emitting layout() in;
2320 // In legacy GLSL, we will still need to emit macros for these, so a layout() in; declaration
2321 // later can use macro overrides for work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002322 bool is_workgroup_size_constant = ConstantID(constant.self) == wg_x.id || ConstantID(constant.self) == wg_y.id ||
2323 ConstantID(constant.self) == wg_z.id;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002324
2325 if (options.vulkan_semantics && is_workgroup_size_constant)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002326 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002327 // Vulkan GLSL does not need to declare workgroup spec constants explicitly, it is handled in layout().
2328 return;
2329 }
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002330 else if (!options.vulkan_semantics && is_workgroup_size_constant &&
2331 !has_decoration(constant.self, DecorationSpecId))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002332 {
2333 // Only bother declaring a workgroup size if it is actually a specialization constant, because we need macros.
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002334 return;
2335 }
2336
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002337 // Only scalars have constant IDs.
2338 if (has_decoration(constant.self, DecorationSpecId))
2339 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002340 if (options.vulkan_semantics)
2341 {
2342 statement("layout(constant_id = ", get_decoration(constant.self, DecorationSpecId), ") const ",
2343 variable_decl(type, name), " = ", constant_expression(constant), ";");
2344 }
2345 else
2346 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002347 const string &macro_name = constant.specialization_constant_macro_name;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002348 statement("#ifndef ", macro_name);
2349 statement("#define ", macro_name, " ", constant_expression(constant));
2350 statement("#endif");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002351
2352 // For workgroup size constants, only emit the macros.
2353 if (!is_workgroup_size_constant)
2354 statement("const ", variable_decl(type, name), " = ", macro_name, ";");
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002355 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002356 }
2357 else
2358 {
2359 statement("const ", variable_decl(type, name), " = ", constant_expression(constant), ";");
2360 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002361}
2362
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +02002363void CompilerGLSL::emit_entry_point_declarations()
2364{
2365}
2366
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002367void CompilerGLSL::replace_illegal_names(const unordered_set<string> &keywords)
2368{
2369 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
2370 if (is_hidden_variable(var))
2371 return;
2372
2373 auto *meta = ir.find_meta(var.self);
2374 if (!meta)
2375 return;
2376
2377 auto &m = meta->decoration;
2378 if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords))
2379 m.alias = join("_", m.alias);
2380 });
2381
2382 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
2383 auto *meta = ir.find_meta(type.self);
2384 if (!meta)
2385 return;
2386
2387 auto &m = meta->decoration;
2388 if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords))
2389 m.alias = join("_", m.alias);
2390
2391 for (auto &memb : meta->members)
2392 if (memb.alias.compare(0, 3, "gl_") == 0 || keywords.find(memb.alias) != end(keywords))
2393 memb.alias = join("_", memb.alias);
2394 });
2395}
2396
Robert Konrad76936562016-08-13 00:14:52 +02002397void CompilerGLSL::replace_illegal_names()
2398{
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002399 // clang-format off
2400 static const unordered_set<string> keywords = {
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002401 "abs", "acos", "acosh", "all", "any", "asin", "asinh", "atan", "atanh",
2402 "atomicAdd", "atomicCompSwap", "atomicCounter", "atomicCounterDecrement", "atomicCounterIncrement",
2403 "atomicExchange", "atomicMax", "atomicMin", "atomicOr", "atomicXor",
2404 "bitCount", "bitfieldExtract", "bitfieldInsert", "bitfieldReverse",
2405 "ceil", "cos", "cosh", "cross", "degrees",
2406 "dFdx", "dFdxCoarse", "dFdxFine",
2407 "dFdy", "dFdyCoarse", "dFdyFine",
2408 "distance", "dot", "EmitStreamVertex", "EmitVertex", "EndPrimitive", "EndStreamPrimitive", "equal", "exp", "exp2",
Chip Davis0d949e12018-11-05 14:55:56 -06002409 "faceforward", "findLSB", "findMSB", "float16BitsToInt16", "float16BitsToUint16", "floatBitsToInt", "floatBitsToUint", "floor", "fma", "fract",
2410 "frexp", "fwidth", "fwidthCoarse", "fwidthFine",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002411 "greaterThan", "greaterThanEqual", "groupMemoryBarrier",
2412 "imageAtomicAdd", "imageAtomicAnd", "imageAtomicCompSwap", "imageAtomicExchange", "imageAtomicMax", "imageAtomicMin", "imageAtomicOr", "imageAtomicXor",
Chip Davis0d949e12018-11-05 14:55:56 -06002413 "imageLoad", "imageSamples", "imageSize", "imageStore", "imulExtended", "int16BitsToFloat16", "intBitsToFloat", "interpolateAtOffset", "interpolateAtCentroid", "interpolateAtSample",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002414 "inverse", "inversesqrt", "isinf", "isnan", "ldexp", "length", "lessThan", "lessThanEqual", "log", "log2",
2415 "matrixCompMult", "max", "memoryBarrier", "memoryBarrierAtomicCounter", "memoryBarrierBuffer", "memoryBarrierImage", "memoryBarrierShared",
2416 "min", "mix", "mod", "modf", "noise", "noise1", "noise2", "noise3", "noise4", "normalize", "not", "notEqual",
Chip Davis0d949e12018-11-05 14:55:56 -06002417 "outerProduct", "packDouble2x32", "packHalf2x16", "packInt2x16", "packInt4x16", "packSnorm2x16", "packSnorm4x8",
2418 "packUint2x16", "packUint4x16", "packUnorm2x16", "packUnorm4x8", "pow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002419 "radians", "reflect", "refract", "round", "roundEven", "sign", "sin", "sinh", "smoothstep", "sqrt", "step",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002420 "tan", "tanh", "texelFetch", "texelFetchOffset", "texture", "textureGather", "textureGatherOffset", "textureGatherOffsets",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002421 "textureGrad", "textureGradOffset", "textureLod", "textureLodOffset", "textureOffset", "textureProj", "textureProjGrad",
2422 "textureProjGradOffset", "textureProjLod", "textureProjLodOffset", "textureProjOffset", "textureQueryLevels", "textureQueryLod", "textureSamples", "textureSize",
Chip Davis0d949e12018-11-05 14:55:56 -06002423 "transpose", "trunc", "uaddCarry", "uint16BitsToFloat16", "uintBitsToFloat", "umulExtended", "unpackDouble2x32", "unpackHalf2x16", "unpackInt2x16", "unpackInt4x16",
2424 "unpackSnorm2x16", "unpackSnorm4x8", "unpackUint2x16", "unpackUint4x16", "unpackUnorm2x16", "unpackUnorm4x8", "usubBorrow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002425
Pascal Muetschardaced6052018-05-04 14:53:32 -07002426 "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002427 "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard",
2428 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4",
2429 "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float",
2430 "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray",
2431 "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
2432 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect",
2433 "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant",
2434 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002435 "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp",
2436 "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump",
2437 "namespace", "noinline", "noperspective", "out", "output", "packed", "partition", "patch", "precise", "precision", "public", "readonly",
2438 "resource", "restrict", "return", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002439 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
2440 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002441 "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "shared", "short", "sizeof", "smooth", "static",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002442 "struct", "subroutine", "superp", "switch", "template", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D",
2443 "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube",
2444 "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
2445 "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002446 "usamplerCubeArray", "using", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile",
2447 "while", "writeonly",
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002448 };
2449 // clang-format on
Bas Zalmstraf537adf2016-10-27 12:51:22 +02002450
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002451 replace_illegal_names(keywords);
Robert Konrad76936562016-08-13 00:14:52 +02002452}
2453
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002454void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
2455{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002456 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002457 uint32_t location = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002458 if (m.decoration_flags.get(DecorationLocation))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002459 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002460
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002461 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
2462 // do the access chain part of this for us.
2463 auto &type = get<SPIRType>(var.basetype);
2464
2465 if (type.array.empty())
2466 {
2467 // Redirect the write to a specific render target in legacy GLSL.
2468 m.alias = join("gl_FragData[", location, "]");
Lubos Lenco52158642016-09-17 15:56:23 +02002469
2470 if (is_legacy_es() && location != 0)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002471 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002472 }
2473 else if (type.array.size() == 1)
2474 {
2475 // If location is non-zero, we probably have to add an offset.
2476 // This gets really tricky since we'd have to inject an offset in the access chain.
2477 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
2478 m.alias = "gl_FragData";
2479 if (location != 0)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002480 SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
2481 "This is unimplemented in SPIRV-Cross.");
Hans-Kristian Arntzen6cc96242016-09-17 18:46:10 +02002482
Lubos Lenco80c39412016-09-17 14:33:16 +02002483 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002484 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002485 }
2486 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002487 SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002488
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002489 var.compat_builtin = true; // We don't want to declare this variable, but use the name as-is.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002490}
2491
2492void CompilerGLSL::replace_fragment_outputs()
2493{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002494 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002495 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002496
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +01002497 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer && var.storage == StorageClassOutput)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002498 replace_fragment_output(var);
2499 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002500}
2501
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002502string CompilerGLSL::remap_swizzle(const SPIRType &out_type, uint32_t input_components, const string &expr)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002503{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002504 if (out_type.vecsize == input_components)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002505 return expr;
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01002506 else if (input_components == 1 && !backend.can_swizzle_scalar)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002507 return join(type_to_glsl(out_type), "(", expr, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002508 else
2509 {
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02002510 // FIXME: This will not work with packed expressions.
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002511 auto e = enclose_expression(expr) + ".";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002512 // Just clamp the swizzle index if we have more outputs than inputs.
2513 for (uint32_t c = 0; c < out_type.vecsize; c++)
2514 e += index_to_swizzle(min(c, input_components - 1));
2515 if (backend.swizzle_is_function && out_type.vecsize > 1)
2516 e += "()";
Hans-Kristian Arntzenffad50b2017-12-12 13:01:10 +01002517
2518 remove_duplicate_swizzle(e);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002519 return e;
2520 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002521}
2522
2523void CompilerGLSL::emit_pls()
2524{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002525 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002526 if (execution.model != ExecutionModelFragment)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002527 SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002529 if (!options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002530 SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002531
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002532 if (options.version < 300)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002533 SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002534
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002535 if (!pls_inputs.empty())
2536 {
2537 statement("__pixel_local_inEXT _PLSIn");
2538 begin_scope();
2539 for (auto &input : pls_inputs)
2540 statement(pls_decl(input), ";");
2541 end_scope_decl();
2542 statement("");
2543 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002545 if (!pls_outputs.empty())
2546 {
2547 statement("__pixel_local_outEXT _PLSOut");
2548 begin_scope();
2549 for (auto &output : pls_outputs)
2550 statement(pls_decl(output), ";");
2551 end_scope_decl();
2552 statement("");
2553 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002554}
2555
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002556void CompilerGLSL::fixup_image_load_store_access()
2557{
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002558 if (!options.enable_storage_image_qualifier_deduction)
2559 return;
2560
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002561 ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002562 auto &vartype = expression_type(var);
Hans-Kristian Arntzenb691b7d2020-04-03 12:26:13 +02002563 if (vartype.basetype == SPIRType::Image && vartype.image.sampled == 2)
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002564 {
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002565 // Very old glslangValidator and HLSL compilers do not emit required qualifiers here.
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002566 // Solve this by making the image access as restricted as possible and loosen up if we need to.
2567 // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
2568
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01002569 auto &flags = ir.meta[var].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002570 if (!flags.get(DecorationNonWritable) && !flags.get(DecorationNonReadable))
2571 {
2572 flags.set(DecorationNonWritable);
2573 flags.set(DecorationNonReadable);
2574 }
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002575 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002576 });
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002577}
2578
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002579static bool is_block_builtin(BuiltIn builtin)
2580{
2581 return builtin == BuiltInPosition || builtin == BuiltInPointSize || builtin == BuiltInClipDistance ||
2582 builtin == BuiltInCullDistance;
2583}
2584
2585bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage)
2586{
2587 // If the builtin block uses XFB, we need to force explicit redeclaration of the builtin block.
2588
2589 if (storage != StorageClassOutput)
2590 return false;
2591 bool should_force = false;
2592
2593 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
2594 if (should_force)
2595 return;
2596
2597 auto &type = this->get<SPIRType>(var.basetype);
2598 bool block = has_decoration(type.self, DecorationBlock);
2599 if (var.storage == storage && block && is_builtin_variable(var))
2600 {
2601 uint32_t member_count = uint32_t(type.member_types.size());
2602 for (uint32_t i = 0; i < member_count; i++)
2603 {
2604 if (has_member_decoration(type.self, i, DecorationBuiltIn) &&
2605 is_block_builtin(BuiltIn(get_member_decoration(type.self, i, DecorationBuiltIn))) &&
2606 has_member_decoration(type.self, i, DecorationOffset))
2607 {
2608 should_force = true;
2609 }
2610 }
2611 }
2612 else if (var.storage == storage && !block && is_builtin_variable(var))
2613 {
2614 if (is_block_builtin(BuiltIn(get_decoration(type.self, DecorationBuiltIn))) &&
2615 has_decoration(var.self, DecorationOffset))
2616 {
2617 should_force = true;
2618 }
2619 }
2620 });
2621
2622 return should_force;
2623}
2624
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002625void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
2626{
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002627 Bitset emitted_builtins;
2628 Bitset global_builtins;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002629 const SPIRVariable *block_var = nullptr;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002630 bool emitted_block = false;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002631 bool builtin_array = false;
2632
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002633 // Need to use declared size in the type.
2634 // These variables might have been declared, but not statically used, so we haven't deduced their size yet.
2635 uint32_t cull_distance_size = 0;
2636 uint32_t clip_distance_size = 0;
2637
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002638 bool have_xfb_buffer_stride = false;
2639 bool have_any_xfb_offset = false;
2640 uint32_t xfb_stride = 0, xfb_buffer = 0;
Hans-Kristian Arntzendfffbb12020-01-27 15:56:47 +01002641 std::unordered_map<uint32_t, uint32_t> builtin_xfb_offsets;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002642
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002643 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002644 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002645 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002646 Bitset builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002647
2648 if (var.storage == storage && block && is_builtin_variable(var))
2649 {
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002650 uint32_t index = 0;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002651 for (auto &m : ir.meta[type.self].members)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002652 {
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002653 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002654 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002655 builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002656 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002657 cull_distance_size = this->get<SPIRType>(type.member_types[index]).array.front();
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002658 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002659 clip_distance_size = this->get<SPIRType>(type.member_types[index]).array.front();
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002660
2661 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationOffset))
2662 {
2663 have_any_xfb_offset = true;
2664 builtin_xfb_offsets[m.builtin_type] = m.offset;
2665 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002666 }
2667 index++;
2668 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002669
2670 if (storage == StorageClassOutput && has_decoration(var.self, DecorationXfbBuffer) &&
2671 has_decoration(var.self, DecorationXfbStride))
2672 {
2673 uint32_t buffer_index = get_decoration(var.self, DecorationXfbBuffer);
2674 uint32_t stride = get_decoration(var.self, DecorationXfbStride);
2675 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
2676 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2677 if (have_xfb_buffer_stride && stride != xfb_stride)
2678 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2679 have_xfb_buffer_stride = true;
2680 xfb_buffer = buffer_index;
2681 xfb_stride = stride;
2682 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002683 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002684 else if (var.storage == storage && !block && is_builtin_variable(var))
2685 {
2686 // While we're at it, collect all declared global builtins (HLSL mostly ...).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002687 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002688 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002689 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002690 global_builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002691 if (m.builtin_type == BuiltInCullDistance)
2692 cull_distance_size = type.array.front();
2693 else if (m.builtin_type == BuiltInClipDistance)
2694 clip_distance_size = type.array.front();
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002695
2696 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationXfbStride) &&
2697 m.decoration_flags.get(DecorationXfbBuffer) && m.decoration_flags.get(DecorationOffset))
2698 {
2699 have_any_xfb_offset = true;
2700 builtin_xfb_offsets[m.builtin_type] = m.offset;
2701 uint32_t buffer_index = m.xfb_buffer;
2702 uint32_t stride = m.xfb_stride;
2703 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
2704 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2705 if (have_xfb_buffer_stride && stride != xfb_stride)
2706 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2707 have_xfb_buffer_stride = true;
2708 xfb_buffer = buffer_index;
2709 xfb_stride = stride;
2710 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002711 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002712 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002713
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002714 if (builtins.empty())
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002715 return;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002716
2717 if (emitted_block)
2718 SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
2719
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002720 emitted_builtins = builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002721 emitted_block = true;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002722 builtin_array = !type.array.empty();
2723 block_var = &var;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002724 });
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002725
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01002726 global_builtins =
2727 Bitset(global_builtins.get_lower() & ((1ull << BuiltInPosition) | (1ull << BuiltInPointSize) |
2728 (1ull << BuiltInClipDistance) | (1ull << BuiltInCullDistance)));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002729
2730 // Try to collect all other declared builtins.
2731 if (!emitted_block)
2732 emitted_builtins = global_builtins;
2733
2734 // Can't declare an empty interface block.
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002735 if (emitted_builtins.empty())
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002736 return;
2737
2738 if (storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002739 {
2740 if (have_xfb_buffer_stride && have_any_xfb_offset)
2741 {
2742 statement("layout(xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride, ") out gl_PerVertex");
2743 if (!options.es)
2744 {
2745 if (options.version < 440 && options.version >= 140)
2746 require_extension_internal("GL_ARB_enhanced_layouts");
2747 else if (options.version < 140)
2748 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
2749 if (!options.es && options.version < 440)
2750 require_extension_internal("GL_ARB_enhanced_layouts");
2751 }
2752 else if (options.es)
2753 SPIRV_CROSS_THROW("Need GL_ARB_enhanced_layouts for xfb_stride or xfb_buffer.");
2754 }
2755 else
2756 statement("out gl_PerVertex");
2757 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002758 else
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002759 {
2760 // If we have passthrough, there is no way PerVertex cannot be passthrough.
2761 if (get_entry_point().geometry_passthrough)
2762 statement("layout(passthrough) in gl_PerVertex");
2763 else
2764 statement("in gl_PerVertex");
2765 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002766
2767 begin_scope();
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002768 if (emitted_builtins.get(BuiltInPosition))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002769 {
2770 auto itr = builtin_xfb_offsets.find(BuiltInPosition);
2771 if (itr != end(builtin_xfb_offsets))
2772 statement("layout(xfb_offset = ", itr->second, ") vec4 gl_Position;");
2773 else
2774 statement("vec4 gl_Position;");
2775 }
2776
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002777 if (emitted_builtins.get(BuiltInPointSize))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002778 {
2779 auto itr = builtin_xfb_offsets.find(BuiltInPointSize);
2780 if (itr != end(builtin_xfb_offsets))
2781 statement("layout(xfb_offset = ", itr->second, ") float gl_PointSize;");
2782 else
2783 statement("float gl_PointSize;");
2784 }
2785
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002786 if (emitted_builtins.get(BuiltInClipDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002787 {
2788 auto itr = builtin_xfb_offsets.find(BuiltInClipDistance);
2789 if (itr != end(builtin_xfb_offsets))
2790 statement("layout(xfb_offset = ", itr->second, ") float gl_ClipDistance[", clip_distance_size, "];");
2791 else
2792 statement("float gl_ClipDistance[", clip_distance_size, "];");
2793 }
2794
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002795 if (emitted_builtins.get(BuiltInCullDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002796 {
2797 auto itr = builtin_xfb_offsets.find(BuiltInCullDistance);
2798 if (itr != end(builtin_xfb_offsets))
2799 statement("layout(xfb_offset = ", itr->second, ") float gl_CullDistance[", cull_distance_size, "];");
2800 else
2801 statement("float gl_CullDistance[", cull_distance_size, "];");
2802 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002803
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002804 if (builtin_array)
2805 {
2806 // Make sure the array has a supported name in the code.
2807 if (storage == StorageClassOutput)
2808 set_name(block_var->self, "gl_out");
2809 else if (storage == StorageClassInput)
2810 set_name(block_var->self, "gl_in");
2811
2812 if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
2813 end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]"));
2814 else
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002815 end_scope_decl(join(to_name(block_var->self), "[]"));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002816 }
2817 else
2818 end_scope_decl();
2819 statement("");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002820}
2821
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002822void CompilerGLSL::declare_undefined_values()
2823{
2824 bool emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002825 ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01002826 string initializer;
2827 if (options.force_zero_initialized_variables && type_can_zero_initialize(this->get<SPIRType>(undef.basetype)))
2828 initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
2829
2830 statement(variable_decl(this->get<SPIRType>(undef.basetype), to_name(undef.self), undef.self), initializer,
2831 ";");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002832 emitted = true;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002833 });
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002834
2835 if (emitted)
2836 statement("");
2837}
2838
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01002839bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const
2840{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002841 bool statically_assigned = var.statically_assigned && var.static_expression != ID(0) && var.remapped_variable;
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01002842
2843 if (statically_assigned)
2844 {
2845 auto *constant = maybe_get<SPIRConstant>(var.static_expression);
2846 if (constant && constant->is_used_as_lut)
2847 return true;
2848 }
2849
2850 return false;
2851}
2852
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002853void CompilerGLSL::emit_resources()
2854{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002855 auto &execution = get_entry_point();
2856
Robert Konrad76936562016-08-13 00:14:52 +02002857 replace_illegal_names();
2858
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002859 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
2860 // with builtins.
2861 if (execution.model == ExecutionModelFragment && is_legacy())
2862 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002863
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002864 // Emit PLS blocks if we have such variables.
2865 if (!pls_inputs.empty() || !pls_outputs.empty())
2866 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002867
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002868 // Emit custom gl_PerVertex for SSO compatibility.
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01002869 if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment)
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002870 {
2871 switch (execution.model)
2872 {
2873 case ExecutionModelGeometry:
2874 case ExecutionModelTessellationControl:
2875 case ExecutionModelTessellationEvaluation:
2876 emit_declared_builtin_block(StorageClassInput, execution.model);
2877 emit_declared_builtin_block(StorageClassOutput, execution.model);
2878 break;
2879
2880 case ExecutionModelVertex:
2881 emit_declared_builtin_block(StorageClassOutput, execution.model);
2882 break;
2883
2884 default:
2885 break;
2886 }
2887 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002888 else if (should_force_emit_builtin_block(StorageClassOutput))
2889 {
2890 emit_declared_builtin_block(StorageClassOutput, execution.model);
2891 }
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002892 else if (execution.geometry_passthrough)
2893 {
2894 // Need to declare gl_in with Passthrough.
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002895 // If we're doing passthrough, we cannot emit an output block, so the output block test above will never pass.
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002896 emit_declared_builtin_block(StorageClassInput, execution.model);
2897 }
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01002898 else
2899 {
2900 // Need to redeclare clip/cull distance with explicit size to use them.
2901 // SPIR-V mandates these builtins have a size declared.
2902 const char *storage = execution.model == ExecutionModelFragment ? "in" : "out";
2903 if (clip_distance_count != 0)
2904 statement(storage, " float gl_ClipDistance[", clip_distance_count, "];");
2905 if (cull_distance_count != 0)
2906 statement(storage, " float gl_CullDistance[", cull_distance_count, "];");
2907 if (clip_distance_count != 0 || cull_distance_count != 0)
2908 statement("");
2909 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002910
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002911 if (position_invariant)
2912 {
2913 statement("invariant gl_Position;");
2914 statement("");
2915 }
2916
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002917 bool emitted = false;
2918
2919 // If emitted Vulkan GLSL,
2920 // emit specialization constants as actual floats,
2921 // spec op expressions will redirect to the constant name.
2922 //
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002923 {
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +02002924 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002925 for (auto &id_ : ir.ids_for_constant_or_type)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002926 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002927 auto &id = ir.ids[id_];
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002928
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002929 if (id.get_type() == TypeConstant)
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002930 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002931 auto &c = id.get<SPIRConstant>();
2932
2933 bool needs_declaration = c.specialization || c.is_used_as_lut;
2934
2935 if (needs_declaration)
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002936 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002937 if (!options.vulkan_semantics && c.specialization)
2938 {
2939 c.specialization_constant_macro_name =
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02002940 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002941 }
2942 emit_constant(c);
2943 emitted = true;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002944 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002945 }
2946 else if (id.get_type() == TypeConstantOp)
2947 {
2948 emit_specialization_constant_op(id.get<SPIRConstantOp>());
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002949 emitted = true;
2950 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002951 else if (id.get_type() == TypeType)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002952 {
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02002953 auto *type = &id.get<SPIRType>();
2954
2955 bool is_natural_struct =
2956 type->basetype == SPIRType::Struct && type->array.empty() && !type->pointer &&
2957 (!has_decoration(type->self, DecorationBlock) && !has_decoration(type->self, DecorationBufferBlock));
2958
2959 // Special case, ray payload and hit attribute blocks are not really blocks, just regular structs.
2960 if (type->basetype == SPIRType::Struct && type->pointer && has_decoration(type->self, DecorationBlock) &&
2961 (type->storage == StorageClassRayPayloadNV || type->storage == StorageClassIncomingRayPayloadNV ||
2962 type->storage == StorageClassHitAttributeNV))
2963 {
2964 type = &get<SPIRType>(type->parent_type);
2965 is_natural_struct = true;
2966 }
2967
2968 if (is_natural_struct)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002969 {
2970 if (emitted)
2971 statement("");
2972 emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002973
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02002974 emit_struct(*type);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002975 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002976 }
2977 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002978 }
2979
2980 if (emitted)
2981 statement("");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002982
2983 // If we needed to declare work group size late, check here.
2984 // If the work group size depends on a specialization constant, we need to declare the layout() block
2985 // after constants (and their macros) have been declared.
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002986 if (execution.model == ExecutionModelGLCompute && !options.vulkan_semantics &&
2987 execution.workgroup_size.constant != 0)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002988 {
2989 SpecializationConstant wg_x, wg_y, wg_z;
2990 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
2991
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002992 if ((wg_x.id != ConstantID(0)) || (wg_y.id != ConstantID(0)) || (wg_z.id != ConstantID(0)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002993 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02002994 SmallVector<string> inputs;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002995 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
2996 statement("layout(", merge(inputs), ") in;");
2997 statement("");
2998 }
2999 }
3000
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003001 emitted = false;
3002
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003003 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
3004 {
3005 for (auto type : physical_storage_non_block_pointer_types)
3006 {
3007 emit_buffer_reference_block(get<SPIRType>(type), false);
3008 }
3009
3010 // Output buffer reference blocks.
3011 // Do this in two stages, one with forward declaration,
3012 // and one without. Buffer reference blocks can reference themselves
3013 // to support things like linked lists.
3014 ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
3015 bool has_block_flags = has_decoration(type.self, DecorationBlock);
3016 if (has_block_flags && type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
3017 type.storage == StorageClassPhysicalStorageBufferEXT)
3018 {
3019 emit_buffer_reference_block(type, true);
3020 }
3021 });
3022
3023 ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
3024 bool has_block_flags = has_decoration(type.self, DecorationBlock);
3025 if (has_block_flags && type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
3026 type.storage == StorageClassPhysicalStorageBufferEXT)
3027 {
3028 emit_buffer_reference_block(type, false);
3029 }
3030 });
3031 }
3032
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003033 // Output UBOs and SSBOs
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003034 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003035 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003036
Patrick Mours78917862019-06-03 15:25:21 +02003037 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform ||
3038 type.storage == StorageClassShaderRecordBufferNV;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003039 bool has_block_flags = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
3040 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
3041
3042 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
3043 has_block_flags)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003044 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003045 emit_buffer_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003046 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003047 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003048
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003049 // Output push constant blocks
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003050 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003051 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003052 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
3053 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003054 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003055 emit_push_constant_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003056 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003057 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003058
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02003059 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003061 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003062 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003063 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003064
3065 // If we're remapping separate samplers and images, only emit the combined samplers.
3066 if (skip_separate_image_sampler)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003067 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003068 // Sampler buffers are always used without a sampler, and they will also work in regular GL.
3069 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
3070 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
3071 bool separate_sampler = type.basetype == SPIRType::Sampler;
3072 if (!sampler_buffer && (separate_image || separate_sampler))
3073 return;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003074 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003075
3076 if (var.storage != StorageClassFunction && type.pointer &&
Patrick Moursda39a7b2019-02-26 15:43:03 +01003077 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter ||
Patrick Moursbe3035d2019-06-05 13:19:41 +02003078 type.storage == StorageClassRayPayloadNV || type.storage == StorageClassIncomingRayPayloadNV ||
3079 type.storage == StorageClassCallableDataNV || type.storage == StorageClassIncomingCallableDataNV ||
3080 type.storage == StorageClassHitAttributeNV) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003081 !is_hidden_variable(var))
3082 {
3083 emit_uniform(var);
3084 emitted = true;
3085 }
3086 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003087
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003088 if (emitted)
3089 statement("");
3090 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003091
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003092 bool emitted_base_instance = false;
3093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003094 // Output in/out interfaces.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003095 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003096 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003097
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003098 bool is_hidden = is_hidden_variable(var);
3099
3100 // Unused output I/O variables might still be required to implement framebuffer fetch.
3101 if (var.storage == StorageClassOutput && !is_legacy() &&
3102 inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
3103 {
3104 is_hidden = false;
3105 }
3106
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003107 if (var.storage != StorageClassFunction && type.pointer &&
3108 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003109 interface_variable_exists_in_entry_point(var.self) && !is_hidden)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003110 {
3111 emit_interface_block(var);
3112 emitted = true;
3113 }
3114 else if (is_builtin_variable(var))
3115 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003116 auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003117 // For gl_InstanceIndex emulation on GLES, the API user needs to
3118 // supply this uniform.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003119
3120 // The draw parameter extension is soft-enabled on GL with some fallbacks.
3121 if (!options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003122 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003123 if (!emitted_base_instance &&
3124 ((options.vertex.support_nonzero_base_instance && builtin == BuiltInInstanceIndex) ||
3125 (builtin == BuiltInBaseInstance)))
3126 {
3127 statement("#ifdef GL_ARB_shader_draw_parameters");
3128 statement("#define SPIRV_Cross_BaseInstance gl_BaseInstanceARB");
3129 statement("#else");
3130 // A crude, but simple workaround which should be good enough for non-indirect draws.
3131 statement("uniform int SPIRV_Cross_BaseInstance;");
3132 statement("#endif");
3133 emitted = true;
3134 emitted_base_instance = true;
3135 }
3136 else if (builtin == BuiltInBaseVertex)
3137 {
3138 statement("#ifdef GL_ARB_shader_draw_parameters");
3139 statement("#define SPIRV_Cross_BaseVertex gl_BaseVertexARB");
3140 statement("#else");
3141 // A crude, but simple workaround which should be good enough for non-indirect draws.
3142 statement("uniform int SPIRV_Cross_BaseVertex;");
3143 statement("#endif");
3144 }
3145 else if (builtin == BuiltInDrawIndex)
3146 {
3147 statement("#ifndef GL_ARB_shader_draw_parameters");
3148 // Cannot really be worked around.
3149 statement("#error GL_ARB_shader_draw_parameters is not supported.");
3150 statement("#endif");
3151 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003152 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003153 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003154 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003156 // Global variables.
3157 for (auto global : global_variables)
3158 {
3159 auto &var = get<SPIRVariable>(global);
3160 if (var.storage != StorageClassOutput)
3161 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003162 if (!variable_is_lut(var))
3163 {
3164 add_resource_name(var.self);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003165
3166 string initializer;
3167 if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate &&
3168 !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var)))
3169 {
3170 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var)));
3171 }
3172
3173 statement(variable_decl(var), initializer, ";");
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003174 emitted = true;
3175 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003176 }
3177 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003178
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003179 if (emitted)
3180 statement("");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003181
3182 declare_undefined_values();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003183}
3184
Bill Hollingsb321b832016-07-06 20:30:47 -04003185// Returns a string representation of the ID, usable as a function arg.
3186// Default is to simply return the expression representation fo the arg ID.
3187// Subclasses may override to modify the return value.
Chip Davis39dce882019-08-02 15:11:19 -05003188string CompilerGLSL::to_func_call_arg(const SPIRFunction::Parameter &, uint32_t id)
Bill Hollingsb321b832016-07-06 20:30:47 -04003189{
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +02003190 // Make sure that we use the name of the original variable, and not the parameter alias.
3191 uint32_t name_id = id;
3192 auto *var = maybe_get<SPIRVariable>(id);
3193 if (var && var->basevariable)
3194 name_id = var->basevariable;
3195 return to_expression(name_id);
Bill Hollingsb321b832016-07-06 20:30:47 -04003196}
3197
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003198void CompilerGLSL::handle_invalid_expression(uint32_t id)
3199{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003200 // We tried to read an invalidated expression.
3201 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
3202 forced_temporaries.insert(id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003203 force_recompile();
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003204}
3205
Bill Hollingsb332bae2017-03-01 13:07:40 -05003206// Converts the format of the current expression from packed to unpacked,
3207// by wrapping the expression in a constructor of the appropriate type.
3208// GLSL does not support packed formats, so simply return the expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003209// Subclasses that do will override.
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02003210string CompilerGLSL::unpack_expression_type(string expr_str, const SPIRType &, uint32_t, bool, bool)
Bill Hollingsb332bae2017-03-01 13:07:40 -05003211{
3212 return expr_str;
3213}
3214
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01003215// Sometimes we proactively enclosed an expression where it turns out we might have not needed it after all.
3216void CompilerGLSL::strip_enclosed_expression(string &expr)
3217{
3218 if (expr.size() < 2 || expr.front() != '(' || expr.back() != ')')
3219 return;
3220
3221 // Have to make sure that our first and last parens actually enclose everything inside it.
3222 uint32_t paren_count = 0;
3223 for (auto &c : expr)
3224 {
3225 if (c == '(')
3226 paren_count++;
3227 else if (c == ')')
3228 {
3229 paren_count--;
3230
3231 // If we hit 0 and this is not the final char, our first and final parens actually don't
3232 // enclose the expression, and we cannot strip, e.g.: (a + b) * (c + d).
3233 if (paren_count == 0 && &c != &expr.back())
3234 return;
3235 }
3236 }
Corentin Walleze88c88c2017-01-18 17:22:19 -05003237 expr.erase(expr.size() - 1, 1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01003238 expr.erase(begin(expr));
3239}
3240
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02003241string CompilerGLSL::enclose_expression(const string &expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003242{
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003243 bool need_parens = false;
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02003244
3245 // If the expression starts with a unary we need to enclose to deal with cases where we have back-to-back
3246 // unary expressions.
3247 if (!expr.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003248 {
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02003249 auto c = expr.front();
Chip Davis3bfb2f92018-12-03 02:06:33 -06003250 if (c == '-' || c == '+' || c == '!' || c == '~' || c == '&' || c == '*')
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003251 need_parens = true;
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003252 }
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02003253
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003254 if (!need_parens)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003255 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003256 uint32_t paren_count = 0;
3257 for (auto c : expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003258 {
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02003259 if (c == '(' || c == '[')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003260 paren_count++;
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02003261 else if (c == ')' || c == ']')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003262 {
3263 assert(paren_count);
3264 paren_count--;
3265 }
3266 else if (c == ' ' && paren_count == 0)
3267 {
3268 need_parens = true;
3269 break;
3270 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003271 }
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003272 assert(paren_count == 0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003273 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003274
3275 // If this expression contains any spaces which are not enclosed by parentheses,
3276 // we need to enclose it so we can treat the whole string as an expression.
3277 // This happens when two expressions have been part of a binary op earlier.
3278 if (need_parens)
3279 return join('(', expr, ')');
3280 else
3281 return expr;
3282}
3283
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02003284string CompilerGLSL::dereference_expression(const SPIRType &expr_type, const std::string &expr)
Chip Davis3bfb2f92018-12-03 02:06:33 -06003285{
3286 // If this expression starts with an address-of operator ('&'), then
3287 // just return the part after the operator.
3288 // TODO: Strip parens if unnecessary?
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01003289 if (expr.front() == '&')
Chip Davis3bfb2f92018-12-03 02:06:33 -06003290 return expr.substr(1);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003291 else if (backend.native_pointers)
Chip Davis3bfb2f92018-12-03 02:06:33 -06003292 return join('*', expr);
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02003293 else if (expr_type.storage == StorageClassPhysicalStorageBufferEXT && expr_type.basetype != SPIRType::Struct &&
3294 expr_type.pointer_depth == 1)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003295 {
3296 return join(enclose_expression(expr), ".value");
3297 }
3298 else
3299 return expr;
Chip Davis3bfb2f92018-12-03 02:06:33 -06003300}
3301
3302string CompilerGLSL::address_of_expression(const std::string &expr)
3303{
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02003304 if (expr.size() > 3 && expr[0] == '(' && expr[1] == '*' && expr.back() == ')')
3305 {
3306 // If we have an expression which looks like (*foo), taking the address of it is the same as stripping
3307 // the first two and last characters. We might have to enclose the expression.
3308 // This doesn't work for cases like (*foo + 10),
3309 // but this is an r-value expression which we cannot take the address of anyways.
3310 return enclose_expression(expr.substr(2, expr.size() - 3));
3311 }
3312 else if (expr.front() == '*')
3313 {
3314 // If this expression starts with a dereference operator ('*'), then
3315 // just return the part after the operator.
Chip Davis3bfb2f92018-12-03 02:06:33 -06003316 return expr.substr(1);
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02003317 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06003318 else
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02003319 return join('&', enclose_expression(expr));
Chip Davis3bfb2f92018-12-03 02:06:33 -06003320}
3321
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02003322// Just like to_expression except that we enclose the expression inside parentheses if needed.
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01003323string CompilerGLSL::to_enclosed_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02003324{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01003325 return enclose_expression(to_expression(id, register_expression_read));
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02003326}
3327
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02003328// Used explicitly when we want to read a row-major expression, but without any transpose shenanigans.
3329// need_transpose must be forced to false.
3330string CompilerGLSL::to_unpacked_row_major_matrix_expression(uint32_t id)
3331{
3332 return unpack_expression_type(to_expression(id), expression_type(id),
3333 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
3334 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), true);
3335}
3336
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003337string CompilerGLSL::to_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003338{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02003339 // If we need to transpose, it will also take care of unpacking rules.
3340 auto *e = maybe_get<SPIRExpression>(id);
3341 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02003342 bool is_remapped = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
3343 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02003344
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02003345 if (!need_transpose && (is_remapped || is_packed))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003346 {
Hans-Kristian Arntzen1ece67a2019-07-23 17:06:37 +02003347 return unpack_expression_type(to_expression(id, register_expression_read),
3348 get_pointee_type(expression_type_id(id)),
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003349 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02003350 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), false);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003351 }
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003352 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003353 return to_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003354}
3355
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003356string CompilerGLSL::to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003357{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02003358 // If we need to transpose, it will also take care of unpacking rules.
3359 auto *e = maybe_get<SPIRExpression>(id);
3360 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02003361 bool is_remapped = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
3362 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
3363 if (!need_transpose && (is_remapped || is_packed))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003364 {
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01003365 return unpack_expression_type(to_expression(id, register_expression_read), expression_type(id),
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003366 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02003367 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), false);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003368 }
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003369 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003370 return to_enclosed_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003371}
3372
Chip Davis3bfb2f92018-12-03 02:06:33 -06003373string CompilerGLSL::to_dereferenced_expression(uint32_t id, bool register_expression_read)
3374{
3375 auto &type = expression_type(id);
3376 if (type.pointer && should_dereference(id))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003377 return dereference_expression(type, to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06003378 else
3379 return to_expression(id, register_expression_read);
3380}
3381
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003382string CompilerGLSL::to_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06003383{
3384 auto &type = expression_type(id);
3385 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003386 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06003387 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003388 return to_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06003389}
3390
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003391string CompilerGLSL::to_enclosed_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06003392{
3393 auto &type = expression_type(id);
3394 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01003395 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06003396 else
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01003397 return to_enclosed_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06003398}
3399
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02003400string CompilerGLSL::to_extract_component_expression(uint32_t id, uint32_t index)
3401{
3402 auto expr = to_enclosed_expression(id);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003403 if (has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02003404 return join(expr, "[", index, "]");
3405 else
3406 return join(expr, ".", index_to_swizzle(index));
3407}
3408
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02003409string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
3410{
3411 uint32_t size = to_array_size_literal(type);
3412 auto &parent = get<SPIRType>(type.parent_type);
3413 string expr = "{ ";
3414
3415 for (uint32_t i = 0; i < size; i++)
3416 {
3417 auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
3418 if (parent.array.empty())
3419 expr += subexpr;
3420 else
3421 expr += to_rerolled_array_expression(subexpr, parent);
3422
3423 if (i + 1 < size)
3424 expr += ", ";
3425 }
3426
3427 expr += " }";
3428 return expr;
3429}
3430
3431string CompilerGLSL::to_composite_constructor_expression(uint32_t id)
3432{
3433 auto &type = expression_type(id);
3434 if (!backend.array_is_value_type && !type.array.empty())
3435 {
3436 // For this case, we need to "re-roll" an array initializer from a temporary.
3437 // We cannot simply pass the array directly, since it decays to a pointer and it cannot
3438 // participate in a struct initializer. E.g.
3439 // float arr[2] = { 1.0, 2.0 };
3440 // Foo foo = { arr }; must be transformed to
3441 // Foo foo = { { arr[0], arr[1] } };
3442 // The array sizes cannot be deduced from specialization constants since we cannot use any loops.
3443
3444 // We're only triggering one read of the array expression, but this is fine since arrays have to be declared
3445 // as temporaries anyways.
3446 return to_rerolled_array_expression(to_enclosed_expression(id), type);
3447 }
3448 else
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02003449 return to_unpacked_expression(id);
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02003450}
3451
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01003452string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003453{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003454 auto itr = invalid_expressions.find(id);
3455 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003456 handle_invalid_expression(id);
3457
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003458 if (ir.ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003459 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003460 // We might have a more complex chain of dependencies.
3461 // A possible scenario is that we
3462 //
3463 // %1 = OpLoad
3464 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
3465 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
3466 // OpStore %1 %foo // Here we can invalidate %1, and hence all expressions which depend on %1. Only %2 will know since it's part of invalid_expressions.
3467 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
3468 //
3469 // However, we can propagate up a list of depended expressions when we used %2, so we can check if %2 is invalid when reading %3 after the store,
3470 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003471 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003472 for (uint32_t dep : expr.expression_dependencies)
3473 if (invalid_expressions.find(dep) != end(invalid_expressions))
3474 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003475 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003476
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01003477 if (register_expression_read)
3478 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003479
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003480 switch (ir.ids[id].get_type())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003481 {
3482 case TypeExpression:
3483 {
3484 auto &e = get<SPIRExpression>(id);
3485 if (e.base_expression)
Hans-Kristian Arntzenea781e62016-12-06 17:19:34 +01003486 return to_enclosed_expression(e.base_expression) + e.expression;
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02003487 else if (e.need_transpose)
Bill Hollings607b0d62018-02-11 16:52:57 -05003488 {
Hans-Kristian Arntzen2172b192019-07-22 16:27:47 +02003489 // This should not be reached for access chains, since we always deal explicitly with transpose state
3490 // when consuming an access chain expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003491 uint32_t physical_type_id = get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
3492 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02003493 return convert_row_major_matrix(e.expression, get<SPIRType>(e.expression_type), physical_type_id,
3494 is_packed);
Bill Hollings607b0d62018-02-11 16:52:57 -05003495 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003496 else
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01003497 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003498 if (is_forcing_recompilation())
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01003499 {
3500 // During first compilation phase, certain expression patterns can trigger exponential growth of memory.
3501 // Avoid this by returning dummy expressions during this phase.
3502 // Do not use empty expressions here, because those are sentinels for other cases.
3503 return "_";
3504 }
3505 else
3506 return e.expression;
3507 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003508 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003509
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003510 case TypeConstant:
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02003511 {
3512 auto &c = get<SPIRConstant>(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01003513 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02003514
3515 // WorkGroupSize may be a constant.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003516 auto &dec = ir.meta[c.self].decoration;
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02003517 if (dec.builtin)
3518 return builtin_to_glsl(dec.builtin_type, StorageClassGeneric);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003519 else if (c.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02003520 return to_name(id);
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02003521 else if (c.is_used_as_lut)
3522 return to_name(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01003523 else if (type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
3524 return to_name(id);
3525 else if (!type.array.empty() && !backend.can_declare_arrays_inline)
3526 return to_name(id);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02003527 else
3528 return constant_expression(c);
3529 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003530
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003531 case TypeConstantOp:
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01003532 return to_name(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003534 case TypeVariable:
3535 {
3536 auto &var = get<SPIRVariable>(id);
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01003537 // If we try to use a loop variable before the loop header, we have to redirect it to the static expression,
3538 // the variable has not been declared yet.
3539 if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003540 return to_expression(var.static_expression);
3541 else if (var.deferred_declaration)
3542 {
3543 var.deferred_declaration = false;
3544 return variable_decl(var);
3545 }
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01003546 else if (flattened_structs.count(id))
3547 {
3548 return load_flattened_struct(var);
3549 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003550 else
3551 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003552 auto &dec = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003553 if (dec.builtin)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02003554 return builtin_to_glsl(dec.builtin_type, var.storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003555 else
3556 return to_name(id);
3557 }
3558 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003559
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003560 case TypeCombinedImageSampler:
3561 // This type should never be taken the expression of directly.
3562 // The intention is that texture sampling functions will extract the image and samplers
3563 // separately and take their expressions as needed.
3564 // GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
3565 // expression ala sampler2D(texture, sampler).
3566 SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
3567
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02003568 case TypeAccessChain:
3569 // We cannot express this type. They only have meaning in other OpAccessChains, OpStore or OpLoad.
3570 SPIRV_CROSS_THROW("Access chains have no default expression representation.");
3571
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003572 default:
3573 return to_name(id);
3574 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003575}
3576
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003577string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
3578{
3579 auto &type = get<SPIRType>(cop.basetype);
3580 bool binary = false;
3581 bool unary = false;
3582 string op;
3583
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02003584 if (is_legacy() && is_unsigned_opcode(cop.opcode))
3585 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
3586
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003587 // TODO: Find a clean way to reuse emit_instruction.
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003588 switch (cop.opcode)
3589 {
3590 case OpSConvert:
3591 case OpUConvert:
3592 case OpFConvert:
3593 op = type_to_glsl_constructor(type);
3594 break;
3595
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02003596#define GLSL_BOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02003597 case Op##opname: \
3598 binary = true; \
3599 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003600 break
3601
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02003602#define GLSL_UOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02003603 case Op##opname: \
3604 unary = true; \
3605 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003606 break
3607
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02003608 GLSL_UOP(SNegate, "-");
3609 GLSL_UOP(Not, "~");
3610 GLSL_BOP(IAdd, "+");
3611 GLSL_BOP(ISub, "-");
3612 GLSL_BOP(IMul, "*");
3613 GLSL_BOP(SDiv, "/");
3614 GLSL_BOP(UDiv, "/");
3615 GLSL_BOP(UMod, "%");
3616 GLSL_BOP(SMod, "%");
3617 GLSL_BOP(ShiftRightLogical, ">>");
3618 GLSL_BOP(ShiftRightArithmetic, ">>");
3619 GLSL_BOP(ShiftLeftLogical, "<<");
3620 GLSL_BOP(BitwiseOr, "|");
3621 GLSL_BOP(BitwiseXor, "^");
3622 GLSL_BOP(BitwiseAnd, "&");
3623 GLSL_BOP(LogicalOr, "||");
3624 GLSL_BOP(LogicalAnd, "&&");
3625 GLSL_UOP(LogicalNot, "!");
3626 GLSL_BOP(LogicalEqual, "==");
3627 GLSL_BOP(LogicalNotEqual, "!=");
3628 GLSL_BOP(IEqual, "==");
3629 GLSL_BOP(INotEqual, "!=");
3630 GLSL_BOP(ULessThan, "<");
3631 GLSL_BOP(SLessThan, "<");
3632 GLSL_BOP(ULessThanEqual, "<=");
3633 GLSL_BOP(SLessThanEqual, "<=");
3634 GLSL_BOP(UGreaterThan, ">");
3635 GLSL_BOP(SGreaterThan, ">");
3636 GLSL_BOP(UGreaterThanEqual, ">=");
3637 GLSL_BOP(SGreaterThanEqual, ">=");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003638
3639 case OpSelect:
3640 {
3641 if (cop.arguments.size() < 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003642 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003643
3644 // This one is pretty annoying. It's triggered from
3645 // uint(bool), int(bool) from spec constants.
3646 // In order to preserve its compile-time constness in Vulkan GLSL,
3647 // we need to reduce the OpSelect expression back to this simplified model.
3648 // If we cannot, fail.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02003649 if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003650 {
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02003651 // Implement as a simple cast down below.
3652 }
3653 else
3654 {
3655 // Implement a ternary and pray the compiler understands it :)
3656 return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003657 }
3658 break;
3659 }
3660
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02003661 case OpVectorShuffle:
3662 {
3663 string expr = type_to_glsl_constructor(type);
3664 expr += "(";
3665
3666 uint32_t left_components = expression_type(cop.arguments[0]).vecsize;
3667 string left_arg = to_enclosed_expression(cop.arguments[0]);
3668 string right_arg = to_enclosed_expression(cop.arguments[1]);
3669
3670 for (uint32_t i = 2; i < uint32_t(cop.arguments.size()); i++)
3671 {
3672 uint32_t index = cop.arguments[i];
3673 if (index >= left_components)
3674 expr += right_arg + "." + "xyzw"[index - left_components];
3675 else
3676 expr += left_arg + "." + "xyzw"[index];
3677
3678 if (i + 1 < uint32_t(cop.arguments.size()))
3679 expr += ", ";
3680 }
3681
3682 expr += ")";
3683 return expr;
3684 }
3685
3686 case OpCompositeExtract:
3687 {
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01003688 auto expr = access_chain_internal(cop.arguments[0], &cop.arguments[1], uint32_t(cop.arguments.size() - 1),
3689 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02003690 return expr;
3691 }
3692
3693 case OpCompositeInsert:
3694 SPIRV_CROSS_THROW("OpCompositeInsert spec constant op is not supported.");
3695
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003696 default:
3697 // Some opcodes are unimplemented here, these are currently not possible to test from glslang.
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003698 SPIRV_CROSS_THROW("Unimplemented spec constant op.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003699 }
3700
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003701 uint32_t bit_width = 0;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02003702 if (unary || binary || cop.opcode == OpSConvert || cop.opcode == OpUConvert)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003703 bit_width = expression_type(cop.arguments[0]).width;
3704
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003705 SPIRType::BaseType input_type;
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003706 bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003707
3708 switch (cop.opcode)
3709 {
3710 case OpIEqual:
3711 case OpINotEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003712 input_type = to_signed_basetype(bit_width);
3713 break;
3714
3715 case OpSLessThan:
3716 case OpSLessThanEqual:
3717 case OpSGreaterThan:
3718 case OpSGreaterThanEqual:
3719 case OpSMod:
3720 case OpSDiv:
3721 case OpShiftRightArithmetic:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02003722 case OpSConvert:
3723 case OpSNegate:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003724 input_type = to_signed_basetype(bit_width);
3725 break;
3726
3727 case OpULessThan:
3728 case OpULessThanEqual:
3729 case OpUGreaterThan:
3730 case OpUGreaterThanEqual:
3731 case OpUMod:
3732 case OpUDiv:
3733 case OpShiftRightLogical:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02003734 case OpUConvert:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003735 input_type = to_unsigned_basetype(bit_width);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003736 break;
3737
3738 default:
3739 input_type = type.basetype;
3740 break;
3741 }
3742
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02003743#undef GLSL_BOP
3744#undef GLSL_UOP
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003745 if (binary)
3746 {
3747 if (cop.arguments.size() < 2)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003748 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003749
3750 string cast_op0;
3751 string cast_op1;
3752 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, cop.arguments[0],
3753 cop.arguments[1], skip_cast_if_equal_type);
3754
3755 if (type.basetype != input_type && type.basetype != SPIRType::Boolean)
3756 {
3757 expected_type.basetype = input_type;
3758 auto expr = bitcast_glsl_op(type, expected_type);
3759 expr += '(';
3760 expr += join(cast_op0, " ", op, " ", cast_op1);
3761 expr += ')';
3762 return expr;
3763 }
3764 else
3765 return join("(", cast_op0, " ", op, " ", cast_op1, ")");
3766 }
3767 else if (unary)
3768 {
3769 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003770 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003771
3772 // Auto-bitcast to result type as needed.
3773 // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
3774 return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")");
3775 }
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02003776 else if (cop.opcode == OpSConvert || cop.opcode == OpUConvert)
3777 {
3778 if (cop.arguments.size() < 1)
3779 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
3780
3781 auto &arg_type = expression_type(cop.arguments[0]);
3782 if (arg_type.width < type.width && input_type != arg_type.basetype)
3783 {
3784 auto expected = arg_type;
3785 expected.basetype = input_type;
3786 return join(op, "(", bitcast_glsl(expected, cop.arguments[0]), ")");
3787 }
3788 else
3789 return join(op, "(", to_expression(cop.arguments[0]), ")");
3790 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003791 else
3792 {
3793 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003794 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003795 return join(op, "(", to_expression(cop.arguments[0]), ")");
3796 }
3797}
3798
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003799string CompilerGLSL::constant_expression(const SPIRConstant &c)
3800{
Chip Davis3bfb2f92018-12-03 02:06:33 -06003801 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02003802
Chip Davis3bfb2f92018-12-03 02:06:33 -06003803 if (type.pointer)
3804 {
3805 return backend.null_pointer_literal;
3806 }
3807 else if (!c.subconstants.empty())
3808 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003809 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003810 string res;
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04003811
Lukas Hermanns50ac6862019-09-18 14:03:54 -04003812 // Allow Metal to use the array<T> template to make arrays a value type
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04003813 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen57a15df2018-09-10 10:08:02 +02003814 if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02003815 type.array.empty())
3816 {
3817 res = type_to_glsl_constructor(type) + "{ ";
3818 }
Hans-Kristian Arntzenc2655ab2020-03-19 14:21:42 +01003819 else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
3820 !type.array.empty())
Mark Satterthwaited50659a2019-08-13 18:18:48 -04003821 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02003822 res = type_to_glsl_constructor(type) + "({ ";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04003823 needs_trailing_tracket = true;
Mark Satterthwaited50659a2019-08-13 18:18:48 -04003824 }
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02003825 else if (backend.use_initializer_list)
3826 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003827 res = "{ ";
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02003828 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003829 else
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02003830 {
3831 res = type_to_glsl_constructor(type) + "(";
3832 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003833
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003834 for (auto &elem : c.subconstants)
3835 {
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02003836 auto &subc = get<SPIRConstant>(elem);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003837 if (subc.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02003838 res += to_name(elem);
3839 else
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02003840 res += constant_expression(subc);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02003841
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003842 if (&elem != &c.subconstants.back())
3843 res += ", ";
3844 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003845
3846 res += backend.use_initializer_list ? " }" : ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04003847 if (needs_trailing_tracket)
Mark Satterthwaited50659a2019-08-13 18:18:48 -04003848 res += ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04003849
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003850 return res;
3851 }
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04003852 else if (type.basetype == SPIRType::Struct && type.member_types.size() == 0)
3853 {
3854 // Metal tessellation likes empty structs which are then constant expressions.
Hans-Kristian Arntzen3b5c4c72019-10-24 17:05:55 +02003855 if (backend.supports_empty_struct)
3856 return "{ }";
3857 else if (backend.use_typed_initializer_list)
3858 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "{ 0 }");
3859 else if (backend.use_initializer_list)
3860 return "{ 0 }";
3861 else
3862 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "(0)");
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04003863 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003864 else if (c.columns() == 1)
3865 {
3866 return constant_expression_vector(c, 0);
3867 }
3868 else
3869 {
3870 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
3871 for (uint32_t col = 0; col < c.columns(); col++)
3872 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003873 if (c.specialization_constant_id(col) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003874 res += to_name(c.specialization_constant_id(col));
3875 else
3876 res += constant_expression_vector(c, col);
3877
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003878 if (col + 1 < c.columns())
3879 res += ", ";
3880 }
3881 res += ")";
3882 return res;
3883 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003884}
3885
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003886#ifdef _MSC_VER
3887// sprintf warning.
3888// We cannot rely on snprintf existing because, ..., MSVC.
3889#pragma warning(push)
3890#pragma warning(disable : 4996)
3891#endif
3892
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003893string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
3894{
3895 string res;
3896 float float_value = c.scalar_f16(col, row);
3897
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003898 // There is no literal "hf" in GL_NV_gpu_shader5, so to avoid lots
3899 // of complicated workarounds, just value-cast to the half type always.
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003900 if (std::isnan(float_value) || std::isinf(float_value))
3901 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003902 SPIRType type;
3903 type.basetype = SPIRType::Half;
3904 type.vecsize = 1;
3905 type.columns = 1;
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003906
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003907 if (float_value == numeric_limits<float>::infinity())
3908 res = join(type_to_glsl(type), "(1.0 / 0.0)");
3909 else if (float_value == -numeric_limits<float>::infinity())
3910 res = join(type_to_glsl(type), "(-1.0 / 0.0)");
3911 else if (std::isnan(float_value))
3912 res = join(type_to_glsl(type), "(0.0 / 0.0)");
3913 else
3914 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003915 }
3916 else
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003917 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003918 SPIRType type;
3919 type.basetype = SPIRType::Half;
3920 type.vecsize = 1;
3921 type.columns = 1;
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01003922 res = join(type_to_glsl(type), "(", convert_to_string(float_value, current_locale_radix_character), ")");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003923 }
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003924
3925 return res;
3926}
3927
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003928string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
3929{
3930 string res;
3931 float float_value = c.scalar_f32(col, row);
3932
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003933 if (std::isnan(float_value) || std::isinf(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003934 {
3935 // Use special representation.
3936 if (!is_legacy())
3937 {
3938 SPIRType out_type;
3939 SPIRType in_type;
3940 out_type.basetype = SPIRType::Float;
3941 in_type.basetype = SPIRType::UInt;
3942 out_type.vecsize = 1;
3943 in_type.vecsize = 1;
3944 out_type.width = 32;
3945 in_type.width = 32;
3946
3947 char print_buffer[32];
3948 sprintf(print_buffer, "0x%xu", c.scalar(col, row));
3949 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
3950 }
3951 else
3952 {
3953 if (float_value == numeric_limits<float>::infinity())
3954 {
3955 if (backend.float_literal_suffix)
3956 res = "(1.0f / 0.0f)";
3957 else
3958 res = "(1.0 / 0.0)";
3959 }
3960 else if (float_value == -numeric_limits<float>::infinity())
3961 {
3962 if (backend.float_literal_suffix)
3963 res = "(-1.0f / 0.0f)";
3964 else
3965 res = "(-1.0 / 0.0)";
3966 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003967 else if (std::isnan(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003968 {
3969 if (backend.float_literal_suffix)
3970 res = "(0.0f / 0.0f)";
3971 else
3972 res = "(0.0 / 0.0)";
3973 }
3974 else
3975 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
3976 }
3977 }
3978 else
3979 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01003980 res = convert_to_string(float_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003981 if (backend.float_literal_suffix)
3982 res += "f";
3983 }
3984
3985 return res;
3986}
3987
3988std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
3989{
3990 string res;
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003991 double double_value = c.scalar_f64(col, row);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003992
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003993 if (std::isnan(double_value) || std::isinf(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003994 {
3995 // Use special representation.
3996 if (!is_legacy())
3997 {
3998 SPIRType out_type;
3999 SPIRType in_type;
4000 out_type.basetype = SPIRType::Double;
4001 in_type.basetype = SPIRType::UInt64;
4002 out_type.vecsize = 1;
4003 in_type.vecsize = 1;
4004 out_type.width = 64;
4005 in_type.width = 64;
4006
4007 uint64_t u64_value = c.scalar_u64(col, row);
4008
4009 if (options.es)
4010 SPIRV_CROSS_THROW("64-bit integers/float not supported in ES profile.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02004011 require_extension_internal("GL_ARB_gpu_shader_int64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004012
4013 char print_buffer[64];
4014 sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
4015 backend.long_long_literal_suffix ? "ull" : "ul");
4016 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
4017 }
4018 else
4019 {
4020 if (options.es)
4021 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
4022 if (options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02004023 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004024
4025 if (double_value == numeric_limits<double>::infinity())
4026 {
4027 if (backend.double_literal_suffix)
4028 res = "(1.0lf / 0.0lf)";
4029 else
4030 res = "(1.0 / 0.0)";
4031 }
4032 else if (double_value == -numeric_limits<double>::infinity())
4033 {
4034 if (backend.double_literal_suffix)
4035 res = "(-1.0lf / 0.0lf)";
4036 else
4037 res = "(-1.0 / 0.0)";
4038 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01004039 else if (std::isnan(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004040 {
4041 if (backend.double_literal_suffix)
4042 res = "(0.0lf / 0.0lf)";
4043 else
4044 res = "(0.0 / 0.0)";
4045 }
4046 else
4047 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
4048 }
4049 }
4050 else
4051 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01004052 res = convert_to_string(double_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004053 if (backend.double_literal_suffix)
4054 res += "lf";
4055 }
4056
4057 return res;
4058}
4059
4060#ifdef _MSC_VER
4061#pragma warning(pop)
4062#endif
4063
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004064string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
4065{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004066 auto type = get<SPIRType>(c.constant_type);
4067 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004068
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004069 auto scalar_type = type;
4070 scalar_type.vecsize = 1;
4071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004072 string res;
Robert Konradea24ee82016-09-23 18:57:18 +02004073 bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004074 bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004075
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004076 if (!type_is_floating_point(type))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004077 {
4078 // Cannot swizzle literal integers as a special case.
4079 swizzle_splat = false;
4080 }
4081
4082 if (splat || swizzle_splat)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004083 {
4084 // Cannot use constant splatting if we have specialization constants somewhere in the vector.
4085 for (uint32_t i = 0; i < c.vector_size(); i++)
4086 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004087 if (c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004088 {
4089 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004090 swizzle_splat = false;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004091 break;
4092 }
4093 }
4094 }
4095
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004096 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004097 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02004098 if (type.width == 64)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004099 {
4100 uint64_t ident = c.scalar_u64(vector, 0);
4101 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004102 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004103 if (ident != c.scalar_u64(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004104 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004105 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004106 swizzle_splat = false;
4107 break;
4108 }
4109 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004110 }
4111 else
4112 {
4113 uint32_t ident = c.scalar(vector, 0);
4114 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004115 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004116 if (ident != c.scalar(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004117 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004118 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004119 swizzle_splat = false;
4120 }
4121 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004122 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004123 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004124
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004125 if (c.vector_size() > 1 && !swizzle_splat)
4126 res += type_to_glsl(type) + "(";
4127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004128 switch (type.basetype)
4129 {
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004130 case SPIRType::Half:
4131 if (splat || swizzle_splat)
4132 {
4133 res += convert_half_to_string(c, vector, 0);
4134 if (swizzle_splat)
4135 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
4136 }
4137 else
4138 {
4139 for (uint32_t i = 0; i < c.vector_size(); i++)
4140 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004141 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004142 res += to_name(c.specialization_constant_id(vector, i));
4143 else
4144 res += convert_half_to_string(c, vector, i);
4145
4146 if (i + 1 < c.vector_size())
4147 res += ", ";
4148 }
4149 }
4150 break;
4151
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004152 case SPIRType::Float:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004153 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004154 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004155 res += convert_float_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004156 if (swizzle_splat)
4157 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004158 }
4159 else
4160 {
4161 for (uint32_t i = 0; i < c.vector_size(); i++)
4162 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004163 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004164 res += to_name(c.specialization_constant_id(vector, i));
4165 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004166 res += convert_float_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004167
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004168 if (i + 1 < c.vector_size())
4169 res += ", ";
4170 }
4171 }
4172 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004173
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004174 case SPIRType::Double:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004175 if (splat || swizzle_splat)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004176 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004177 res += convert_double_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004178 if (swizzle_splat)
4179 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004180 }
4181 else
4182 {
4183 for (uint32_t i = 0; i < c.vector_size(); i++)
4184 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004185 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004186 res += to_name(c.specialization_constant_id(vector, i));
4187 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004188 res += convert_double_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004189
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004190 if (i + 1 < c.vector_size())
4191 res += ", ";
4192 }
4193 }
4194 break;
4195
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004196 case SPIRType::Int64:
4197 if (splat)
4198 {
4199 res += convert_to_string(c.scalar_i64(vector, 0));
4200 if (backend.long_long_literal_suffix)
4201 res += "ll";
4202 else
4203 res += "l";
4204 }
4205 else
4206 {
4207 for (uint32_t i = 0; i < c.vector_size(); i++)
4208 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004209 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004210 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004211 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004212 {
4213 res += convert_to_string(c.scalar_i64(vector, i));
4214 if (backend.long_long_literal_suffix)
4215 res += "ll";
4216 else
4217 res += "l";
4218 }
4219
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004220 if (i + 1 < c.vector_size())
4221 res += ", ";
4222 }
4223 }
4224 break;
4225
4226 case SPIRType::UInt64:
4227 if (splat)
4228 {
4229 res += convert_to_string(c.scalar_u64(vector, 0));
4230 if (backend.long_long_literal_suffix)
4231 res += "ull";
4232 else
4233 res += "ul";
4234 }
4235 else
4236 {
4237 for (uint32_t i = 0; i < c.vector_size(); i++)
4238 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004239 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004240 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004241 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004242 {
4243 res += convert_to_string(c.scalar_u64(vector, i));
4244 if (backend.long_long_literal_suffix)
4245 res += "ull";
4246 else
4247 res += "ul";
4248 }
4249
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004250 if (i + 1 < c.vector_size())
4251 res += ", ";
4252 }
4253 }
4254 break;
4255
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004256 case SPIRType::UInt:
4257 if (splat)
4258 {
4259 res += convert_to_string(c.scalar(vector, 0));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004260 if (is_legacy())
4261 {
4262 // Fake unsigned constant literals with signed ones if possible.
4263 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
4264 if (c.scalar_i32(vector, 0) < 0)
4265 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative.");
4266 }
4267 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004268 res += "u";
4269 }
4270 else
4271 {
4272 for (uint32_t i = 0; i < c.vector_size(); i++)
4273 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004274 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004275 res += to_name(c.specialization_constant_id(vector, i));
4276 else
4277 {
4278 res += convert_to_string(c.scalar(vector, i));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004279 if (is_legacy())
4280 {
4281 // Fake unsigned constant literals with signed ones if possible.
4282 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
4283 if (c.scalar_i32(vector, i) < 0)
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02004284 SPIRV_CROSS_THROW(
4285 "Tried to convert uint literal into int, but this made the literal negative.");
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004286 }
4287 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004288 res += "u";
4289 }
4290
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004291 if (i + 1 < c.vector_size())
4292 res += ", ";
4293 }
4294 }
4295 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004297 case SPIRType::Int:
4298 if (splat)
4299 res += convert_to_string(c.scalar_i32(vector, 0));
4300 else
4301 {
4302 for (uint32_t i = 0; i < c.vector_size(); i++)
4303 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004304 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004305 res += to_name(c.specialization_constant_id(vector, i));
4306 else
4307 res += convert_to_string(c.scalar_i32(vector, i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004308 if (i + 1 < c.vector_size())
4309 res += ", ";
4310 }
4311 }
4312 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004313
Chip Davisca4744a2018-11-02 14:39:55 -05004314 case SPIRType::UShort:
4315 if (splat)
4316 {
4317 res += convert_to_string(c.scalar(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05004318 }
4319 else
4320 {
4321 for (uint32_t i = 0; i < c.vector_size(); i++)
4322 {
4323 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
4324 res += to_name(c.specialization_constant_id(vector, i));
4325 else
4326 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02004327 if (*backend.uint16_t_literal_suffix)
Chip Davisca4744a2018-11-02 14:39:55 -05004328 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02004329 res += convert_to_string(c.scalar_u16(vector, i));
4330 res += backend.uint16_t_literal_suffix;
Chip Davisca4744a2018-11-02 14:39:55 -05004331 }
Bill Hollingsc48702d2019-03-28 14:23:32 -04004332 else
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02004333 {
4334 // If backend doesn't have a literal suffix, we need to value cast.
4335 res += type_to_glsl(scalar_type);
4336 res += "(";
4337 res += convert_to_string(c.scalar_u16(vector, i));
4338 res += ")";
4339 }
Chip Davisca4744a2018-11-02 14:39:55 -05004340 }
4341
4342 if (i + 1 < c.vector_size())
4343 res += ", ";
4344 }
4345 }
4346 break;
4347
4348 case SPIRType::Short:
4349 if (splat)
4350 {
4351 res += convert_to_string(c.scalar_i16(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05004352 }
4353 else
4354 {
4355 for (uint32_t i = 0; i < c.vector_size(); i++)
4356 {
4357 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
4358 res += to_name(c.specialization_constant_id(vector, i));
4359 else
4360 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02004361 if (*backend.int16_t_literal_suffix)
4362 {
4363 res += convert_to_string(c.scalar_i16(vector, i));
4364 res += backend.int16_t_literal_suffix;
4365 }
4366 else
4367 {
4368 // If backend doesn't have a literal suffix, we need to value cast.
4369 res += type_to_glsl(scalar_type);
4370 res += "(";
4371 res += convert_to_string(c.scalar_i16(vector, i));
4372 res += ")";
4373 }
Chip Davisca4744a2018-11-02 14:39:55 -05004374 }
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02004375
Chip Davisca4744a2018-11-02 14:39:55 -05004376 if (i + 1 < c.vector_size())
4377 res += ", ";
4378 }
4379 }
4380 break;
4381
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004382 case SPIRType::UByte:
4383 if (splat)
4384 {
4385 res += convert_to_string(c.scalar_u8(vector, 0));
4386 }
4387 else
4388 {
4389 for (uint32_t i = 0; i < c.vector_size(); i++)
4390 {
4391 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
4392 res += to_name(c.specialization_constant_id(vector, i));
4393 else
4394 {
4395 res += type_to_glsl(scalar_type);
4396 res += "(";
4397 res += convert_to_string(c.scalar_u8(vector, i));
4398 res += ")";
4399 }
4400
4401 if (i + 1 < c.vector_size())
4402 res += ", ";
4403 }
4404 }
4405 break;
4406
4407 case SPIRType::SByte:
4408 if (splat)
4409 {
4410 res += convert_to_string(c.scalar_i8(vector, 0));
4411 }
4412 else
4413 {
4414 for (uint32_t i = 0; i < c.vector_size(); i++)
4415 {
4416 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
4417 res += to_name(c.specialization_constant_id(vector, i));
4418 else
4419 {
4420 res += type_to_glsl(scalar_type);
4421 res += "(";
4422 res += convert_to_string(c.scalar_i8(vector, i));
4423 res += ")";
4424 }
4425
4426 if (i + 1 < c.vector_size())
4427 res += ", ";
4428 }
4429 }
4430 break;
4431
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004432 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004433 if (splat)
4434 res += c.scalar(vector, 0) ? "true" : "false";
4435 else
4436 {
4437 for (uint32_t i = 0; i < c.vector_size(); i++)
4438 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004439 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004440 res += to_name(c.specialization_constant_id(vector, i));
4441 else
4442 res += c.scalar(vector, i) ? "true" : "false";
4443
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004444 if (i + 1 < c.vector_size())
4445 res += ", ";
4446 }
4447 }
4448 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004449
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004450 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004451 SPIRV_CROSS_THROW("Invalid constant expression basetype.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004452 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004453
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004454 if (c.vector_size() > 1 && !swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004455 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004457 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004458}
4459
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02004460SPIRExpression &CompilerGLSL::emit_uninitialized_temporary_expression(uint32_t type, uint32_t id)
4461{
4462 forced_temporaries.insert(id);
4463 emit_uninitialized_temporary(type, id);
4464 return set<SPIRExpression>(id, to_name(id), type, true);
4465}
4466
4467void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t result_id)
4468{
4469 // If we're declaring temporaries inside continue blocks,
4470 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
4471 if (current_continue_block && !hoisted_temporaries.count(result_id))
4472 {
4473 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
4474 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
4475 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
4476 return tmp.first == result_type && tmp.second == result_id;
4477 }) == end(header.declare_temporary))
4478 {
4479 header.declare_temporary.emplace_back(result_type, result_id);
4480 hoisted_temporaries.insert(result_id);
4481 force_recompile();
4482 }
4483 }
4484 else if (hoisted_temporaries.count(result_id) == 0)
4485 {
4486 auto &type = get<SPIRType>(result_type);
4487 auto &flags = ir.meta[result_id].decoration.decoration_flags;
4488
4489 // The result_id has not been made into an expression yet, so use flags interface.
4490 add_local_variable_name(result_id);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01004491
4492 string initializer;
4493 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
4494 initializer = join(" = ", to_zero_initialized_expression(result_type));
4495
4496 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), initializer, ";");
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02004497 }
4498}
4499
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004500string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
4501{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004502 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01004503 auto &flags = ir.meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004504
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004505 // If we're declaring temporaries inside continue blocks,
4506 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
Hans-Kristian Arntzen0fd02812017-11-21 18:19:51 +01004507 if (current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004508 {
4509 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
4510 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02004511 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004512 return tmp.first == result_type && tmp.second == result_id;
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01004513 }) == end(header.declare_temporary))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004514 {
4515 header.declare_temporary.emplace_back(result_type, result_id);
Hans-Kristian Arntzen7d223b82018-01-18 12:07:10 +01004516 hoisted_temporaries.insert(result_id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02004517 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004518 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004519
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004520 return join(to_name(result_id), " = ");
4521 }
Hans-Kristian Arntzenb629ca12017-11-21 09:27:49 +01004522 else if (hoisted_temporaries.count(result_id))
4523 {
4524 // The temporary has already been declared earlier, so just "declare" the temporary by writing to it.
4525 return join(to_name(result_id), " = ");
4526 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004527 else
4528 {
4529 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen35f64d02018-03-24 01:53:08 +01004530 add_local_variable_name(result_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004531 return join(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004532 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004533}
4534
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02004535bool CompilerGLSL::expression_is_forwarded(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004536{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02004537 return forwarded_temporaries.count(id) != 0;
4538}
4539
4540bool CompilerGLSL::expression_suppresses_usage_tracking(uint32_t id) const
4541{
4542 return suppressed_usage_tracking.count(id) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004543}
4544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004545SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004546 bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004547{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004548 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
4549 {
4550 // Just forward it without temporary.
4551 // If the forward is trivial, we do not force flushing to temporary for this expression.
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02004552 forwarded_temporaries.insert(result_id);
4553 if (suppress_usage_tracking)
4554 suppressed_usage_tracking.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004555
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004556 return set<SPIRExpression>(result_id, rhs, result_type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004557 }
4558 else
4559 {
4560 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
4561 statement(declare_temporary(result_type, result_id), rhs, ";");
4562 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
4563 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004564}
4565
4566void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
4567{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004568 bool forward = should_forward(op0);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02004569 emit_op(result_type, result_id, join(op, to_enclosed_unpacked_expression(op0)), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004570 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004571}
4572
4573void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
4574{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004575 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02004576 emit_op(result_type, result_id,
4577 join(to_enclosed_unpacked_expression(op0), " ", op, " ", to_enclosed_unpacked_expression(op1)), forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004578
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004579 inherit_expression_dependencies(result_id, op0);
4580 inherit_expression_dependencies(result_id, op1);
4581}
4582
Robert Konradf3a82772017-03-24 15:00:48 +01004583void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
4584{
4585 auto &type = get<SPIRType>(result_type);
4586 auto expr = type_to_glsl_constructor(type);
4587 expr += '(';
4588 for (uint32_t i = 0; i < type.vecsize; i++)
4589 {
4590 // Make sure to call to_expression multiple times to ensure
4591 // that these expressions are properly flushed to temporaries if needed.
4592 expr += op;
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004593 expr += to_extract_component_expression(operand, i);
Robert Konradf3a82772017-03-24 15:00:48 +01004594
4595 if (i + 1 < type.vecsize)
4596 expr += ", ";
4597 }
4598 expr += ')';
4599 emit_op(result_type, result_id, expr, should_forward(operand));
4600
4601 inherit_expression_dependencies(result_id, operand);
4602}
4603
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004604void CompilerGLSL::emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02004605 const char *op, bool negate, SPIRType::BaseType expected_type)
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004606{
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02004607 auto &type0 = expression_type(op0);
4608 auto &type1 = expression_type(op1);
4609
4610 SPIRType target_type0 = type0;
4611 SPIRType target_type1 = type1;
4612 target_type0.basetype = expected_type;
4613 target_type1.basetype = expected_type;
4614 target_type0.vecsize = 1;
4615 target_type1.vecsize = 1;
4616
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004617 auto &type = get<SPIRType>(result_type);
4618 auto expr = type_to_glsl_constructor(type);
4619 expr += '(';
4620 for (uint32_t i = 0; i < type.vecsize; i++)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004621 {
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004622 // Make sure to call to_expression multiple times to ensure
4623 // that these expressions are properly flushed to temporaries if needed.
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02004624 if (negate)
4625 expr += "!(";
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02004626
4627 if (expected_type != SPIRType::Unknown && type0.basetype != expected_type)
4628 expr += bitcast_expression(target_type0, type0.basetype, to_extract_component_expression(op0, i));
4629 else
4630 expr += to_extract_component_expression(op0, i);
4631
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004632 expr += ' ';
4633 expr += op;
4634 expr += ' ';
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02004635
4636 if (expected_type != SPIRType::Unknown && type1.basetype != expected_type)
4637 expr += bitcast_expression(target_type1, type1.basetype, to_extract_component_expression(op1, i));
4638 else
4639 expr += to_extract_component_expression(op1, i);
4640
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02004641 if (negate)
4642 expr += ")";
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004643
4644 if (i + 1 < type.vecsize)
4645 expr += ", ";
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004646 }
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004647 expr += ')';
4648 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
4649
4650 inherit_expression_dependencies(result_id, op0);
4651 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004652}
4653
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004654SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
4655 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
4656{
4657 auto &type0 = expression_type(op0);
4658 auto &type1 = expression_type(op1);
4659
4660 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
4661 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
4662 // since equality test is exactly the same.
4663 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
4664
4665 // Create a fake type so we can bitcast to it.
4666 // We only deal with regular arithmetic types here like int, uints and so on.
4667 SPIRType expected_type;
4668 expected_type.basetype = input_type;
4669 expected_type.vecsize = type0.vecsize;
4670 expected_type.columns = type0.columns;
4671 expected_type.width = type0.width;
4672
4673 if (cast)
4674 {
4675 cast_op0 = bitcast_glsl(expected_type, op0);
4676 cast_op1 = bitcast_glsl(expected_type, op1);
4677 }
4678 else
4679 {
4680 // If we don't cast, our actual input type is that of the first (or second) argument.
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02004681 cast_op0 = to_enclosed_unpacked_expression(op0);
4682 cast_op1 = to_enclosed_unpacked_expression(op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004683 input_type = type0.basetype;
4684 }
4685
4686 return expected_type;
4687}
4688
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02004689bool CompilerGLSL::emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0)
4690{
4691 // Some bitcasts may require complex casting sequences, and are implemented here.
4692 // Otherwise a simply unary function will do with bitcast_glsl_op.
4693
4694 auto &output_type = get<SPIRType>(result_type);
4695 auto &input_type = expression_type(op0);
4696 string expr;
4697
4698 if (output_type.basetype == SPIRType::Half && input_type.basetype == SPIRType::Float && input_type.vecsize == 1)
4699 expr = join("unpackFloat2x16(floatBitsToUint(", to_unpacked_expression(op0), "))");
4700 else if (output_type.basetype == SPIRType::Float && input_type.basetype == SPIRType::Half && input_type.vecsize == 2)
4701 expr = join("uintBitsToFloat(packFloat2x16(", to_unpacked_expression(op0), "))");
4702 else
4703 return false;
4704
4705 emit_op(result_type, id, expr, should_forward(op0));
4706 return true;
4707}
4708
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004709void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4710 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
4711{
4712 string cast_op0, cast_op1;
4713 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
4714 auto &out_type = get<SPIRType>(result_type);
4715
4716 // We might have casted away from the result type, so bitcast again.
4717 // For example, arithmetic right shift with uint inputs.
4718 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004719 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004720 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004721 {
4722 expected_type.basetype = input_type;
4723 expr = bitcast_glsl_op(out_type, expected_type);
4724 expr += '(';
4725 expr += join(cast_op0, " ", op, " ", cast_op1);
4726 expr += ')';
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004727 }
4728 else
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004729 expr += join(cast_op0, " ", op, " ", cast_op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004730
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004731 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004732 inherit_expression_dependencies(result_id, op0);
4733 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004734}
4735
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004736void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
4737{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004738 bool forward = should_forward(op0);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004739 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004740 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004741}
4742
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004743void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4744 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004745{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004746 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004747 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ")"),
4748 forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004749 inherit_expression_dependencies(result_id, op0);
4750 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004751}
4752
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004753void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op,
4754 SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type)
4755{
4756 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004757 auto &expr_type = expression_type(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004758 auto expected_type = out_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004759
4760 // Bit-widths might be different in unary cases because we use it for SConvert/UConvert and friends.
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004761 expected_type.basetype = input_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004762 expected_type.width = expr_type.width;
4763 string cast_op = expr_type.basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004764
4765 string expr;
4766 if (out_type.basetype != expected_result_type)
4767 {
4768 expected_type.basetype = expected_result_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004769 expected_type.width = out_type.width;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004770 expr = bitcast_glsl_op(out_type, expected_type);
4771 expr += '(';
4772 expr += join(op, "(", cast_op, ")");
4773 expr += ')';
4774 }
4775 else
4776 {
4777 expr += join(op, "(", cast_op, ")");
4778 }
4779
4780 emit_op(result_type, result_id, expr, should_forward(op0));
4781 inherit_expression_dependencies(result_id, op0);
4782}
4783
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004784// Very special case. Handling bitfieldExtract requires us to deal with different bitcasts of different signs
4785// and different vector sizes all at once. Need a special purpose method here.
4786void CompilerGLSL::emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4787 uint32_t op2, const char *op,
4788 SPIRType::BaseType expected_result_type,
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02004789 SPIRType::BaseType input_type0, SPIRType::BaseType input_type1,
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004790 SPIRType::BaseType input_type2)
4791{
4792 auto &out_type = get<SPIRType>(result_type);
4793 auto expected_type = out_type;
4794 expected_type.basetype = input_type0;
4795
4796 string cast_op0 =
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02004797 expression_type(op0).basetype != input_type0 ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004798
4799 auto op1_expr = to_unpacked_expression(op1);
4800 auto op2_expr = to_unpacked_expression(op2);
4801
4802 // Use value casts here instead. Input must be exactly int or uint, but SPIR-V might be 16-bit.
4803 expected_type.basetype = input_type1;
4804 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02004805 string cast_op1 = expression_type(op1).basetype != input_type1 ?
4806 join(type_to_glsl_constructor(expected_type), "(", op1_expr, ")") :
4807 op1_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004808
4809 expected_type.basetype = input_type2;
4810 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02004811 string cast_op2 = expression_type(op2).basetype != input_type2 ?
4812 join(type_to_glsl_constructor(expected_type), "(", op2_expr, ")") :
4813 op2_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004814
4815 string expr;
4816 if (out_type.basetype != expected_result_type)
4817 {
4818 expected_type.vecsize = out_type.vecsize;
4819 expected_type.basetype = expected_result_type;
4820 expr = bitcast_glsl_op(out_type, expected_type);
4821 expr += '(';
4822 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
4823 expr += ')';
4824 }
4825 else
4826 {
4827 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
4828 }
4829
4830 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
4831 inherit_expression_dependencies(result_id, op0);
4832 inherit_expression_dependencies(result_id, op1);
4833 inherit_expression_dependencies(result_id, op2);
4834}
4835
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02004836void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4837 uint32_t op2, const char *op, SPIRType::BaseType input_type)
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004838{
4839 auto &out_type = get<SPIRType>(result_type);
4840 auto expected_type = out_type;
4841 expected_type.basetype = input_type;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02004842 string cast_op0 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004843 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02004844 string cast_op1 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004845 expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_unpacked_expression(op1);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02004846 string cast_op2 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004847 expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_unpacked_expression(op2);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004848
4849 string expr;
4850 if (out_type.basetype != input_type)
4851 {
4852 expr = bitcast_glsl_op(out_type, expected_type);
4853 expr += '(';
4854 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
4855 expr += ')';
4856 }
4857 else
4858 {
4859 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
4860 }
4861
4862 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
4863 inherit_expression_dependencies(result_id, op0);
4864 inherit_expression_dependencies(result_id, op1);
4865 inherit_expression_dependencies(result_id, op2);
4866}
4867
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01004868void CompilerGLSL::emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0,
4869 uint32_t op1, const char *op, SPIRType::BaseType input_type)
4870{
4871 // Special purpose method for implementing clustered subgroup opcodes.
4872 // Main difference is that op1 does not participate in any casting, it needs to be a literal.
4873 auto &out_type = get<SPIRType>(result_type);
4874 auto expected_type = out_type;
4875 expected_type.basetype = input_type;
4876 string cast_op0 =
4877 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
4878
4879 string expr;
4880 if (out_type.basetype != input_type)
4881 {
4882 expr = bitcast_glsl_op(out_type, expected_type);
4883 expr += '(';
4884 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
4885 expr += ')';
4886 }
4887 else
4888 {
4889 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
4890 }
4891
4892 emit_op(result_type, result_id, expr, should_forward(op0));
4893 inherit_expression_dependencies(result_id, op0);
4894}
4895
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004896void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4897 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
4898{
4899 string cast_op0, cast_op1;
4900 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
4901 auto &out_type = get<SPIRType>(result_type);
4902
4903 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
4904 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004905 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004906 {
4907 expected_type.basetype = input_type;
4908 expr = bitcast_glsl_op(out_type, expected_type);
4909 expr += '(';
4910 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
4911 expr += ')';
4912 }
4913 else
4914 {
4915 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
4916 }
4917
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004918 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004919 inherit_expression_dependencies(result_id, op0);
4920 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004921}
4922
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004923void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4924 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004925{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004926 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004927 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004928 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
4929 to_unpacked_expression(op2), ")"),
4930 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004931
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004932 inherit_expression_dependencies(result_id, op0);
4933 inherit_expression_dependencies(result_id, op1);
4934 inherit_expression_dependencies(result_id, op2);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004935}
4936
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004937void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4938 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004939{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004940 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01004941 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004942 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
4943 to_unpacked_expression(op2), ", ", to_unpacked_expression(op3), ")"),
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004944 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004945
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01004946 inherit_expression_dependencies(result_id, op0);
4947 inherit_expression_dependencies(result_id, op1);
4948 inherit_expression_dependencies(result_id, op2);
4949 inherit_expression_dependencies(result_id, op3);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004950}
4951
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004952void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
4953 uint32_t op2, uint32_t op3, const char *op,
4954 SPIRType::BaseType offset_count_type)
4955{
4956 // Only need to cast offset/count arguments. Types of base/insert must be same as result type,
4957 // and bitfieldInsert is sign invariant.
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02004958 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004959
4960 auto op0_expr = to_unpacked_expression(op0);
4961 auto op1_expr = to_unpacked_expression(op1);
4962 auto op2_expr = to_unpacked_expression(op2);
4963 auto op3_expr = to_unpacked_expression(op3);
4964
4965 SPIRType target_type;
4966 target_type.vecsize = 1;
4967 target_type.basetype = offset_count_type;
4968
4969 if (expression_type(op2).basetype != offset_count_type)
4970 {
4971 // Value-cast here. Input might be 16-bit. GLSL requires int.
4972 op2_expr = join(type_to_glsl_constructor(target_type), "(", op2_expr, ")");
4973 }
4974
4975 if (expression_type(op3).basetype != offset_count_type)
4976 {
4977 // Value-cast here. Input might be 16-bit. GLSL requires int.
4978 op3_expr = join(type_to_glsl_constructor(target_type), "(", op3_expr, ")");
4979 }
4980
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02004981 emit_op(result_type, result_id, join(op, "(", op0_expr, ", ", op1_expr, ", ", op2_expr, ", ", op3_expr, ")"),
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02004982 forward);
4983
4984 inherit_expression_dependencies(result_id, op0);
4985 inherit_expression_dependencies(result_id, op1);
4986 inherit_expression_dependencies(result_id, op2);
4987 inherit_expression_dependencies(result_id, op3);
4988}
4989
Robert Konradedfc2972017-03-23 13:25:24 +01004990// EXT_shader_texture_lod only concerns fragment shaders so lod tex functions
4991// are not allowed in ES 2 vertex shaders. But SPIR-V only supports lod tex
4992// functions in vertex shaders so we revert those back to plain calls when
4993// the lod is a constant value of zero.
Robert Konrad9760f152017-03-23 14:43:54 +01004994bool CompilerGLSL::check_explicit_lod_allowed(uint32_t lod)
Robert Konradedfc2972017-03-23 13:25:24 +01004995{
4996 auto &execution = get_entry_point();
Robert Konrad9760f152017-03-23 14:43:54 +01004997 bool allowed = !is_legacy_es() || execution.model == ExecutionModelFragment;
Robert Konradec396472017-03-24 09:26:02 +01004998 if (!allowed && lod != 0)
Robert Konrad9760f152017-03-23 14:43:54 +01004999 {
5000 auto *lod_constant = maybe_get<SPIRConstant>(lod);
5001 if (!lod_constant || lod_constant->scalar_f32() != 0.0f)
5002 {
5003 SPIRV_CROSS_THROW("Explicit lod not allowed in legacy ES non-fragment shaders.");
5004 }
5005 }
5006 return allowed;
Robert Konradedfc2972017-03-23 13:25:24 +01005007}
5008
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02005009string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t tex)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005010{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005011 const char *type;
5012 switch (imgtype.image.dim)
5013 {
5014 case spv::Dim1D:
Rob Fischer21990632016-09-17 17:01:50 +09005015 type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005016 break;
5017 case spv::Dim2D:
Rob Fischer21990632016-09-17 17:01:50 +09005018 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005019 break;
5020 case spv::Dim3D:
5021 type = "3D";
5022 break;
5023 case spv::DimCube:
5024 type = "Cube";
5025 break;
Sidney Justfbb4df32019-01-06 12:21:59 -08005026 case spv::DimRect:
5027 type = "2DRect";
5028 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005029 case spv::DimBuffer:
5030 type = "Buffer";
5031 break;
5032 case spv::DimSubpassData:
5033 type = "2D";
5034 break;
5035 default:
5036 type = "";
5037 break;
5038 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005039
Robert Konrad9760f152017-03-23 14:43:54 +01005040 bool use_explicit_lod = check_explicit_lod_allowed(lod);
Robert Konrad3f745032017-03-23 09:55:32 +01005041
Sidney Just5ac55ee2018-06-25 02:11:46 -07005042 if (op == "textureLod" || op == "textureProjLod" || op == "textureGrad" || op == "textureProjGrad")
Lubos Lenco0028b4f2016-11-21 22:37:20 +01005043 {
Robert Konradedfc2972017-03-23 13:25:24 +01005044 if (is_legacy_es())
5045 {
Robert Konrad9760f152017-03-23 14:43:54 +01005046 if (use_explicit_lod)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005047 require_extension_internal("GL_EXT_shader_texture_lod");
Robert Konradedfc2972017-03-23 13:25:24 +01005048 }
5049 else if (is_legacy())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005050 require_extension_internal("GL_ARB_shader_texture_lod");
Lubos Lenco0028b4f2016-11-21 22:37:20 +01005051 }
Lubos Lenco52158642016-09-17 15:56:23 +02005052
Sidney Just5ac55ee2018-06-25 02:11:46 -07005053 if (op == "textureLodOffset" || op == "textureProjLodOffset")
5054 {
5055 if (is_legacy_es())
5056 SPIRV_CROSS_THROW(join(op, " not allowed in legacy ES"));
5057
5058 require_extension_internal("GL_EXT_gpu_shader4");
5059 }
5060
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02005061 // GLES has very limited support for shadow samplers.
Sidney Just5ac55ee2018-06-25 02:11:46 -07005062 // Basically shadow2D and shadow2DProj work through EXT_shadow_samplers,
5063 // everything else can just throw
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02005064 if (image_is_comparison(imgtype, tex) && is_legacy_es())
Sidney Just5ac55ee2018-06-25 02:11:46 -07005065 {
5066 if (op == "texture" || op == "textureProj")
5067 require_extension_internal("GL_EXT_shadow_samplers");
5068 else
5069 SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
5070 }
5071
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02005072 bool is_es_and_depth = is_legacy_es() && image_is_comparison(imgtype, tex);
5073 std::string type_prefix = image_is_comparison(imgtype, tex) ? "shadow" : "texture";
Sidney Just0f62b5d2018-06-22 01:40:01 -07005074
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005075 if (op == "texture")
Sidney Just5ac55ee2018-06-25 02:11:46 -07005076 return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
Robert Konradedfc2972017-03-23 13:25:24 +01005077 else if (op == "textureLod")
5078 {
Robert Konrad9760f152017-03-23 14:43:54 +01005079 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07005080 return join(type_prefix, type, is_legacy_es() ? "LodEXT" : "Lod");
Robert Konrad9760f152017-03-23 14:43:54 +01005081 else
Sidney Just0f62b5d2018-06-22 01:40:01 -07005082 return join(type_prefix, type);
Robert Konrad3f745032017-03-23 09:55:32 +01005083 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005084 else if (op == "textureProj")
Sidney Just5ac55ee2018-06-25 02:11:46 -07005085 return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
Sidney Juste66fd6c2018-03-12 00:59:06 +10005086 else if (op == "textureGrad")
Sidney Just0f62b5d2018-06-22 01:40:01 -07005087 return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005088 else if (op == "textureProjLod")
Robert Konrad9760f152017-03-23 14:43:54 +01005089 {
5090 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07005091 return join(type_prefix, type, is_legacy_es() ? "ProjLodEXT" : "ProjLod");
Robert Konrad9760f152017-03-23 14:43:54 +01005092 else
Sidney Justceec7082018-06-25 02:06:45 -07005093 return join(type_prefix, type, "Proj");
Robert Konrad9760f152017-03-23 14:43:54 +01005094 }
Sidney Just0f62b5d2018-06-22 01:40:01 -07005095 else if (op == "textureLodOffset")
Sidney Justf6dad782018-06-22 00:28:40 -07005096 {
5097 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07005098 return join(type_prefix, type, "LodOffset");
Sidney Justf6dad782018-06-22 00:28:40 -07005099 else
Sidney Just0f62b5d2018-06-22 01:40:01 -07005100 return join(type_prefix, type);
Sidney Justf6dad782018-06-22 00:28:40 -07005101 }
Sidney Just0f62b5d2018-06-22 01:40:01 -07005102 else if (op == "textureProjGrad")
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02005103 return join(type_prefix, type,
5104 is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
Sidney Just0f62b5d2018-06-22 01:40:01 -07005105 else if (op == "textureProjLodOffset")
Sidney Justf6dad782018-06-22 00:28:40 -07005106 {
5107 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07005108 return join(type_prefix, type, "ProjLodOffset");
Sidney Justf6dad782018-06-22 00:28:40 -07005109 else
Sidney Justceec7082018-06-25 02:06:45 -07005110 return join(type_prefix, type, "ProjOffset");
Robert Konrad3f745032017-03-23 09:55:32 +01005111 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005112 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005113 {
5114 SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
5115 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005116}
5117
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005118bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
5119{
5120 auto *cleft = maybe_get<SPIRConstant>(left);
5121 auto *cright = maybe_get<SPIRConstant>(right);
5122 auto &lerptype = expression_type(lerp);
5123
5124 // If our targets aren't constants, we cannot use construction.
5125 if (!cleft || !cright)
5126 return false;
5127
5128 // If our targets are spec constants, we cannot use construction.
5129 if (cleft->specialization || cright->specialization)
5130 return false;
5131
5132 // We can only use trivial construction if we have a scalar
5133 // (should be possible to do it for vectors as well, but that is overkill for now).
5134 if (lerptype.basetype != SPIRType::Boolean || lerptype.vecsize > 1)
5135 return false;
5136
5137 // If our bool selects between 0 and 1, we can cast from bool instead, making our trivial constructor.
5138 bool ret = false;
5139 switch (type.basetype)
5140 {
Chip Davis117ccf42018-11-01 17:20:07 -05005141 case SPIRType::Short:
5142 case SPIRType::UShort:
5143 ret = cleft->scalar_u16() == 0 && cright->scalar_u16() == 1;
5144 break;
5145
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005146 case SPIRType::Int:
5147 case SPIRType::UInt:
5148 ret = cleft->scalar() == 0 && cright->scalar() == 1;
5149 break;
5150
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005151 case SPIRType::Half:
5152 ret = cleft->scalar_f16() == 0.0f && cright->scalar_f16() == 1.0f;
5153 break;
5154
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005155 case SPIRType::Float:
5156 ret = cleft->scalar_f32() == 0.0f && cright->scalar_f32() == 1.0f;
5157 break;
5158
5159 case SPIRType::Double:
5160 ret = cleft->scalar_f64() == 0.0 && cright->scalar_f64() == 1.0;
5161 break;
5162
5163 case SPIRType::Int64:
5164 case SPIRType::UInt64:
5165 ret = cleft->scalar_u64() == 0 && cright->scalar_u64() == 1;
5166 break;
5167
5168 default:
5169 break;
5170 }
5171
5172 if (ret)
5173 op = type_to_glsl_constructor(type);
5174 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005175}
5176
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005177string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
5178 uint32_t false_value)
5179{
5180 string expr;
5181 auto &lerptype = expression_type(select);
5182
5183 if (lerptype.vecsize == 1)
Chip Davis3bfb2f92018-12-03 02:06:33 -06005184 expr = join(to_enclosed_expression(select), " ? ", to_enclosed_pointer_expression(true_value), " : ",
5185 to_enclosed_pointer_expression(false_value));
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005186 else
5187 {
5188 auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
5189
5190 expr = type_to_glsl_constructor(restype);
5191 expr += "(";
5192 for (uint32_t i = 0; i < restype.vecsize; i++)
5193 {
5194 expr += swiz(select, i);
5195 expr += " ? ";
5196 expr += swiz(true_value, i);
5197 expr += " : ";
5198 expr += swiz(false_value, i);
5199 if (i + 1 < restype.vecsize)
5200 expr += ", ";
5201 }
5202 expr += ")";
5203 }
5204
5205 return expr;
5206}
5207
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005208void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005209{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005210 auto &lerptype = expression_type(lerp);
5211 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005212
Chip Davis3bfb2f92018-12-03 02:06:33 -06005213 // If this results in a variable pointer, assume it may be written through.
5214 if (restype.pointer)
5215 {
5216 register_write(left);
5217 register_write(right);
5218 }
5219
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005220 string mix_op;
Chip Davis6628ea62019-07-10 23:46:40 -05005221 bool has_boolean_mix = *backend.boolean_mix_function &&
Hans-Kristian Arntzen851acf32017-05-04 10:28:30 +02005222 ((options.es && options.version >= 310) || (!options.es && options.version >= 450));
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005223 bool trivial_mix = to_trivial_mix_op(restype, mix_op, left, right, lerp);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005224
Hans-Kristian Arntzen0e7c33f2017-02-11 10:52:34 +01005225 // Cannot use boolean mix when the lerp argument is just one boolean,
5226 // fall back to regular trinary statements.
5227 if (lerptype.vecsize == 1)
5228 has_boolean_mix = false;
5229
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005230 // If we can reduce the mix to a simple cast, do so.
5231 // This helps for cases like int(bool), uint(bool) which is implemented with
5232 // OpSelect bool 1 0.
5233 if (trivial_mix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005234 {
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005235 emit_unary_func_op(result_type, id, lerp, mix_op.c_str());
5236 }
5237 else if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
5238 {
5239 // Boolean mix not supported on desktop without extension.
5240 // Was added in OpenGL 4.5 with ES 3.1 compat.
5241 //
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005242 // Could use GL_EXT_shader_integer_mix on desktop at least,
5243 // but Apple doesn't support it. :(
5244 // Just implement it as ternary expressions.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005245 auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005246 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005247 inherit_expression_dependencies(id, left);
5248 inherit_expression_dependencies(id, right);
5249 inherit_expression_dependencies(id, lerp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005250 }
Chip Davis6628ea62019-07-10 23:46:40 -05005251 else if (lerptype.basetype == SPIRType::Boolean)
5252 emit_trinary_func_op(result_type, id, left, right, lerp, backend.boolean_mix_function);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005253 else
5254 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005255}
5256
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005257string CompilerGLSL::to_combined_image_sampler(VariableID image_id, VariableID samp_id)
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005258{
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02005259 // Keep track of the array indices we have used to load the image.
5260 // We'll need to use the same array index into the combined image sampler array.
5261 auto image_expr = to_expression(image_id);
5262 string array_expr;
5263 auto array_index = image_expr.find_first_of('[');
5264 if (array_index != string::npos)
5265 array_expr = image_expr.substr(array_index, string::npos);
5266
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005267 auto &args = current_function->arguments;
5268
5269 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
5270 // all possible combinations into new sampler2D uniforms.
5271 auto *image = maybe_get_backing_variable(image_id);
5272 auto *samp = maybe_get_backing_variable(samp_id);
5273 if (image)
5274 image_id = image->self;
5275 if (samp)
5276 samp_id = samp->self;
5277
5278 auto image_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005279 [image_id](const SPIRFunction::Parameter &param) { return image_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005280
5281 auto sampler_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005282 [samp_id](const SPIRFunction::Parameter &param) { return samp_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005283
5284 if (image_itr != end(args) || sampler_itr != end(args))
5285 {
5286 // If any parameter originates from a parameter, we will find it in our argument list.
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02005287 bool global_image = image_itr == end(args);
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005288 bool global_sampler = sampler_itr == end(args);
Hans-Kristian Arntzenc3ff67c2019-09-17 10:16:47 +02005289 VariableID iid = global_image ? image_id : VariableID(uint32_t(image_itr - begin(args)));
5290 VariableID sid = global_sampler ? samp_id : VariableID(uint32_t(sampler_itr - begin(args)));
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005291
5292 auto &combined = current_function->combined_parameters;
5293 auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02005294 return p.global_image == global_image && p.global_sampler == global_sampler && p.image_id == iid &&
5295 p.sampler_id == sid;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005296 });
5297
5298 if (itr != end(combined))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02005299 return to_expression(itr->id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005300 else
5301 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005302 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005303 "Cannot find mapping for combined sampler parameter, was build_combined_image_samplers() used "
5304 "before compile() was called?");
5305 }
5306 }
5307 else
5308 {
5309 // For global sampler2D, look directly at the global remapping table.
5310 auto &mapping = combined_image_samplers;
5311 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
5312 return combined.image_id == image_id && combined.sampler_id == samp_id;
5313 });
5314
5315 if (itr != end(combined_image_samplers))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02005316 return to_expression(itr->combined_id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005317 else
5318 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005319 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
5320 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005321 }
5322 }
5323}
5324
Bill Hollings5aafb282016-04-23 21:47:41 -04005325void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
5326{
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02005327 if (options.vulkan_semantics && combined_image_samplers.empty())
5328 {
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02005329 emit_binary_func_op(result_type, result_id, image_id, samp_id,
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02005330 type_to_glsl(get<SPIRType>(result_type), result_id).c_str());
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02005331 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02005332 else
Hans-Kristian Arntzen02808002018-04-27 09:34:13 +02005333 {
5334 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
5335 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true);
5336 }
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02005337
5338 // Make sure to suppress usage tracking and any expression invalidation.
5339 // It is illegal to create temporaries of opaque types.
5340 forwarded_temporaries.erase(result_id);
Bill Hollings5aafb282016-04-23 21:47:41 -04005341}
5342
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01005343static inline bool image_opcode_is_sample_no_dref(Op op)
5344{
5345 switch (op)
5346 {
5347 case OpImageSampleExplicitLod:
5348 case OpImageSampleImplicitLod:
5349 case OpImageSampleProjExplicitLod:
5350 case OpImageSampleProjImplicitLod:
5351 case OpImageFetch:
5352 case OpImageRead:
5353 case OpImageSparseSampleExplicitLod:
5354 case OpImageSparseSampleImplicitLod:
5355 case OpImageSparseSampleProjExplicitLod:
5356 case OpImageSparseSampleProjImplicitLod:
5357 case OpImageSparseFetch:
5358 case OpImageSparseRead:
5359 return true;
5360
5361 default:
5362 return false;
5363 }
5364}
5365
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005366void CompilerGLSL::emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id,
5367 uint32_t &feedback_id, uint32_t &texel_id)
5368{
5369 // Need to allocate two temporaries.
5370 if (options.es)
5371 SPIRV_CROSS_THROW("Sparse texture feedback is not supported on ESSL.");
5372 require_extension_internal("GL_ARB_sparse_texture2");
5373
5374 auto &temps = extra_sub_expressions[id];
5375 if (temps == 0)
5376 temps = ir.increase_bound_by(2);
5377
5378 feedback_id = temps + 0;
5379 texel_id = temps + 1;
5380
5381 auto &return_type = get<SPIRType>(result_type_id);
5382 if (return_type.basetype != SPIRType::Struct || return_type.member_types.size() != 2)
5383 SPIRV_CROSS_THROW("Invalid return type for sparse feedback.");
5384 emit_uninitialized_temporary(return_type.member_types[0], feedback_id);
5385 emit_uninitialized_temporary(return_type.member_types[1], texel_id);
5386}
5387
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005388uint32_t CompilerGLSL::get_sparse_feedback_texel_id(uint32_t id) const
5389{
5390 auto itr = extra_sub_expressions.find(id);
5391 if (itr == extra_sub_expressions.end())
5392 return 0;
5393 else
5394 return itr->second + 1;
5395}
5396
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005397void CompilerGLSL::emit_texture_op(const Instruction &i, bool sparse)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005398{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02005399 auto *ops = stream(i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005400 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005401
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02005402 SmallVector<uint32_t> inherited_expressions;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005403
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02005404 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005405 uint32_t id = ops[1];
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005406 auto &return_type = get<SPIRType>(result_type_id);
5407
5408 uint32_t sparse_code_id = 0;
5409 uint32_t sparse_texel_id = 0;
5410 if (sparse)
5411 emit_sparse_feedback_temporaries(result_type_id, id, sparse_code_id, sparse_texel_id);
Chip Davis39dce882019-08-02 15:11:19 -05005412
5413 bool forward = false;
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005414 string expr = to_texture_op(i, sparse, &forward, inherited_expressions);
5415
5416 if (sparse)
5417 {
5418 statement(to_expression(sparse_code_id), " = ", expr, ";");
5419 expr = join(type_to_glsl(return_type), "(", to_expression(sparse_code_id), ", ", to_expression(sparse_texel_id), ")");
5420 forward = true;
5421 inherited_expressions.clear();
5422 }
5423
Chip Davis39dce882019-08-02 15:11:19 -05005424 emit_op(result_type_id, id, expr, forward);
5425 for (auto &inherit : inherited_expressions)
5426 inherit_expression_dependencies(id, inherit);
5427
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005428 // Do not register sparse ops as control dependent as they are always lowered to a temporary.
Chip Davis39dce882019-08-02 15:11:19 -05005429 switch (op)
5430 {
5431 case OpImageSampleDrefImplicitLod:
5432 case OpImageSampleImplicitLod:
5433 case OpImageSampleProjImplicitLod:
5434 case OpImageSampleProjDrefImplicitLod:
5435 register_control_dependent_expression(id);
5436 break;
5437
5438 default:
5439 break;
5440 }
5441}
5442
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005443std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool *forward,
Chip Davis39dce882019-08-02 15:11:19 -05005444 SmallVector<uint32_t> &inherited_expressions)
5445{
5446 auto *ops = stream(i);
5447 auto op = static_cast<Op>(i.op);
5448 uint32_t length = i.length;
5449
5450 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005451 VariableID img = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005452 uint32_t coord = ops[3];
5453 uint32_t dref = 0;
5454 uint32_t comp = 0;
5455 bool gather = false;
5456 bool proj = false;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005457 bool fetch = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005458 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005459
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02005460 auto &result_type = get<SPIRType>(result_type_id);
5461
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005462 inherited_expressions.push_back(coord);
5463
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02005464 // Make sure non-uniform decoration is back-propagated to where it needs to be.
5465 if (has_decoration(img, DecorationNonUniformEXT))
5466 propagate_nonuniform_qualifier(img);
5467
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005468 switch (op)
5469 {
5470 case OpImageSampleDrefImplicitLod:
5471 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005472 case OpImageSparseSampleDrefImplicitLod:
5473 case OpImageSparseSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005474 dref = ops[4];
5475 opt = &ops[5];
5476 length -= 5;
5477 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005479 case OpImageSampleProjDrefImplicitLod:
5480 case OpImageSampleProjDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005481 case OpImageSparseSampleProjDrefImplicitLod:
5482 case OpImageSparseSampleProjDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005483 dref = ops[4];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005484 opt = &ops[5];
5485 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005486 proj = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005487 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005488
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005489 case OpImageDrefGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005490 case OpImageSparseDrefGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005491 dref = ops[4];
5492 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005493 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005494 gather = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005495 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005496
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005497 case OpImageGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005498 case OpImageSparseGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005499 comp = ops[4];
5500 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005501 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005502 gather = true;
5503 break;
5504
5505 case OpImageFetch:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005506 case OpImageSparseFetch:
Bill Hollings8f6df772017-05-19 18:14:08 -04005507 case OpImageRead: // Reads == fetches in Metal (other langs will not get here)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005508 opt = &ops[4];
5509 length -= 4;
5510 fetch = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005511 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005512
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005513 case OpImageSampleProjImplicitLod:
5514 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005515 case OpImageSparseSampleProjImplicitLod:
5516 case OpImageSparseSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005517 opt = &ops[4];
5518 length -= 4;
5519 proj = true;
5520 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005521
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005522 default:
5523 opt = &ops[4];
5524 length -= 4;
5525 break;
5526 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005527
Bill Hollings8f6df772017-05-19 18:14:08 -04005528 // Bypass pointers because we need the real image struct
5529 auto &type = expression_type(img);
5530 auto &imgtype = get<SPIRType>(type.self);
5531
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005532 uint32_t coord_components = 0;
5533 switch (imgtype.image.dim)
5534 {
5535 case spv::Dim1D:
5536 coord_components = 1;
5537 break;
5538 case spv::Dim2D:
5539 coord_components = 2;
5540 break;
5541 case spv::Dim3D:
5542 coord_components = 3;
5543 break;
5544 case spv::DimCube:
5545 coord_components = 3;
5546 break;
5547 case spv::DimBuffer:
5548 coord_components = 1;
5549 break;
5550 default:
5551 coord_components = 2;
5552 break;
5553 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005554
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005555 if (dref)
5556 inherited_expressions.push_back(dref);
5557
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005558 if (proj)
5559 coord_components++;
5560 if (imgtype.image.arrayed)
5561 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005562
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005563 uint32_t bias = 0;
5564 uint32_t lod = 0;
5565 uint32_t grad_x = 0;
5566 uint32_t grad_y = 0;
5567 uint32_t coffset = 0;
5568 uint32_t offset = 0;
5569 uint32_t coffsets = 0;
5570 uint32_t sample = 0;
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02005571 uint32_t minlod = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005572 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005574 if (length)
5575 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005576 flags = *opt++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005577 length--;
5578 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005579
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005580 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005581 if (length && (flags & flag))
5582 {
5583 v = *opt++;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005584 inherited_expressions.push_back(v);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005585 length--;
5586 }
5587 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005588
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005589 test(bias, ImageOperandsBiasMask);
5590 test(lod, ImageOperandsLodMask);
5591 test(grad_x, ImageOperandsGradMask);
5592 test(grad_y, ImageOperandsGradMask);
5593 test(coffset, ImageOperandsConstOffsetMask);
5594 test(offset, ImageOperandsOffsetMask);
5595 test(coffsets, ImageOperandsConstOffsetsMask);
5596 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02005597 test(minlod, ImageOperandsMinLodMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005598
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005599 TextureFunctionBaseArguments base_args = {};
5600 base_args.img = img;
5601 base_args.imgtype = &imgtype;
5602 base_args.is_fetch = fetch != 0;
5603 base_args.is_gather = gather != 0;
5604 base_args.is_proj = proj != 0;
5605
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005606 string expr;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005607 TextureFunctionNameArguments name_args = {};
5608
5609 name_args.base = base_args;
5610 name_args.has_array_offsets = coffsets != 0;
5611 name_args.has_offset = coffset != 0 || offset != 0;
5612 name_args.has_grad = grad_x != 0 || grad_y != 0;
5613 name_args.has_dref = dref != 0;
5614 name_args.is_sparse_feedback = sparse;
5615 name_args.has_min_lod = minlod != 0;
5616 name_args.lod = lod;
5617 expr += to_function_name(name_args);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005618 expr += "(";
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005619
5620 uint32_t sparse_texel_id = 0;
5621 if (sparse)
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005622 sparse_texel_id = get_sparse_feedback_texel_id(ops[1]);
5623
5624 TextureFunctionArguments args = {};
5625 args.base = base_args;
5626 args.coord = coord;
5627 args.coord_components = coord_components;
5628 args.dref = dref;
5629 args.grad_x = grad_x;
5630 args.grad_y = grad_y;
5631 args.lod = lod;
5632 args.coffset = coffset;
5633 args.offset = offset;
5634 args.bias = bias;
5635 args.component = comp;
5636 args.sample = sample;
5637 args.sparse_texel = sparse_texel_id;
5638 args.min_lod = minlod;
5639 expr += to_function_args(args, forward);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005640 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005641
Sidney Justf6dad782018-06-22 00:28:40 -07005642 // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02005643 if (is_legacy() && image_is_comparison(imgtype, img))
Sidney Justf6dad782018-06-22 00:28:40 -07005644 expr += ".r";
5645
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01005646 // Sampling from a texture which was deduced to be a depth image, might actually return 1 component here.
5647 // Remap back to 4 components as sampling opcodes expect.
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02005648 if (backend.comparison_image_samples_scalar && image_opcode_is_sample_no_dref(op))
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01005649 {
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02005650 bool image_is_depth = false;
5651 const auto *combined = maybe_get<SPIRCombinedImageSampler>(img);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005652 VariableID image_id = combined ? combined->image : img;
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02005653
5654 if (combined && image_is_comparison(imgtype, combined->image))
5655 image_is_depth = true;
5656 else if (image_is_comparison(imgtype, img))
5657 image_is_depth = true;
5658
5659 // We must also check the backing variable for the image.
5660 // We might have loaded an OpImage, and used that handle for two different purposes.
5661 // Once with comparison, once without.
5662 auto *image_variable = maybe_get_backing_variable(image_id);
5663 if (image_variable && image_is_comparison(get<SPIRType>(image_variable->basetype), image_variable->self))
5664 image_is_depth = true;
5665
5666 if (image_is_depth)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02005667 expr = remap_swizzle(result_type, 1, expr);
5668 }
5669
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005670 if (!sparse && !backend.support_small_type_sampling_result && result_type.width < 32)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02005671 {
5672 // Just value cast (narrowing) to expected type since we cannot rely on narrowing to work automatically.
5673 // Hopefully compiler picks this up and converts the texturing instruction to the appropriate precision.
5674 expr = join(type_to_glsl_constructor(result_type), "(", expr, ")");
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01005675 }
5676
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01005677 // Deals with reads from MSL. We might need to downconvert to fewer components.
5678 if (op == OpImageRead)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02005679 expr = remap_swizzle(result_type, 4, expr);
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01005680
Chip Davis39dce882019-08-02 15:11:19 -05005681 return expr;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005682}
5683
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01005684bool CompilerGLSL::expression_is_constant_null(uint32_t id) const
5685{
5686 auto *c = maybe_get<SPIRConstant>(id);
5687 if (!c)
5688 return false;
5689 return c->constant_is_null();
5690}
5691
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005692// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
5693// For some subclasses, the function is a method on the specified image.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005694string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005695{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005696 if (args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005697 {
5698 if (options.es)
5699 SPIRV_CROSS_THROW("Sparse residency is not supported in ESSL.");
5700 require_extension_internal("GL_ARB_sparse_texture_clamp");
5701 return "sparseTextureClampARB";
5702 }
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02005703
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005704 string fname;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005705 auto &imgtype = *args.base.imgtype;
5706 VariableID tex = args.base.img;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005707
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02005708 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005709 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
5710 // The workaround will assert that the LOD is in fact constant 0, or we cannot emit correct code.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02005711 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005712 bool workaround_lod_array_shadow_as_grad = false;
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02005713 if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005714 image_is_comparison(imgtype, tex) && args.lod)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005715 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005716 if (!expression_is_constant_null(args.lod))
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01005717 {
Hans-Kristian Arntzen7bb74912017-06-23 09:46:15 +02005718 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01005719 "textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be expressed in GLSL.");
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01005720 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005721 workaround_lod_array_shadow_as_grad = true;
5722 }
5723
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005724 if (args.is_sparse_feedback)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005725 fname += "sparse";
5726
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005727 if (args.base.is_fetch)
5728 fname += args.is_sparse_feedback ? "TexelFetch" : "texelFetch";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005729 else
5730 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005731 fname += args.is_sparse_feedback ? "Texture" : "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005732
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005733 if (args.base.is_gather)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005734 fname += "Gather";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005735 if (args.has_array_offsets)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005736 fname += "Offsets";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005737 if (args.base.is_proj)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005738 fname += "Proj";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005739 if (args.has_grad || workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005740 fname += "Grad";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005741 if (args.lod != 0 && !workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005742 fname += "Lod";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005743 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005744
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005745 if (args.has_offset)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005746 fname += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005747
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005748 if (args.is_sparse_feedback)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005749 fname += "ARB";
5750
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005751 return is_legacy() ? legacy_tex_op(fname, imgtype, args.lod, tex) : fname;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005752}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005753
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02005754std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id)
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005755{
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005756 auto *var = maybe_get_backing_variable(id);
5757
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02005758 // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler in GLSL.
5759 // In Vulkan GLSL, we can make use of the newer GL_EXT_samplerless_texture_functions.
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005760 if (var)
5761 {
5762 auto &type = get<SPIRType>(var->basetype);
5763 if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer)
5764 {
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005765 if (options.vulkan_semantics)
5766 {
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02005767 if (dummy_sampler_id)
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02005768 {
5769 // Don't need to consider Shadow state since the dummy sampler is always non-shadow.
5770 auto sampled_type = type;
5771 sampled_type.basetype = SPIRType::SampledImage;
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02005772 return join(type_to_glsl(sampled_type), "(", to_expression(id), ", ",
5773 to_expression(dummy_sampler_id), ")");
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02005774 }
5775 else
5776 {
5777 // Newer glslang supports this extension to deal with texture2D as argument to texture functions.
5778 require_extension_internal("GL_EXT_samplerless_texture_functions");
5779 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005780 }
5781 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02005782 {
5783 if (!dummy_sampler_id)
5784 SPIRV_CROSS_THROW(
5785 "Cannot find dummy sampler ID. Was build_dummy_sampler_for_combined_images() called?");
5786
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005787 return to_combined_image_sampler(id, dummy_sampler_id);
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02005788 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005789 }
5790 }
5791
5792 return to_expression(id);
5793}
5794
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005795// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005796string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool *p_forward)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005797{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005798 VariableID img = args.base.img;
5799 auto &imgtype = *args.base.imgtype;
5800
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005801 string farg_str;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005802 if (args.base.is_fetch)
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02005803 farg_str = convert_separate_image_to_expression(img);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02005804 else
5805 farg_str = to_expression(img);
Hans-Kristian Arntzen1a2e4de2018-02-21 13:43:16 +01005806
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005807 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005808 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005809 if (comps == in_comps)
5810 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005811
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005812 switch (comps)
5813 {
5814 case 1:
5815 return ".x";
5816 case 2:
5817 return swizz_func ? ".xy()" : ".xy";
5818 case 3:
5819 return swizz_func ? ".xyz()" : ".xyz";
5820 default:
5821 return "";
5822 }
5823 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005824
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005825 bool forward = should_forward(args.coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005826
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005827 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005828 auto swizzle_expr = swizzle(args.coord_components, expression_type(args.coord).vecsize);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005829 // Only enclose the UV expression if needed.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005830 auto coord_expr = (*swizzle_expr == '\0') ? to_expression(args.coord) : (to_enclosed_expression(args.coord) + swizzle_expr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005831
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01005832 // texelFetch only takes int, not uint.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005833 auto &coord_type = expression_type(args.coord);
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01005834 if (coord_type.basetype == SPIRType::UInt)
5835 {
5836 auto expected_type = coord_type;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005837 expected_type.vecsize = args.coord_components;
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01005838 expected_type.basetype = SPIRType::Int;
5839 coord_expr = bitcast_expression(expected_type, coord_type.basetype, coord_expr);
5840 }
5841
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02005842 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005843 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
5844 // The workaround will assert that the LOD is in fact constant 0, or we cannot emit correct code.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02005845 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02005846 bool workaround_lod_array_shadow_as_grad =
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02005847 ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005848 image_is_comparison(imgtype, img) && args.lod != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005849
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005850 if (args.dref)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005851 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005852 forward = forward && should_forward(args.dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005853
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005854 // SPIR-V splits dref and coordinate.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005855 if (args.base.is_gather || args.coord_components == 4) // GLSL also splits the arguments in two. Same for textureGather.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005856 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005857 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005858 farg_str += to_expression(args.coord);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005859 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005860 farg_str += to_expression(args.dref);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005861 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005862 else if (args.base.is_proj)
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02005863 {
5864 // Have to reshuffle so we get vec4(coord, dref, proj), special case.
5865 // Other shading languages splits up the arguments for coord and compare value like SPIR-V.
5866 // The coordinate type for textureProj shadow is always vec4 even for sampler1DShadow.
5867 farg_str += ", vec4(";
5868
5869 if (imgtype.image.dim == Dim1D)
5870 {
5871 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005872 farg_str += to_enclosed_expression(args.coord) + ".x";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02005873 farg_str += ", ";
5874 farg_str += "0.0, ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005875 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02005876 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005877 farg_str += to_enclosed_expression(args.coord) + ".y)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02005878 }
5879 else if (imgtype.image.dim == Dim2D)
5880 {
5881 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005882 farg_str += to_enclosed_expression(args.coord) + (swizz_func ? ".xy()" : ".xy");
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02005883 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005884 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02005885 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005886 farg_str += to_enclosed_expression(args.coord) + ".z)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02005887 }
5888 else
5889 SPIRV_CROSS_THROW("Invalid type for textureProj with shadow.");
5890 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005891 else
5892 {
5893 // Create a composite which merges coord/dref into a single vector.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005894 auto type = expression_type(args.coord);
5895 type.vecsize = args.coord_components + 1;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005896 farg_str += ", ";
5897 farg_str += type_to_glsl_constructor(type);
5898 farg_str += "(";
5899 farg_str += coord_expr;
5900 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005901 farg_str += to_expression(args.dref);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005902 farg_str += ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005903 }
5904 }
5905 else
5906 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005907 farg_str += ", ";
5908 farg_str += coord_expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005909 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005910
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005911 if (args.grad_x || args.grad_y)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005912 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005913 forward = forward && should_forward(args.grad_x);
5914 forward = forward && should_forward(args.grad_y);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005915 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005916 farg_str += to_expression(args.grad_x);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005917 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005918 farg_str += to_expression(args.grad_y);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005919 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005920
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005921 if (args.lod)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005922 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005923 if (workaround_lod_array_shadow_as_grad)
Robert Konrad3f745032017-03-23 09:55:32 +01005924 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005925 // Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
5926 // Implementing this as plain texture() is not safe on some implementations.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02005927 if (imgtype.image.dim == Dim2D)
5928 farg_str += ", vec2(0.0), vec2(0.0)";
5929 else if (imgtype.image.dim == DimCube)
5930 farg_str += ", vec3(0.0), vec3(0.0)";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005931 }
5932 else
5933 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005934 if (check_explicit_lod_allowed(args.lod))
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005935 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005936 forward = forward && should_forward(args.lod);
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005937 farg_str += ", ";
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02005938
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005939 auto &lod_expr_type = expression_type(args.lod);
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02005940
5941 // Lod expression for TexelFetch in GLSL must be int, and only int.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005942 if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms &&
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02005943 lod_expr_type.basetype != SPIRType::Int)
5944 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005945 farg_str += join("int(", to_expression(args.lod), ")");
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02005946 }
5947 else
5948 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005949 farg_str += to_expression(args.lod);
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02005950 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02005951 }
Robert Konrad3f745032017-03-23 09:55:32 +01005952 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005953 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005954 else if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms)
Hans-Kristian Arntzend93807a2018-04-30 10:53:21 +02005955 {
5956 // Lod argument is optional in OpImageFetch, but we require a LOD value, pick 0 as the default.
5957 farg_str += ", 0";
5958 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005959
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005960 if (args.coffset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005961 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005962 forward = forward && should_forward(args.coffset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005963 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005964 farg_str += to_expression(args.coffset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005965 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005966 else if (args.offset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005967 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005968 forward = forward && should_forward(args.offset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005969 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005970 farg_str += to_expression(args.offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005971 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005972
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005973 if (args.sample)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005974 {
5975 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005976 farg_str += to_expression(args.sample);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005977 }
5978
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005979 if (args.min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005980 {
5981 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005982 farg_str += to_expression(args.min_lod);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005983 }
5984
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005985 if (args.sparse_texel)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005986 {
5987 // Sparse texel output parameter comes after everything else, except it's before the optional, component/bias arguments.
5988 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005989 farg_str += to_expression(args.sparse_texel);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005990 }
5991
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005992 if (args.bias)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005993 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005994 forward = forward && should_forward(args.bias);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05005995 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005996 farg_str += to_expression(args.bias);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005997 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005998
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02005999 if (args.component)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006000 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006001 forward = forward && should_forward(args.component);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006002 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006003 farg_str += to_expression(args.component);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006004 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006005
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006006 *p_forward = forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006007
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006008 return farg_str;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006009}
6010
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006011void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t length)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006012{
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02006013 auto op = static_cast<GLSLstd450>(eop);
6014
6015 if (is_legacy() && is_unsigned_glsl_opcode(op))
6016 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy GLSL targets.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006017
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006018 // If we need to do implicit bitcasts, make sure we do it with the correct type.
6019 uint32_t integer_width = get_integer_width_for_glsl_instruction(op, args, length);
6020 auto int_type = to_signed_basetype(integer_width);
6021 auto uint_type = to_unsigned_basetype(integer_width);
6022
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006023 switch (op)
6024 {
6025 // FP fiddling
6026 case GLSLstd450Round:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006027 emit_unary_func_op(result_type, id, args[0], "round");
6028 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006029
6030 case GLSLstd450RoundEven:
6031 if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
6032 emit_unary_func_op(result_type, id, args[0], "roundEven");
6033 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006034 SPIRV_CROSS_THROW("roundEven supported only in ESSL 300 and GLSL 130 and up.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006035 break;
6036
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006037 case GLSLstd450Trunc:
6038 emit_unary_func_op(result_type, id, args[0], "trunc");
6039 break;
6040 case GLSLstd450SAbs:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006041 emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type);
6042 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006043 case GLSLstd450FAbs:
6044 emit_unary_func_op(result_type, id, args[0], "abs");
6045 break;
6046 case GLSLstd450SSign:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006047 emit_unary_func_op_cast(result_type, id, args[0], "sign", int_type, int_type);
6048 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006049 case GLSLstd450FSign:
6050 emit_unary_func_op(result_type, id, args[0], "sign");
6051 break;
6052 case GLSLstd450Floor:
6053 emit_unary_func_op(result_type, id, args[0], "floor");
6054 break;
6055 case GLSLstd450Ceil:
6056 emit_unary_func_op(result_type, id, args[0], "ceil");
6057 break;
6058 case GLSLstd450Fract:
6059 emit_unary_func_op(result_type, id, args[0], "fract");
6060 break;
6061 case GLSLstd450Radians:
6062 emit_unary_func_op(result_type, id, args[0], "radians");
6063 break;
6064 case GLSLstd450Degrees:
6065 emit_unary_func_op(result_type, id, args[0], "degrees");
6066 break;
6067 case GLSLstd450Fma:
Hans-Kristian Arntzen3ca8bc52019-04-08 10:33:34 +02006068 if ((!options.es && options.version < 400) || (options.es && options.version < 320))
6069 {
6070 auto expr = join(to_enclosed_expression(args[0]), " * ", to_enclosed_expression(args[1]), " + ",
6071 to_enclosed_expression(args[2]));
6072
6073 emit_op(result_type, id, expr,
6074 should_forward(args[0]) && should_forward(args[1]) && should_forward(args[2]));
6075 for (uint32_t i = 0; i < 3; i++)
6076 inherit_expression_dependencies(id, args[i]);
6077 }
6078 else
6079 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006080 break;
6081 case GLSLstd450Modf:
6082 register_call_out_argument(args[1]);
6083 forced_temporaries.insert(id);
6084 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
6085 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006086
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006087 case GLSLstd450ModfStruct:
6088 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006089 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02006090 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006091 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
6092 to_expression(id), ".", to_member_name(type, 1), ");");
6093 break;
6094 }
6095
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006096 // Minmax
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006097 case GLSLstd450UMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006098 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", uint_type, false);
6099 break;
6100
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006101 case GLSLstd450SMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006102 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", int_type, false);
6103 break;
6104
6105 case GLSLstd450FMin:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006106 emit_binary_func_op(result_type, id, args[0], args[1], "min");
6107 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006109 case GLSLstd450FMax:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006110 emit_binary_func_op(result_type, id, args[0], args[1], "max");
6111 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006112
6113 case GLSLstd450UMax:
6114 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", uint_type, false);
6115 break;
6116
6117 case GLSLstd450SMax:
6118 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", int_type, false);
6119 break;
6120
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006121 case GLSLstd450FClamp:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006122 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
6123 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006124
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006125 case GLSLstd450UClamp:
6126 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", uint_type);
6127 break;
6128
6129 case GLSLstd450SClamp:
6130 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", int_type);
6131 break;
6132
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006133 // Trig
6134 case GLSLstd450Sin:
6135 emit_unary_func_op(result_type, id, args[0], "sin");
6136 break;
6137 case GLSLstd450Cos:
6138 emit_unary_func_op(result_type, id, args[0], "cos");
6139 break;
6140 case GLSLstd450Tan:
6141 emit_unary_func_op(result_type, id, args[0], "tan");
6142 break;
6143 case GLSLstd450Asin:
6144 emit_unary_func_op(result_type, id, args[0], "asin");
6145 break;
6146 case GLSLstd450Acos:
6147 emit_unary_func_op(result_type, id, args[0], "acos");
6148 break;
6149 case GLSLstd450Atan:
6150 emit_unary_func_op(result_type, id, args[0], "atan");
6151 break;
6152 case GLSLstd450Sinh:
6153 emit_unary_func_op(result_type, id, args[0], "sinh");
6154 break;
6155 case GLSLstd450Cosh:
6156 emit_unary_func_op(result_type, id, args[0], "cosh");
6157 break;
6158 case GLSLstd450Tanh:
6159 emit_unary_func_op(result_type, id, args[0], "tanh");
6160 break;
6161 case GLSLstd450Asinh:
6162 emit_unary_func_op(result_type, id, args[0], "asinh");
6163 break;
6164 case GLSLstd450Acosh:
6165 emit_unary_func_op(result_type, id, args[0], "acosh");
6166 break;
6167 case GLSLstd450Atanh:
6168 emit_unary_func_op(result_type, id, args[0], "atanh");
6169 break;
6170 case GLSLstd450Atan2:
6171 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
6172 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006173
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006174 // Exponentials
6175 case GLSLstd450Pow:
6176 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
6177 break;
6178 case GLSLstd450Exp:
6179 emit_unary_func_op(result_type, id, args[0], "exp");
6180 break;
6181 case GLSLstd450Log:
6182 emit_unary_func_op(result_type, id, args[0], "log");
6183 break;
6184 case GLSLstd450Exp2:
6185 emit_unary_func_op(result_type, id, args[0], "exp2");
6186 break;
6187 case GLSLstd450Log2:
6188 emit_unary_func_op(result_type, id, args[0], "log2");
6189 break;
6190 case GLSLstd450Sqrt:
6191 emit_unary_func_op(result_type, id, args[0], "sqrt");
6192 break;
6193 case GLSLstd450InverseSqrt:
6194 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
6195 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006196
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006197 // Matrix math
6198 case GLSLstd450Determinant:
6199 emit_unary_func_op(result_type, id, args[0], "determinant");
6200 break;
6201 case GLSLstd450MatrixInverse:
6202 emit_unary_func_op(result_type, id, args[0], "inverse");
6203 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006204
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006205 // Lerping
6206 case GLSLstd450FMix:
6207 case GLSLstd450IMix:
6208 {
6209 emit_mix_op(result_type, id, args[0], args[1], args[2]);
6210 break;
6211 }
6212 case GLSLstd450Step:
6213 emit_binary_func_op(result_type, id, args[0], args[1], "step");
6214 break;
6215 case GLSLstd450SmoothStep:
6216 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
6217 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006218
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006219 // Packing
6220 case GLSLstd450Frexp:
6221 register_call_out_argument(args[1]);
6222 forced_temporaries.insert(id);
6223 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
6224 break;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006225
6226 case GLSLstd450FrexpStruct:
6227 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006228 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02006229 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006230 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
6231 to_expression(id), ".", to_member_name(type, 1), ");");
6232 break;
6233 }
6234
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006235 case GLSLstd450Ldexp:
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02006236 {
6237 bool forward = should_forward(args[0]) && should_forward(args[1]);
6238
6239 auto op0 = to_unpacked_expression(args[0]);
6240 auto op1 = to_unpacked_expression(args[1]);
6241 auto &op1_type = expression_type(args[1]);
6242 if (op1_type.basetype != SPIRType::Int)
6243 {
6244 // Need a value cast here.
6245 auto target_type = op1_type;
6246 target_type.basetype = SPIRType::Int;
6247 op1 = join(type_to_glsl_constructor(target_type), "(", op1, ")");
6248 }
6249
6250 auto expr = join("ldexp(", op0, ", ", op1, ")");
6251
6252 emit_op(result_type, id, expr, forward);
6253 inherit_expression_dependencies(id, args[0]);
6254 inherit_expression_dependencies(id, args[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006255 break;
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02006256 }
6257
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006258 case GLSLstd450PackSnorm4x8:
6259 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
6260 break;
6261 case GLSLstd450PackUnorm4x8:
6262 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
6263 break;
6264 case GLSLstd450PackSnorm2x16:
6265 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
6266 break;
6267 case GLSLstd450PackUnorm2x16:
6268 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
6269 break;
6270 case GLSLstd450PackHalf2x16:
6271 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
6272 break;
6273 case GLSLstd450UnpackSnorm4x8:
6274 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
6275 break;
6276 case GLSLstd450UnpackUnorm4x8:
6277 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
6278 break;
6279 case GLSLstd450UnpackSnorm2x16:
6280 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
6281 break;
6282 case GLSLstd450UnpackUnorm2x16:
6283 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
6284 break;
6285 case GLSLstd450UnpackHalf2x16:
6286 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
6287 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006288
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006289 case GLSLstd450PackDouble2x32:
6290 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
6291 break;
6292 case GLSLstd450UnpackDouble2x32:
6293 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
6294 break;
6295
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006296 // Vector math
6297 case GLSLstd450Length:
6298 emit_unary_func_op(result_type, id, args[0], "length");
6299 break;
6300 case GLSLstd450Distance:
6301 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
6302 break;
6303 case GLSLstd450Cross:
6304 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
6305 break;
6306 case GLSLstd450Normalize:
6307 emit_unary_func_op(result_type, id, args[0], "normalize");
6308 break;
6309 case GLSLstd450FaceForward:
6310 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
6311 break;
6312 case GLSLstd450Reflect:
6313 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
6314 break;
6315 case GLSLstd450Refract:
6316 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
6317 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006318
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006319 // Bit-fiddling
6320 case GLSLstd450FindILsb:
Hans-Kristian Arntzen932ee0e2019-07-12 10:57:56 +02006321 // findLSB always returns int.
6322 emit_unary_func_op_cast(result_type, id, args[0], "findLSB", expression_type(args[0]).basetype, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006323 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006324
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006325 case GLSLstd450FindSMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006326 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", int_type, int_type);
6327 break;
6328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006329 case GLSLstd450FindUMsb:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006330 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type,
6331 int_type); // findMSB always returns int.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006332 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006334 // Multisampled varying
6335 case GLSLstd450InterpolateAtCentroid:
6336 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
6337 break;
6338 case GLSLstd450InterpolateAtSample:
6339 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
6340 break;
6341 case GLSLstd450InterpolateAtOffset:
6342 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
6343 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006344
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02006345 case GLSLstd450NMin:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02006346 case GLSLstd450NMax:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01006347 {
6348 emit_nminmax_op(result_type, id, args[0], args[1], op);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02006349 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01006350 }
6351
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02006352 case GLSLstd450NClamp:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01006353 {
6354 // Make sure we have a unique ID here to avoid aliasing the extra sub-expressions between clamp and NMin sub-op.
6355 // IDs cannot exceed 24 bits, so we can make use of the higher bits for some unique flags.
6356 uint32_t &max_id = extra_sub_expressions[id | 0x80000000u];
6357 if (!max_id)
6358 max_id = ir.increase_bound_by(1);
6359
6360 // Inherit precision qualifiers.
6361 ir.meta[max_id] = ir.meta[id];
6362
6363 emit_nminmax_op(result_type, max_id, args[0], args[1], GLSLstd450NMax);
6364 emit_nminmax_op(result_type, id, max_id, args[2], GLSLstd450NMin);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02006365 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01006366 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02006367
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006368 default:
6369 statement("// unimplemented GLSL op ", eop);
6370 break;
6371 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006372}
6373
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01006374void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op)
6375{
6376 // Need to emulate this call.
6377 uint32_t &ids = extra_sub_expressions[id];
6378 if (!ids)
6379 {
6380 ids = ir.increase_bound_by(5);
6381 auto btype = get<SPIRType>(result_type);
6382 btype.basetype = SPIRType::Boolean;
6383 set<SPIRType>(ids, btype);
6384 }
6385
6386 uint32_t btype_id = ids + 0;
6387 uint32_t left_nan_id = ids + 1;
6388 uint32_t right_nan_id = ids + 2;
6389 uint32_t tmp_id = ids + 3;
6390 uint32_t mixed_first_id = ids + 4;
6391
6392 // Inherit precision qualifiers.
6393 ir.meta[tmp_id] = ir.meta[id];
6394 ir.meta[mixed_first_id] = ir.meta[id];
6395
6396 emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
6397 emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
6398 emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max");
6399 emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id);
6400 emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id);
6401}
6402
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006403void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
6404 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01006405{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02006406 require_extension_internal("GL_AMD_shader_ballot");
Lou Kramer6671f522017-11-21 14:04:57 +01006407
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006408 enum AMDShaderBallot
6409 {
Lou Kramer6671f522017-11-21 14:04:57 +01006410 SwizzleInvocationsAMD = 1,
6411 SwizzleInvocationsMaskedAMD = 2,
6412 WriteInvocationAMD = 3,
6413 MbcntAMD = 4
6414 };
6415
6416 auto op = static_cast<AMDShaderBallot>(eop);
6417
6418 switch (op)
6419 {
6420 case SwizzleInvocationsAMD:
6421 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01006422 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01006423 break;
6424
6425 case SwizzleInvocationsMaskedAMD:
6426 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsMaskedAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01006427 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01006428 break;
6429
6430 case WriteInvocationAMD:
6431 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "writeInvocationAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01006432 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01006433 break;
6434
6435 case MbcntAMD:
6436 emit_unary_func_op(result_type, id, args[0], "mbcntAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01006437 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01006438 break;
6439
6440 default:
6441 statement("// unimplemented SPV AMD shader ballot op ", eop);
6442 break;
6443 }
6444}
6445
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006446void CompilerGLSL::emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t id, uint32_t eop,
6447 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01006448{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02006449 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Lou Kramer6671f522017-11-21 14:04:57 +01006450
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006451 enum AMDShaderExplicitVertexParameter
6452 {
Lou Kramer6671f522017-11-21 14:04:57 +01006453 InterpolateAtVertexAMD = 1
6454 };
6455
6456 auto op = static_cast<AMDShaderExplicitVertexParameter>(eop);
6457
6458 switch (op)
6459 {
6460 case InterpolateAtVertexAMD:
6461 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtVertexAMD");
6462 break;
6463
6464 default:
6465 statement("// unimplemented SPV AMD shader explicit vertex parameter op ", eop);
6466 break;
6467 }
6468}
6469
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006470void CompilerGLSL::emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t id, uint32_t eop,
6471 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01006472{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02006473 require_extension_internal("GL_AMD_shader_trinary_minmax");
Lou Kramer6671f522017-11-21 14:04:57 +01006474
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006475 enum AMDShaderTrinaryMinMax
6476 {
Lou Kramer6671f522017-11-21 14:04:57 +01006477 FMin3AMD = 1,
6478 UMin3AMD = 2,
6479 SMin3AMD = 3,
6480 FMax3AMD = 4,
6481 UMax3AMD = 5,
6482 SMax3AMD = 6,
6483 FMid3AMD = 7,
6484 UMid3AMD = 8,
6485 SMid3AMD = 9
6486 };
6487
6488 auto op = static_cast<AMDShaderTrinaryMinMax>(eop);
6489
6490 switch (op)
6491 {
6492 case FMin3AMD:
6493 case UMin3AMD:
6494 case SMin3AMD:
6495 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "min3");
6496 break;
6497
6498 case FMax3AMD:
6499 case UMax3AMD:
6500 case SMax3AMD:
6501 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "max3");
6502 break;
6503
6504 case FMid3AMD:
6505 case UMid3AMD:
6506 case SMid3AMD:
6507 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mid3");
6508 break;
6509
6510 default:
6511 statement("// unimplemented SPV AMD shader trinary minmax op ", eop);
6512 break;
6513 }
6514}
6515
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006516void CompilerGLSL::emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
6517 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01006518{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02006519 require_extension_internal("GL_AMD_gcn_shader");
Lou Kramer6671f522017-11-21 14:04:57 +01006520
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006521 enum AMDGCNShader
6522 {
Lou Kramer6671f522017-11-21 14:04:57 +01006523 CubeFaceIndexAMD = 1,
6524 CubeFaceCoordAMD = 2,
6525 TimeAMD = 3
6526 };
6527
6528 auto op = static_cast<AMDGCNShader>(eop);
6529
6530 switch (op)
6531 {
6532 case CubeFaceIndexAMD:
6533 emit_unary_func_op(result_type, id, args[0], "cubeFaceIndexAMD");
6534 break;
6535 case CubeFaceCoordAMD:
6536 emit_unary_func_op(result_type, id, args[0], "cubeFaceCoordAMD");
6537 break;
6538 case TimeAMD:
6539 {
6540 string expr = "timeAMD()";
6541 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01006542 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01006543 break;
6544 }
6545
6546 default:
6547 statement("// unimplemented SPV AMD gcn shader op ", eop);
6548 break;
6549 }
6550}
6551
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006552void CompilerGLSL::emit_subgroup_op(const Instruction &i)
6553{
6554 const uint32_t *ops = stream(i);
6555 auto op = static_cast<Op>(i.op);
6556
6557 if (!options.vulkan_semantics)
6558 SPIRV_CROSS_THROW("Can only use subgroup operations in Vulkan semantics.");
6559
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01006560 // If we need to do implicit bitcasts, make sure we do it with the correct type.
6561 uint32_t integer_width = get_integer_width_for_instruction(i);
6562 auto int_type = to_signed_basetype(integer_width);
6563 auto uint_type = to_unsigned_basetype(integer_width);
6564
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006565 switch (op)
6566 {
6567 case OpGroupNonUniformElect:
6568 require_extension_internal("GL_KHR_shader_subgroup_basic");
6569 break;
6570
6571 case OpGroupNonUniformBroadcast:
6572 case OpGroupNonUniformBroadcastFirst:
6573 case OpGroupNonUniformBallot:
6574 case OpGroupNonUniformInverseBallot:
6575 case OpGroupNonUniformBallotBitExtract:
6576 case OpGroupNonUniformBallotBitCount:
6577 case OpGroupNonUniformBallotFindLSB:
6578 case OpGroupNonUniformBallotFindMSB:
6579 require_extension_internal("GL_KHR_shader_subgroup_ballot");
6580 break;
6581
6582 case OpGroupNonUniformShuffle:
6583 case OpGroupNonUniformShuffleXor:
6584 require_extension_internal("GL_KHR_shader_subgroup_shuffle");
6585 break;
6586
6587 case OpGroupNonUniformShuffleUp:
6588 case OpGroupNonUniformShuffleDown:
6589 require_extension_internal("GL_KHR_shader_subgroup_shuffle_relative");
6590 break;
6591
6592 case OpGroupNonUniformAll:
6593 case OpGroupNonUniformAny:
6594 case OpGroupNonUniformAllEqual:
6595 require_extension_internal("GL_KHR_shader_subgroup_vote");
6596 break;
6597
6598 case OpGroupNonUniformFAdd:
6599 case OpGroupNonUniformFMul:
6600 case OpGroupNonUniformFMin:
6601 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006602 case OpGroupNonUniformIAdd:
6603 case OpGroupNonUniformIMul:
6604 case OpGroupNonUniformSMin:
6605 case OpGroupNonUniformSMax:
6606 case OpGroupNonUniformUMin:
6607 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006608 case OpGroupNonUniformBitwiseAnd:
6609 case OpGroupNonUniformBitwiseOr:
6610 case OpGroupNonUniformBitwiseXor:
6611 {
6612 auto operation = static_cast<GroupOperation>(ops[3]);
6613 if (operation == GroupOperationClusteredReduce)
6614 {
6615 require_extension_internal("GL_KHR_shader_subgroup_clustered");
6616 }
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02006617 else if (operation == GroupOperationExclusiveScan || operation == GroupOperationInclusiveScan ||
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006618 operation == GroupOperationReduce)
6619 {
6620 require_extension_internal("GL_KHR_shader_subgroup_arithmetic");
6621 }
6622 else
6623 SPIRV_CROSS_THROW("Invalid group operation.");
6624 break;
6625 }
6626
6627 case OpGroupNonUniformQuadSwap:
6628 case OpGroupNonUniformQuadBroadcast:
6629 require_extension_internal("GL_KHR_shader_subgroup_quad");
6630 break;
6631
6632 default:
6633 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
6634 }
6635
6636 uint32_t result_type = ops[0];
6637 uint32_t id = ops[1];
6638
6639 auto scope = static_cast<Scope>(get<SPIRConstant>(ops[2]).scalar());
6640 if (scope != ScopeSubgroup)
6641 SPIRV_CROSS_THROW("Only subgroup scope is supported.");
6642
6643 switch (op)
6644 {
6645 case OpGroupNonUniformElect:
6646 emit_op(result_type, id, "subgroupElect()", true);
6647 break;
6648
6649 case OpGroupNonUniformBroadcast:
6650 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBroadcast");
6651 break;
6652
6653 case OpGroupNonUniformBroadcastFirst:
6654 emit_unary_func_op(result_type, id, ops[3], "subgroupBroadcastFirst");
6655 break;
6656
6657 case OpGroupNonUniformBallot:
6658 emit_unary_func_op(result_type, id, ops[3], "subgroupBallot");
6659 break;
6660
6661 case OpGroupNonUniformInverseBallot:
6662 emit_unary_func_op(result_type, id, ops[3], "subgroupInverseBallot");
6663 break;
6664
6665 case OpGroupNonUniformBallotBitExtract:
6666 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBallotBitExtract");
6667 break;
6668
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006669 case OpGroupNonUniformBallotFindLSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006670 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindLSB");
6671 break;
6672
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006673 case OpGroupNonUniformBallotFindMSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006674 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindMSB");
6675 break;
6676
6677 case OpGroupNonUniformBallotBitCount:
6678 {
6679 auto operation = static_cast<GroupOperation>(ops[3]);
6680 if (operation == GroupOperationReduce)
6681 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotBitCount");
6682 else if (operation == GroupOperationInclusiveScan)
6683 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotInclusiveBitCount");
6684 else if (operation == GroupOperationExclusiveScan)
6685 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotExclusiveBitCount");
6686 else
6687 SPIRV_CROSS_THROW("Invalid BitCount operation.");
6688 break;
6689 }
6690
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006691 case OpGroupNonUniformShuffle:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006692 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffle");
6693 break;
6694
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006695 case OpGroupNonUniformShuffleXor:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006696 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleXor");
6697 break;
6698
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006699 case OpGroupNonUniformShuffleUp:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006700 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleUp");
6701 break;
6702
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006703 case OpGroupNonUniformShuffleDown:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006704 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleDown");
6705 break;
6706
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006707 case OpGroupNonUniformAll:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006708 emit_unary_func_op(result_type, id, ops[3], "subgroupAll");
6709 break;
6710
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006711 case OpGroupNonUniformAny:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006712 emit_unary_func_op(result_type, id, ops[3], "subgroupAny");
6713 break;
6714
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006715 case OpGroupNonUniformAllEqual:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006716 emit_unary_func_op(result_type, id, ops[3], "subgroupAllEqual");
6717 break;
6718
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02006719 // clang-format off
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02006720#define GLSL_GROUP_OP(op, glsl_op) \
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006721case OpGroupNonUniform##op: \
6722 { \
6723 auto operation = static_cast<GroupOperation>(ops[3]); \
6724 if (operation == GroupOperationReduce) \
6725 emit_unary_func_op(result_type, id, ops[4], "subgroup" #glsl_op); \
6726 else if (operation == GroupOperationInclusiveScan) \
6727 emit_unary_func_op(result_type, id, ops[4], "subgroupInclusive" #glsl_op); \
6728 else if (operation == GroupOperationExclusiveScan) \
6729 emit_unary_func_op(result_type, id, ops[4], "subgroupExclusive" #glsl_op); \
6730 else if (operation == GroupOperationClusteredReduce) \
6731 emit_binary_func_op(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op); \
6732 else \
6733 SPIRV_CROSS_THROW("Invalid group operation."); \
6734 break; \
6735 }
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01006736
6737#define GLSL_GROUP_OP_CAST(op, glsl_op, type) \
6738case OpGroupNonUniform##op: \
6739 { \
6740 auto operation = static_cast<GroupOperation>(ops[3]); \
6741 if (operation == GroupOperationReduce) \
6742 emit_unary_func_op_cast(result_type, id, ops[4], "subgroup" #glsl_op, type, type); \
6743 else if (operation == GroupOperationInclusiveScan) \
6744 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupInclusive" #glsl_op, type, type); \
6745 else if (operation == GroupOperationExclusiveScan) \
6746 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupExclusive" #glsl_op, type, type); \
6747 else if (operation == GroupOperationClusteredReduce) \
6748 emit_binary_func_op_cast_clustered(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op, type); \
6749 else \
6750 SPIRV_CROSS_THROW("Invalid group operation."); \
6751 break; \
6752 }
6753
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02006754 GLSL_GROUP_OP(FAdd, Add)
6755 GLSL_GROUP_OP(FMul, Mul)
6756 GLSL_GROUP_OP(FMin, Min)
6757 GLSL_GROUP_OP(FMax, Max)
6758 GLSL_GROUP_OP(IAdd, Add)
6759 GLSL_GROUP_OP(IMul, Mul)
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01006760 GLSL_GROUP_OP_CAST(SMin, Min, int_type)
6761 GLSL_GROUP_OP_CAST(SMax, Max, int_type)
6762 GLSL_GROUP_OP_CAST(UMin, Min, uint_type)
6763 GLSL_GROUP_OP_CAST(UMax, Max, uint_type)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02006764 GLSL_GROUP_OP(BitwiseAnd, And)
6765 GLSL_GROUP_OP(BitwiseOr, Or)
6766 GLSL_GROUP_OP(BitwiseXor, Xor)
6767#undef GLSL_GROUP_OP
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01006768#undef GLSL_GROUP_OP_CAST
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02006769 // clang-format on
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006770
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006771 case OpGroupNonUniformQuadSwap:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006772 {
6773 uint32_t direction = get<SPIRConstant>(ops[4]).scalar();
6774 if (direction == 0)
6775 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapHorizontal");
6776 else if (direction == 1)
6777 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapVertical");
6778 else if (direction == 2)
6779 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapDiagonal");
6780 else
6781 SPIRV_CROSS_THROW("Invalid quad swap direction.");
6782 break;
6783 }
6784
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006785 case OpGroupNonUniformQuadBroadcast:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02006786 {
6787 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupQuadBroadcast");
6788 break;
6789 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02006790
6791 default:
6792 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
6793 }
6794
6795 register_control_dependent_expression(id);
6796}
6797
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006798string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006799{
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02006800 // OpBitcast can deal with pointers.
6801 if (out_type.pointer || in_type.pointer)
6802 return type_to_glsl(out_type);
6803
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01006804 if (out_type.basetype == in_type.basetype)
6805 return "";
6806
Chip Davisef0b1fc2019-01-30 20:19:05 -06006807 assert(out_type.basetype != SPIRType::Boolean);
6808 assert(in_type.basetype != SPIRType::Boolean);
6809
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01006810 bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
6811 bool same_size_cast = out_type.width == in_type.width;
6812
6813 // Trivial bitcast case, casts between integers.
6814 if (integral_cast && same_size_cast)
Chip Davis0d949e12018-11-05 14:55:56 -06006815 return type_to_glsl(out_type);
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01006816
6817 // Catch-all 8-bit arithmetic casts (GL_EXT_shader_explicit_arithmetic_types).
6818 if (out_type.width == 8 && in_type.width >= 16 && integral_cast && in_type.vecsize == 1)
6819 return "unpack8";
6820 else if (in_type.width == 8 && out_type.width == 16 && integral_cast && out_type.vecsize == 1)
6821 return "pack16";
6822 else if (in_type.width == 8 && out_type.width == 32 && integral_cast && out_type.vecsize == 1)
6823 return "pack32";
6824
6825 // Floating <-> Integer special casts. Just have to enumerate all cases. :(
6826 // 16-bit, 32-bit and 64-bit floats.
6827 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006828 {
6829 if (is_legacy_es())
6830 SPIRV_CROSS_THROW("Float -> Uint bitcast not supported on legacy ESSL.");
6831 else if (!options.es && options.version < 330)
6832 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006833 return "floatBitsToUint";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006834 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006835 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006836 {
6837 if (is_legacy_es())
6838 SPIRV_CROSS_THROW("Float -> Int bitcast not supported on legacy ESSL.");
6839 else if (!options.es && options.version < 330)
6840 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006841 return "floatBitsToInt";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006842 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006843 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006844 {
6845 if (is_legacy_es())
6846 SPIRV_CROSS_THROW("Uint -> Float bitcast not supported on legacy ESSL.");
6847 else if (!options.es && options.version < 330)
6848 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006849 return "uintBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006850 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006851 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006852 {
6853 if (is_legacy_es())
6854 SPIRV_CROSS_THROW("Int -> Float bitcast not supported on legacy ESSL.");
6855 else if (!options.es && options.version < 330)
6856 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006857 return "intBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02006858 }
6859
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02006860 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
6861 return "doubleBitsToInt64";
6862 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
6863 return "doubleBitsToUint64";
6864 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
6865 return "int64BitsToDouble";
6866 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
6867 return "uint64BitsToDouble";
Chip Davis0d949e12018-11-05 14:55:56 -06006868 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Half)
6869 return "float16BitsToInt16";
6870 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half)
6871 return "float16BitsToUint16";
6872 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Short)
6873 return "int16BitsToFloat16";
6874 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
6875 return "uint16BitsToFloat16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01006876
6877 // And finally, some even more special purpose casts.
6878 if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
Lou Kramer6671f522017-11-21 14:04:57 +01006879 return "packUint2x32";
Asuka55dfbea2020-04-17 22:46:06 +08006880 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UInt64 && out_type.vecsize == 2)
6881 return "unpackUint2x32";
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01006882 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
6883 return "unpackFloat2x16";
6884 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)
6885 return "packFloat2x16";
Chip Davis0d949e12018-11-05 14:55:56 -06006886 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Short && in_type.vecsize == 2)
6887 return "packInt2x16";
6888 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int && in_type.vecsize == 1)
6889 return "unpackInt2x16";
6890 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UShort && in_type.vecsize == 2)
6891 return "packUint2x16";
6892 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
6893 return "unpackUint2x16";
6894 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Short && in_type.vecsize == 4)
6895 return "packInt4x16";
6896 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int64 && in_type.vecsize == 1)
6897 return "unpackInt4x16";
6898 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UShort && in_type.vecsize == 4)
6899 return "packUint4x16";
6900 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt64 && in_type.vecsize == 1)
6901 return "unpackUint4x16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01006902
6903 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006904}
6905
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006906string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006907{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006908 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006909 if (op.empty())
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006910 return to_enclosed_unpacked_expression(argument);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006911 else
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006912 return join(op, "(", to_unpacked_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006913}
6914
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006915std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg)
6916{
6917 auto expr = to_expression(arg);
6918 auto &src_type = expression_type(arg);
6919 if (src_type.basetype != target_type)
6920 {
6921 auto target = src_type;
6922 target.basetype = target_type;
6923 expr = join(bitcast_glsl_op(target, src_type), "(", expr, ")");
6924 }
6925
6926 return expr;
6927}
6928
6929std::string CompilerGLSL::bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type,
6930 const std::string &expr)
6931{
6932 if (target_type.basetype == expr_type)
6933 return expr;
6934
6935 auto src_type = target_type;
6936 src_type.basetype = expr_type;
6937 return join(bitcast_glsl_op(target_type, src_type), "(", expr, ")");
6938}
6939
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02006940string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006941{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006942 switch (builtin)
6943 {
6944 case BuiltInPosition:
6945 return "gl_Position";
6946 case BuiltInPointSize:
6947 return "gl_PointSize";
Bill Hollingse73e8e42016-12-17 17:07:53 -05006948 case BuiltInClipDistance:
6949 return "gl_ClipDistance";
Hans-Kristian Arntzen7f2e1792017-03-05 12:44:29 +01006950 case BuiltInCullDistance:
6951 return "gl_CullDistance";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006952 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006953 if (options.vulkan_semantics)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006954 SPIRV_CROSS_THROW(
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006955 "Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006956 return "gl_VertexID";
6957 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006958 if (options.vulkan_semantics)
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02006959 {
6960 auto model = get_entry_point().model;
6961 switch (model)
6962 {
6963 case spv::ExecutionModelIntersectionKHR:
6964 case spv::ExecutionModelAnyHitKHR:
6965 case spv::ExecutionModelClosestHitKHR:
6966 // gl_InstanceID is allowed in these shaders.
6967 break;
6968
6969 default:
6970 SPIRV_CROSS_THROW(
6971 "Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
6972 }
6973 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006974 return "gl_InstanceID";
6975 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006976 if (options.vulkan_semantics)
6977 return "gl_VertexIndex";
6978 else
6979 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006980 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006981 if (options.vulkan_semantics)
6982 return "gl_InstanceIndex";
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02006983 else if (options.vertex.support_nonzero_base_instance)
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02006984 {
6985 if (!options.vulkan_semantics)
6986 {
6987 // This is a soft-enable. We will opt-in to using gl_BaseInstanceARB if supported.
6988 require_extension_internal("GL_ARB_shader_draw_parameters");
6989 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006990 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02006991 }
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02006992 else
6993 return "gl_InstanceID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006994 case BuiltInPrimitiveId:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02006995 if (storage == StorageClassInput && get_entry_point().model == ExecutionModelGeometry)
6996 return "gl_PrimitiveIDIn";
6997 else
6998 return "gl_PrimitiveID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006999 case BuiltInInvocationId:
7000 return "gl_InvocationID";
7001 case BuiltInLayer:
7002 return "gl_Layer";
Hans-Kristian Arntzenf825bd92018-01-04 12:41:25 +01007003 case BuiltInViewportIndex:
7004 return "gl_ViewportIndex";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007005 case BuiltInTessLevelOuter:
7006 return "gl_TessLevelOuter";
7007 case BuiltInTessLevelInner:
7008 return "gl_TessLevelInner";
7009 case BuiltInTessCoord:
7010 return "gl_TessCoord";
7011 case BuiltInFragCoord:
7012 return "gl_FragCoord";
7013 case BuiltInPointCoord:
7014 return "gl_PointCoord";
7015 case BuiltInFrontFacing:
7016 return "gl_FrontFacing";
7017 case BuiltInFragDepth:
7018 return "gl_FragDepth";
7019 case BuiltInNumWorkgroups:
7020 return "gl_NumWorkGroups";
7021 case BuiltInWorkgroupSize:
7022 return "gl_WorkGroupSize";
7023 case BuiltInWorkgroupId:
7024 return "gl_WorkGroupID";
7025 case BuiltInLocalInvocationId:
7026 return "gl_LocalInvocationID";
7027 case BuiltInGlobalInvocationId:
7028 return "gl_GlobalInvocationID";
7029 case BuiltInLocalInvocationIndex:
7030 return "gl_LocalInvocationIndex";
Hans-Kristian Arntzen61f1d8b2018-11-28 15:18:43 +01007031 case BuiltInHelperInvocation:
7032 return "gl_HelperInvocation";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007033
Chip Davisfcad0192018-08-28 13:47:29 -05007034 case BuiltInBaseVertex:
7035 if (options.es)
7036 SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007037
7038 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05007039 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007040 if (options.version < 460)
7041 {
7042 require_extension_internal("GL_ARB_shader_draw_parameters");
7043 return "gl_BaseVertexARB";
7044 }
7045 return "gl_BaseVertex";
Chip Davisfcad0192018-08-28 13:47:29 -05007046 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007047 else
7048 {
7049 // On regular GL, this is soft-enabled and we emit ifdefs in code.
7050 require_extension_internal("GL_ARB_shader_draw_parameters");
7051 return "SPIRV_Cross_BaseVertex";
7052 }
7053 break;
7054
Chip Davisfcad0192018-08-28 13:47:29 -05007055 case BuiltInBaseInstance:
7056 if (options.es)
7057 SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007058
7059 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05007060 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007061 if (options.version < 460)
7062 {
7063 require_extension_internal("GL_ARB_shader_draw_parameters");
7064 return "gl_BaseInstanceARB";
7065 }
7066 return "gl_BaseInstance";
Chip Davisfcad0192018-08-28 13:47:29 -05007067 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007068 else
7069 {
7070 // On regular GL, this is soft-enabled and we emit ifdefs in code.
7071 require_extension_internal("GL_ARB_shader_draw_parameters");
7072 return "SPIRV_Cross_BaseInstance";
7073 }
7074 break;
7075
Chip Davisfcad0192018-08-28 13:47:29 -05007076 case BuiltInDrawIndex:
7077 if (options.es)
7078 SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007079
7080 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05007081 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007082 if (options.version < 460)
7083 {
7084 require_extension_internal("GL_ARB_shader_draw_parameters");
7085 return "gl_DrawIDARB";
7086 }
7087 return "gl_DrawID";
7088 }
7089 else
7090 {
7091 // On regular GL, this is soft-enabled and we emit ifdefs in code.
Chip Davisfcad0192018-08-28 13:47:29 -05007092 require_extension_internal("GL_ARB_shader_draw_parameters");
7093 return "gl_DrawIDARB";
7094 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007095 break;
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007096
7097 case BuiltInSampleId:
7098 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007099 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007100 if (!options.es && options.version < 400)
7101 SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
7102 return "gl_SampleID";
7103
7104 case BuiltInSampleMask:
7105 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007106 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007107 if (!options.es && options.version < 400)
7108 SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
7109
7110 if (storage == StorageClassInput)
7111 return "gl_SampleMaskIn";
7112 else
7113 return "gl_SampleMask";
7114
7115 case BuiltInSamplePosition:
7116 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007117 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007118 if (!options.es && options.version < 400)
7119 SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
7120 return "gl_SamplePosition";
7121
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02007122 case BuiltInViewIndex:
7123 if (options.vulkan_semantics)
7124 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007125 require_extension_internal("GL_EXT_multiview");
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02007126 return "gl_ViewIndex";
7127 }
7128 else
7129 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007130 require_extension_internal("GL_OVR_multiview2");
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02007131 return "gl_ViewID_OVR";
7132 }
7133
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007134 case BuiltInNumSubgroups:
7135 if (!options.vulkan_semantics)
7136 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7137 require_extension_internal("GL_KHR_shader_subgroup_basic");
7138 return "gl_NumSubgroups";
7139
7140 case BuiltInSubgroupId:
7141 if (!options.vulkan_semantics)
7142 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7143 require_extension_internal("GL_KHR_shader_subgroup_basic");
7144 return "gl_SubgroupID";
7145
7146 case BuiltInSubgroupSize:
7147 if (!options.vulkan_semantics)
7148 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7149 require_extension_internal("GL_KHR_shader_subgroup_basic");
7150 return "gl_SubgroupSize";
7151
7152 case BuiltInSubgroupLocalInvocationId:
7153 if (!options.vulkan_semantics)
7154 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7155 require_extension_internal("GL_KHR_shader_subgroup_basic");
7156 return "gl_SubgroupInvocationID";
7157
7158 case BuiltInSubgroupEqMask:
7159 if (!options.vulkan_semantics)
7160 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7161 require_extension_internal("GL_KHR_shader_subgroup_ballot");
7162 return "gl_SubgroupEqMask";
7163
7164 case BuiltInSubgroupGeMask:
7165 if (!options.vulkan_semantics)
7166 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7167 require_extension_internal("GL_KHR_shader_subgroup_ballot");
7168 return "gl_SubgroupGeMask";
7169
7170 case BuiltInSubgroupGtMask:
7171 if (!options.vulkan_semantics)
7172 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7173 require_extension_internal("GL_KHR_shader_subgroup_ballot");
7174 return "gl_SubgroupGtMask";
7175
7176 case BuiltInSubgroupLeMask:
7177 if (!options.vulkan_semantics)
7178 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7179 require_extension_internal("GL_KHR_shader_subgroup_ballot");
7180 return "gl_SubgroupLeMask";
7181
7182 case BuiltInSubgroupLtMask:
7183 if (!options.vulkan_semantics)
7184 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
7185 require_extension_internal("GL_KHR_shader_subgroup_ballot");
7186 return "gl_SubgroupLtMask";
7187
Patrick Moursda39a7b2019-02-26 15:43:03 +01007188 case BuiltInLaunchIdNV:
7189 return "gl_LaunchIDNV";
7190 case BuiltInLaunchSizeNV:
7191 return "gl_LaunchSizeNV";
7192 case BuiltInWorldRayOriginNV:
7193 return "gl_WorldRayOriginNV";
7194 case BuiltInWorldRayDirectionNV:
7195 return "gl_WorldRayDirectionNV";
7196 case BuiltInObjectRayOriginNV:
7197 return "gl_ObjectRayOriginNV";
7198 case BuiltInObjectRayDirectionNV:
7199 return "gl_ObjectRayDirectionNV";
7200 case BuiltInRayTminNV:
7201 return "gl_RayTminNV";
7202 case BuiltInRayTmaxNV:
7203 return "gl_RayTmaxNV";
7204 case BuiltInInstanceCustomIndexNV:
7205 return "gl_InstanceCustomIndexNV";
7206 case BuiltInObjectToWorldNV:
7207 return "gl_ObjectToWorldNV";
7208 case BuiltInWorldToObjectNV:
7209 return "gl_WorldToObjectNV";
7210 case BuiltInHitTNV:
7211 return "gl_HitTNV";
7212 case BuiltInHitKindNV:
7213 return "gl_HitKindNV";
7214 case BuiltInIncomingRayFlagsNV:
7215 return "gl_IncomingRayFlagsNV";
7216
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02007217 case BuiltInBaryCoordNV:
7218 {
7219 if (options.es && options.version < 320)
7220 SPIRV_CROSS_THROW("gl_BaryCoordNV requires ESSL 320.");
7221 else if (!options.es && options.version < 450)
7222 SPIRV_CROSS_THROW("gl_BaryCoordNV requires GLSL 450.");
7223 require_extension_internal("GL_NV_fragment_shader_barycentric");
7224 return "gl_BaryCoordNV";
7225 }
7226
7227 case BuiltInBaryCoordNoPerspNV:
7228 {
7229 if (options.es && options.version < 320)
7230 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires ESSL 320.");
7231 else if (!options.es && options.version < 450)
7232 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires GLSL 450.");
7233 require_extension_internal("GL_NV_fragment_shader_barycentric");
7234 return "gl_BaryCoordNoPerspNV";
7235 }
7236
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +02007237 case BuiltInFragStencilRefEXT:
7238 {
7239 if (!options.es)
7240 {
7241 require_extension_internal("GL_ARB_shader_stencil_export");
7242 return "gl_FragStencilRefARB";
7243 }
7244 else
7245 SPIRV_CROSS_THROW("Stencil export not supported in GLES.");
7246 }
7247
Chip Davis6a585542019-07-12 21:50:50 -05007248 case BuiltInDeviceIndex:
7249 if (!options.vulkan_semantics)
7250 SPIRV_CROSS_THROW("Need Vulkan semantics for device group support.");
7251 require_extension_internal("GL_EXT_device_group");
7252 return "gl_DeviceIndex";
7253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007254 default:
Bill Hollingse73e8e42016-12-17 17:07:53 -05007255 return join("gl_BuiltIn_", convert_to_string(builtin));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007256 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007257}
7258
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007259const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007260{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007261 switch (index)
7262 {
7263 case 0:
7264 return "x";
7265 case 1:
7266 return "y";
7267 case 2:
7268 return "z";
7269 case 3:
7270 return "w";
7271 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01007272 SPIRV_CROSS_THROW("Swizzle index out of range");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007273 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007274}
7275
Lukas Hermanns6673a672019-10-22 11:06:16 -04007276void CompilerGLSL::access_chain_internal_append_index(std::string &expr, uint32_t /*base*/, const SPIRType *type,
7277 AccessChainFlags flags, bool & /*access_chain_is_arrayed*/,
7278 uint32_t index)
7279{
7280 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
7281 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
7282
7283 expr += "[";
7284
7285 // If we are indexing into an array of SSBOs or UBOs, we need to index it with a non-uniform qualifier.
7286 bool nonuniform_index =
7287 has_decoration(index, DecorationNonUniformEXT) &&
7288 (has_decoration(type->self, DecorationBlock) || has_decoration(type->self, DecorationBufferBlock));
7289 if (nonuniform_index)
7290 {
7291 expr += backend.nonuniform_qualifier;
7292 expr += "(";
7293 }
7294
7295 if (index_is_literal)
7296 expr += convert_to_string(index);
7297 else
7298 expr += to_expression(index, register_expression_read);
7299
7300 if (nonuniform_index)
7301 expr += ")";
7302
7303 expr += "]";
7304}
7305
Hans-Kristian Arntzeneb5e09f2017-02-23 19:33:14 +01007306string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007307 AccessChainFlags flags, AccessChainMeta *meta)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007308{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007309 string expr;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007310
7311 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007312 bool msb_is_id = (flags & ACCESS_CHAIN_LITERAL_MSB_FORCE_ID) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007313 bool chain_only = (flags & ACCESS_CHAIN_CHAIN_ONLY_BIT) != 0;
7314 bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0;
7315 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
7316
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007317 if (!chain_only)
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02007318 {
7319 // We handle transpose explicitly, so don't resolve that here.
7320 auto *e = maybe_get<SPIRExpression>(base);
7321 bool old_transpose = e && e->need_transpose;
7322 if (e)
7323 e->need_transpose = false;
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007324 expr = to_enclosed_expression(base, register_expression_read);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02007325 if (e)
7326 e->need_transpose = old_transpose;
7327 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007328
Bill Hollings1e84a372017-08-12 00:21:13 -04007329 // Start traversing type hierarchy at the proper non-pointer types,
7330 // but keep type_id referencing the original pointer for use below.
Bill Hollingse0910312018-06-24 15:06:12 -04007331 uint32_t type_id = expression_type_id(base);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02007332
7333 if (!backend.native_pointers)
7334 {
7335 if (ptr_chain)
7336 SPIRV_CROSS_THROW("Backend does not support native pointers and does not support OpPtrAccessChain.");
7337
7338 // Wrapped buffer reference pointer types will need to poke into the internal "value" member before
7339 // continuing the access chain.
7340 if (should_dereference(base))
7341 {
7342 auto &type = get<SPIRType>(type_id);
7343 expr = dereference_expression(type, expr);
7344 }
7345 }
7346
Chip Davisfc02b3d2019-01-08 12:54:40 -06007347 const auto *type = &get_pointee_type(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007348
Hans-Kristian Arntzenb71f5df2018-05-08 15:33:51 +02007349 bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos;
Bill Hollings13583622016-12-14 02:12:52 -05007350 bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02007351 bool is_packed = has_extended_decoration(base, SPIRVCrossDecorationPhysicalTypePacked);
7352 uint32_t physical_type = get_extended_decoration(base, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007353 bool is_invariant = has_decoration(base, DecorationInvariant);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007354 bool pending_array_enclose = false;
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02007355 bool dimension_flatten = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007356
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007357 const auto append_index = [&](uint32_t index, bool is_literal) {
7358 AccessChainFlags mod_flags = flags;
7359 if (!is_literal)
7360 mod_flags &= ~ACCESS_CHAIN_INDEX_IS_LITERAL_BIT;
7361 access_chain_internal_append_index(expr, base, type, mod_flags, access_chain_is_arrayed, index);
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02007362 };
7363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007364 for (uint32_t i = 0; i < count; i++)
7365 {
7366 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007367
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007368 bool is_literal = index_is_literal;
7369 if (is_literal && msb_is_id && (index >> 31u) != 0u)
7370 {
7371 is_literal = false;
7372 index &= 0x7fffffffu;
7373 }
7374
Chip Davis3bfb2f92018-12-03 02:06:33 -06007375 // Pointer chains
7376 if (ptr_chain && i == 0)
7377 {
7378 // If we are flattening multidimensional arrays, only create opening bracket on first
7379 // array index.
7380 if (options.flatten_multidimensional_arrays)
7381 {
7382 dimension_flatten = type->array.size() >= 1;
7383 pending_array_enclose = dimension_flatten;
7384 if (pending_array_enclose)
7385 expr += "[";
7386 }
7387
7388 if (options.flatten_multidimensional_arrays && dimension_flatten)
7389 {
7390 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007391 if (is_literal)
Chip Davis3bfb2f92018-12-03 02:06:33 -06007392 expr += convert_to_string(index);
7393 else
7394 expr += to_enclosed_expression(index, register_expression_read);
7395
7396 for (auto j = uint32_t(type->array.size()); j; j--)
7397 {
7398 expr += " * ";
7399 expr += enclose_expression(to_array_size(*type, j - 1));
7400 }
7401
7402 if (type->array.empty())
7403 pending_array_enclose = false;
7404 else
7405 expr += " + ";
7406
7407 if (!pending_array_enclose)
7408 expr += "]";
7409 }
7410 else
7411 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007412 append_index(index, is_literal);
Chip Davis3bfb2f92018-12-03 02:06:33 -06007413 }
7414
Chip Davise75add42019-02-05 18:13:26 -06007415 if (type->basetype == SPIRType::ControlPointArray)
7416 {
7417 type_id = type->parent_type;
7418 type = &get<SPIRType>(type_id);
7419 }
7420
Chip Davis3bfb2f92018-12-03 02:06:33 -06007421 access_chain_is_arrayed = true;
7422 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007423 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06007424 else if (!type->array.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007425 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007426 // If we are flattening multidimensional arrays, only create opening bracket on first
7427 // array index.
7428 if (options.flatten_multidimensional_arrays && !pending_array_enclose)
7429 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02007430 dimension_flatten = type->array.size() > 1;
7431 pending_array_enclose = dimension_flatten;
7432 if (pending_array_enclose)
7433 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007434 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007435
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01007436 assert(type->parent_type);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007437
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007438 auto *var = maybe_get<SPIRVariable>(base);
Bill Hollings27d4af72018-01-08 16:18:34 -05007439 if (backend.force_gl_in_out_block && i == 0 && var && is_builtin_variable(*var) &&
7440 !has_decoration(type->self, DecorationBlock))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007441 {
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007442 // This deals with scenarios for tesc/geom where arrays of gl_Position[] are declared.
7443 // Normally, these variables live in blocks when compiled from GLSL,
7444 // but HLSL seems to just emit straight arrays here.
7445 // We must pretend this access goes through gl_in/gl_out arrays
7446 // to be able to access certain builtins as arrays.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02007447 auto builtin = ir.meta[base].decoration.builtin_type;
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007448 switch (builtin)
7449 {
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01007450 // case BuiltInCullDistance: // These are already arrays, need to figure out rules for these in tess/geom.
7451 // case BuiltInClipDistance:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007452 case BuiltInPosition:
7453 case BuiltInPointSize:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007454 if (var->storage == StorageClassInput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007455 expr = join("gl_in[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007456 else if (var->storage == StorageClassOutput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007457 expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007458 else
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007459 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007460 break;
7461
7462 default:
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007463 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007464 break;
7465 }
7466 }
7467 else if (options.flatten_multidimensional_arrays && dimension_flatten)
7468 {
7469 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007470 auto &parent_type = get<SPIRType>(type->parent_type);
7471
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007472 if (is_literal)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007473 expr += convert_to_string(index);
7474 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007475 expr += to_enclosed_expression(index, register_expression_read);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007476
7477 for (auto j = uint32_t(parent_type.array.size()); j; j--)
7478 {
7479 expr += " * ";
7480 expr += enclose_expression(to_array_size(parent_type, j - 1));
7481 }
7482
7483 if (parent_type.array.empty())
7484 pending_array_enclose = false;
7485 else
7486 expr += " + ";
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01007487
7488 if (!pending_array_enclose)
7489 expr += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007490 }
Hans-Kristian Arntzen9d18c822019-10-24 17:10:22 +02007491 // Some builtins are arrays in SPIR-V but not in other languages, e.g. gl_SampleMask[] is an array in SPIR-V but not in Metal.
7492 // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask.
7493 else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn))))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007494 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007495 append_index(index, is_literal);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007496 }
7497
Bill Hollings1e84a372017-08-12 00:21:13 -04007498 type_id = type->parent_type;
7499 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007500
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007501 access_chain_is_arrayed = true;
7502 }
7503 // For structs, the index refers to a constant, which indexes into the members.
7504 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
7505 else if (type->basetype == SPIRType::Struct)
7506 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007507 if (!is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007508 index = get<SPIRConstant>(index).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007509
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007510 if (index >= type->member_types.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01007511 SPIRV_CROSS_THROW("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007512
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007513 BuiltIn builtin;
7514 if (is_member_builtin(*type, index, &builtin))
7515 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007516 if (access_chain_is_arrayed)
7517 {
7518 expr += ".";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007519 expr += builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007520 }
7521 else
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007522 expr = builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007523 }
7524 else
7525 {
Bill Hollingsc1b81542017-05-22 21:41:19 -04007526 // If the member has a qualified name, use it as the entire chain
Bill Hollings1e84a372017-08-12 00:21:13 -04007527 string qual_mbr_name = get_member_qualified_name(type_id, index);
Bill Hollingsc1b81542017-05-22 21:41:19 -04007528 if (!qual_mbr_name.empty())
7529 expr = qual_mbr_name;
7530 else
Chip Davis3bfb2f92018-12-03 02:06:33 -06007531 expr += to_member_reference(base, *type, index, ptr_chain);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007532 }
Bill Hollingsb332bae2017-03-01 13:07:40 -05007533
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007534 if (has_member_decoration(type->self, index, DecorationInvariant))
7535 is_invariant = true;
7536
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02007537 is_packed = member_is_packed_physical_type(*type, index);
Hans-Kristian Arntzenf6251e42019-07-19 11:21:02 +02007538 if (member_is_remapped_physical_type(*type, index))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02007539 physical_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01007540 else
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02007541 physical_type = 0;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01007542
Bill Hollings13583622016-12-14 02:12:52 -05007543 row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007544 type = &get<SPIRType>(type->member_types[index]);
7545 }
7546 // Matrix -> Vector
7547 else if (type->columns > 1)
7548 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02007549 // If we have a row-major matrix here, we need to defer any transpose in case this access chain
7550 // is used to store a column. We can resolve it right here and now if we access a scalar directly,
7551 // by flipping indexing order of the matrix.
Bill Hollings343677e2016-12-11 11:01:08 -05007552
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007553 expr += "[";
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007554 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007555 expr += convert_to_string(index);
7556 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007557 expr += to_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007558 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007559
Bill Hollings1e84a372017-08-12 00:21:13 -04007560 type_id = type->parent_type;
7561 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007562 }
7563 // Vector -> Scalar
7564 else if (type->vecsize > 1)
7565 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02007566 string deferred_index;
7567 if (row_major_matrix_needs_conversion)
7568 {
7569 // Flip indexing order.
7570 auto column_index = expr.find_last_of('[');
7571 if (column_index != string::npos)
7572 {
7573 deferred_index = expr.substr(column_index);
7574 expr.resize(column_index);
7575 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02007576 }
7577
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007578 if (is_literal && !is_packed && !row_major_matrix_needs_conversion)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007579 {
7580 expr += ".";
7581 expr += index_to_swizzle(index);
7582 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02007583 else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007584 {
7585 auto &c = get<SPIRConstant>(index);
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02007586 if (c.specialization)
7587 {
7588 // If the index is a spec constant, we cannot turn extract into a swizzle.
7589 expr += join("[", to_expression(index), "]");
7590 }
7591 else
7592 {
7593 expr += ".";
7594 expr += index_to_swizzle(c.scalar());
7595 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007596 }
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01007597 else if (is_literal)
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01007598 {
7599 // For packed vectors, we can only access them as an array, not by swizzle.
7600 expr += join("[", index, "]");
7601 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007602 else
7603 {
7604 expr += "[";
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007605 expr += to_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007606 expr += "]";
7607 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007608
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02007609 expr += deferred_index;
7610 row_major_matrix_needs_conversion = false;
7611
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01007612 is_packed = false;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02007613 physical_type = 0;
Bill Hollings1e84a372017-08-12 00:21:13 -04007614 type_id = type->parent_type;
7615 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007616 }
Bill Hollings2964e322018-02-13 14:44:40 -05007617 else if (!backend.allow_truncated_access_chain)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01007618 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007619 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007620
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007621 if (pending_array_enclose)
7622 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02007623 SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
7624 "but the access chain was terminated in the middle of a multidimensional array. "
7625 "This is not supported.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007626 }
7627
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007628 if (meta)
7629 {
7630 meta->need_transpose = row_major_matrix_needs_conversion;
7631 meta->storage_is_packed = is_packed;
7632 meta->storage_is_invariant = is_invariant;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02007633 meta->storage_physical_type = physical_type;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007634 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05007635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007636 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007637}
7638
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01007639string CompilerGLSL::to_flattened_struct_member(const SPIRVariable &var, uint32_t index)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01007640{
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01007641 auto &type = get<SPIRType>(var.basetype);
7642 return sanitize_underscores(join(to_name(var.self), "_", to_member_name(type, index)));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01007643}
7644
Bill Hollings2d0d3282017-01-20 11:33:59 -05007645string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
Chip Davis3bfb2f92018-12-03 02:06:33 -06007646 AccessChainMeta *meta, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007647{
Arseny Kapoulkine24c66252017-01-16 14:19:49 -08007648 if (flattened_buffer_blocks.count(base))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007649 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02007650 uint32_t matrix_stride = 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007651 uint32_t array_stride = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02007652 bool need_transpose = false;
Chip Davis3bfb2f92018-12-03 02:06:33 -06007653 flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007654 &array_stride, ptr_chain);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007655
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007656 if (meta)
7657 {
7658 meta->need_transpose = target_type.columns > 1 && need_transpose;
7659 meta->storage_is_packed = false;
7660 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007661
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01007662 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, array_stride,
7663 need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007664 }
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01007665 else if (flattened_structs.count(base) && count > 0)
7666 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007667 AccessChainFlags flags = ACCESS_CHAIN_CHAIN_ONLY_BIT | ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
7668 if (ptr_chain)
7669 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
7670
7671 auto chain = access_chain_internal(base, indices, count, flags, nullptr).substr(1);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007672 if (meta)
7673 {
7674 meta->need_transpose = false;
7675 meta->storage_is_packed = false;
7676 }
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01007677 return sanitize_underscores(join(to_name(base), "_", chain));
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01007678 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007679 else
7680 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007681 AccessChainFlags flags = ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
7682 if (ptr_chain)
7683 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
7684 return access_chain_internal(base, indices, count, flags, meta);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007685 }
7686}
7687
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01007688string CompilerGLSL::load_flattened_struct(SPIRVariable &var)
7689{
7690 auto expr = type_to_glsl_constructor(get<SPIRType>(var.basetype));
7691 expr += '(';
7692
7693 auto &type = get<SPIRType>(var.basetype);
7694 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
7695 {
7696 if (i)
7697 expr += ", ";
7698
7699 // Flatten the varyings.
7700 // Apply name transformation for flattened I/O blocks.
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01007701 expr += to_flattened_struct_member(var, i);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01007702 }
7703 expr += ')';
7704 return expr;
7705}
7706
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01007707void CompilerGLSL::store_flattened_struct(SPIRVariable &var, uint32_t value)
7708{
7709 // We're trying to store a structure which has been flattened.
7710 // Need to copy members one by one.
7711 auto rhs = to_expression(value);
7712
7713 // Store result locally.
7714 // Since we're declaring a variable potentially multiple times here,
7715 // store the variable in an isolated scope.
7716 begin_scope();
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01007717 statement(variable_decl_function_local(var), " = ", rhs, ";");
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01007718
7719 auto &type = get<SPIRType>(var.basetype);
7720 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
7721 {
7722 // Flatten the varyings.
7723 // Apply name transformation for flattened I/O blocks.
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01007724
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01007725 auto lhs = sanitize_underscores(join(to_name(var.self), "_", to_member_name(type, i)));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01007726 rhs = join(to_name(var.self), ".", to_member_name(type, i));
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01007727 statement(lhs, " = ", rhs, ";");
7728 }
7729 end_scope();
7730}
7731
Bill Hollings2d0d3282017-01-20 11:33:59 -05007732std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007733 const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007734 uint32_t /* array_stride */, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007735{
7736 if (!target_type.array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007737 SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007738 else if (target_type.basetype == SPIRType::Struct)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007739 return flattened_access_chain_struct(base, indices, count, target_type, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007740 else if (target_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007741 return flattened_access_chain_matrix(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007742 else
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007743 return flattened_access_chain_vector(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007744}
7745
Bill Hollings2d0d3282017-01-20 11:33:59 -05007746std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
7747 const SPIRType &target_type, uint32_t offset)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007748{
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007749 std::string expr;
7750
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01007751 expr += type_to_glsl_constructor(target_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007752 expr += "(";
7753
Henrik Rydgårdbfae0412017-03-07 09:59:26 +01007754 for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007755 {
7756 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08007757 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007758
7759 const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007760 uint32_t member_offset = type_struct_member_offset(target_type, i);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007761
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007762 // The access chain terminates at the struct, so we need to find matrix strides and row-major information
7763 // ahead of time.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007764 bool need_transpose = false;
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007765 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007766 if (member_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007767 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01007768 need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007769 matrix_stride = type_struct_member_matrix_stride(target_type, i);
7770 }
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007771
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007772 auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007773 0 /* array_stride */, need_transpose);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007774
7775 // Cannot forward transpositions, so resolve them here.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007776 if (need_transpose)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02007777 expr += convert_row_major_matrix(tmp, member_type, 0, false);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007778 else
7779 expr += tmp;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007780 }
7781
7782 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007783
7784 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007785}
7786
Bill Hollings2d0d3282017-01-20 11:33:59 -05007787std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007788 const SPIRType &target_type, uint32_t offset,
7789 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007790{
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007791 assert(matrix_stride);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007792 SPIRType tmp_type = target_type;
7793 if (need_transpose)
7794 swap(tmp_type.vecsize, tmp_type.columns);
7795
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007796 std::string expr;
7797
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007798 expr += type_to_glsl_constructor(tmp_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007799 expr += "(";
7800
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007801 for (uint32_t i = 0; i < tmp_type.columns; i++)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007802 {
7803 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08007804 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007805
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007806 expr += flattened_access_chain_vector(base, indices, count, tmp_type, offset + i * matrix_stride, matrix_stride,
7807 /* need_transpose= */ false);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007808 }
7809
7810 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007811
7812 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007813}
7814
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007815std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
7816 const SPIRType &target_type, uint32_t offset,
7817 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007818{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02007819 auto result = flattened_access_chain_offset(expression_type(base), indices, count, offset, 16);
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007820
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007821 auto buffer_name = to_name(expression_type(base).self);
7822
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007823 if (need_transpose)
7824 {
7825 std::string expr;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007826
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08007827 if (target_type.vecsize > 1)
7828 {
7829 expr += type_to_glsl_constructor(target_type);
7830 expr += "(";
7831 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007832
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007833 for (uint32_t i = 0; i < target_type.vecsize; ++i)
7834 {
7835 if (i != 0)
7836 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007837
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007838 uint32_t component_offset = result.second + i * matrix_stride;
7839
7840 assert(component_offset % (target_type.width / 8) == 0);
7841 uint32_t index = component_offset / (target_type.width / 8);
7842
7843 expr += buffer_name;
7844 expr += "[";
7845 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
7846 expr += convert_to_string(index / 4);
7847 expr += "]";
7848
7849 expr += vector_swizzle(1, index % 4);
7850 }
7851
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08007852 if (target_type.vecsize > 1)
7853 {
7854 expr += ")";
7855 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08007856
7857 return expr;
7858 }
7859 else
7860 {
7861 assert(result.second % (target_type.width / 8) == 0);
7862 uint32_t index = result.second / (target_type.width / 8);
7863
7864 std::string expr;
7865
7866 expr += buffer_name;
7867 expr += "[";
7868 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
7869 expr += convert_to_string(index / 4);
7870 expr += "]";
7871
7872 expr += vector_swizzle(target_type.vecsize, index % 4);
7873
7874 return expr;
7875 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007876}
7877
Chip Davis3bfb2f92018-12-03 02:06:33 -06007878std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(
7879 const SPIRType &basetype, const uint32_t *indices, uint32_t count, uint32_t offset, uint32_t word_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007880 bool *need_transpose, uint32_t *out_matrix_stride, uint32_t *out_array_stride, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007881{
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01007882 // Start traversing type hierarchy at the proper non-pointer types.
Chip Davisfc02b3d2019-01-08 12:54:40 -06007883 const auto *type = &get_pointee_type(basetype);
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01007884
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007885 std::string expr;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02007886
7887 // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout.
7888 bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false;
7889 uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007890 uint32_t array_stride = out_array_stride ? *out_array_stride : 0;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08007891
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007892 for (uint32_t i = 0; i < count; i++)
7893 {
7894 uint32_t index = indices[i];
7895
Chip Davis3bfb2f92018-12-03 02:06:33 -06007896 // Pointers
7897 if (ptr_chain && i == 0)
7898 {
7899 // Here, the pointer type will be decorated with an array stride.
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007900 array_stride = get_decoration(basetype.self, DecorationArrayStride);
Chip Davis3bfb2f92018-12-03 02:06:33 -06007901 if (!array_stride)
7902 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
7903
7904 auto *constant = maybe_get<SPIRConstant>(index);
7905 if (constant)
7906 {
7907 // Constant array access.
7908 offset += constant->scalar() * array_stride;
7909 }
7910 else
7911 {
7912 // Dynamic array access.
7913 if (array_stride % word_stride)
7914 {
7915 SPIRV_CROSS_THROW(
7916 "Array stride for dynamic indexing must be divisible by the size of a 4-component vector. "
7917 "Likely culprit here is a float or vec2 array inside a push constant block which is std430. "
7918 "This cannot be flattened. Try using std140 layout instead.");
7919 }
7920
7921 expr += to_enclosed_expression(index);
7922 expr += " * ";
7923 expr += convert_to_string(array_stride / word_stride);
7924 expr += " + ";
7925 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06007926 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007927 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06007928 else if (!type->array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007929 {
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01007930 auto *constant = maybe_get<SPIRConstant>(index);
7931 if (constant)
7932 {
7933 // Constant array access.
7934 offset += constant->scalar() * array_stride;
7935 }
7936 else
7937 {
7938 // Dynamic array access.
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01007939 if (array_stride % word_stride)
7940 {
Hans-Kristian Arntzen87f3c572017-01-21 12:47:26 +01007941 SPIRV_CROSS_THROW(
7942 "Array stride for dynamic indexing must be divisible by the size of a 4-component vector. "
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01007943 "Likely culprit here is a float or vec2 array inside a push constant block which is std430. "
7944 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01007945 }
7946
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007947 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01007948 expr += " * ";
7949 expr += convert_to_string(array_stride / word_stride);
7950 expr += " + ";
7951 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007952
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01007953 uint32_t parent_type = type->parent_type;
7954 type = &get<SPIRType>(parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01007955
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007956 if (!type->array.empty())
7957 array_stride = get_decoration(parent_type, DecorationArrayStride);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007958 }
7959 // For structs, the index refers to a constant, which indexes into the members.
7960 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
7961 else if (type->basetype == SPIRType::Struct)
7962 {
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01007963 index = get<SPIRConstant>(index).scalar();
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007964
7965 if (index >= type->member_types.size())
7966 SPIRV_CROSS_THROW("Member index is out of bounds!");
7967
7968 offset += type_struct_member_offset(*type, index);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01007969
7970 auto &struct_type = *type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007971 type = &get<SPIRType>(type->member_types[index]);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01007972
7973 if (type->columns > 1)
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007974 {
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01007975 matrix_stride = type_struct_member_matrix_stride(struct_type, index);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007976 row_major_matrix_needs_conversion =
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01007977 combined_decoration_for_member(struct_type, index).get(DecorationRowMajor);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01007978 }
7979 else
7980 row_major_matrix_needs_conversion = false;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01007981
7982 if (!type->array.empty())
7983 array_stride = type_struct_member_array_stride(struct_type, index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007984 }
7985 // Matrix -> Vector
7986 else if (type->columns > 1)
7987 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02007988 auto *constant = maybe_get<SPIRConstant>(index);
7989 if (constant)
7990 {
7991 index = get<SPIRConstant>(index).scalar();
7992 offset += index * (row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride);
7993 }
7994 else
7995 {
7996 uint32_t indexing_stride = row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride;
7997 // Dynamic array access.
7998 if (indexing_stride % word_stride)
7999 {
8000 SPIRV_CROSS_THROW(
8001 "Matrix stride for dynamic indexing must be divisible by the size of a 4-component vector. "
8002 "Likely culprit here is a row-major matrix being accessed dynamically. "
8003 "This cannot be flattened. Try using std140 layout instead.");
8004 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008005
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008006 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008007 expr += " * ";
8008 expr += convert_to_string(indexing_stride / word_stride);
8009 expr += " + ";
8010 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008011
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008012 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008013 }
8014 // Vector -> Scalar
8015 else if (type->vecsize > 1)
8016 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008017 auto *constant = maybe_get<SPIRConstant>(index);
8018 if (constant)
8019 {
8020 index = get<SPIRConstant>(index).scalar();
8021 offset += index * (row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8));
8022 }
8023 else
8024 {
8025 uint32_t indexing_stride = row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008026
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008027 // Dynamic array access.
8028 if (indexing_stride % word_stride)
8029 {
8030 SPIRV_CROSS_THROW(
8031 "Stride for dynamic vector indexing must be divisible by the size of a 4-component vector. "
8032 "This cannot be flattened in legacy targets.");
8033 }
8034
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008035 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008036 expr += " * ";
8037 expr += convert_to_string(indexing_stride / word_stride);
8038 expr += " + ";
8039 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008040
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008041 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008042 }
8043 else
8044 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
8045 }
8046
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08008047 if (need_transpose)
8048 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01008049 if (out_matrix_stride)
8050 *out_matrix_stride = matrix_stride;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008051 if (out_array_stride)
8052 *out_array_stride = array_stride;
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08008053
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008054 return std::make_pair(expr, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008055}
8056
Chip Davis3bfb2f92018-12-03 02:06:33 -06008057bool CompilerGLSL::should_dereference(uint32_t id)
8058{
8059 const auto &type = expression_type(id);
8060 // Non-pointer expressions don't need to be dereferenced.
8061 if (!type.pointer)
8062 return false;
8063
8064 // Handles shouldn't be dereferenced either.
8065 if (!expression_is_lvalue(id))
8066 return false;
8067
8068 // If id is a variable but not a phi variable, we should not dereference it.
8069 if (auto *var = maybe_get<SPIRVariable>(id))
8070 return var->phi_variable;
8071
8072 // If id is an access chain, we should not dereference it.
8073 if (auto *expr = maybe_get<SPIRExpression>(id))
8074 return !expr->access_chain;
8075
8076 // Otherwise, we should dereference this pointer expression.
8077 return true;
8078}
8079
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02008080bool CompilerGLSL::should_forward(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008081{
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07008082 // If id is a variable we will try to forward it regardless of force_temporary check below
8083 // This is important because otherwise we'll get local sampler copies (highp sampler2D foo = bar) that are invalid in OpenGL GLSL
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02008084 auto *var = maybe_get<SPIRVariable>(id);
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07008085 if (var && var->forwardable)
8086 return true;
8087
8088 // For debugging emit temporary variables for all expressions
8089 if (options.force_temporary)
8090 return false;
8091
8092 // Immutable expression can always be forwarded.
8093 if (is_immutable(id))
8094 return true;
8095
8096 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008097}
8098
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02008099bool CompilerGLSL::should_suppress_usage_tracking(uint32_t id) const
8100{
8101 // Used only by opcodes which don't do any real "work", they just swizzle data in some fashion.
8102 return !expression_is_forwarded(id) || expression_suppresses_usage_tracking(id);
8103}
8104
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008105void CompilerGLSL::track_expression_read(uint32_t id)
8106{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008107 switch (ir.ids[id].get_type())
8108 {
8109 case TypeExpression:
8110 {
8111 auto &e = get<SPIRExpression>(id);
8112 for (auto implied_read : e.implied_read_expressions)
8113 track_expression_read(implied_read);
8114 break;
8115 }
8116
8117 case TypeAccessChain:
8118 {
8119 auto &e = get<SPIRAccessChain>(id);
8120 for (auto implied_read : e.implied_read_expressions)
8121 track_expression_read(implied_read);
8122 break;
8123 }
8124
8125 default:
8126 break;
8127 }
8128
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008129 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
8130 // In this case, it's better to just bind the complex expression to the temporary and read that temporary twice.
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02008131 if (expression_is_forwarded(id) && !expression_suppresses_usage_tracking(id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008132 {
8133 auto &v = expression_usage_counts[id];
8134 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008135
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008136 if (v >= 2)
8137 {
8138 //if (v == 2)
8139 // fprintf(stderr, "ID %u was forced to temporary due to more than 1 expression use!\n", id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008140
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008141 forced_temporaries.insert(id);
8142 // Force a recompile after this pass to avoid forwarding this variable.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02008143 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008144 }
8145 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008146}
8147
8148bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
8149{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008150 if (forced_temporaries.find(id) != end(forced_temporaries))
8151 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008152
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008153 for (uint32_t i = 0; i < num_args; i++)
8154 if (!should_forward(args[i]))
8155 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008156
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008157 // We need to forward globals as well.
8158 if (!pure)
8159 {
8160 for (auto global : global_variables)
8161 if (!should_forward(global))
8162 return false;
8163 for (auto aliased : aliased_variables)
8164 if (!should_forward(aliased))
8165 return false;
8166 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008167
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008168 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008169}
8170
8171void CompilerGLSL::register_impure_function_call()
8172{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008173 // Impure functions can modify globals and aliased variables, so invalidate them as well.
8174 for (auto global : global_variables)
8175 flush_dependees(get<SPIRVariable>(global));
8176 for (auto aliased : aliased_variables)
8177 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008178}
8179
8180void CompilerGLSL::register_call_out_argument(uint32_t id)
8181{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008182 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008183
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008184 auto *var = maybe_get<SPIRVariable>(id);
8185 if (var)
8186 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008187}
8188
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01008189string CompilerGLSL::variable_decl_function_local(SPIRVariable &var)
8190{
8191 // These variables are always function local,
8192 // so make sure we emit the variable without storage qualifiers.
8193 // Some backends will inject custom variables locally in a function
8194 // with a storage qualifier which is not function-local.
8195 auto old_storage = var.storage;
8196 var.storage = StorageClassFunction;
8197 auto expr = variable_decl(var);
8198 var.storage = old_storage;
8199 return expr;
8200}
8201
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02008202void CompilerGLSL::emit_variable_temporary_copies(const SPIRVariable &var)
8203{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04008204 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen3f569ed2019-10-24 17:12:23 +02008205 if (var.allocate_temporary_copy && !flushed_phi_variables.count(var.self))
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02008206 {
8207 auto &type = get<SPIRType>(var.basetype);
8208 auto &flags = get_decoration_bitset(var.self);
8209 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, join("_", var.self, "_copy")), ";");
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04008210 flushed_phi_variables.insert(var.self);
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02008211 }
8212}
8213
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008214void CompilerGLSL::flush_variable_declaration(uint32_t id)
8215{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04008216 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008217 auto *var = maybe_get<SPIRVariable>(id);
8218 if (var && var->deferred_declaration)
8219 {
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01008220 string initializer;
8221 if (options.force_zero_initialized_variables &&
8222 (var->storage == StorageClassFunction || var->storage == StorageClassGeneric ||
8223 var->storage == StorageClassPrivate) &&
8224 !var->initializer && type_can_zero_initialize(get_variable_data_type(*var)))
8225 {
8226 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(*var)));
8227 }
8228
8229 statement(variable_decl_function_local(*var), initializer, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008230 var->deferred_declaration = false;
8231 }
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04008232 if (var)
8233 {
8234 emit_variable_temporary_copies(*var);
8235 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008236}
8237
8238bool CompilerGLSL::remove_duplicate_swizzle(string &op)
8239{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008240 auto pos = op.find_last_of('.');
8241 if (pos == string::npos || pos == 0)
8242 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008243
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008244 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008245
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008246 if (backend.swizzle_is_function)
8247 {
8248 if (final_swiz.size() < 2)
8249 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008250
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008251 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
8252 final_swiz.erase(final_swiz.size() - 2, string::npos);
8253 else
8254 return false;
8255 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008257 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
8258 // If so, and previous swizzle is of same length,
8259 // we can drop the final swizzle altogether.
8260 for (uint32_t i = 0; i < final_swiz.size(); i++)
8261 {
8262 static const char expected[] = { 'x', 'y', 'z', 'w' };
8263 if (i >= 4 || final_swiz[i] != expected[i])
8264 return false;
8265 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008266
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008267 auto prevpos = op.find_last_of('.', pos - 1);
8268 if (prevpos == string::npos)
8269 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008270
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008271 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008272
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008273 // Make sure there are only swizzles here ...
8274 for (auto i = prevpos; i < pos; i++)
8275 {
8276 if (op[i] < 'w' || op[i] > 'z')
8277 {
8278 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
8279 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
8280 break;
8281 return false;
8282 }
8283 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008284
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008285 // If original swizzle is large enough, just carve out the components we need.
8286 // E.g. foobar.wyx.xy will turn into foobar.wy.
8287 if (pos - prevpos >= final_swiz.size())
8288 {
8289 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008290
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008291 // Add back the function call ...
8292 if (backend.swizzle_is_function)
8293 op += "()";
8294 }
8295 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008296}
8297
8298// Optimizes away vector swizzles where we have something like
8299// vec3 foo;
8300// foo.xyz <-- swizzle expression does nothing.
8301// This is a very common pattern after OpCompositeCombine.
8302bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
8303{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008304 auto pos = op.find_last_of('.');
8305 if (pos == string::npos || pos == 0)
8306 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008307
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008308 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008309
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008310 if (backend.swizzle_is_function)
8311 {
8312 if (final_swiz.size() < 2)
8313 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008315 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
8316 final_swiz.erase(final_swiz.size() - 2, string::npos);
8317 else
8318 return false;
8319 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008320
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008321 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
8322 // If so, and previous swizzle is of same length,
8323 // we can drop the final swizzle altogether.
8324 for (uint32_t i = 0; i < final_swiz.size(); i++)
8325 {
8326 static const char expected[] = { 'x', 'y', 'z', 'w' };
8327 if (i >= 4 || final_swiz[i] != expected[i])
8328 return false;
8329 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008330
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008331 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008332
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008333 // Sanity checking ...
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04008334 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008336 if (type.vecsize == final_swiz.size())
8337 op.erase(pos, string::npos);
8338 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008339}
8340
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01008341string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008342{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02008343 ID base = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008344 string op;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008345 string subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008346
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01008347 // Can only merge swizzles for vectors.
8348 auto &type = get<SPIRType>(return_type);
8349 bool can_apply_swizzle_opt = type.basetype != SPIRType::Struct && type.array.empty() && type.columns == 1;
8350 bool swizzle_optimization = false;
8351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008352 for (uint32_t i = 0; i < length; i++)
8353 {
8354 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008355
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008356 // If we're merging another scalar which belongs to the same base
8357 // object, just merge the swizzles to avoid triggering more than 1 expression read as much as possible!
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01008358 if (can_apply_swizzle_opt && e && e->base_expression && e->base_expression == base)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008359 {
8360 // Only supposed to be used for vector swizzle -> scalar.
8361 assert(!e->expression.empty() && e->expression.front() == '.');
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008362 subop += e->expression.substr(1, string::npos);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008363 swizzle_optimization = true;
8364 }
8365 else
8366 {
8367 // We'll likely end up with duplicated swizzles, e.g.
8368 // foobar.xyz.xyz from patterns like
Bill Hollingsd8d2da92018-01-05 17:46:56 -05008369 // OpVectorShuffle
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008370 // OpCompositeExtract x 3
8371 // OpCompositeConstruct 3x + other scalar.
8372 // Just modify op in-place.
8373 if (swizzle_optimization)
8374 {
8375 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008376 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008377
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008378 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
8379 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
8380 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
8381 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
8382 // Case 1:
8383 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
8384 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
8385 // Case 2:
8386 // foo.xyz: Duplicate swizzle won't kick in.
8387 // If foo is vec3, we can remove xyz, giving just foo.
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008388 if (!remove_duplicate_swizzle(subop))
8389 remove_unity_swizzle(base, subop);
8390
8391 // Strips away redundant parens if we created them during component extraction.
8392 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008393 swizzle_optimization = false;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008394 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008395 }
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008396 else
8397 op += subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008398
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008399 if (i)
8400 op += ", ";
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02008401 subop = to_composite_constructor_expression(elems[i]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008402 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008403
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02008404 base = e ? e->base_expression : ID(0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008405 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008406
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008407 if (swizzle_optimization)
8408 {
8409 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008410 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008411
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008412 if (!remove_duplicate_swizzle(subop))
8413 remove_unity_swizzle(base, subop);
8414 // Strips away redundant parens if we created them during component extraction.
8415 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008416 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008417
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01008418 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008419 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008420}
8421
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02008422bool CompilerGLSL::skip_argument(uint32_t id) const
8423{
8424 if (!combined_image_samplers.empty() || !options.vulkan_semantics)
8425 {
8426 auto &type = expression_type(id);
8427 if (type.basetype == SPIRType::Sampler || (type.basetype == SPIRType::Image && type.image.sampled == 1))
8428 return true;
8429 }
8430 return false;
8431}
8432
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02008433bool CompilerGLSL::optimize_read_modify_write(const SPIRType &type, const string &lhs, const string &rhs)
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01008434{
8435 // Do this with strings because we have a very clear pattern we can check for and it avoids
8436 // adding lots of special cases to the code emission.
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01008437 if (rhs.size() < lhs.size() + 3)
8438 return false;
8439
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02008440 // Do not optimize matrices. They are a bit awkward to reason about in general
8441 // (in which order does operation happen?), and it does not work on MSL anyways.
8442 if (type.vecsize > 1 && type.columns > 1)
8443 return false;
8444
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01008445 auto index = rhs.find(lhs);
8446 if (index != 0)
8447 return false;
8448
8449 // TODO: Shift operators, but it's not important for now.
8450 auto op = rhs.find_first_of("+-/*%|&^", lhs.size() + 1);
8451 if (op != lhs.size() + 1)
8452 return false;
8453
David Srbeckye596d402017-09-05 16:05:53 +01008454 // Check that the op is followed by space. This excludes && and ||.
Hans-Kristian Arntzen03db5c42017-09-06 09:15:27 +02008455 if (rhs[op + 1] != ' ')
David Srbeckye596d402017-09-05 16:05:53 +01008456 return false;
8457
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01008458 char bop = rhs[op];
8459 auto expr = rhs.substr(lhs.size() + 3);
8460 // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code.
8461 // Find some common patterns which are equivalent.
8462 if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)"))
8463 statement(lhs, bop, bop, ";");
8464 else
8465 statement(lhs, " ", bop, "= ", expr, ";");
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01008466 return true;
8467}
8468
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008469void CompilerGLSL::register_control_dependent_expression(uint32_t expr)
8470{
8471 if (forwarded_temporaries.find(expr) == end(forwarded_temporaries))
8472 return;
8473
8474 assert(current_emitting_block);
8475 current_emitting_block->invalidate_expressions.push_back(expr);
8476}
8477
8478void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02008479{
8480 current_emitting_block = &block;
8481 for (auto &op : block.ops)
8482 emit_instruction(op);
8483 current_emitting_block = nullptr;
8484}
8485
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008486void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression &expr)
8487{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02008488 // Allow trivially forwarded expressions like OpLoad or trivial shuffles,
8489 // these will be marked as having suppressed usage tracking.
8490 // Our only concern is to make sure arithmetic operations are done in similar ways.
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02008491 if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) &&
8492 forced_invariant_temporaries.count(expr.self) == 0)
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008493 {
8494 forced_temporaries.insert(expr.self);
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02008495 forced_invariant_temporaries.insert(expr.self);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02008496 force_recompile();
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008497
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02008498 for (auto &dependent : expr.expression_dependencies)
8499 disallow_forwarding_in_expression_chain(get<SPIRExpression>(dependent));
8500 }
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008501}
8502
8503void CompilerGLSL::handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id)
8504{
8505 // Variables or access chains marked invariant are complicated. We will need to make sure the code-gen leading up to
8506 // this variable is consistent. The failure case for SPIRV-Cross is when an expression is forced to a temporary
8507 // in one translation unit, but not another, e.g. due to multiple use of an expression.
8508 // This causes variance despite the output variable being marked invariant, so the solution here is to force all dependent
8509 // expressions to be temporaries.
8510 // It is uncertain if this is enough to support invariant in all possible cases, but it should be good enough
8511 // for all reasonable uses of invariant.
8512 if (!has_decoration(store_id, DecorationInvariant))
8513 return;
8514
8515 auto *expr = maybe_get<SPIRExpression>(value_id);
8516 if (!expr)
8517 return;
8518
8519 disallow_forwarding_in_expression_chain(*expr);
8520}
8521
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01008522void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01008523{
8524 auto rhs = to_pointer_expression(rhs_expression);
8525
8526 // Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
8527 if (!rhs.empty())
8528 {
8529 handle_store_to_invariant_variable(lhs_expression, rhs_expression);
8530
8531 auto lhs = to_dereferenced_expression(lhs_expression);
8532
8533 // We might need to bitcast in order to store to a builtin.
8534 bitcast_to_builtin_store(lhs_expression, rhs, expression_type(rhs_expression));
8535
8536 // Tries to optimize assignments like "<lhs> = <lhs> op expr".
8537 // While this is purely cosmetic, this is important for legacy ESSL where loop
8538 // variable increments must be in either i++ or i += const-expr.
8539 // Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
8540 if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
8541 statement(lhs, " = ", rhs, ";");
8542 register_write(lhs_expression);
8543 }
8544}
8545
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008546uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &instr) const
8547{
8548 if (instr.length < 3)
8549 return 32;
8550
8551 auto *ops = stream(instr);
8552
8553 switch (instr.op)
8554 {
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02008555 case OpSConvert:
8556 case OpConvertSToF:
8557 case OpUConvert:
8558 case OpConvertUToF:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008559 case OpIEqual:
8560 case OpINotEqual:
8561 case OpSLessThan:
8562 case OpSLessThanEqual:
8563 case OpSGreaterThan:
8564 case OpSGreaterThanEqual:
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02008565 case OpULessThan:
8566 case OpULessThanEqual:
8567 case OpUGreaterThan:
8568 case OpUGreaterThanEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008569 return expression_type(ops[2]).width;
8570
8571 default:
8572 {
8573 // We can look at result type which is more robust.
8574 auto *type = maybe_get<SPIRType>(ops[0]);
8575 if (type && type_is_integral(*type))
8576 return type->width;
8577 else
8578 return 32;
8579 }
8580 }
8581}
8582
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01008583uint32_t CompilerGLSL::get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *ops, uint32_t length) const
8584{
8585 if (length < 1)
8586 return 32;
8587
8588 switch (op)
8589 {
8590 case GLSLstd450SAbs:
8591 case GLSLstd450SSign:
8592 case GLSLstd450UMin:
8593 case GLSLstd450SMin:
8594 case GLSLstd450UMax:
8595 case GLSLstd450SMax:
8596 case GLSLstd450UClamp:
8597 case GLSLstd450SClamp:
8598 case GLSLstd450FindSMsb:
8599 case GLSLstd450FindUMsb:
8600 return expression_type(ops[0]).width;
8601
8602 default:
8603 {
8604 // We don't need to care about other opcodes, just return 32.
8605 return 32;
8606 }
8607 }
8608}
8609
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02008610void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008611{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008612 auto ops = stream(instruction);
8613 auto opcode = static_cast<Op>(instruction.op);
8614 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008615
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008616#define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
8617#define GLSL_BOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008618 emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008619#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
8620#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
8621#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
8622#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
8623#define GLSL_BFOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008624 emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008625#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
8626#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008627
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008628 // If we need to do implicit bitcasts, make sure we do it with the correct type.
8629 uint32_t integer_width = get_integer_width_for_instruction(instruction);
8630 auto int_type = to_signed_basetype(integer_width);
8631 auto uint_type = to_unsigned_basetype(integer_width);
8632
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008633 switch (opcode)
8634 {
8635 // Dealing with memory
8636 case OpLoad:
8637 {
8638 uint32_t result_type = ops[0];
8639 uint32_t id = ops[1];
8640 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008641
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008642 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008643
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008644 // If we're loading from memory that cannot be changed by the shader,
8645 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02008646 // If an expression is mutable and forwardable, we speculate that it is immutable.
8647 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
8648
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01008649 // If loading a non-native row-major matrix, mark the expression as need_transpose.
8650 bool need_transpose = false;
8651 bool old_need_transpose = false;
8652
8653 auto *ptr_expression = maybe_get<SPIRExpression>(ptr);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008654
8655 if (forward)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01008656 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008657 // If we're forwarding the load, we're also going to forward transpose state, so don't transpose while
8658 // taking the expression.
8659 if (ptr_expression && ptr_expression->need_transpose)
8660 {
8661 old_need_transpose = true;
8662 ptr_expression->need_transpose = false;
8663 need_transpose = true;
8664 }
8665 else if (is_non_native_row_major_matrix(ptr))
8666 need_transpose = true;
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01008667 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01008668
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008669 // If we are forwarding this load,
8670 // don't register the read to access chain here, defer that to when we actually use the expression,
8671 // using the add_implied_read_expression mechanism.
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008672 string expr;
8673
8674 bool is_packed = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked);
8675 bool is_remapped = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID);
8676 if (forward || (!is_packed && !is_remapped))
8677 {
8678 // For the simple case, we do not need to deal with repacking.
8679 expr = to_dereferenced_expression(ptr, false);
8680 }
8681 else
8682 {
8683 // If we are not forwarding the expression, we need to unpack and resolve any physical type remapping here before
8684 // storing the expression to a temporary.
8685 expr = to_unpacked_expression(ptr);
8686 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01008687
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02008688 // We might need to bitcast in order to load from a builtin.
8689 bitcast_from_builtin_load(ptr, expr, get<SPIRType>(result_type));
8690
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +01008691 // We might be trying to load a gl_Position[N], where we should be
8692 // doing float4[](gl_in[i].gl_Position, ...) instead.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +01008693 // Similar workarounds are required for input arrays in tessellation.
8694 unroll_array_from_complex_load(id, ptr, expr);
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +01008695
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02008696 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02008697 // Shouldn't need to check for ID, but current glslang codegen requires it in some cases
8698 // when loading Image/Sampler descriptors. It does not hurt to check ID as well.
8699 if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ptr, DecorationNonUniformEXT))
8700 {
8701 propagate_nonuniform_qualifier(ptr);
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02008702 convert_non_uniform_expression(type, expr);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02008703 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02008704
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008705 if (forward && ptr_expression)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01008706 ptr_expression->need_transpose = old_need_transpose;
Bill Hollings13583622016-12-14 02:12:52 -05008707
Hans-Kristian Arntzen18b82ca2018-07-09 14:02:50 +02008708 // By default, suppress usage tracking since using same expression multiple times does not imply any extra work.
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +02008709 // However, if we try to load a complex, composite object from a flattened buffer,
8710 // we should avoid emitting the same code over and over and lower the result to a temporary.
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +02008711 bool usage_tracking = ptr_expression && flattened_buffer_blocks.count(ptr_expression->loaded_from) != 0 &&
8712 (type.basetype == SPIRType::Struct || (type.columns > 1));
8713
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02008714 SPIRExpression *e = nullptr;
8715 if (!backend.array_is_value_type && !type.array.empty() && !forward)
8716 {
8717 // Complicated load case where we need to make a copy of ptr, but we cannot, because
8718 // it is an array, and our backend does not support arrays as value types.
8719 // Emit the temporary, and copy it explicitly.
8720 e = &emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +02008721 emit_array_copy(to_expression(id), ptr, StorageClassFunction, get_backing_variable_storage(ptr));
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02008722 }
8723 else
8724 e = &emit_op(result_type, id, expr, forward, !usage_tracking);
8725
8726 e->need_transpose = need_transpose;
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02008727 register_read(id, ptr, forward);
Bill Hollingsd8d2da92018-01-05 17:46:56 -05008728
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008729 if (forward)
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008730 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008731 // Pass through whether the result is of a packed type and the physical type ID.
8732 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked))
8733 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
8734 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID))
8735 {
8736 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID,
8737 get_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID));
8738 }
8739 }
8740 else
8741 {
8742 // This might have been set on an earlier compilation iteration, force it to be unset.
8743 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
8744 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008745 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05008746
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008747 inherit_expression_dependencies(id, ptr);
8748 if (forward)
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02008749 add_implied_read_expression(*e, ptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008750 break;
8751 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008752
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008753 case OpInBoundsAccessChain:
8754 case OpAccessChain:
Chip Davis3bfb2f92018-12-03 02:06:33 -06008755 case OpPtrAccessChain:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008756 {
8757 auto *var = maybe_get<SPIRVariable>(ops[2]);
8758 if (var)
8759 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008760
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008761 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02008762 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008763 AccessChainMeta meta;
Chip Davis3bfb2f92018-12-03 02:06:33 -06008764 bool ptr_chain = opcode == OpPtrAccessChain;
8765 auto e = access_chain(ops[2], &ops[3], length - 3, get<SPIRType>(ops[0]), &meta, ptr_chain);
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +02008766
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02008767 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +02008768
8769 auto *backing_variable = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02008770 expr.loaded_from = backing_variable ? backing_variable->self : ID(ops[2]);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008771 expr.need_transpose = meta.need_transpose;
Chip Davis3bfb2f92018-12-03 02:06:33 -06008772 expr.access_chain = true;
Bill Hollingsd8d2da92018-01-05 17:46:56 -05008773
8774 // Mark the result as being packed. Some platforms handled packed vectors differently than non-packed.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008775 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008776 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypePacked);
8777 if (meta.storage_physical_type != 0)
8778 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008779 if (meta.storage_is_invariant)
8780 set_decoration(ops[1], DecorationInvariant);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008781
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +02008782 // If we have some expression dependencies in our access chain, this access chain is technically a forwarded
8783 // temporary which could be subject to invalidation.
8784 // Need to assume we're forwarded while calling inherit_expression_depdendencies.
8785 forwarded_temporaries.insert(ops[1]);
8786 // The access chain itself is never forced to a temporary, but its dependencies might.
8787 suppressed_usage_tracking.insert(ops[1]);
8788
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008789 for (uint32_t i = 2; i < length; i++)
8790 {
8791 inherit_expression_dependencies(ops[1], ops[i]);
8792 add_implied_read_expression(expr, ops[i]);
8793 }
8794
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +02008795 // If we have no dependencies after all, i.e., all indices in the access chain are immutable temporaries,
8796 // we're not forwarded after all.
8797 if (expr.expression_dependencies.empty())
8798 forwarded_temporaries.erase(ops[1]);
8799
Hans-Kristian Arntzenbdb343e2020-04-21 14:43:26 +02008800 if (has_decoration(ops[1], DecorationNonUniformEXT))
Hans-Kristian Arntzen05004a52020-03-19 12:05:03 +01008801 propagate_nonuniform_qualifier(ops[1]);
8802
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008803 break;
8804 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008806 case OpStore:
8807 {
8808 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008809
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008810 if (var && var->statically_assigned)
8811 var->static_expression = ops[1];
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01008812 else if (var && var->loop_variable && !var->loop_variable_enable)
8813 var->static_expression = ops[1];
Hans-Kristian Arntzend31bc022020-05-28 11:49:28 +02008814 else if (var && var->remapped_variable && var->static_expression)
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02008815 {
8816 // Skip the write.
8817 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008818 else if (var && flattened_structs.count(ops[0]))
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01008819 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008820 store_flattened_struct(*var, ops[1]);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01008821 register_write(ops[0]);
8822 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008823 else
8824 {
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01008825 emit_store_statement(ops[0], ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008826 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01008827
Chip Davis3bfb2f92018-12-03 02:06:33 -06008828 // Storing a pointer results in a variable pointer, so we must conservatively assume
8829 // we can write through it.
8830 if (expression_type(ops[1]).pointer)
8831 register_write(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008832 break;
8833 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008835 case OpArrayLength:
8836 {
8837 uint32_t result_type = ops[0];
8838 uint32_t id = ops[1];
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01008839 auto e = access_chain_internal(ops[2], &ops[3], length - 3, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzenb6f8a202019-05-07 19:02:32 +02008840 set<SPIRExpression>(id, join(type_to_glsl(get<SPIRType>(result_type)), "(", e, ".length())"), result_type,
8841 true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008842 break;
8843 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008845 // Function calls
8846 case OpFunctionCall:
8847 {
8848 uint32_t result_type = ops[0];
8849 uint32_t id = ops[1];
8850 uint32_t func = ops[2];
8851 const auto *arg = &ops[3];
8852 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008853
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008854 auto &callee = get<SPIRFunction>(func);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01008855 auto &return_type = get<SPIRType>(callee.return_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008856 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008858 bool callee_has_out_variables = false;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01008859 bool emit_return_value_as_argument = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008861 // Invalidate out variables passed to functions since they can be OpStore'd to.
8862 for (uint32_t i = 0; i < length; i++)
8863 {
8864 if (callee.arguments[i].write_count)
8865 {
8866 register_call_out_argument(arg[i]);
8867 callee_has_out_variables = true;
8868 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008869
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008870 flush_variable_declaration(arg[i]);
8871 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008872
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01008873 if (!return_type.array.empty() && !backend.can_return_array)
8874 {
8875 callee_has_out_variables = true;
8876 emit_return_value_as_argument = true;
8877 }
8878
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008879 if (!pure)
8880 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008881
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008882 string funexpr;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02008883 SmallVector<string> arglist;
Bill Hollings1c180782017-11-05 21:34:42 -05008884 funexpr += to_name(func) + "(";
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01008885
8886 if (emit_return_value_as_argument)
8887 {
8888 statement(type_to_glsl(return_type), " ", to_name(id), type_to_array_glsl(return_type), ";");
8889 arglist.push_back(to_name(id));
8890 }
8891
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008892 for (uint32_t i = 0; i < length; i++)
8893 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02008894 // Do not pass in separate images or samplers if we're remapping
8895 // to combined image samplers.
8896 if (skip_argument(arg[i]))
8897 continue;
8898
Chip Davis39dce882019-08-02 15:11:19 -05008899 arglist.push_back(to_func_call_arg(callee.arguments[i], arg[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008900 }
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02008901
8902 for (auto &combined : callee.combined_parameters)
8903 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02008904 auto image_id = combined.global_image ? combined.image_id : VariableID(arg[combined.image_id]);
8905 auto sampler_id = combined.global_sampler ? combined.sampler_id : VariableID(arg[combined.sampler_id]);
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02008906 arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02008907 }
Bill Hollingsa759e2c2016-10-19 14:09:51 -07008908
Bill Hollingsac00c602016-10-24 09:24:24 -04008909 append_global_func_args(callee, length, arglist);
Bill Hollingsa759e2c2016-10-19 14:09:51 -07008910
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02008911 funexpr += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008912 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008913
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02008914 // Check for function call constraints.
8915 check_function_call_constraints(arg, length);
8916
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01008917 if (return_type.basetype != SPIRType::Void)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008918 {
8919 // If the function actually writes to an out variable,
8920 // take the conservative route and do not forward.
8921 // The problem is that we might not read the function
8922 // result (and emit the function) before an out variable
8923 // is read (common case when return value is ignored!
8924 // In order to avoid start tracking invalid variables,
8925 // just avoid the forwarding problem altogether.
8926 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
8927 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008928
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01008929 if (emit_return_value_as_argument)
8930 {
8931 statement(funexpr, ";");
8932 set<SPIRExpression>(id, to_name(id), result_type, true);
8933 }
8934 else
8935 emit_op(result_type, id, funexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008936
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008937 // Function calls are implicit loads from all variables in question.
8938 // Set dependencies for them.
8939 for (uint32_t i = 0; i < length; i++)
8940 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008941
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008942 // If we're going to forward the temporary result,
8943 // put dependencies on every variable that must not change.
8944 if (forward)
8945 register_global_read_dependencies(callee, id);
8946 }
8947 else
8948 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008949
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008950 break;
8951 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008952
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008953 // Composite munging
8954 case OpCompositeConstruct:
8955 {
8956 uint32_t result_type = ops[0];
8957 uint32_t id = ops[1];
Hans-Kristian Arntzen9a527132018-03-09 15:26:36 +01008958 const auto *const elems = &ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008959 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008960
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008961 bool forward = true;
8962 for (uint32_t i = 0; i < length; i++)
8963 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008964
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02008965 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02008966 auto *in_type = length > 0 ? &expression_type(elems[0]) : nullptr;
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02008967
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02008968 // Only splat if we have vector constructors.
8969 // Arrays and structs must be initialized properly in full.
8970 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008971
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02008972 bool splat = false;
8973 bool swizzle_splat = false;
8974
8975 if (in_type)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01008976 {
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02008977 splat = in_type->vecsize == 1 && in_type->columns == 1 && !composite && backend.use_constructor_splatting;
8978 swizzle_splat = in_type->vecsize == 1 && in_type->columns == 1 && backend.can_swizzle_scalar;
8979
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02008980 if (ir.ids[elems[0]].get_type() == TypeConstant && !type_is_floating_point(*in_type))
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02008981 {
8982 // Cannot swizzle literal integers as a special case.
8983 swizzle_splat = false;
8984 }
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01008985 }
8986
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01008987 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008988 {
8989 uint32_t input = elems[0];
8990 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01008991 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008992 if (input != elems[i])
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01008993 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008994 splat = false;
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01008995 swizzle_splat = false;
8996 }
8997 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008998 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008999
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01009000 if (out_type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
9001 forward = false;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01009002 if (!out_type.array.empty() && !backend.can_declare_arrays_inline)
9003 forward = false;
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009004 if (type_is_empty(out_type) && !backend.supports_empty_struct)
9005 forward = false;
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01009006
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009007 string constructor_op;
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02009008 if (backend.use_initializer_list && composite)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009009 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009010 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009011 // Only use this path if we are building composites.
9012 // This path cannot be used for arithmetic.
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02009013 if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01009014 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
Hans-Kristian Arntzenc9d4f9c2020-02-24 12:47:14 +01009015 else if (backend.use_typed_initializer_list && backend.array_is_value_type && !out_type.array.empty())
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009016 {
9017 // MSL path. Array constructor is baked into type here, do not use _constructor variant.
9018 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
9019 needs_trailing_tracket = true;
9020 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009021 constructor_op += "{ ";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009022
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009023 if (type_is_empty(out_type) && !backend.supports_empty_struct)
9024 constructor_op += "0";
9025 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02009026 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009027 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009028 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009029 constructor_op += " }";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009030 if (needs_trailing_tracket)
9031 constructor_op += ")";
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009032 }
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01009033 else if (swizzle_splat && !composite)
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01009034 {
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02009035 constructor_op = remap_swizzle(get<SPIRType>(result_type), 1, to_unpacked_expression(elems[0]));
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01009036 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009037 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009038 {
9039 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009040 if (type_is_empty(out_type) && !backend.supports_empty_struct)
9041 constructor_op += "0";
9042 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02009043 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009044 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009045 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009046 constructor_op += ")";
9047 }
9048
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +02009049 if (!constructor_op.empty())
9050 {
9051 emit_op(result_type, id, constructor_op, forward);
9052 for (uint32_t i = 0; i < length; i++)
9053 inherit_expression_dependencies(id, elems[i]);
9054 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009055 break;
9056 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009057
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009058 case OpVectorInsertDynamic:
9059 {
9060 uint32_t result_type = ops[0];
9061 uint32_t id = ops[1];
9062 uint32_t vec = ops[2];
9063 uint32_t comp = ops[3];
9064 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009066 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009067
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009068 // Make a copy, then use access chain to store the variable.
9069 statement(declare_temporary(result_type, id), to_expression(vec), ";");
9070 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009071 auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009072 statement(chain, " = ", to_expression(comp), ";");
9073 break;
9074 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009076 case OpVectorExtractDynamic:
9077 {
9078 uint32_t result_type = ops[0];
9079 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009080
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009081 auto expr = access_chain_internal(ops[2], &ops[3], 1, 0, nullptr);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01009082 emit_op(result_type, id, expr, should_forward(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01009083 inherit_expression_dependencies(id, ops[2]);
9084 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009085 break;
9086 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009087
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009088 case OpCompositeExtract:
9089 {
9090 uint32_t result_type = ops[0];
9091 uint32_t id = ops[1];
9092 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009094 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009095
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02009096 // We can only split the expression here if our expression is forwarded as a temporary.
9097 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
9098
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01009099 // Do not allow base expression for struct members. We risk doing "swizzle" optimizations in this case.
9100 auto &composite_type = expression_type(ops[2]);
Hans-Kristian Arntzen3fac2892017-11-22 12:07:37 +01009101 if (composite_type.basetype == SPIRType::Struct || !composite_type.array.empty())
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01009102 allow_base_expression = false;
9103
Hans-Kristian Arntzenc7b75a82020-04-07 18:22:14 +02009104 // Packed expressions or physical ID mapped expressions cannot be split up.
9105 if (has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypePacked) ||
9106 has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypeID))
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01009107 allow_base_expression = false;
9108
Hans-Kristian Arntzen7ff2db42019-08-27 11:41:54 +02009109 // Cannot use base expression for row-major matrix row-extraction since we need to interleave access pattern
9110 // into the base expression.
9111 if (is_non_native_row_major_matrix(ops[2]))
9112 allow_base_expression = false;
9113
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01009114 AccessChainMeta meta;
9115 SPIRExpression *e = nullptr;
9116
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009117 // Only apply this optimization if result is scalar.
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02009118 if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009119 {
9120 // We want to split the access chain from the base.
9121 // This is so we can later combine different CompositeExtract results
9122 // with CompositeConstruct without emitting code like
9123 //
9124 // vec3 temp = texture(...).xyz
9125 // vec4(temp.x, temp.y, temp.z, 1.0).
9126 //
9127 // when we actually wanted to emit this
9128 // vec4(texture(...).xyz, 1.0).
9129 //
9130 // Including the base will prevent this and would trigger multiple reads
9131 // from expression causing it to be forced to an actual temporary in GLSL.
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009132 auto expr = access_chain_internal(ops[2], &ops[3], length,
9133 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_CHAIN_ONLY_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009134 e = &emit_op(result_type, id, expr, true, should_suppress_usage_tracking(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01009135 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01009136 e->base_expression = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009137 }
9138 else
9139 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009140 auto expr = access_chain_internal(ops[2], &ops[3], length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009141 e = &emit_op(result_type, id, expr, should_forward(ops[2]), should_suppress_usage_tracking(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01009142 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009143 }
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01009144
9145 // Pass through some meta information to the loaded expression.
9146 // We can still end up loading a buffer type to a variable, then CompositeExtract from it
9147 // instead of loading everything through an access chain.
9148 e->need_transpose = meta.need_transpose;
9149 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009150 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
9151 if (meta.storage_physical_type != 0)
9152 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01009153 if (meta.storage_is_invariant)
9154 set_decoration(id, DecorationInvariant);
9155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009156 break;
9157 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009158
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009159 case OpCompositeInsert:
9160 {
9161 uint32_t result_type = ops[0];
9162 uint32_t id = ops[1];
9163 uint32_t obj = ops[2];
9164 uint32_t composite = ops[3];
9165 const auto *elems = &ops[4];
9166 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009167
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009168 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009169
David Srbecky77b5b442017-06-26 18:32:53 +01009170 // Make a copy, then use access chain to store the variable.
9171 statement(declare_temporary(result_type, id), to_expression(composite), ";");
9172 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009173 auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
David Srbecky77b5b442017-06-26 18:32:53 +01009174 statement(chain, " = ", to_expression(obj), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009175
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009176 break;
9177 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009178
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01009179 case OpCopyMemory:
9180 {
9181 uint32_t lhs = ops[0];
9182 uint32_t rhs = ops[1];
9183 if (lhs != rhs)
9184 {
9185 flush_variable_declaration(lhs);
9186 flush_variable_declaration(rhs);
9187 statement(to_expression(lhs), " = ", to_expression(rhs), ";");
9188 register_write(lhs);
9189 }
9190 break;
9191 }
9192
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +01009193 case OpCopyLogical:
9194 {
9195 // This is used for copying object of different types, arrays and structs.
9196 // We need to unroll the copy, element-by-element.
9197 uint32_t result_type = ops[0];
9198 uint32_t id = ops[1];
9199 uint32_t rhs = ops[2];
9200
9201 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +01009202 emit_copy_logical_type(id, result_type, rhs, expression_type_id(rhs), {});
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +01009203 break;
9204 }
9205
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009206 case OpCopyObject:
9207 {
9208 uint32_t result_type = ops[0];
9209 uint32_t id = ops[1];
9210 uint32_t rhs = ops[2];
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01009211 bool pointer = get<SPIRType>(result_type).pointer;
9212
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02009213 auto *chain = maybe_get<SPIRAccessChain>(rhs);
9214 if (chain)
9215 {
9216 // Cannot lower to a SPIRExpression, just copy the object.
9217 auto &e = set<SPIRAccessChain>(id, *chain);
9218 e.self = id;
9219 }
9220 else if (expression_is_lvalue(rhs) && !pointer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009221 {
9222 // Need a copy.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01009223 // For pointer types, we copy the pointer itself.
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +02009224 statement(declare_temporary(result_type, id), to_unpacked_expression(rhs), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009225 set<SPIRExpression>(id, to_name(id), result_type, true);
9226 }
9227 else
9228 {
9229 // RHS expression is immutable, so just forward it.
9230 // Copying these things really make no sense, but
9231 // seems to be allowed anyways.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01009232 auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
9233 if (pointer)
9234 {
9235 auto *var = maybe_get_backing_variable(rhs);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009236 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01009237 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02009238
9239 // If we're copying an access chain, need to inherit the read expressions.
9240 auto *rhs_expr = maybe_get<SPIRExpression>(rhs);
9241 if (rhs_expr)
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +02009242 {
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02009243 e.implied_read_expressions = rhs_expr->implied_read_expressions;
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +02009244 e.expression_dependencies = rhs_expr->expression_dependencies;
9245 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009246 }
9247 break;
9248 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009250 case OpVectorShuffle:
9251 {
9252 uint32_t result_type = ops[0];
9253 uint32_t id = ops[1];
9254 uint32_t vec0 = ops[2];
9255 uint32_t vec1 = ops[3];
9256 const auto *elems = &ops[4];
9257 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009258
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009259 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009260
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01009261 // If we have the undefined swizzle index -1, we need to swizzle in undefined data,
9262 // or in our case, T(0).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009263 bool shuffle = false;
9264 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01009265 if (elems[i] >= type0.vecsize || elems[i] == 0xffffffffu)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009266 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009267
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02009268 // Cannot use swizzles with packed expressions, force shuffle path.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009269 if (!shuffle && has_extended_decoration(vec0, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02009270 shuffle = true;
9271
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009272 string expr;
Bill Hollings1845f312017-12-31 18:55:04 -05009273 bool should_fwd, trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009274
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009275 if (shuffle)
9276 {
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01009277 should_fwd = should_forward(vec0) && should_forward(vec1);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009278 trivial_forward = should_suppress_usage_tracking(vec0) && should_suppress_usage_tracking(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009279
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009280 // Constructor style and shuffling from two different vectors.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02009281 SmallVector<string> args;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009282 for (uint32_t i = 0; i < length; i++)
9283 {
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01009284 if (elems[i] == 0xffffffffu)
9285 {
9286 // Use a constant 0 here.
9287 // We could use the first component or similar, but then we risk propagating
9288 // a value we might not need, and bog down codegen.
9289 SPIRConstant c;
9290 c.constant_type = type0.parent_type;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009291 assert(type0.parent_type != ID(0));
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01009292 args.push_back(constant_expression(c));
9293 }
9294 else if (elems[i] >= type0.vecsize)
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02009295 args.push_back(to_extract_component_expression(vec1, elems[i] - type0.vecsize));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009296 else
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02009297 args.push_back(to_extract_component_expression(vec0, elems[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009298 }
9299 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
9300 }
9301 else
9302 {
Bill Hollings1845f312017-12-31 18:55:04 -05009303 should_fwd = should_forward(vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009304 trivial_forward = should_suppress_usage_tracking(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009305
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009306 // We only source from first vector, so can use swizzle.
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009307 // If the vector is packed, unpack it before applying a swizzle (needed for MSL)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02009308 expr += to_enclosed_unpacked_expression(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009309 expr += ".";
9310 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01009311 {
9312 assert(elems[i] != 0xffffffffu);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009313 expr += index_to_swizzle(elems[i]);
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01009314 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009315
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009316 if (backend.swizzle_is_function && length > 1)
9317 expr += "()";
9318 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009320 // A shuffle is trivial in that it doesn't actually *do* anything.
9321 // We inherit the forwardedness from our arguments to avoid flushing out to temporaries when it's not really needed.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009322
Bill Hollings1845f312017-12-31 18:55:04 -05009323 emit_op(result_type, id, expr, should_fwd, trivial_forward);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009324
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01009325 inherit_expression_dependencies(id, vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009326 if (vec0 != vec1)
9327 inherit_expression_dependencies(id, vec1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009328 break;
9329 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009330
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009331 // ALU
9332 case OpIsNan:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009333 GLSL_UFOP(isnan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009334 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009336 case OpIsInf:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009337 GLSL_UFOP(isinf);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009338 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009339
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009340 case OpSNegate:
9341 case OpFNegate:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009342 GLSL_UOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009343 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009345 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009346 {
9347 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
9348 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009349 GLSL_BOP_CAST(+, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009350 break;
9351 }
9352
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009353 case OpFAdd:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009354 GLSL_BOP(+);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009355 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009356
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009357 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009358 {
9359 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009360 GLSL_BOP_CAST(-, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009361 break;
9362 }
9363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009364 case OpFSub:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009365 GLSL_BOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009366 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009367
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009368 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009369 {
9370 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009371 GLSL_BOP_CAST(*, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009372 break;
9373 }
9374
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009375 case OpVectorTimesMatrix:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009376 case OpMatrixTimesVector:
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009377 {
9378 // If the matrix needs transpose, just flip the multiply order.
9379 auto *e = maybe_get<SPIRExpression>(ops[opcode == OpMatrixTimesVector ? 2 : 3]);
9380 if (e && e->need_transpose)
9381 {
9382 e->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02009383 string expr;
9384
9385 if (opcode == OpMatrixTimesVector)
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02009386 expr = join(to_enclosed_unpacked_expression(ops[3]), " * ",
9387 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02009388 else
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02009389 expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
9390 to_enclosed_unpacked_expression(ops[2]));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02009391
9392 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
9393 emit_op(ops[0], ops[1], expr, forward);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009394 e->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02009395 inherit_expression_dependencies(ops[1], ops[2]);
9396 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009397 }
9398 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009399 GLSL_BOP(*);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009400 break;
9401 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009402
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +02009403 case OpMatrixTimesMatrix:
9404 {
9405 auto *a = maybe_get<SPIRExpression>(ops[2]);
9406 auto *b = maybe_get<SPIRExpression>(ops[3]);
9407
9408 // If both matrices need transpose, we can multiply in flipped order and tag the expression as transposed.
9409 // a^T * b^T = (b * a)^T.
9410 if (a && b && a->need_transpose && b->need_transpose)
9411 {
9412 a->need_transpose = false;
9413 b->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02009414 auto expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
9415 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
9416 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
9417 auto &e = emit_op(ops[0], ops[1], expr, forward);
9418 e.need_transpose = true;
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +02009419 a->need_transpose = true;
9420 b->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02009421 inherit_expression_dependencies(ops[1], ops[2]);
9422 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +02009423 }
9424 else
9425 GLSL_BOP(*);
9426
9427 break;
9428 }
9429
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009430 case OpFMul:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009431 case OpMatrixTimesScalar:
9432 case OpVectorTimesScalar:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009433 GLSL_BOP(*);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009434 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009436 case OpOuterProduct:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009437 GLSL_BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009438 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009440 case OpDot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009441 GLSL_BFOP(dot);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009442 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009443
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009444 case OpTranspose:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009445 GLSL_UFOP(transpose);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009446 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009447
Jin Zhoue792cd62018-05-22 00:44:34 -04009448 case OpSRem:
Jin Zhou6b144cc2018-05-24 01:17:47 -04009449 {
9450 uint32_t result_type = ops[0];
9451 uint32_t result_id = ops[1];
9452 uint32_t op0 = ops[2];
9453 uint32_t op1 = ops[3];
9454
9455 // Needs special handling.
9456 bool forward = should_forward(op0) && should_forward(op1);
9457 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
9458 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
9459
9460 emit_op(result_type, result_id, expr, forward);
9461 inherit_expression_dependencies(result_id, op0);
9462 inherit_expression_dependencies(result_id, op1);
Jin Zhoue792cd62018-05-22 00:44:34 -04009463 break;
Jin Zhou6b144cc2018-05-24 01:17:47 -04009464 }
Jin Zhoue792cd62018-05-22 00:44:34 -04009465
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009466 case OpSDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009467 GLSL_BOP_CAST(/, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009468 break;
9469
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009470 case OpUDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009471 GLSL_BOP_CAST(/, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009472 break;
9473
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01009474 case OpIAddCarry:
9475 case OpISubBorrow:
9476 {
9477 if (options.es && options.version < 310)
9478 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
9479 else if (!options.es && options.version < 400)
9480 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 400.");
9481
9482 uint32_t result_type = ops[0];
9483 uint32_t result_id = ops[1];
9484 uint32_t op0 = ops[2];
9485 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01009486 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02009487 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01009488 const char *op = opcode == OpIAddCarry ? "uaddCarry" : "usubBorrow";
9489
9490 statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", op, "(", to_expression(op0), ", ",
9491 to_expression(op1), ", ", to_expression(result_id), ".", to_member_name(type, 1), ");");
9492 break;
9493 }
9494
9495 case OpUMulExtended:
9496 case OpSMulExtended:
9497 {
9498 if (options.es && options.version < 310)
9499 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
9500 else if (!options.es && options.version < 400)
9501 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 4000.");
9502
9503 uint32_t result_type = ops[0];
9504 uint32_t result_id = ops[1];
9505 uint32_t op0 = ops[2];
9506 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01009507 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02009508 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01009509 const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended";
9510
9511 statement(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(result_id), ".",
9512 to_member_name(type, 1), ", ", to_expression(result_id), ".", to_member_name(type, 0), ");");
9513 break;
9514 }
9515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009516 case OpFDiv:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009517 GLSL_BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009518 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009519
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009520 case OpShiftRightLogical:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009521 GLSL_BOP_CAST(>>, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009522 break;
9523
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009524 case OpShiftRightArithmetic:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009525 GLSL_BOP_CAST(>>, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009526 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009527
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009528 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02009529 {
9530 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009531 GLSL_BOP_CAST(<<, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009532 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02009533 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009534
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009535 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009536 {
9537 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009538 GLSL_BOP_CAST(|, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009539 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009540 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009542 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009543 {
9544 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01009545 GLSL_BOP_CAST(^, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009546 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009547 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009548
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009549 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009550 {
9551 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009552 GLSL_BOP_CAST(&, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009553 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009554 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009555
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009556 case OpNot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009557 GLSL_UOP(~);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009558 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009559
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009560 case OpUMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009561 GLSL_BOP_CAST(%, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009562 break;
9563
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009564 case OpSMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009565 GLSL_BOP_CAST(%, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009566 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009567
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009568 case OpFMod:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009569 GLSL_BFOP(mod);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009570 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +02009571
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +01009572 case OpFRem:
9573 {
9574 if (is_legacy())
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +01009575 SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is "
9576 "needed for legacy.");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +01009577
9578 uint32_t result_type = ops[0];
9579 uint32_t result_id = ops[1];
9580 uint32_t op0 = ops[2];
9581 uint32_t op1 = ops[3];
9582
9583 // Needs special handling.
9584 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +01009585 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
9586 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +01009587
9588 emit_op(result_type, result_id, expr, forward);
9589 inherit_expression_dependencies(result_id, op0);
9590 inherit_expression_dependencies(result_id, op1);
9591 break;
9592 }
9593
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009594 // Relational
9595 case OpAny:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009596 GLSL_UFOP(any);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009597 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009598
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009599 case OpAll:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009600 GLSL_UFOP(all);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009601 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009602
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009603 case OpSelect:
9604 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
9605 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009606
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009607 case OpLogicalOr:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009608 {
9609 // No vector variant in GLSL for logical OR.
9610 auto result_type = ops[0];
9611 auto id = ops[1];
9612 auto &type = get<SPIRType>(result_type);
9613
9614 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02009615 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009616 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009617 GLSL_BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009618 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009619 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009620
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009621 case OpLogicalAnd:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009622 {
9623 // No vector variant in GLSL for logical AND.
9624 auto result_type = ops[0];
9625 auto id = ops[1];
9626 auto &type = get<SPIRType>(result_type);
9627
9628 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02009629 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009630 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009631 GLSL_BOP(&&);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009632 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009633 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009634
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009635 case OpLogicalNot:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009636 {
9637 auto &type = get<SPIRType>(ops[0]);
9638 if (type.vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009639 GLSL_UFOP(not);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009640 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009641 GLSL_UOP(!);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009642 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01009643 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009644
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009645 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009646 {
9647 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009648 GLSL_BFOP_CAST(equal, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009649 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009650 GLSL_BOP_CAST(==, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009651 break;
9652 }
9653
9654 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009655 case OpFOrdEqual:
9656 {
9657 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009658 GLSL_BFOP(equal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009659 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009660 GLSL_BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009661 break;
9662 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009663
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009664 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009665 {
9666 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009667 GLSL_BFOP_CAST(notEqual, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009668 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009669 GLSL_BOP_CAST(!=, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009670 break;
9671 }
9672
9673 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009674 case OpFOrdNotEqual:
9675 {
9676 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009677 GLSL_BFOP(notEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009678 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009679 GLSL_BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009680 break;
9681 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009683 case OpUGreaterThan:
9684 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009685 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +02009686 auto type = opcode == OpUGreaterThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009687 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009688 GLSL_BFOP_CAST(greaterThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009689 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009690 GLSL_BOP_CAST(>, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009691 break;
9692 }
9693
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009694 case OpFOrdGreaterThan:
9695 {
9696 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009697 GLSL_BFOP(greaterThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009698 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009699 GLSL_BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009700 break;
9701 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009702
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009703 case OpUGreaterThanEqual:
9704 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009705 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +02009706 auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009707 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009708 GLSL_BFOP_CAST(greaterThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009709 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009710 GLSL_BOP_CAST(>=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009711 break;
9712 }
9713
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009714 case OpFOrdGreaterThanEqual:
9715 {
9716 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009717 GLSL_BFOP(greaterThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009718 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009719 GLSL_BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009720 break;
9721 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009723 case OpULessThan:
9724 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009725 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +02009726 auto type = opcode == OpULessThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009727 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009728 GLSL_BFOP_CAST(lessThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009729 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009730 GLSL_BOP_CAST(<, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009731 break;
9732 }
9733
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009734 case OpFOrdLessThan:
9735 {
9736 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009737 GLSL_BFOP(lessThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009738 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009739 GLSL_BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009740 break;
9741 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009742
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009743 case OpULessThanEqual:
9744 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009745 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +02009746 auto type = opcode == OpULessThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009747 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009748 GLSL_BFOP_CAST(lessThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009749 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009750 GLSL_BOP_CAST(<=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02009751 break;
9752 }
9753
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009754 case OpFOrdLessThanEqual:
9755 {
9756 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009757 GLSL_BFOP(lessThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009758 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009759 GLSL_BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009760 break;
9761 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009762
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009763 // Conversion
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02009764 case OpSConvert:
9765 case OpConvertSToF:
9766 case OpUConvert:
9767 case OpConvertUToF:
9768 {
9769 auto input_type = opcode == OpSConvert || opcode == OpConvertSToF ? int_type : uint_type;
9770 uint32_t result_type = ops[0];
9771 uint32_t id = ops[1];
9772
9773 auto &type = get<SPIRType>(result_type);
9774 auto &arg_type = expression_type(ops[2]);
9775 auto func = type_to_glsl_constructor(type);
9776
Hans-Kristian Arntzen4edb99d2019-11-28 13:49:53 +01009777 if (arg_type.width < type.width || type_is_floating_point(type))
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02009778 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), input_type, type.basetype);
9779 else
9780 emit_unary_func_op(result_type, id, ops[2], func.c_str());
9781 break;
9782 }
9783
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009784 case OpConvertFToU:
9785 case OpConvertFToS:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02009786 {
9787 // Cast to expected arithmetic type, then potentially bitcast away to desired signedness.
9788 uint32_t result_type = ops[0];
9789 uint32_t id = ops[1];
9790 auto &type = get<SPIRType>(result_type);
9791 auto expected_type = type;
9792 auto &float_type = expression_type(ops[2]);
9793 expected_type.basetype =
9794 opcode == OpConvertFToS ? to_signed_basetype(type.width) : to_unsigned_basetype(type.width);
9795
9796 auto func = type_to_glsl_constructor(expected_type);
9797 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), float_type.basetype, expected_type.basetype);
9798 break;
9799 }
9800
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009801 case OpFConvert:
9802 {
9803 uint32_t result_type = ops[0];
9804 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009806 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
9807 emit_unary_func_op(result_type, id, ops[2], func.c_str());
9808 break;
9809 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009810
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009811 case OpBitcast:
9812 {
9813 uint32_t result_type = ops[0];
9814 uint32_t id = ops[1];
9815 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009816
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02009817 if (!emit_complex_bitcast(result_type, id, arg))
9818 {
9819 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
9820 emit_unary_func_op(result_type, id, arg, op.c_str());
9821 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009822 break;
9823 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009824
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02009825 case OpQuantizeToF16:
9826 {
9827 uint32_t result_type = ops[0];
9828 uint32_t id = ops[1];
9829 uint32_t arg = ops[2];
9830
9831 string op;
9832 auto &type = get<SPIRType>(result_type);
9833
9834 switch (type.vecsize)
9835 {
9836 case 1:
9837 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
9838 break;
9839 case 2:
9840 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
9841 break;
9842 case 3:
9843 {
9844 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
9845 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
9846 op = join("vec3(", op0, ", ", op1, ")");
9847 break;
9848 }
9849 case 4:
9850 {
9851 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
9852 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
9853 op = join("vec4(", op0, ", ", op1, ")");
9854 break;
9855 }
9856 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01009857 SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02009858 }
9859
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01009860 emit_op(result_type, id, op, should_forward(arg));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01009861 inherit_expression_dependencies(id, arg);
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02009862 break;
9863 }
9864
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009865 // Derivatives
9866 case OpDPdx:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009867 GLSL_UFOP(dFdx);
Lubos Lenco80c39412016-09-17 14:33:16 +02009868 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009869 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009870 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009871 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009872
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009873 case OpDPdy:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009874 GLSL_UFOP(dFdy);
Lubos Lenco80c39412016-09-17 14:33:16 +02009875 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009876 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009877 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009878 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009879
Robert Konrad9ec9dd02017-03-24 13:59:19 +01009880 case OpDPdxFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009881 GLSL_UFOP(dFdxFine);
Robert Konradcb637db2017-03-24 15:58:54 +01009882 if (options.es)
9883 {
9884 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
9885 }
9886 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009887 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009888 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01009889 break;
9890
9891 case OpDPdyFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009892 GLSL_UFOP(dFdyFine);
Robert Konradcb637db2017-03-24 15:58:54 +01009893 if (options.es)
9894 {
9895 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
9896 }
9897 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009898 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009899 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01009900 break;
9901
9902 case OpDPdxCoarse:
Robert Konradcb637db2017-03-24 15:58:54 +01009903 if (options.es)
9904 {
9905 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
9906 }
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009907 GLSL_UFOP(dFdxCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +01009908 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009909 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009910 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01009911 break;
9912
9913 case OpDPdyCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009914 GLSL_UFOP(dFdyCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +01009915 if (options.es)
9916 {
9917 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
9918 }
9919 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009920 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009921 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01009922 break;
9923
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009924 case OpFwidth:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009925 GLSL_UFOP(fwidth);
Lubos Lenco80c39412016-09-17 14:33:16 +02009926 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009927 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009928 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009929 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009930
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01009931 case OpFwidthCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009932 GLSL_UFOP(fwidthCoarse);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01009933 if (options.es)
9934 {
9935 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
9936 }
9937 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009938 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009939 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01009940 break;
9941
9942 case OpFwidthFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009943 GLSL_UFOP(fwidthFine);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01009944 if (options.es)
9945 {
9946 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
9947 }
9948 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009949 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009950 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01009951 break;
9952
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009953 // Bitfield
9954 case OpBitFieldInsert:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009955 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02009956 emit_bitfield_insert_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], "bitfieldInsert", SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009957 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009958 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009959
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009960 case OpBitFieldSExtract:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009961 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02009962 emit_trinary_func_op_bitextract(ops[0], ops[1], ops[2], ops[3], ops[4], "bitfieldExtract", int_type, int_type,
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009963 SPIRType::Int, SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009964 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009965 }
9966
9967 case OpBitFieldUExtract:
9968 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02009969 emit_trinary_func_op_bitextract(ops[0], ops[1], ops[2], ops[3], ops[4], "bitfieldExtract", uint_type, uint_type,
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009970 SPIRType::Int, SPIRType::Int);
9971 break;
9972 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009973
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009974 case OpBitReverse:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009975 // BitReverse does not have issues with sign since result type must match input type.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009976 GLSL_UFOP(bitfieldReverse);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009977 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009978
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009979 case OpBitCount:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009980 {
9981 auto basetype = expression_type(ops[2]).basetype;
9982 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "bitCount", basetype, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009983 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02009984 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009985
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009986 // Atomics
9987 case OpAtomicExchange:
9988 {
9989 uint32_t result_type = ops[0];
9990 uint32_t id = ops[1];
9991 uint32_t ptr = ops[2];
9992 // Ignore semantics for now, probably only relevant to CL.
9993 uint32_t val = ops[5];
9994 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
9995 forced_temporaries.insert(id);
9996 emit_binary_func_op(result_type, id, ptr, val, op);
9997 flush_all_atomic_capable_variables();
9998 break;
9999 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010000
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010001 case OpAtomicCompareExchange:
10002 {
10003 uint32_t result_type = ops[0];
10004 uint32_t id = ops[1];
10005 uint32_t ptr = ops[2];
10006 uint32_t val = ops[6];
10007 uint32_t comp = ops[7];
10008 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010009
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010010 forced_temporaries.insert(id);
10011 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
10012 flush_all_atomic_capable_variables();
10013 break;
10014 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010016 case OpAtomicLoad:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010017 {
10018 // In plain GLSL, we have no atomic loads, so emulate this by fetch adding by 0 and hope compiler figures it out.
10019 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
10020 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen8b236f22019-04-24 09:31:44 +020010021 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010022 bool atomic_image = check_atomic_image(ops[2]);
10023 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
10024 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
10025 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
10026 const char *increment = unsigned_type ? "0u" : "0";
10027 emit_op(ops[0], ops[1], join(op, "(", to_expression(ops[2]), ", ", increment, ")"), false);
10028 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010029 break;
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010030 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010031
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010010032 case OpAtomicStore:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010033 {
10034 // In plain GLSL, we have no atomic stores, so emulate this with an atomic exchange where we don't consume the result.
10035 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
10036 uint32_t ptr = ops[0];
10037 // Ignore semantics for now, probably only relevant to CL.
10038 uint32_t val = ops[3];
10039 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
10040 statement(op, "(", to_expression(ptr), ", ", to_expression(val), ");");
10041 flush_all_atomic_capable_variables();
10042 break;
10043 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010044
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010045 case OpAtomicIIncrement:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010046 case OpAtomicIDecrement:
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020010047 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010048 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020010049 auto &type = expression_type(ops[2]);
10050 if (type.storage == StorageClassAtomicCounter)
10051 {
10052 // Legacy GLSL stuff, not sure if this is relevant to support.
10053 if (opcode == OpAtomicIIncrement)
10054 GLSL_UFOP(atomicCounterIncrement);
10055 else
10056 GLSL_UFOP(atomicCounterDecrement);
10057 }
10058 else
10059 {
10060 bool atomic_image = check_atomic_image(ops[2]);
10061 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
10062 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
10063 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
10064
10065 const char *increment = nullptr;
10066 if (opcode == OpAtomicIIncrement && unsigned_type)
10067 increment = "1u";
10068 else if (opcode == OpAtomicIIncrement)
10069 increment = "1";
10070 else if (unsigned_type)
10071 increment = "uint(-1)";
10072 else
10073 increment = "-1";
10074
10075 emit_op(ops[0], ops[1], join(op, "(", to_expression(ops[2]), ", ", increment, ")"), false);
10076 }
10077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010078 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010079 break;
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020010080 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010081
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010082 case OpAtomicIAdd:
10083 {
10084 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
10085 forced_temporaries.insert(ops[1]);
10086 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
10087 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010088 break;
10089 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010090
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010091 case OpAtomicISub:
10092 {
10093 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
10094 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010010095 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_enclosed_expression(ops[5]), ")");
10096 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010097 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010098 break;
10099 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010100
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010101 case OpAtomicSMin:
10102 case OpAtomicUMin:
10103 {
10104 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
10105 forced_temporaries.insert(ops[1]);
10106 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
10107 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010108 break;
10109 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010110
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010111 case OpAtomicSMax:
10112 case OpAtomicUMax:
10113 {
10114 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
10115 forced_temporaries.insert(ops[1]);
10116 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
10117 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010118 break;
10119 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010120
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010121 case OpAtomicAnd:
10122 {
10123 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
10124 forced_temporaries.insert(ops[1]);
10125 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
10126 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010127 break;
10128 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010129
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010130 case OpAtomicOr:
10131 {
10132 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
10133 forced_temporaries.insert(ops[1]);
10134 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
10135 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010136 break;
10137 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010138
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010139 case OpAtomicXor:
10140 {
10141 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
10142 forced_temporaries.insert(ops[1]);
10143 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
10144 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010145 break;
10146 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010147
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010148 // Geometry shaders
10149 case OpEmitVertex:
10150 statement("EmitVertex();");
10151 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010152
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010153 case OpEndPrimitive:
10154 statement("EndPrimitive();");
10155 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010156
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010157 case OpEmitStreamVertex:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010010158 {
10159 if (options.es)
10160 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
10161 else if (!options.es && options.version < 400)
10162 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
10163
10164 auto stream_expr = to_expression(ops[0]);
10165 if (expression_type(ops[0]).basetype != SPIRType::Int)
10166 stream_expr = join("int(", stream_expr, ")");
10167 statement("EmitStreamVertex(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010168 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010010169 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010170
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010171 case OpEndStreamPrimitive:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010010172 {
10173 if (options.es)
10174 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
10175 else if (!options.es && options.version < 400)
10176 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
10177
10178 auto stream_expr = to_expression(ops[0]);
10179 if (expression_type(ops[0]).basetype != SPIRType::Int)
10180 stream_expr = join("int(", stream_expr, ")");
10181 statement("EndStreamPrimitive(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010182 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010010183 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010184
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010185 // Textures
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010186 case OpImageSampleExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010187 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010188 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010189 case OpImageSampleProjDrefExplicitLod:
Lubos Lenco80c39412016-09-17 14:33:16 +020010190 case OpImageSampleImplicitLod:
10191 case OpImageSampleProjImplicitLod:
10192 case OpImageSampleDrefImplicitLod:
10193 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010194 case OpImageFetch:
10195 case OpImageGather:
10196 case OpImageDrefGather:
10197 // Gets a bit hairy, so move this to a separate instruction.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010198 emit_texture_op(instruction, false);
10199 break;
10200
10201 case OpImageSparseSampleExplicitLod:
10202 case OpImageSparseSampleProjExplicitLod:
10203 case OpImageSparseSampleDrefExplicitLod:
10204 case OpImageSparseSampleProjDrefExplicitLod:
10205 case OpImageSparseSampleImplicitLod:
10206 case OpImageSparseSampleProjImplicitLod:
10207 case OpImageSparseSampleDrefImplicitLod:
10208 case OpImageSparseSampleProjDrefImplicitLod:
10209 case OpImageSparseFetch:
10210 case OpImageSparseGather:
10211 case OpImageSparseDrefGather:
10212 // Gets a bit hairy, so move this to a separate instruction.
10213 emit_texture_op(instruction, true);
10214 break;
10215
10216 case OpImageSparseTexelsResident:
10217 if (options.es)
10218 SPIRV_CROSS_THROW("Sparse feedback is not supported in GLSL.");
10219 require_extension_internal("GL_ARB_sparse_texture2");
10220 GLSL_UFOP(sparseTexelsResidentARB);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010221 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010222
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010223 case OpImage:
10224 {
10225 uint32_t result_type = ops[0];
10226 uint32_t id = ops[1];
Hans-Kristian Arntzenaaf397c2018-04-27 11:10:10 +020010227
10228 // Suppress usage tracking.
10229 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020010230
10231 // When using the image, we need to know which variable it is actually loaded from.
10232 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010233 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020010234 break;
10235 }
10236
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020010237 case OpImageQueryLod:
10238 {
10239 if (!options.es && options.version < 400)
10240 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010241 require_extension_internal("GL_ARB_texture_query_lod");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020010242 // For some reason, the ARB spec is all-caps.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010243 GLSL_BFOP(textureQueryLOD);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020010244 }
10245 else if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010246 SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020010247 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010248 GLSL_BFOP(textureQueryLod);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010249 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020010250 break;
10251 }
10252
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020010253 case OpImageQueryLevels:
10254 {
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020010255 uint32_t result_type = ops[0];
10256 uint32_t id = ops[1];
10257
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020010258 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010259 require_extension_internal("GL_ARB_texture_query_levels");
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020010260 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010261 SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020010262
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020010263 auto expr = join("textureQueryLevels(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020010264 auto &restype = get<SPIRType>(ops[0]);
10265 expr = bitcast_expression(restype, SPIRType::Int, expr);
10266 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020010267 break;
10268 }
10269
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020010270 case OpImageQuerySamples:
10271 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010272 auto &type = expression_type(ops[2]);
10273 uint32_t result_type = ops[0];
10274 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020010275
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010276 string expr;
10277 if (type.image.sampled == 2)
10278 expr = join("imageSamples(", to_expression(ops[2]), ")");
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020010279 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020010280 expr = join("textureSamples(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010281
10282 auto &restype = get<SPIRType>(ops[0]);
10283 expr = bitcast_expression(restype, SPIRType::Int, expr);
10284 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010285 break;
10286 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010287
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010288 case OpSampledImage:
10289 {
10290 uint32_t result_type = ops[0];
10291 uint32_t id = ops[1];
10292 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010293 inherit_expression_dependencies(id, ops[2]);
10294 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010295 break;
10296 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +020010297
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010298 case OpImageQuerySizeLod:
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010299 {
10300 uint32_t result_type = ops[0];
10301 uint32_t id = ops[1];
10302
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020010303 auto expr = join("textureSize(", convert_separate_image_to_expression(ops[2]), ", ",
Hans-Kristian Arntzen7e23e692018-04-30 12:46:21 +020010304 bitcast_expression(SPIRType::Int, ops[3]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010305 auto &restype = get<SPIRType>(ops[0]);
10306 expr = bitcast_expression(restype, SPIRType::Int, expr);
10307 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010308 break;
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010309 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010311 // Image load/store
10312 case OpImageRead:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010313 case OpImageSparseRead:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010314 {
10315 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
10316 // not adding the proper qualifiers.
10317 // If it turns out we need to read the image after all, remove the qualifier and recompile.
10318 auto *var = maybe_get_backing_variable(ops[2]);
10319 if (var)
10320 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010010321 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010322 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010323 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010324 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020010325 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010326 }
10327 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010329 uint32_t result_type = ops[0];
10330 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010332 bool pure;
10333 string imgexpr;
10334 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010335
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020010336 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010337 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020010338 if (type.image.ms)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010339 SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020010340
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +020010341 auto itr =
10342 find_if(begin(pls_inputs), end(pls_inputs), [var](const PlsRemap &pls) { return pls.id == var->self; });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010343
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010344 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020010345 {
10346 // For non-PLS inputs, we rely on subpass type remapping information to get it right
10347 // since ImageRead always returns 4-component vectors and the backing type is opaque.
10348 if (!var->remapped_components)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010349 SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020010350 imgexpr = remap_swizzle(get<SPIRType>(result_type), var->remapped_components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020010351 }
10352 else
10353 {
10354 // PLS input could have different number of components than what the SPIR expects, swizzle to
10355 // the appropriate vector size.
10356 uint32_t components = pls_format_to_components(itr->format);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020010357 imgexpr = remap_swizzle(get<SPIRType>(result_type), components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020010358 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010359 pure = true;
10360 }
10361 else if (type.image.dim == DimSubpassData)
10362 {
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010010363 if (var && subpass_input_is_framebuffer_fetch(var->self))
10364 {
10365 imgexpr = to_expression(var->self);
10366 }
10367 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020010368 {
10369 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020010370 if (type.image.ms)
10371 {
10372 uint32_t operands = ops[4];
10373 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010374 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020010375 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
10376
10377 uint32_t samples = ops[5];
10378 imgexpr = join("subpassLoad(", to_expression(ops[2]), ", ", to_expression(samples), ")");
10379 }
10380 else
10381 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020010382 }
10383 else
10384 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020010385 if (type.image.ms)
10386 {
10387 uint32_t operands = ops[4];
10388 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010389 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020010390 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
10391
10392 uint32_t samples = ops[5];
10393 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
10394 to_expression(samples), ")");
10395 }
10396 else
10397 {
10398 // Implement subpass loads via texture barrier style sampling.
10399 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
10400 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020010401 }
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020010402 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010403 pure = true;
10404 }
10405 else
10406 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010407 bool sparse = opcode == OpImageSparseRead;
10408 uint32_t sparse_code_id = 0;
10409 uint32_t sparse_texel_id = 0;
10410 if (sparse)
10411 emit_sparse_feedback_temporaries(ops[0], ops[1], sparse_code_id, sparse_texel_id);
10412
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010010413 // imageLoad only accepts int coords, not uint.
10414 auto coord_expr = to_expression(ops[3]);
10415 auto target_coord_type = expression_type(ops[3]);
10416 target_coord_type.basetype = SPIRType::Int;
10417 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
10418
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010419 // Plain image load/store.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010420 if (sparse)
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020010421 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010422 if (type.image.ms)
10423 {
10424 uint32_t operands = ops[4];
10425 if (operands != ImageOperandsSampleMask || length != 6)
10426 SPIRV_CROSS_THROW(
10427 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020010428
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010429 uint32_t samples = ops[5];
10430 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_expression(ops[2]), ", ",
10431 coord_expr, ", ", to_expression(samples), ", ", to_expression(sparse_texel_id), ");");
10432 }
10433 else
10434 {
10435 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_expression(ops[2]), ", ",
10436 coord_expr, ", ", to_expression(sparse_texel_id), ");");
10437 }
10438 imgexpr = join(type_to_glsl(get<SPIRType>(result_type)), "(",
10439 to_expression(sparse_code_id), ", ", to_expression(sparse_texel_id), ")");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020010440 }
10441 else
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010442 {
10443 if (type.image.ms)
10444 {
10445 uint32_t operands = ops[4];
10446 if (operands != ImageOperandsSampleMask || length != 6)
10447 SPIRV_CROSS_THROW(
10448 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020010449
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020010450 uint32_t samples = ops[5];
10451 imgexpr =
10452 join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ", ", to_expression(samples), ")");
10453 }
10454 else
10455 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ")");
10456 }
10457
10458 if (!sparse)
10459 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010460 pure = false;
10461 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010462
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010463 if (var && var->forwardable)
10464 {
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010010465 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
10466 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010467
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010468 // We only need to track dependencies if we're reading from image load/store.
10469 if (!pure)
10470 {
10471 e.loaded_from = var->self;
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010010472 if (forward)
10473 var->dependees.push_back(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010474 }
10475 }
10476 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010010477 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010478
10479 inherit_expression_dependencies(id, ops[2]);
10480 if (type.image.ms)
10481 inherit_expression_dependencies(id, ops[5]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010482 break;
10483 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010484
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010485 case OpImageTexelPointer:
10486 {
10487 uint32_t result_type = ops[0];
10488 uint32_t id = ops[1];
Mark Satterthwaitec4f97042019-08-26 11:28:13 -040010489
10490 auto coord_expr = to_expression(ops[3]);
10491 auto target_coord_type = expression_type(ops[3]);
10492 target_coord_type.basetype = SPIRType::Int;
10493 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
10494
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010010495 auto expr = join(to_expression(ops[2]), ", ", coord_expr);
10496 if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
10497 convert_non_uniform_expression(expression_type(ops[2]), expr);
10498
10499 auto &e = set<SPIRExpression>(id, expr, result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010500
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020010501 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010502 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010503 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen6edbf0c2019-10-24 11:30:20 +020010504 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010505 break;
10506 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010507
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010508 case OpImageWrite:
10509 {
10510 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
10511 // not adding the proper qualifiers.
10512 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
10513 auto *var = maybe_get_backing_variable(ops[0]);
10514 if (var)
10515 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010010516 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010517 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010518 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010519 flags.clear(DecorationNonWritable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020010520 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010521 }
10522 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010523
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020010524 auto &type = expression_type(ops[0]);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020010525 auto &value_type = expression_type(ops[2]);
10526 auto store_type = value_type;
10527 store_type.vecsize = 4;
10528
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010010529 // imageStore only accepts int coords, not uint.
10530 auto coord_expr = to_expression(ops[1]);
10531 auto target_coord_type = expression_type(ops[1]);
10532 target_coord_type.basetype = SPIRType::Int;
10533 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
10534
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020010535 if (type.image.ms)
10536 {
10537 uint32_t operands = ops[3];
10538 if (operands != ImageOperandsSampleMask || length != 5)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010539 SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020010540 uint32_t samples = ops[4];
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010010541 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ", to_expression(samples), ", ",
10542 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020010543 }
10544 else
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010010545 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ",
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020010546 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010547
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010548 if (var && variable_storage_is_aliased(*var))
10549 flush_all_aliased_variables();
10550 break;
10551 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010552
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010553 case OpImageQuerySize:
10554 {
10555 auto &type = expression_type(ops[2]);
10556 uint32_t result_type = ops[0];
10557 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010558
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010559 if (type.basetype == SPIRType::Image)
10560 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010561 string expr;
10562 if (type.image.sampled == 2)
10563 {
10564 // The size of an image is always constant.
10565 expr = join("imageSize(", to_expression(ops[2]), ")");
10566 }
10567 else
10568 {
10569 // This path is hit for samplerBuffers and multisampled images which do not have LOD.
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020010570 expr = join("textureSize(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020010571 }
10572
10573 auto &restype = get<SPIRType>(ops[0]);
10574 expr = bitcast_expression(restype, SPIRType::Int, expr);
10575 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010576 }
10577 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010578 SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010579 break;
10580 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010581
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010582 // Compute
10583 case OpControlBarrier:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010584 case OpMemoryBarrier:
10585 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010586 uint32_t execution_scope = 0;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010587 uint32_t memory;
10588 uint32_t semantics;
10589
10590 if (opcode == OpMemoryBarrier)
10591 {
10592 memory = get<SPIRConstant>(ops[0]).scalar();
10593 semantics = get<SPIRConstant>(ops[1]).scalar();
10594 }
10595 else
10596 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010597 execution_scope = get<SPIRConstant>(ops[0]).scalar();
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010598 memory = get<SPIRConstant>(ops[1]).scalar();
10599 semantics = get<SPIRConstant>(ops[2]).scalar();
10600 }
10601
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010602 if (execution_scope == ScopeSubgroup || memory == ScopeSubgroup)
10603 {
10604 if (!options.vulkan_semantics)
10605 SPIRV_CROSS_THROW("Can only use subgroup operations in Vulkan semantics.");
10606 require_extension_internal("GL_KHR_shader_subgroup_basic");
10607 }
10608
10609 if (execution_scope != ScopeSubgroup && get_entry_point().model == ExecutionModelTessellationControl)
10610 {
10611 // Control shaders only have barriers, and it implies memory barriers.
10612 if (opcode == OpControlBarrier)
10613 statement("barrier();");
10614 break;
10615 }
10616
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010617 // We only care about these flags, acquire/release and friends are not relevant to GLSL.
10618 semantics = mask_relevant_memory_semantics(semantics);
10619
10620 if (opcode == OpMemoryBarrier)
10621 {
10622 // If we are a memory barrier, and the next instruction is a control barrier, check if that memory barrier
10623 // does what we need, so we avoid redundant barriers.
10624 const Instruction *next = get_next_instruction_in_block(instruction);
10625 if (next && next->op == OpControlBarrier)
10626 {
10627 auto *next_ops = stream(*next);
10628 uint32_t next_memory = get<SPIRConstant>(next_ops[1]).scalar();
10629 uint32_t next_semantics = get<SPIRConstant>(next_ops[2]).scalar();
10630 next_semantics = mask_relevant_memory_semantics(next_semantics);
10631
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010010632 bool memory_scope_covered = false;
10633 if (next_memory == memory)
10634 memory_scope_covered = true;
10635 else if (next_semantics == MemorySemanticsWorkgroupMemoryMask)
10636 {
10637 // If we only care about workgroup memory, either Device or Workgroup scope is fine,
10638 // scope does not have to match.
10639 if ((next_memory == ScopeDevice || next_memory == ScopeWorkgroup) &&
10640 (memory == ScopeDevice || memory == ScopeWorkgroup))
10641 {
10642 memory_scope_covered = true;
10643 }
10644 }
10645 else if (memory == ScopeWorkgroup && next_memory == ScopeDevice)
10646 {
10647 // The control barrier has device scope, but the memory barrier just has workgroup scope.
10648 memory_scope_covered = true;
10649 }
10650
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010651 // If we have the same memory scope, and all memory types are covered, we're good.
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010010652 if (memory_scope_covered && (semantics & next_semantics) == semantics)
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010653 break;
10654 }
10655 }
10656
10657 // We are synchronizing some memory or syncing execution,
10658 // so we cannot forward any loads beyond the memory barrier.
10659 if (semantics || opcode == OpControlBarrier)
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010660 {
10661 assert(current_emitting_block);
10662 flush_control_dependent_expressions(current_emitting_block->self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010663 flush_all_active_variables();
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010664 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010665
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010666 if (memory == ScopeWorkgroup) // Only need to consider memory within a group
10667 {
10668 if (semantics == MemorySemanticsWorkgroupMemoryMask)
Hans-Kristian Arntzen67b29912019-12-04 15:06:19 +010010669 {
10670 // OpControlBarrier implies a memory barrier for shared memory as well.
10671 bool implies_shared_barrier = opcode == OpControlBarrier && execution_scope == ScopeWorkgroup;
10672 if (!implies_shared_barrier)
10673 statement("memoryBarrierShared();");
10674 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010675 else if (semantics != 0)
10676 statement("groupMemoryBarrier();");
10677 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010678 else if (memory == ScopeSubgroup)
10679 {
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +020010680 const uint32_t all_barriers =
10681 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010682
10683 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
10684 {
10685 // These are not relevant for GLSL, but assume it means memoryBarrier().
10686 // memoryBarrier() does everything, so no need to test anything else.
10687 statement("subgroupMemoryBarrier();");
10688 }
10689 else if ((semantics & all_barriers) == all_barriers)
10690 {
10691 // Short-hand instead of emitting 3 barriers.
10692 statement("subgroupMemoryBarrier();");
10693 }
10694 else
10695 {
10696 // Pick out individual barriers.
10697 if (semantics & MemorySemanticsWorkgroupMemoryMask)
10698 statement("subgroupMemoryBarrierShared();");
10699 if (semantics & MemorySemanticsUniformMemoryMask)
10700 statement("subgroupMemoryBarrierBuffer();");
10701 if (semantics & MemorySemanticsImageMemoryMask)
10702 statement("subgroupMemoryBarrierImage();");
10703 }
10704 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010705 else
10706 {
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010010707 const uint32_t all_barriers =
10708 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010709
10710 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
10711 {
10712 // These are not relevant for GLSL, but assume it means memoryBarrier().
10713 // memoryBarrier() does everything, so no need to test anything else.
10714 statement("memoryBarrier();");
10715 }
10716 else if ((semantics & all_barriers) == all_barriers)
10717 {
10718 // Short-hand instead of emitting 4 barriers.
10719 statement("memoryBarrier();");
10720 }
10721 else
10722 {
10723 // Pick out individual barriers.
10724 if (semantics & MemorySemanticsWorkgroupMemoryMask)
10725 statement("memoryBarrierShared();");
10726 if (semantics & MemorySemanticsUniformMemoryMask)
10727 statement("memoryBarrierBuffer();");
10728 if (semantics & MemorySemanticsImageMemoryMask)
10729 statement("memoryBarrierImage();");
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010010730 }
10731 }
10732
10733 if (opcode == OpControlBarrier)
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010734 {
10735 if (execution_scope == ScopeSubgroup)
10736 statement("subgroupBarrier();");
10737 else
10738 statement("barrier();");
10739 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010740 break;
10741 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010742
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010743 case OpExtInst:
10744 {
10745 uint32_t extension_set = ops[2];
Lou Kramer6671f522017-11-21 14:04:57 +010010746
10747 if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010748 {
Lou Kramer6671f522017-11-21 14:04:57 +010010749 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
10750 }
10751 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_ballot)
10752 {
10753 emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
10754 }
10755 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
10756 {
10757 emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
10758 }
10759 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_trinary_minmax)
10760 {
10761 emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
10762 }
10763 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_gcn_shader)
10764 {
10765 emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
10766 }
Lifeng Pan5ca87792019-07-04 16:03:06 +080010767 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_debug_info)
10768 {
10769 break; // Ignore SPIR-V debug information extended instructions.
10770 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010010771 else
10772 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010773 statement("// unimplemented ext op ", instruction.op);
10774 break;
10775 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010776
Lou Kramer6671f522017-11-21 14:04:57 +010010777 break;
10778 }
10779
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010780 // Legacy sub-group stuff ...
Lou Kramer6671f522017-11-21 14:04:57 +010010781 case OpSubgroupBallotKHR:
10782 {
Lou Kramer6671f522017-11-21 14:04:57 +010010783 uint32_t result_type = ops[0];
10784 uint32_t id = ops[1];
10785 string expr;
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010786 expr = join("uvec4(unpackUint2x32(ballotARB(" + to_expression(ops[2]) + ")), 0u, 0u)");
Hans-Kristian Arntzen4979d102018-03-12 17:51:14 +010010787 emit_op(result_type, id, expr, should_forward(ops[2]));
Lou Kramer6671f522017-11-21 14:04:57 +010010788
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010789 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzenae2680c2018-03-12 17:42:48 +010010790 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010791 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010792 break;
10793 }
10794
10795 case OpSubgroupFirstInvocationKHR:
10796 {
Lou Kramer6671f522017-11-21 14:04:57 +010010797 uint32_t result_type = ops[0];
10798 uint32_t id = ops[1];
10799 emit_unary_func_op(result_type, id, ops[2], "readFirstInvocationARB");
10800
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010801 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010802 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010803 break;
10804 }
10805
10806 case OpSubgroupReadInvocationKHR:
10807 {
Lou Kramer6671f522017-11-21 14:04:57 +010010808 uint32_t result_type = ops[0];
10809 uint32_t id = ops[1];
10810 emit_binary_func_op(result_type, id, ops[2], ops[3], "readInvocationARB");
10811
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010812 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010813 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010814 break;
10815 }
10816
10817 case OpSubgroupAllKHR:
10818 {
Lou Kramer6671f522017-11-21 14:04:57 +010010819 uint32_t result_type = ops[0];
10820 uint32_t id = ops[1];
10821 emit_unary_func_op(result_type, id, ops[2], "allInvocationsARB");
10822
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010823 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010824 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010825 break;
10826 }
10827
10828 case OpSubgroupAnyKHR:
10829 {
Lou Kramer6671f522017-11-21 14:04:57 +010010830 uint32_t result_type = ops[0];
10831 uint32_t id = ops[1];
10832 emit_unary_func_op(result_type, id, ops[2], "anyInvocationARB");
10833
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010834 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010835 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010836 break;
10837 }
10838
10839 case OpSubgroupAllEqualKHR:
10840 {
Lou Kramer6671f522017-11-21 14:04:57 +010010841 uint32_t result_type = ops[0];
10842 uint32_t id = ops[1];
10843 emit_unary_func_op(result_type, id, ops[2], "allInvocationsEqualARB");
10844
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010845 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010846 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010847 break;
10848 }
10849
10850 case OpGroupIAddNonUniformAMD:
10851 case OpGroupFAddNonUniformAMD:
10852 {
Lou Kramer6671f522017-11-21 14:04:57 +010010853 uint32_t result_type = ops[0];
10854 uint32_t id = ops[1];
10855 emit_unary_func_op(result_type, id, ops[4], "addInvocationsNonUniformAMD");
10856
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010857 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010858 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010859 break;
10860 }
10861
10862 case OpGroupFMinNonUniformAMD:
10863 case OpGroupUMinNonUniformAMD:
10864 case OpGroupSMinNonUniformAMD:
10865 {
Lou Kramer6671f522017-11-21 14:04:57 +010010866 uint32_t result_type = ops[0];
10867 uint32_t id = ops[1];
10868 emit_unary_func_op(result_type, id, ops[4], "minInvocationsNonUniformAMD");
10869
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010870 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010871 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010872 break;
10873 }
10874
10875 case OpGroupFMaxNonUniformAMD:
10876 case OpGroupUMaxNonUniformAMD:
10877 case OpGroupSMaxNonUniformAMD:
10878 {
Lou Kramer6671f522017-11-21 14:04:57 +010010879 uint32_t result_type = ops[0];
10880 uint32_t id = ops[1];
10881 emit_unary_func_op(result_type, id, ops[4], "maxInvocationsNonUniformAMD");
10882
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010883 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010884 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010010885 break;
10886 }
10887
10888 case OpFragmentMaskFetchAMD:
10889 {
10890 auto &type = expression_type(ops[2]);
10891 uint32_t result_type = ops[0];
10892 uint32_t id = ops[1];
10893
10894 if (type.image.dim == spv::DimSubpassData)
10895 {
10896 emit_unary_func_op(result_type, id, ops[2], "fragmentMaskFetchAMD");
10897 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010010898 else
Lou Kramer6671f522017-11-21 14:04:57 +010010899 {
10900 emit_binary_func_op(result_type, id, ops[2], ops[3], "fragmentMaskFetchAMD");
10901 }
10902
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010903 require_extension_internal("GL_AMD_shader_fragment_mask");
Lou Kramer6671f522017-11-21 14:04:57 +010010904 break;
10905 }
10906
10907 case OpFragmentFetchAMD:
10908 {
10909 auto &type = expression_type(ops[2]);
10910 uint32_t result_type = ops[0];
10911 uint32_t id = ops[1];
10912
10913 if (type.image.dim == spv::DimSubpassData)
10914 {
10915 emit_binary_func_op(result_type, id, ops[2], ops[4], "fragmentFetchAMD");
10916 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010010917 else
Lou Kramer6671f522017-11-21 14:04:57 +010010918 {
10919 emit_trinary_func_op(result_type, id, ops[2], ops[3], ops[4], "fragmentFetchAMD");
10920 }
10921
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010922 require_extension_internal("GL_AMD_shader_fragment_mask");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010923 break;
10924 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010925
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010926 // Vulkan 1.1 sub-group stuff ...
10927 case OpGroupNonUniformElect:
10928 case OpGroupNonUniformBroadcast:
10929 case OpGroupNonUniformBroadcastFirst:
10930 case OpGroupNonUniformBallot:
10931 case OpGroupNonUniformInverseBallot:
10932 case OpGroupNonUniformBallotBitExtract:
10933 case OpGroupNonUniformBallotBitCount:
10934 case OpGroupNonUniformBallotFindLSB:
10935 case OpGroupNonUniformBallotFindMSB:
10936 case OpGroupNonUniformShuffle:
10937 case OpGroupNonUniformShuffleXor:
10938 case OpGroupNonUniformShuffleUp:
10939 case OpGroupNonUniformShuffleDown:
10940 case OpGroupNonUniformAll:
10941 case OpGroupNonUniformAny:
10942 case OpGroupNonUniformAllEqual:
10943 case OpGroupNonUniformFAdd:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020010944 case OpGroupNonUniformIAdd:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010945 case OpGroupNonUniformFMul:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020010946 case OpGroupNonUniformIMul:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010947 case OpGroupNonUniformFMin:
10948 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020010949 case OpGroupNonUniformSMin:
10950 case OpGroupNonUniformSMax:
10951 case OpGroupNonUniformUMin:
10952 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020010953 case OpGroupNonUniformBitwiseAnd:
10954 case OpGroupNonUniformBitwiseOr:
10955 case OpGroupNonUniformBitwiseXor:
10956 case OpGroupNonUniformQuadSwap:
10957 case OpGroupNonUniformQuadBroadcast:
10958 emit_subgroup_op(instruction);
10959 break;
10960
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020010961 case OpFUnordEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020010962 case OpFUnordNotEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020010963 case OpFUnordLessThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020010964 case OpFUnordGreaterThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020010965 case OpFUnordLessThanEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020010966 case OpFUnordGreaterThanEqual:
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020010967 {
10968 // GLSL doesn't specify if floating point comparisons are ordered or unordered,
10969 // but glslang always emits ordered floating point compares for GLSL.
10970 // To get unordered compares, we can test the opposite thing and invert the result.
10971 // This way, we force true when there is any NaN present.
10972 uint32_t op0 = ops[2];
10973 uint32_t op1 = ops[3];
10974
10975 string expr;
10976 if (expression_type(op0).vecsize > 1)
10977 {
10978 const char *comp_op = nullptr;
10979 switch (opcode)
10980 {
10981 case OpFUnordEqual:
10982 comp_op = "notEqual";
10983 break;
10984
10985 case OpFUnordNotEqual:
10986 comp_op = "equal";
10987 break;
10988
10989 case OpFUnordLessThan:
10990 comp_op = "greaterThanEqual";
10991 break;
10992
10993 case OpFUnordLessThanEqual:
10994 comp_op = "greaterThan";
10995 break;
10996
10997 case OpFUnordGreaterThan:
10998 comp_op = "lessThanEqual";
10999 break;
11000
11001 case OpFUnordGreaterThanEqual:
11002 comp_op = "lessThan";
11003 break;
11004
11005 default:
11006 assert(0);
11007 break;
11008 }
11009
11010 expr = join("not(", comp_op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), "))");
11011 }
11012 else
11013 {
11014 const char *comp_op = nullptr;
11015 switch (opcode)
11016 {
11017 case OpFUnordEqual:
11018 comp_op = " != ";
11019 break;
11020
11021 case OpFUnordNotEqual:
11022 comp_op = " == ";
11023 break;
11024
11025 case OpFUnordLessThan:
11026 comp_op = " >= ";
11027 break;
11028
11029 case OpFUnordLessThanEqual:
11030 comp_op = " > ";
11031 break;
11032
11033 case OpFUnordGreaterThan:
11034 comp_op = " <= ";
11035 break;
11036
11037 case OpFUnordGreaterThanEqual:
11038 comp_op = " < ";
11039 break;
11040
11041 default:
11042 assert(0);
11043 break;
11044 }
11045
11046 expr = join("!(", to_enclosed_unpacked_expression(op0), comp_op, to_enclosed_unpacked_expression(op1), ")");
11047 }
11048
11049 emit_op(ops[0], ops[1], expr, should_forward(op0) && should_forward(op1));
11050 inherit_expression_dependencies(ops[1], op0);
11051 inherit_expression_dependencies(ops[1], op1);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011052 break;
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020011053 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011054
Patrick Moursda39a7b2019-02-26 15:43:03 +010011055 case OpReportIntersectionNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010011056 statement("reportIntersectionNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020011057 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010011058 break;
11059 case OpIgnoreIntersectionNV:
11060 statement("ignoreIntersectionNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020011061 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010011062 break;
11063 case OpTerminateRayNV:
11064 statement("terminateRayNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020011065 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010011066 break;
11067 case OpTraceNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010011068 statement("traceNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
11069 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
11070 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
11071 to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020011072 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010011073 break;
11074 case OpExecuteCallableNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010011075 statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020011076 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010011077 break;
11078
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020011079 case OpConvertUToPtr:
11080 {
11081 auto &type = get<SPIRType>(ops[0]);
11082 if (type.storage != StorageClassPhysicalStorageBufferEXT)
11083 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertUToPtr.");
11084
11085 auto op = type_to_glsl(type);
11086 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
11087 break;
11088 }
11089
11090 case OpConvertPtrToU:
11091 {
11092 auto &type = get<SPIRType>(ops[0]);
11093 auto &ptr_type = expression_type(ops[2]);
11094 if (ptr_type.storage != StorageClassPhysicalStorageBufferEXT)
11095 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertPtrToU.");
11096
11097 auto op = type_to_glsl(type);
11098 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
11099 break;
11100 }
11101
lifpan876627d2019-04-08 19:45:31 +080011102 case OpUndef:
11103 // Undefined value has been declared.
11104 break;
11105
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020011106 case OpLine:
11107 {
11108 emit_line_directive(ops[0], ops[1]);
11109 break;
11110 }
11111
Lifeng Pan5ca87792019-07-04 16:03:06 +080011112 case OpNoLine:
11113 break;
11114
Chip Davis50dce102019-07-13 15:57:33 -050011115 case OpDemoteToHelperInvocationEXT:
11116 if (!options.vulkan_semantics)
11117 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
11118 require_extension_internal("GL_EXT_demote_to_helper_invocation");
11119 statement(backend.demote_literal, ";");
11120 break;
11121
11122 case OpIsHelperInvocationEXT:
11123 if (!options.vulkan_semantics)
11124 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
11125 require_extension_internal("GL_EXT_demote_to_helper_invocation");
Chip Davis12a86542019-07-18 17:32:35 -050011126 emit_op(ops[0], ops[1], "helperInvocationEXT()", false);
Chip Davis50dce102019-07-13 15:57:33 -050011127 break;
11128
Chip Davis2eff4202019-08-04 00:07:20 -050011129 case OpBeginInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020011130 // If the interlock is complex, we emit this elsewhere.
11131 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050011132 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020011133 if (options.es)
11134 statement("beginInvocationInterlockNV();");
11135 else
11136 statement("beginInvocationInterlockARB();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020011137
11138 flush_all_active_variables();
11139 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050011140 }
11141 break;
11142
11143 case OpEndInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020011144 // If the interlock is complex, we emit this elsewhere.
11145 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050011146 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020011147 if (options.es)
11148 statement("endInvocationInterlockNV();");
11149 else
11150 statement("endInvocationInterlockARB();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020011151
11152 flush_all_active_variables();
11153 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050011154 }
11155 break;
11156
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011157 default:
11158 statement("// unimplemented op ", instruction.op);
11159 break;
11160 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011161}
11162
Bill Hollingsa759e2c2016-10-19 14:09:51 -070011163// Appends function arguments, mapped from global variables, beyond the specified arg index.
Bill Hollingsfe8b8602016-07-06 16:55:45 -040011164// This is used when a function call uses fewer arguments than the function defines.
Bill Hollingsa759e2c2016-10-19 14:09:51 -070011165// This situation may occur if the function signature has been dynamically modified to
11166// extract global variables referenced from within the function, and convert them to
11167// function arguments. This is necessary for shader languages that do not support global
11168// access to shader input content from within a function (eg. Metal). Each additional
11169// function args uses the name of the global variable. Function nesting will modify the
Bill Hollingsfe3683e2018-01-24 15:38:17 -050011170// functions and function calls all the way up the nesting chain.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020011171void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<string> &arglist)
Bill Hollingsfe8b8602016-07-06 16:55:45 -040011172{
Bill Hollingsac00c602016-10-24 09:24:24 -040011173 auto &args = func.arguments;
Bill Hollings943191a2016-10-27 10:20:01 -040011174 uint32_t arg_cnt = uint32_t(args.size());
Bill Hollingsac00c602016-10-24 09:24:24 -040011175 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010011176 {
Bill Hollingsfe3683e2018-01-24 15:38:17 -050011177 auto &arg = args[arg_idx];
11178 assert(arg.alias_global_variable);
Bill Hollingsfe3683e2018-01-24 15:38:17 -050011179
11180 // If the underlying variable needs to be declared
11181 // (ie. a local variable with deferred declaration), do so now.
11182 uint32_t var_id = get<SPIRVariable>(arg.id).basevariable;
11183 if (var_id)
11184 flush_variable_declaration(var_id);
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +020011185
Chip Davis39dce882019-08-02 15:11:19 -050011186 arglist.push_back(to_func_call_arg(arg, arg.id));
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010011187 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -040011188}
11189
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011190string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
11191{
Hans-Kristian Arntzena0c13e42019-10-07 10:31:42 +020011192 if (type.type_alias != TypeID(0) &&
11193 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
11194 {
11195 return to_member_name(get<SPIRType>(type.type_alias), index);
11196 }
11197
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020011198 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011199 if (index < memb.size() && !memb[index].alias.empty())
11200 return memb[index].alias;
11201 else
Hans-Kristian Arntzen1c6df1b2017-07-29 21:44:20 +020011202 return join("_m", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011203}
11204
Chip Davis3bfb2f92018-12-03 02:06:33 -060011205string CompilerGLSL::to_member_reference(uint32_t, const SPIRType &type, uint32_t index, bool)
Chip Davis3a9af962018-09-26 20:06:05 -050011206{
11207 return join(".", to_member_name(type, index));
11208}
11209
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020011210void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
11211{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020011212 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020011213 if (index < memb.size() && !memb[index].alias.empty())
11214 {
11215 auto &name = memb[index].alias;
11216 if (name.empty())
11217 return;
11218
11219 // Reserved for temporaries.
11220 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
11221 {
11222 name.clear();
11223 return;
11224 }
11225
11226 update_name_cache(type.member_name_cache, name);
11227 }
11228}
11229
Bill Hollingsb332bae2017-03-01 13:07:40 -050011230// Checks whether the ID is a row_major matrix that requires conversion before use
Bill Hollings13583622016-12-14 02:12:52 -050011231bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011232{
Bill Hollings13583622016-12-14 02:12:52 -050011233 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010011234 // Legacy targets do not support row major.
11235 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050011236 return false;
11237
11238 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +010011239 if (!has_decoration(id, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -050011240 return false;
11241
11242 // Only square row-major matrices can be converted at this time.
11243 // Converting non-square matrices will require defining custom GLSL function that
11244 // swaps matrix elements while retaining the original dimensional form of the matrix.
11245 const auto type = expression_type(id);
11246 if (type.columns != type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +010011247 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -050011248
11249 return true;
Bill Hollings343677e2016-12-11 11:01:08 -050011250}
11251
Bill Hollings13583622016-12-14 02:12:52 -050011252// Checks whether the member is a row_major matrix that requires conversion before use
11253bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index)
Bill Hollings343677e2016-12-11 11:01:08 -050011254{
Bill Hollings13583622016-12-14 02:12:52 -050011255 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010011256 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050011257 return false;
11258
11259 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +010011260 if (!has_member_decoration(type.self, index, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -050011261 return false;
11262
11263 // Only square row-major matrices can be converted at this time.
11264 // Converting non-square matrices will require defining custom GLSL function that
11265 // swaps matrix elements while retaining the original dimensional form of the matrix.
11266 const auto mbr_type = get<SPIRType>(type.member_types[index]);
11267 if (mbr_type.columns != mbr_type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +010011268 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -050011269
11270 return true;
Bill Hollings343677e2016-12-11 11:01:08 -050011271}
11272
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020011273// Checks if we need to remap physical type IDs when declaring the type in a buffer.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020011274bool CompilerGLSL::member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const
Bill Hollingsb332bae2017-03-01 13:07:40 -050011275{
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020011276 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID);
11277}
11278
11279// Checks whether the member is in packed data type, that might need to be unpacked.
11280bool CompilerGLSL::member_is_packed_physical_type(const SPIRType &type, uint32_t index) const
11281{
11282 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
Bill Hollingsb332bae2017-03-01 13:07:40 -050011283}
11284
Bill Hollings13583622016-12-14 02:12:52 -050011285// Wraps the expression string in a function call that converts the
11286// row_major matrix result of the expression to a column_major matrix.
11287// Base implementation uses the standard library transpose() function.
11288// Subclasses may override to use a different function.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020011289string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t /* physical_type_id */,
11290 bool /*is_packed*/)
Bill Hollings343677e2016-12-11 11:01:08 -050011291{
11292 strip_enclosed_expression(exp_str);
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020011293 if (!is_matrix(exp_type))
11294 {
11295 auto column_index = exp_str.find_last_of('[');
11296 if (column_index == string::npos)
11297 return exp_str;
11298
11299 auto column_expr = exp_str.substr(column_index);
11300 exp_str.resize(column_index);
11301
11302 auto transposed_expr = type_to_glsl_constructor(exp_type) + "(";
11303
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020011304 // Loading a column from a row-major matrix. Unroll the load.
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020011305 for (uint32_t c = 0; c < exp_type.vecsize; c++)
11306 {
11307 transposed_expr += join(exp_str, '[', c, ']', column_expr);
11308 if (c + 1 < exp_type.vecsize)
11309 transposed_expr += ", ";
11310 }
11311
11312 transposed_expr += ")";
11313 return transposed_expr;
11314 }
11315 else
11316 return join("transpose(", exp_str, ")");
Bill Hollings343677e2016-12-11 11:01:08 -050011317}
11318
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020011319string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011320{
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020011321 string type_name = type_to_glsl(type, id);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +020011322 remap_variable_type_name(type, name, type_name);
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +020011323 return join(type_name, " ", name, type_to_array_glsl(type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011324}
11325
Bill Hollings484931d2017-02-28 21:44:36 -050011326// Emit a structure member. Subclasses may override to modify output,
11327// or to dynamically add a padding member if needed.
Bill Hollingsdc694272017-03-11 12:17:22 -050011328void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
msiglreithd096f5c2017-11-27 16:00:56 +010011329 const string &qualifier, uint32_t)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011330{
Bill Hollings484931d2017-02-28 21:44:36 -050011331 auto &membertype = get<SPIRType>(member_type_id);
11332
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011333 Bitset memberflags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020011334 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011335 if (index < memb.size())
11336 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011337
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020011338 string qualifiers;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020011339 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
11340 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011341
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020011342 if (is_block)
11343 qualifiers = to_interpolation_qualifiers(memberflags);
11344
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020011345 statement(layout_for_member(type, index), qualifiers, qualifier, flags_to_qualifiers_glsl(membertype, memberflags),
Bill Hollings484931d2017-02-28 21:44:36 -050011346 variable_decl(membertype, to_member_name(type, index)), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011347}
11348
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +020011349void CompilerGLSL::emit_struct_padding_target(const SPIRType &)
11350{
11351}
11352
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020011353const char *CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011354{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020011355 // GL_EXT_buffer_reference variables can be marked as restrict.
11356 if (flags.get(DecorationRestrictPointerEXT))
11357 return "restrict ";
11358
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010011359 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
11360 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
11361 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
11362 type.basetype != SPIRType::Sampler)
11363 return "";
11364
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011365 if (options.es)
11366 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +020011367 auto &execution = get_entry_point();
11368
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011369 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011370 {
11371 bool implied_fmediump = type.basetype == SPIRType::Float &&
11372 options.fragment.default_float_precision == Options::Mediump &&
11373 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011374
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011375 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
11376 options.fragment.default_int_precision == Options::Mediump &&
11377 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011378
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011379 return implied_fmediump || implied_imediump ? "" : "mediump ";
11380 }
11381 else
11382 {
11383 bool implied_fhighp =
11384 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
11385 execution.model == ExecutionModelFragment) ||
11386 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011387
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011388 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
11389 ((options.fragment.default_int_precision == Options::Highp &&
11390 execution.model == ExecutionModelFragment) ||
11391 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011392
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011393 return implied_fhighp || implied_ihighp ? "" : "highp ";
11394 }
11395 }
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010011396 else if (backend.allow_precision_qualifiers)
11397 {
11398 // Vulkan GLSL supports precision qualifiers, even in desktop profiles, which is convenient.
11399 // The default is highp however, so only emit mediump in the rare case that a shader has these.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011400 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen01080362018-05-11 10:59:29 +020011401 return "mediump ";
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010011402 else
11403 return "";
11404 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011405 else
11406 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011407}
11408
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011409const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011410{
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020011411 auto &type = expression_type(id);
11412 bool use_precision_qualifiers = backend.allow_precision_qualifiers || options.es;
11413 if (use_precision_qualifiers && (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage))
11414 {
11415 // Force mediump for the sampler type. We cannot declare 16-bit or smaller image types.
11416 auto &result_type = get<SPIRType>(type.image.type);
11417 if (result_type.width < 32)
11418 return "mediump ";
11419 }
11420 return flags_to_qualifiers_glsl(type, ir.meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011421}
11422
11423string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
11424{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010011425 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011426 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011428 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011429
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011430 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
11431 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011432
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020011433 res += to_interpolation_qualifiers(flags);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010011434 if (var)
11435 res += to_storage_qualifiers_glsl(*var);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010011436
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020011437 auto &type = expression_type(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011438 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
11439 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011440 if (flags.get(DecorationCoherent))
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020011441 res += "coherent ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011442 if (flags.get(DecorationRestrict))
Hans-Kristian Arntzen11dfcb62017-08-29 15:54:22 +020011443 res += "restrict ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011444 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011445 res += "readonly ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011446 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011447 res += "writeonly ";
11448 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011449
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020011450 res += to_precision_qualifiers_glsl(id);
11451
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011452 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011453}
11454
11455string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
11456{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011457 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011458 auto &type = expression_type(arg.id);
11459 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011460
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011461 if (type.pointer)
11462 {
11463 if (arg.write_count && arg.read_count)
11464 direction = "inout ";
11465 else if (arg.write_count)
11466 direction = "out ";
11467 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011468
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020011469 return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id), arg.id));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011470}
11471
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020011472string CompilerGLSL::to_initializer_expression(const SPIRVariable &var)
11473{
11474 return to_expression(var.initializer);
11475}
11476
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010011477string CompilerGLSL::to_zero_initialized_expression(uint32_t type_id)
11478{
11479#ifndef NDEBUG
11480 auto &type = get<SPIRType>(type_id);
11481 assert(type.storage == StorageClassPrivate || type.storage == StorageClassFunction ||
11482 type.storage == StorageClassGeneric);
11483#endif
11484 uint32_t id = ir.increase_bound_by(1);
11485 ir.make_constant_null(id, type_id, false);
11486 return constant_expression(get<SPIRConstant>(id));
11487}
11488
11489bool CompilerGLSL::type_can_zero_initialize(const SPIRType &type) const
11490{
11491 if (type.pointer)
11492 return false;
11493
11494 if (!type.array.empty() && options.flatten_multidimensional_arrays)
11495 return false;
11496
11497 for (auto &literal : type.array_size_literal)
11498 if (!literal)
11499 return false;
11500
11501 for (auto &memb : type.member_types)
11502 if (!type_can_zero_initialize(get<SPIRType>(memb)))
11503 return false;
11504
11505 return true;
11506}
11507
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011508string CompilerGLSL::variable_decl(const SPIRVariable &variable)
11509{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011510 // Ignore the pointer type since GLSL doesn't have pointers.
Chip Davis3bfb2f92018-12-03 02:06:33 -060011511 auto &type = get_variable_data_type(variable);
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +020011512
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +010011513 if (type.pointer_depth > 1)
11514 SPIRV_CROSS_THROW("Cannot declare pointer-to-pointer types.");
11515
Hans-Kristian Arntzenb0f7dee2017-06-17 10:56:24 +020011516 auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self), variable.self));
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +020011517
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010011518 if (variable.loop_variable && variable.static_expression)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010011519 {
11520 uint32_t expr = variable.static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020011521 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010011522 res += join(" = ", to_expression(variable.static_expression));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010011523 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
11524 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010011525 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010011526 else if (variable.initializer)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010011527 {
11528 uint32_t expr = variable.initializer;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020011529 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020011530 res += join(" = ", to_initializer_expression(variable));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010011531 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
11532 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010011533 }
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010011534
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011535 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011536}
11537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011538const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011539{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010011540 auto &flags = ir.meta[variable.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011541 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011542 return "mediump ";
11543 else
11544 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011545}
11546
11547string CompilerGLSL::pls_decl(const PlsRemap &var)
11548{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011549 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011550
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011551 SPIRType type;
11552 type.vecsize = pls_format_to_components(var.format);
11553 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011555 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
11556 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011557}
11558
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +010011559uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type) const
11560{
11561 return to_array_size_literal(type, uint32_t(type.array.size() - 1));
11562}
11563
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020011564uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t index) const
11565{
11566 assert(type.array.size() == type.array_size_literal.size());
11567
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010011568 if (type.array_size_literal[index])
11569 {
11570 return type.array[index];
11571 }
11572 else
11573 {
11574 // Use the default spec constant value.
11575 // This is the best we can do.
11576 uint32_t array_size_id = type.array[index];
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +010011577
11578 // Explicitly check for this case. The error message you would get (bad cast) makes no sense otherwise.
11579 if (ir.ids[array_size_id].get_type() == TypeConstantOp)
11580 SPIRV_CROSS_THROW("An array size was found to be an OpSpecConstantOp. This is not supported since "
11581 "SPIRV-Cross cannot deduce the actual size here.");
11582
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010011583 uint32_t array_size = get<SPIRConstant>(array_size_id).scalar();
11584 return array_size;
11585 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020011586}
11587
11588string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index)
11589{
11590 assert(type.array.size() == type.array_size_literal.size());
11591
11592 auto &size = type.array[index];
11593 if (!type.array_size_literal[index])
11594 return to_expression(size);
11595 else if (size)
11596 return convert_to_string(size);
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020011597 else if (!backend.unsized_array_supported)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020011598 {
11599 // For runtime-sized arrays, we can work around
11600 // lack of standard support for this by simply having
11601 // a single element array.
11602 //
11603 // Runtime length arrays must always be the last element
11604 // in an interface block.
11605 return "1";
11606 }
11607 else
11608 return "";
11609}
11610
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011611string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
11612{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020011613 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
11614 {
11615 // We are using a wrapped pointer type, and we should not emit any array declarations here.
11616 return "";
11617 }
11618
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011619 if (type.array.empty())
11620 return "";
11621
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020011622 if (options.flatten_multidimensional_arrays)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011623 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020011624 string res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011625 res += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020011626 for (auto i = uint32_t(type.array.size()); i; i--)
11627 {
11628 res += enclose_expression(to_array_size(type, i - 1));
11629 if (i > 1)
11630 res += " * ";
11631 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011632 res += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020011633 return res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011634 }
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020011635 else
11636 {
11637 if (type.array.size() > 1)
11638 {
11639 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011640 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020011641 else if (options.es && options.version < 310)
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020011642 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
11643 "Try using --flatten-multidimensional-arrays or set "
11644 "options.flatten_multidimensional_arrays to true.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020011645 }
11646
11647 string res;
11648 for (auto i = uint32_t(type.array.size()); i; i--)
11649 {
11650 res += "[";
11651 res += to_array_size(type, i - 1);
11652 res += "]";
11653 }
11654 return res;
11655 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011656}
11657
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020011658string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011659{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011660 auto &imagetype = get<SPIRType>(type.image.type);
11661 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011662
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011663 switch (imagetype.basetype)
11664 {
11665 case SPIRType::Int:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020011666 case SPIRType::Short:
11667 case SPIRType::SByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011668 res = "i";
11669 break;
11670 case SPIRType::UInt:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020011671 case SPIRType::UShort:
11672 case SPIRType::UByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011673 res = "u";
11674 break;
11675 default:
11676 break;
11677 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011678
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020011679 // For half image types, we will force mediump for the sampler, and cast to f16 after any sampling operation.
11680 // We cannot express a true half texture type in GLSL. Neither for short integer formats for that matter.
11681
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011682 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011683 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010011684 else if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
11685 subpass_input_is_framebuffer_fetch(id))
11686 {
11687 SPIRType sampled_type = get<SPIRType>(type.image.type);
11688 sampled_type.vecsize = 4;
11689 return type_to_glsl(sampled_type);
11690 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011691
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011692 // If we're emulating subpassInput with samplers, force sampler2D
11693 // so we don't have to specify format.
11694 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +020011695 {
11696 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
11697 if (type.image.dim == DimBuffer && type.image.sampled == 1)
11698 res += "sampler";
11699 else
11700 res += type.image.sampled == 2 ? "image" : "texture";
11701 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011702 else
11703 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011705 switch (type.image.dim)
11706 {
11707 case Dim1D:
11708 res += "1D";
11709 break;
11710 case Dim2D:
11711 res += "2D";
11712 break;
11713 case Dim3D:
11714 res += "3D";
11715 break;
11716 case DimCube:
11717 res += "Cube";
11718 break;
Sidney Justfbb4df32019-01-06 12:21:59 -080011719 case DimRect:
11720 if (options.es)
11721 SPIRV_CROSS_THROW("Rectangle textures are not supported on OpenGL ES.");
11722
11723 if (is_legacy_desktop())
11724 require_extension_internal("GL_ARB_texture_rectangle");
11725
11726 res += "2DRect";
11727 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011728
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011729 case DimBuffer:
11730 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011731 require_extension_internal("GL_OES_texture_buffer");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011732 else if (!options.es && options.version < 300)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011733 require_extension_internal("GL_EXT_texture_buffer_object");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011734 res += "Buffer";
11735 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011736
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011737 case DimSubpassData:
11738 res += "2D";
11739 break;
11740 default:
Sidney Justfbb4df32019-01-06 12:21:59 -080011741 SPIRV_CROSS_THROW("Only 1D, 2D, 2DRect, 3D, Buffer, InputTarget and Cube textures supported.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011742 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011743
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011744 if (type.image.ms)
11745 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011746 if (type.image.arrayed)
Rob Fischer21990632016-09-17 17:01:50 +090011747 {
Lubos Lenco52158642016-09-17 15:56:23 +020011748 if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011749 require_extension_internal("GL_EXT_texture_array");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011750 res += "Array";
Rob Fischer21990632016-09-17 17:01:50 +090011751 }
Hans-Kristian Arntzena3ae8612018-02-09 12:37:17 +010011752
11753 // "Shadow" state in GLSL only exists for samplers and combined image samplers.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020011754 if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) &&
11755 image_is_comparison(type, id))
11756 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011757 res += "Shadow";
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020011758 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011759
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011760 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011761}
11762
11763string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
11764{
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020011765 if (backend.use_array_constructor && type.array.size() > 1)
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020011766 {
11767 if (options.flatten_multidimensional_arrays)
11768 SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, e.g. float[][]().");
11769 else if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011770 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020011771 else if (options.es && options.version < 310)
11772 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
11773 }
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020011774
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011775 auto e = type_to_glsl(type);
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020011776 if (backend.use_array_constructor)
11777 {
11778 for (uint32_t i = 0; i < type.array.size(); i++)
11779 e += "[]";
11780 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011781 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011782}
11783
Bill Hollingsb41e1482017-05-29 20:45:05 -040011784// The optional id parameter indicates the object whose type we are trying
11785// to find the description for. It is optional. Most type descriptions do not
11786// depend on a specific object's use of that type.
11787string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011788{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020011789 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
11790 {
11791 // Need to create a magic type name which compacts the entire type information.
11792 string name = type_to_glsl(get_pointee_type(type));
11793 for (size_t i = 0; i < type.array.size(); i++)
11794 {
11795 if (type.array_size_literal[i])
11796 name += join(type.array[i], "_");
11797 else
11798 name += join("id", type.array[i], "_");
11799 }
11800 name += "Pointer";
11801 return name;
11802 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011803
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011804 switch (type.basetype)
11805 {
11806 case SPIRType::Struct:
11807 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020011808 if (backend.explicit_struct_type)
11809 return join("struct ", to_name(type.self));
11810 else
11811 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011812
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011813 case SPIRType::Image:
11814 case SPIRType::SampledImage:
Bill Hollingsb41e1482017-05-29 20:45:05 -040011815 return image_type_glsl(type, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011816
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011817 case SPIRType::Sampler:
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +020011818 // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
11819 // this distinction into the type system.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020011820 return comparison_ids.count(id) ? "samplerShadow" : "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011821
Hans-Kristian Arntzen6b0e5582020-04-21 14:25:18 +020011822 case SPIRType::AccelerationStructure:
Patrick Moursda39a7b2019-02-26 15:43:03 +010011823 return "accelerationStructureNV";
11824
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011825 case SPIRType::Void:
11826 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011827
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011828 default:
11829 break;
11830 }
11831
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020011832 if (type.basetype == SPIRType::UInt && is_legacy())
11833 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
11834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011835 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
11836 {
11837 switch (type.basetype)
11838 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020011839 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011840 return "bool";
Chip Davis117ccf42018-11-01 17:20:07 -050011841 case SPIRType::SByte:
11842 return backend.basic_int8_type;
11843 case SPIRType::UByte:
11844 return backend.basic_uint8_type;
11845 case SPIRType::Short:
11846 return backend.basic_int16_type;
11847 case SPIRType::UShort:
11848 return backend.basic_uint16_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011849 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050011850 return backend.basic_int_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011851 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050011852 return backend.basic_uint_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011853 case SPIRType::AtomicCounter:
11854 return "atomic_uint";
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010011855 case SPIRType::Half:
11856 return "float16_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011857 case SPIRType::Float:
11858 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020011859 case SPIRType::Double:
11860 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020011861 case SPIRType::Int64:
11862 return "int64_t";
11863 case SPIRType::UInt64:
11864 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011865 default:
11866 return "???";
11867 }
11868 }
11869 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
11870 {
11871 switch (type.basetype)
11872 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020011873 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011874 return join("bvec", type.vecsize);
Chip Davis117ccf42018-11-01 17:20:07 -050011875 case SPIRType::SByte:
11876 return join("i8vec", type.vecsize);
11877 case SPIRType::UByte:
11878 return join("u8vec", type.vecsize);
11879 case SPIRType::Short:
11880 return join("i16vec", type.vecsize);
11881 case SPIRType::UShort:
11882 return join("u16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011883 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050011884 return join("ivec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011885 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050011886 return join("uvec", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010011887 case SPIRType::Half:
11888 return join("f16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011889 case SPIRType::Float:
11890 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020011891 case SPIRType::Double:
11892 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020011893 case SPIRType::Int64:
11894 return join("i64vec", type.vecsize);
11895 case SPIRType::UInt64:
11896 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011897 default:
11898 return "???";
11899 }
11900 }
11901 else if (type.vecsize == type.columns) // Simple Matrix builtin
11902 {
11903 switch (type.basetype)
11904 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020011905 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011906 return join("bmat", type.vecsize);
11907 case SPIRType::Int:
11908 return join("imat", type.vecsize);
11909 case SPIRType::UInt:
11910 return join("umat", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010011911 case SPIRType::Half:
11912 return join("f16mat", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011913 case SPIRType::Float:
11914 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020011915 case SPIRType::Double:
11916 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020011917 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011918 default:
11919 return "???";
11920 }
11921 }
11922 else
11923 {
11924 switch (type.basetype)
11925 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020011926 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011927 return join("bmat", type.columns, "x", type.vecsize);
11928 case SPIRType::Int:
11929 return join("imat", type.columns, "x", type.vecsize);
11930 case SPIRType::UInt:
11931 return join("umat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010011932 case SPIRType::Half:
11933 return join("f16mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011934 case SPIRType::Float:
11935 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020011936 case SPIRType::Double:
11937 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020011938 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011939 default:
11940 return "???";
11941 }
11942 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011943}
11944
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010011945void CompilerGLSL::add_variable(unordered_set<string> &variables_primary,
11946 const unordered_set<string> &variables_secondary, string &name)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011947{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011948 if (name.empty())
11949 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011950
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011951 // Reserved for temporaries.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020011952 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011953 {
11954 name.clear();
11955 return;
11956 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011957
Hans-Kristian Arntzen6bcc8902018-06-04 10:13:57 +020011958 // Avoid double underscores.
11959 name = sanitize_underscores(name);
11960
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010011961 update_name_cache(variables_primary, variables_secondary, name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +010011962}
11963
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020011964void CompilerGLSL::add_local_variable_name(uint32_t id)
11965{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010011966 add_variable(local_variable_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020011967}
11968
11969void CompilerGLSL::add_resource_name(uint32_t id)
11970{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010011971 add_variable(resource_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011972}
11973
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +020011974void CompilerGLSL::add_header_line(const std::string &line)
11975{
11976 header_lines.push_back(line);
11977}
11978
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010011979bool CompilerGLSL::has_extension(const std::string &ext) const
11980{
11981 auto itr = find(begin(forced_extensions), end(forced_extensions), ext);
11982 return itr != end(forced_extensions);
11983}
11984
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011985void CompilerGLSL::require_extension(const std::string &ext)
11986{
11987 if (!has_extension(ext))
11988 forced_extensions.push_back(ext);
11989}
11990
11991void CompilerGLSL::require_extension_internal(const string &ext)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011992{
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010011993 if (backend.supports_extensions && !has_extension(ext))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011994 {
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010011995 forced_extensions.push_back(ext);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011996 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011997 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011998}
11999
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012000void CompilerGLSL::flatten_buffer_block(VariableID id)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012001{
12002 auto &var = get<SPIRVariable>(id);
12003 auto &type = get<SPIRType>(var.basetype);
12004 auto name = to_name(type.self, false);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010012005 auto &flags = ir.meta[type.self].decoration.decoration_flags;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012006
12007 if (!type.array.empty())
12008 SPIRV_CROSS_THROW(name + " is an array of UBOs.");
12009 if (type.basetype != SPIRType::Struct)
12010 SPIRV_CROSS_THROW(name + " is not a struct.");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012011 if (!flags.get(DecorationBlock))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012012 SPIRV_CROSS_THROW(name + " is not a block.");
12013 if (type.member_types.empty())
12014 SPIRV_CROSS_THROW(name + " is an empty struct.");
12015
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012016 flattened_buffer_blocks.insert(id);
12017}
12018
Lukas Hermanns6673a672019-10-22 11:06:16 -040012019bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) const
12020{
12021 return false; // GLSL itself does not need to translate array builtin types to non-array builtin types
12022}
12023
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012024bool CompilerGLSL::check_atomic_image(uint32_t id)
12025{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012026 auto &type = expression_type(id);
12027 if (type.storage == StorageClassImage)
12028 {
12029 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012030 require_extension_internal("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012031
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012032 auto *var = maybe_get_backing_variable(id);
12033 if (var)
12034 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010012035 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012036 if (flags.get(DecorationNonWritable) || flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012037 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012038 flags.clear(DecorationNonWritable);
12039 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012040 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012041 }
12042 }
12043 return true;
12044 }
12045 else
12046 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012047}
12048
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010012049void CompilerGLSL::add_function_overload(const SPIRFunction &func)
12050{
12051 Hasher hasher;
12052 for (auto &arg : func.arguments)
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010012053 {
12054 // Parameters can vary with pointer type or not,
12055 // but that will not change the signature in GLSL/HLSL,
12056 // so strip the pointer type before hashing.
Chip Davisfc02b3d2019-01-08 12:54:40 -060012057 uint32_t type_id = get_pointee_type_id(arg.type);
Bill Hollingse0910312018-06-24 15:06:12 -040012058 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020012059
12060 if (!combined_image_samplers.empty())
12061 {
12062 // If we have combined image samplers, we cannot really trust the image and sampler arguments
12063 // we pass down to callees, because they may be shuffled around.
12064 // Ignore these arguments, to make sure that functions need to differ in some other way
12065 // to be considered different overloads.
Bill Hollingse0910312018-06-24 15:06:12 -040012066 if (type.basetype == SPIRType::SampledImage ||
12067 (type.basetype == SPIRType::Image && type.image.sampled == 1) || type.basetype == SPIRType::Sampler)
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020012068 {
12069 continue;
12070 }
12071 }
12072
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010012073 hasher.u32(type_id);
12074 }
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010012075 uint64_t types_hash = hasher.get();
12076
12077 auto function_name = to_name(func.self);
12078 auto itr = function_overloads.find(function_name);
12079 if (itr != end(function_overloads))
12080 {
12081 // There exists a function with this name already.
12082 auto &overloads = itr->second;
12083 if (overloads.count(types_hash) != 0)
12084 {
12085 // Overload conflict, assign a new name.
12086 add_resource_name(func.self);
12087 function_overloads[to_name(func.self)].insert(types_hash);
12088 }
12089 else
12090 {
12091 // Can reuse the name.
12092 overloads.insert(types_hash);
12093 }
12094 }
12095 else
12096 {
12097 // First time we see this function name.
12098 add_resource_name(func.self);
12099 function_overloads[to_name(func.self)].insert(types_hash);
12100 }
12101}
12102
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012103void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012104{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012105 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010012106 add_function_overload(func);
12107
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012108 // Avoid shadow declarations.
12109 local_variable_names = resource_names;
12110
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012111 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012112
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012113 auto &type = get<SPIRType>(func.return_type);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012114 decl += flags_to_qualifiers_glsl(type, return_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012115 decl += type_to_glsl(type);
Hans-Kristian Arntzen9fa91f72018-02-05 09:34:54 +010012116 decl += type_to_array_glsl(type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012117 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012118
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012119 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012120 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012121 // If we need complex fallback in GLSL, we just wrap main() in a function
12122 // and interlock the entire shader ...
12123 if (interlocked_is_complex)
12124 decl += "spvMainInterlockedBody";
12125 else
12126 decl += "main";
12127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012128 processing_entry_point = true;
12129 }
12130 else
Bill Hollings1c180782017-11-05 21:34:42 -050012131 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012132
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012133 decl += "(";
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020012134 SmallVector<string> arglist;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012135 for (auto &arg : func.arguments)
12136 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020012137 // Do not pass in separate images or samplers if we're remapping
12138 // to combined image samplers.
12139 if (skip_argument(arg.id))
12140 continue;
12141
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012142 // Might change the variable name if it already exists in this function.
12143 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
12144 // to use same name for variables.
12145 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012146 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012147
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020012148 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012149
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012150 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
12151 auto *var = maybe_get<SPIRVariable>(arg.id);
12152 if (var)
12153 var->parameter = &arg;
12154 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012155
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +020012156 for (auto &arg : func.shadow_arguments)
12157 {
12158 // Might change the variable name if it already exists in this function.
12159 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
12160 // to use same name for variables.
12161 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
12162 add_local_variable_name(arg.id);
12163
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020012164 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012165
12166 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
12167 auto *var = maybe_get<SPIRVariable>(arg.id);
12168 if (var)
12169 var->parameter = &arg;
12170 }
12171
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020012172 decl += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012173 decl += ")";
12174 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012175}
12176
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012177void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012178{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012179 // Avoid potential cycles.
12180 if (func.active)
12181 return;
12182 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012183
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012184 // If we depend on a function, emit that function before we emit our own function.
12185 for (auto block : func.blocks)
12186 {
12187 auto &b = get<SPIRBlock>(block);
12188 for (auto &i : b.ops)
12189 {
12190 auto ops = stream(i);
12191 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012193 if (op == OpFunctionCall)
12194 {
12195 // Recursively emit functions which are called.
12196 uint32_t id = ops[2];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012197 emit_function(get<SPIRFunction>(id), ir.meta[ops[1]].decoration.decoration_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012198 }
12199 }
12200 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012201
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020012202 if (func.entry_line.file_id != 0)
12203 emit_line_directive(func.entry_line.file_id, func.entry_line.line_literal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012204 emit_function_prototype(func, return_flags);
12205 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012206
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012207 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +020012208 emit_entry_point_declarations();
12209
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012210 current_function = &func;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012211 auto &entry_block = get<SPIRBlock>(func.entry_block);
12212
Hans-Kristian Arntzen30343f32020-02-24 13:22:52 +010012213 sort(begin(func.constant_arrays_needed_on_stack), end(func.constant_arrays_needed_on_stack));
12214 for (auto &array : func.constant_arrays_needed_on_stack)
12215 {
12216 auto &c = get<SPIRConstant>(array);
12217 auto &type = get<SPIRType>(c.constant_type);
12218 statement(variable_decl(type, join("_", array, "_array_copy")), " = ", constant_expression(c), ";");
12219 }
12220
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012221 for (auto &v : func.local_variables)
12222 {
12223 auto &var = get<SPIRVariable>(v);
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020012224 var.deferred_declaration = false;
12225
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020012226 if (var.storage == StorageClassWorkgroup)
12227 {
12228 // Special variable type which cannot have initializer,
12229 // need to be declared as standalone variables.
12230 // Comes from MSL which can push global variables as local variables in main function.
12231 add_local_variable_name(var.self);
12232 statement(variable_decl(var), ";");
12233 var.deferred_declaration = false;
12234 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020012235 else if (var.storage == StorageClassPrivate)
12236 {
12237 // These variables will not have had their CFG usage analyzed, so move it to the entry block.
12238 // Comes from MSL which can push global variables as local variables in main function.
12239 // We could just declare them right now, but we would miss out on an important initialization case which is
12240 // LUT declaration in MSL.
12241 // If we don't declare the variable when it is assigned we're forced to go through a helper function
12242 // which copies elements one by one.
12243 add_local_variable_name(var.self);
Hans-Kristian Arntzenf8592ec2020-04-21 11:20:49 +020012244
12245 if (var.initializer)
12246 {
12247 statement(variable_decl(var), ";");
12248 var.deferred_declaration = false;
12249 }
12250 else
12251 {
12252 auto &dominated = entry_block.dominated_variables;
12253 if (find(begin(dominated), end(dominated), var.self) == end(dominated))
12254 entry_block.dominated_variables.push_back(var.self);
12255 var.deferred_declaration = true;
12256 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020012257 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020012258 else if (var.storage == StorageClassFunction && var.remapped_variable && var.static_expression)
12259 {
12260 // No need to declare this variable, it has a static expression.
12261 var.deferred_declaration = false;
12262 }
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020012263 else if (expression_is_lvalue(v))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012264 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012265 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012266
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012267 if (var.initializer)
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +010012268 statement(variable_decl_function_local(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012269 else
12270 {
12271 // Don't declare variable until first use to declutter the GLSL output quite a lot.
12272 // If we don't touch the variable before first branch,
12273 // declare it then since we need variable declaration to be in top scope.
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020012274 var.deferred_declaration = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012275 }
12276 }
12277 else
12278 {
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020012279 // HACK: SPIR-V in older glslang output likes to use samplers and images as local variables, but GLSL does not allow this.
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012280 // For these types (non-lvalue), we enforce forwarding through a shadowed variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012281 // This means that when we OpStore to these variables, we just write in the expression ID directly.
12282 // This breaks any kind of branching, since the variable must be statically assigned.
12283 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
12284 var.statically_assigned = true;
12285 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012286
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012287 var.loop_variable_enable = false;
Hans-Kristian Arntzenb847c882016-11-18 17:06:49 +010012288
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012289 // Loop variables are never declared outside their for-loop, so block any implicit declaration.
12290 if (var.loop_variable)
12291 var.deferred_declaration = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012292 }
12293
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020012294 // Enforce declaration order for regression testing purposes.
12295 for (auto &block_id : func.blocks)
12296 {
12297 auto &block = get<SPIRBlock>(block_id);
12298 sort(begin(block.dominated_variables), end(block.dominated_variables));
12299 }
12300
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020012301 for (auto &line : current_function->fixup_hooks_in)
12302 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040012303
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012304 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012305
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012306 end_scope();
12307 processing_entry_point = false;
12308 statement("");
Hans-Kristian Arntzend81bfc52019-06-13 10:31:37 +020012309
12310 // Make sure deferred declaration state for local variables is cleared when we are done with function.
12311 // We risk declaring Private/Workgroup variables in places we are not supposed to otherwise.
12312 for (auto &v : func.local_variables)
12313 {
12314 auto &var = get<SPIRVariable>(v);
12315 var.deferred_declaration = false;
12316 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012317}
12318
12319void CompilerGLSL::emit_fixup()
12320{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +020012321 auto &execution = get_entry_point();
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020012322 if (execution.model == ExecutionModelVertex)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012323 {
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020012324 if (options.vertex.fixup_clipspace)
12325 {
12326 const char *suffix = backend.float_literal_suffix ? "f" : "";
12327 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
12328 }
12329
12330 if (options.vertex.flip_vert_y)
12331 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012332 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012333}
12334
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012335void CompilerGLSL::flush_phi(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012336{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012337 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020012338 if (child.ignore_phi_from_block == from)
12339 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012340
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012341 unordered_set<uint32_t> temporary_phi_variables;
12342
12343 for (auto itr = begin(child.phi_variables); itr != end(child.phi_variables); ++itr)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020012344 {
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012345 auto &phi = *itr;
12346
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012347 if (phi.parent == from)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020012348 {
12349 auto &var = get<SPIRVariable>(phi.function_variable);
12350
12351 // A Phi variable might be a loop variable, so flush to static expression.
12352 if (var.loop_variable && !var.loop_variable_enable)
12353 var.static_expression = phi.local_variable;
12354 else
12355 {
12356 flush_variable_declaration(phi.function_variable);
12357
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012358 // Check if we are going to write to a Phi variable that another statement will read from
12359 // as part of another Phi node in our target block.
12360 // For this case, we will need to copy phi.function_variable to a temporary, and use that for future reads.
12361 // This is judged to be extremely rare, so deal with it here using a simple, but suboptimal algorithm.
12362 bool need_saved_temporary =
12363 find_if(itr + 1, end(child.phi_variables), [&](const SPIRBlock::Phi &future_phi) -> bool {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012364 return future_phi.local_variable == ID(phi.function_variable) && future_phi.parent == from;
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012365 }) != end(child.phi_variables);
12366
12367 if (need_saved_temporary)
12368 {
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010012369 // Need to make sure we declare the phi variable with a copy at the right scope.
12370 // We cannot safely declare a temporary here since we might be inside a continue block.
12371 if (!var.allocate_temporary_copy)
12372 {
12373 var.allocate_temporary_copy = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012374 force_recompile();
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010012375 }
12376 statement("_", phi.function_variable, "_copy", " = ", to_name(phi.function_variable), ";");
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012377 temporary_phi_variables.insert(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012378 }
12379
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020012380 // This might be called in continue block, so make sure we
Hans-Kristian Arntzen91753632017-09-25 10:16:45 +020012381 // use this to emit ESSL 1.0 compliant increments/decrements.
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020012382 auto lhs = to_expression(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012383
12384 string rhs;
12385 if (temporary_phi_variables.count(phi.local_variable))
12386 rhs = join("_", phi.local_variable, "_copy");
12387 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060012388 rhs = to_pointer_expression(phi.local_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012389
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020012390 if (!optimize_read_modify_write(get<SPIRType>(var.basetype), lhs, rhs))
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020012391 statement(lhs, " = ", rhs, ";");
12392 }
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010012393
12394 register_write(phi.function_variable);
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020012395 }
12396 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012397}
12398
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012399void CompilerGLSL::branch_to_continue(BlockID from, BlockID to)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012400{
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012401 auto &to_block = get<SPIRBlock>(to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010012402 if (from == to)
12403 return;
12404
12405 assert(is_continue(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012406 if (to_block.complex_continue)
12407 {
12408 // Just emit the whole block chain as is.
12409 auto usage_counts = expression_usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012410
12411 emit_block_chain(to_block);
12412
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020012413 // Expression usage counts are moot after returning from the continue block.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012414 expression_usage_counts = usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012415 }
12416 else
12417 {
12418 auto &from_block = get<SPIRBlock>(from);
12419 bool outside_control_flow = false;
12420 uint32_t loop_dominator = 0;
12421
12422 // FIXME: Refactor this to not use the old loop_dominator tracking.
12423 if (from_block.merge_block)
12424 {
12425 // If we are a loop header, we don't set the loop dominator,
12426 // so just use "self" here.
12427 loop_dominator = from;
12428 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012429 else if (from_block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012430 {
12431 loop_dominator = from_block.loop_dominator;
12432 }
12433
12434 if (loop_dominator != 0)
12435 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020012436 auto &cfg = get_cfg_for_current_function();
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012437
12438 // For non-complex continue blocks, we implicitly branch to the continue block
12439 // by having the continue block be part of the loop header in for (; ; continue-block).
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020012440 outside_control_flow = cfg.node_terminates_control_flow_in_sub_graph(loop_dominator, from);
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012441 }
12442
12443 // Some simplification for for-loops. We always end up with a useless continue;
12444 // statement since we branch to a loop block.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020012445 // Walk the CFG, if we unconditionally execute the block calling continue assuming we're in the loop block,
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012446 // we can avoid writing out an explicit continue statement.
12447 // Similar optimization to return statements if we know we're outside flow control.
12448 if (!outside_control_flow)
12449 statement("continue;");
12450 }
12451}
12452
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012453void CompilerGLSL::branch(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012454{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012455 flush_phi(from, to);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012456 flush_control_dependent_expressions(from);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012457
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020012458 bool to_is_continue = is_continue(to);
12459
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012460 // This is only a continue if we branch to our loop dominator.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012461 if ((ir.block_meta[to] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) != 0 && get<SPIRBlock>(from).loop_dominator == to)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012462 {
12463 // This can happen if we had a complex continue block which was emitted.
12464 // Once the continue block tries to branch to the loop header, just emit continue;
12465 // and end the chain here.
12466 statement("continue;");
12467 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012468 else if (is_break(to))
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020012469 {
12470 // Very dirty workaround.
12471 // Switch constructs are able to break, but they cannot break out of a loop at the same time.
12472 // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block,
12473 // write to the ladder here, and defer the break.
12474 // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012475 if (current_emitting_switch && is_loop_break(to) &&
12476 current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) &&
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020012477 get<SPIRBlock>(current_emitting_switch->loop_dominator).merge_block == to)
12478 {
12479 if (!current_emitting_switch->need_ladder_break)
12480 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012481 force_recompile();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020012482 current_emitting_switch->need_ladder_break = true;
12483 }
12484
12485 statement("_", current_emitting_switch->self, "_ladder_break = true;");
12486 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012487 statement("break;");
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020012488 }
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020012489 else if (to_is_continue || from == to)
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010012490 {
12491 // For from == to case can happen for a do-while loop which branches into itself.
12492 // We don't mark these cases as continue blocks, but the only possible way to branch into
12493 // ourselves is through means of continue blocks.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020012494
12495 // If we are merging to a continue block, there is no need to emit the block chain for continue here.
12496 // We can branch to the continue block after we merge execution.
12497
12498 // Here we make use of structured control flow rules from spec:
12499 // 2.11: - the merge block declared by a header block cannot be a merge block declared by any other header block
12500 // - each header block must strictly dominate its merge block, unless the merge block is unreachable in the CFG
12501 // If we are branching to a merge block, we must be inside a construct which dominates the merge block.
12502 auto &block_meta = ir.block_meta[to];
12503 bool branching_to_merge =
12504 (block_meta & (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT |
12505 ParsedIR::BLOCK_META_LOOP_MERGE_BIT)) != 0;
12506 if (!to_is_continue || !branching_to_merge)
12507 branch_to_continue(from, to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010012508 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012509 else if (!is_conditional(to))
12510 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012511
12512 // It is important that we check for break before continue.
12513 // A block might serve two purposes, a break block for the inner scope, and
12514 // a continue block in the outer scope.
12515 // Inner scope always takes precedence.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012516}
12517
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012518void CompilerGLSL::branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012519{
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020012520 auto &from_block = get<SPIRBlock>(from);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012521 BlockID merge_block = from_block.merge == SPIRBlock::MergeSelection ? from_block.next_block : BlockID(0);
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020012522
12523 // If we branch directly to a selection merge target, we don't need a code path.
12524 // This covers both merge out of if () / else () as well as a break for switch blocks.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012525 bool true_sub = !is_conditional(true_block);
12526 bool false_sub = !is_conditional(false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012527
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020012528 bool true_block_is_selection_merge = true_block == merge_block;
12529 bool false_block_is_selection_merge = false_block == merge_block;
12530
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012531 if (true_sub)
12532 {
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020012533 emit_block_hints(get<SPIRBlock>(from));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012534 statement("if (", to_expression(cond), ")");
12535 begin_scope();
12536 branch(from, true_block);
12537 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012538
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020012539 // If we merge to continue, we handle that explicitly in emit_block_chain(),
12540 // so there is no need to branch to it directly here.
12541 // break; is required to handle ladder fallthrough cases, so keep that in for now, even
12542 // if we could potentially handle it in emit_block_chain().
12543 if (false_sub || (!false_block_is_selection_merge && is_continue(false_block)) || is_break(false_block))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012544 {
12545 statement("else");
12546 begin_scope();
12547 branch(from, false_block);
12548 end_scope();
12549 }
12550 else if (flush_phi_required(from, false_block))
12551 {
12552 statement("else");
12553 begin_scope();
12554 flush_phi(from, false_block);
12555 end_scope();
12556 }
12557 }
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020012558 else if (false_sub)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012559 {
12560 // Only need false path, use negative conditional.
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020012561 emit_block_hints(get<SPIRBlock>(from));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010012562 statement("if (!", to_enclosed_expression(cond), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012563 begin_scope();
12564 branch(from, false_block);
12565 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012566
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020012567 if ((!true_block_is_selection_merge && is_continue(true_block)) || is_break(true_block))
Hans-Kristian Arntzen1de74fd2018-03-09 13:59:39 +010012568 {
12569 statement("else");
12570 begin_scope();
12571 branch(from, true_block);
12572 end_scope();
12573 }
12574 else if (flush_phi_required(from, true_block))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012575 {
12576 statement("else");
12577 begin_scope();
12578 flush_phi(from, true_block);
12579 end_scope();
12580 }
12581 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012582}
12583
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012584// FIXME: This currently cannot handle complex continue blocks
12585// as in do-while.
12586// This should be seen as a "trivial" continue block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010012587string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012588{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012589 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012590
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012591 // While emitting the continue block, declare_temporary will check this
12592 // if we have to emit temporaries.
12593 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012594
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020012595 SmallVector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012596
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012597 // Capture all statements into our list.
12598 auto *old = redirect_statement;
12599 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012600
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012601 // Stamp out all blocks one after each other.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012602 while ((ir.block_meta[block->self] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) == 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012603 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012604 // Write out all instructions we have in this block.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020012605 emit_block_instructions(*block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012606
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012607 // For plain branchless for/while continue blocks.
12608 if (block->next_block)
12609 {
12610 flush_phi(continue_block, block->next_block);
12611 block = &get<SPIRBlock>(block->next_block);
12612 }
12613 // For do while blocks. The last block will be a select block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010012614 else if (block->true_block && follow_true_block)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012615 {
12616 flush_phi(continue_block, block->true_block);
12617 block = &get<SPIRBlock>(block->true_block);
12618 }
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010012619 else if (block->false_block && follow_false_block)
12620 {
12621 flush_phi(continue_block, block->false_block);
12622 block = &get<SPIRBlock>(block->false_block);
12623 }
12624 else
12625 {
12626 SPIRV_CROSS_THROW("Invalid continue block detected!");
12627 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012628 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012629
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012630 // Restore old pointer.
12631 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012632
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012633 // Somewhat ugly, strip off the last ';' since we use ',' instead.
12634 // Ideally, we should select this behavior in statement().
12635 for (auto &s : statements)
12636 {
12637 if (!s.empty() && s.back() == ';')
Corentin Wallezef9ee492016-10-05 13:01:31 -040012638 s.erase(s.size() - 1, 1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012639 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012640
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012641 current_continue_block = nullptr;
12642 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012643}
12644
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020012645void CompilerGLSL::emit_while_loop_initializers(const SPIRBlock &block)
12646{
12647 // While loops do not take initializers, so declare all of them outside.
12648 for (auto &loop_var : block.loop_variables)
12649 {
12650 auto &var = get<SPIRVariable>(loop_var);
12651 statement(variable_decl(var), ";");
12652 }
12653}
12654
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012655string CompilerGLSL::emit_for_loop_initializers(const SPIRBlock &block)
12656{
12657 if (block.loop_variables.empty())
12658 return "";
12659
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010012660 bool same_types = for_loop_initializers_are_same_type(block);
12661 // We can only declare for loop initializers if all variables are of same type.
12662 // If we cannot do this, declare individual variables before the loop header.
12663
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010012664 // We might have a loop variable candidate which was not assigned to for some reason.
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012665 uint32_t missing_initializers = 0;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010012666 for (auto &variable : block.loop_variables)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012667 {
12668 uint32_t expr = get<SPIRVariable>(variable).static_expression;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010012669
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012670 // Sometimes loop variables are initialized with OpUndef, but we can just declare
12671 // a plain variable without initializer in this case.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012672 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012673 missing_initializers++;
12674 }
12675
12676 if (block.loop_variables.size() == 1 && missing_initializers == 0)
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012677 {
12678 return variable_decl(get<SPIRVariable>(block.loop_variables.front()));
12679 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012680 else if (!same_types || missing_initializers == uint32_t(block.loop_variables.size()))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010012681 {
12682 for (auto &loop_var : block.loop_variables)
12683 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
12684 return "";
12685 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012686 else
12687 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012688 // We have a mix of loop variables, either ones with a clear initializer, or ones without.
12689 // Separate the two streams.
12690 string expr;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012691
12692 for (auto &loop_var : block.loop_variables)
12693 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012694 uint32_t static_expr = get<SPIRVariable>(loop_var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012695 if (static_expr == 0 || ir.ids[static_expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012696 {
12697 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
12698 }
12699 else
12700 {
Chip Davis3bfb2f92018-12-03 02:06:33 -060012701 auto &var = get<SPIRVariable>(loop_var);
12702 auto &type = get_variable_data_type(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012703 if (expr.empty())
12704 {
12705 // For loop initializers are of the form <type id = value, id = value, id = value, etc ...
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012706 expr = join(to_qualifiers_glsl(var.self), type_to_glsl(type), " ");
12707 }
12708 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060012709 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012710 expr += ", ";
Chip Davis3bfb2f92018-12-03 02:06:33 -060012711 // In MSL, being based on C++, the asterisk marking a pointer
12712 // binds to the identifier, not the type.
12713 if (type.pointer)
12714 expr += "* ";
12715 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012716
Chip Davis3bfb2f92018-12-03 02:06:33 -060012717 expr += join(to_name(loop_var), " = ", to_pointer_expression(var.static_expression));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012718 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012719 }
12720 return expr;
12721 }
12722}
12723
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010012724bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
12725{
12726 if (block.loop_variables.size() <= 1)
12727 return true;
12728
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012729 uint32_t expected = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012730 Bitset expected_flags;
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010012731 for (auto &var : block.loop_variables)
12732 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012733 // Don't care about uninitialized variables as they will not be part of the initializers.
12734 uint32_t expr = get<SPIRVariable>(var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012735 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012736 continue;
12737
12738 if (expected == 0)
12739 {
12740 expected = get<SPIRVariable>(var).basetype;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012741 expected_flags = get_decoration_bitset(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012742 }
12743 else if (expected != get<SPIRVariable>(var).basetype)
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010012744 return false;
12745
12746 // Precision flags and things like that must also match.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012747 if (expected_flags != get_decoration_bitset(var))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010012748 return false;
12749 }
12750
12751 return true;
12752}
12753
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012754bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
12755{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012756 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012757
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010012758 if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012759 {
12760 uint32_t current_count = statement_count;
12761 // If we're trying to create a true for loop,
12762 // we need to make sure that all opcodes before branch statement do not actually emit any code.
12763 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020012764 emit_block_instructions(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012765
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012766 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012767
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012768 // This can work! We only did trivial things which could be forwarded in block body!
12769 if (current_count == statement_count && condition_is_temporary)
12770 {
12771 switch (continue_type)
12772 {
12773 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010012774 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010012775 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
12776 flush_undeclared_variables(block);
12777
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010012778 // Important that we do this in this order because
12779 // emitting the continue block can invalidate the condition expression.
12780 auto initializer = emit_for_loop_initializers(block);
12781 auto condition = to_expression(block.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012782
12783 // Condition might have to be inverted.
12784 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
12785 condition = join("!", enclose_expression(condition));
12786
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020012787 emit_block_hints(block);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010012788 if (method != SPIRBlock::MergeToSelectContinueForLoop)
12789 {
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010012790 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010012791 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
12792 }
12793 else
12794 statement("for (", initializer, "; ", condition, "; )");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012795 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010012796 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012797
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012798 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012799 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010012800 // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
12801 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020012802 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020012803 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012804
12805 auto condition = to_expression(block.condition);
12806 // Condition might have to be inverted.
12807 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
12808 condition = join("!", enclose_expression(condition));
12809
12810 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012811 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012812 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012814 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020012815 block.disable_block_optimization = true;
12816 force_recompile();
12817 begin_scope(); // We'll see an end_scope() later.
12818 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012819 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012820
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012821 begin_scope();
12822 return true;
12823 }
12824 else
12825 {
12826 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012827 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012828 begin_scope(); // We'll see an end_scope() later.
12829 return false;
12830 }
12831 }
12832 else if (method == SPIRBlock::MergeToDirectForLoop)
12833 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012834 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012835
Hans-Kristian Arntzen5ff11cc2016-11-18 16:45:11 +010012836 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
12837 flush_undeclared_variables(child);
12838
12839 uint32_t current_count = statement_count;
12840
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012841 // If we're trying to create a true for loop,
12842 // we need to make sure that all opcodes before branch statement do not actually emit any code.
12843 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020012844 emit_block_instructions(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012845
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012846 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012847
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012848 if (current_count == statement_count && condition_is_temporary)
12849 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012850 uint32_t target_block = child.true_block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012851
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012852 switch (continue_type)
12853 {
12854 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010012855 {
12856 // Important that we do this in this order because
12857 // emitting the continue block can invalidate the condition expression.
12858 auto initializer = emit_for_loop_initializers(block);
12859 auto condition = to_expression(child.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012860
12861 // Condition might have to be inverted.
12862 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
12863 {
12864 condition = join("!", enclose_expression(condition));
12865 target_block = child.false_block;
12866 }
12867
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010012868 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020012869 emit_block_hints(block);
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010012870 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012871 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010012872 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012873
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012874 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012875 {
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020012876 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020012877 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012878
12879 auto condition = to_expression(child.condition);
12880 // Condition might have to be inverted.
12881 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
12882 {
12883 condition = join("!", enclose_expression(condition));
12884 target_block = child.false_block;
12885 }
12886
12887 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012888 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012889 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012890
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012891 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020012892 block.disable_block_optimization = true;
12893 force_recompile();
12894 begin_scope(); // We'll see an end_scope() later.
12895 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012896 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012897
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012898 begin_scope();
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012899 branch(child.self, target_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012900 return true;
12901 }
12902 else
12903 {
12904 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012905 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012906 begin_scope(); // We'll see an end_scope() later.
12907 return false;
12908 }
12909 }
12910 else
12911 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012912}
12913
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010012914void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012915{
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010012916 for (auto &v : block.dominated_variables)
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010012917 flush_variable_declaration(v);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012918}
12919
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012920void CompilerGLSL::emit_hoisted_temporaries(SmallVector<pair<TypeID, ID>> &temporaries)
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010012921{
12922 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
12923 // Need to sort these to ensure that reference output is stable.
12924 sort(begin(temporaries), end(temporaries),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012925 [](const pair<TypeID, ID> &a, const pair<TypeID, ID> &b) { return a.second < b.second; });
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010012926
12927 for (auto &tmp : temporaries)
12928 {
12929 add_local_variable_name(tmp.second);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012930 auto &flags = ir.meta[tmp.second].decoration.decoration_flags;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010012931 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010012932
12933 // Not all targets support pointer literals, so don't bother with that case.
12934 string initializer;
12935 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
12936 initializer = join(" = ", to_zero_initialized_expression(tmp.first));
12937
12938 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), initializer, ";");
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010012939
12940 hoisted_temporaries.insert(tmp.second);
12941 forced_temporaries.insert(tmp.second);
12942
12943 // The temporary might be read from before it's assigned, set up the expression now.
12944 set<SPIRExpression>(tmp.second, to_name(tmp.second), tmp.first, true);
12945 }
12946}
12947
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012948void CompilerGLSL::emit_block_chain(SPIRBlock &block)
12949{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012950 bool select_branch_to_true_block = false;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012951 bool select_branch_to_false_block = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012952 bool skip_direct_branch = false;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010012953 bool emitted_loop_header_variables = false;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010012954 bool force_complex_continue_block = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012955
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010012956 emit_hoisted_temporaries(block.declare_temporary);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012957
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012958 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
12959 if (block.continue_block)
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010012960 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012961 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010012962 // If we know we cannot emit a loop, mark the block early as a complex loop so we don't force unnecessary recompiles.
12963 if (continue_type == SPIRBlock::ComplexLoop)
12964 block.complex_continue = true;
12965 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012966
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010012967 // If we have loop variables, stop masking out access to the variable now.
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020012968 for (auto var_id : block.loop_variables)
12969 {
12970 auto &var = get<SPIRVariable>(var_id);
12971 var.loop_variable_enable = true;
12972 // We're not going to declare the variable directly, so emit a copy here.
12973 emit_variable_temporary_copies(var);
12974 }
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010012975
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020012976 // Remember deferred declaration state. We will restore it before returning.
12977 SmallVector<bool, 64> rearm_dominated_variables(block.dominated_variables.size());
12978 for (size_t i = 0; i < block.dominated_variables.size(); i++)
12979 {
12980 uint32_t var_id = block.dominated_variables[i];
12981 auto &var = get<SPIRVariable>(var_id);
12982 rearm_dominated_variables[i] = var.deferred_declaration;
12983 }
12984
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010012985 // This is the method often used by spirv-opt to implement loops.
12986 // The loop header goes straight into the continue block.
12987 // However, don't attempt this on ESSL 1.0, because if a loop variable is used in a continue block,
12988 // it *MUST* be used in the continue block. This loop method will not work.
12989 if (!is_legacy_es() && block_is_loop_candidate(block, SPIRBlock::MergeToSelectContinueForLoop))
12990 {
12991 flush_undeclared_variables(block);
12992 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
12993 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010012994 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
12995 select_branch_to_false_block = true;
12996 else
12997 select_branch_to_true_block = true;
12998
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010012999 emitted_loop_header_variables = true;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013000 force_complex_continue_block = true;
13001 }
13002 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013003 // This is the older loop behavior in glslang which branches to loop body directly from the loop header.
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013004 else if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013005 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013006 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013007 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
13008 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013009 // The body of while, is actually just the true (or false) block, so always branch there unconditionally.
13010 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
13011 select_branch_to_false_block = true;
13012 else
13013 select_branch_to_true_block = true;
13014
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013015 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013016 }
13017 }
13018 // This is the newer loop behavior in glslang which branches from Loop header directly to
13019 // a new block, which in turn has a OpBranchSelection without a selection merge.
13020 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
13021 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013022 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013023 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013024 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013025 skip_direct_branch = true;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013026 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013027 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013028 }
13029 else if (continue_type == SPIRBlock::DoWhileLoop)
13030 {
Hans-Kristian Arntzenb3f6e3d2018-01-24 19:46:53 +010013031 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013032 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013033 emitted_loop_header_variables = true;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013034 // We have some temporaries where the loop header is the dominator.
13035 // We risk a case where we have code like:
13036 // for (;;) { create-temporary; break; } consume-temporary;
13037 // so force-declare temporaries here.
13038 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013039 statement("do");
13040 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020013041
13042 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013043 }
13044 else if (block.merge == SPIRBlock::MergeLoop)
13045 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013046 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013047 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013048 emitted_loop_header_variables = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013049
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013050 // We have a generic loop without any distinguishable pattern like for, while or do while.
13051 get<SPIRBlock>(block.continue_block).complex_continue = true;
13052 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013053
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013054 // We have some temporaries where the loop header is the dominator.
13055 // We risk a case where we have code like:
13056 // for (;;) { create-temporary; break; } consume-temporary;
13057 // so force-declare temporaries here.
13058 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013059 statement("for (;;)");
13060 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020013061
13062 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013063 }
13064 else
13065 {
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020013066 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013067 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013068
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013069 // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
13070 // as writes to said loop variables might have been masked out, we need a recompile.
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013071 if (!emitted_loop_header_variables && !block.loop_variables.empty())
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013072 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013073 force_recompile();
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013074 for (auto var : block.loop_variables)
13075 get<SPIRVariable>(var).loop_variable = false;
13076 block.loop_variables.clear();
13077 }
13078
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013079 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013080 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013081
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013082 // Handle end of block.
13083 switch (block.terminator)
13084 {
13085 case SPIRBlock::Direct:
13086 // True when emitting complex continue block.
13087 if (block.loop_dominator == block.next_block)
13088 {
13089 branch(block.self, block.next_block);
13090 emit_next_block = false;
13091 }
13092 // True if MergeToDirectForLoop succeeded.
13093 else if (skip_direct_branch)
13094 emit_next_block = false;
13095 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
13096 {
13097 branch(block.self, block.next_block);
13098 emit_next_block = false;
13099 }
13100 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013102 case SPIRBlock::Select:
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013103 // True if MergeToSelectForLoop or MergeToSelectContinueForLoop succeeded.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013104 if (select_branch_to_true_block)
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013105 {
13106 if (force_complex_continue_block)
13107 {
13108 assert(block.true_block == block.continue_block);
13109
13110 // We're going to emit a continue block directly here, so make sure it's marked as complex.
13111 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
13112 bool old_complex = complex_continue;
13113 complex_continue = true;
13114 branch(block.self, block.true_block);
13115 complex_continue = old_complex;
13116 }
13117 else
13118 branch(block.self, block.true_block);
13119 }
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013120 else if (select_branch_to_false_block)
13121 {
13122 if (force_complex_continue_block)
13123 {
13124 assert(block.false_block == block.continue_block);
13125
13126 // We're going to emit a continue block directly here, so make sure it's marked as complex.
13127 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
13128 bool old_complex = complex_continue;
13129 complex_continue = true;
13130 branch(block.self, block.false_block);
13131 complex_continue = old_complex;
13132 }
13133 else
13134 branch(block.self, block.false_block);
13135 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013136 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013137 branch(block.self, block.condition, block.true_block, block.false_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013138 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013139
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013140 case SPIRBlock::MultiSelect:
13141 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013142 auto &type = expression_type(block.condition);
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020013143 bool unsigned_case =
13144 type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort || type.basetype == SPIRType::UByte;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013145
Hans-Kristian Arntzen45baf242019-03-20 10:42:38 +010013146 if (block.merge == SPIRBlock::MergeNone)
13147 SPIRV_CROSS_THROW("Switch statement is not structured");
13148
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010013149 if (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64)
13150 {
13151 // SPIR-V spec suggests this is allowed, but we cannot support it in higher level languages.
13152 SPIRV_CROSS_THROW("Cannot use 64-bit switch selectors.");
13153 }
13154
13155 const char *label_suffix = "";
13156 if (type.basetype == SPIRType::UInt && backend.uint32_t_literal_suffix)
13157 label_suffix = "u";
13158 else if (type.basetype == SPIRType::UShort)
13159 label_suffix = backend.uint16_t_literal_suffix;
13160 else if (type.basetype == SPIRType::Short)
13161 label_suffix = backend.int16_t_literal_suffix;
13162
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020013163 SPIRBlock *old_emitting_switch = current_emitting_switch;
13164 current_emitting_switch = &block;
13165
13166 if (block.need_ladder_break)
13167 statement("bool _", block.self, "_ladder_break = false;");
13168
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013169 // Find all unique case constructs.
13170 unordered_map<uint32_t, SmallVector<uint32_t>> case_constructs;
13171 SmallVector<uint32_t> block_declaration_order;
13172 SmallVector<uint32_t> literals_to_merge;
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020013173
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013174 // If a switch case branches to the default block for some reason, we can just remove that literal from consideration
13175 // and let the default: block handle it.
13176 // 2.11 in SPIR-V spec states that for fall-through cases, there is a very strict declaration order which we can take advantage of here.
13177 // We only need to consider possible fallthrough if order[i] branches to order[i + 1].
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013178 for (auto &c : block.cases)
13179 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013180 if (c.block != block.next_block && c.block != block.default_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020013181 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013182 if (!case_constructs.count(c.block))
13183 block_declaration_order.push_back(c.block);
13184 case_constructs[c.block].push_back(c.value);
13185 }
13186 else if (c.block == block.next_block && block.default_block != block.next_block)
13187 {
13188 // We might have to flush phi inside specific case labels.
13189 // If we can piggyback on default:, do so instead.
13190 literals_to_merge.push_back(c.value);
13191 }
13192 }
13193
13194 // Empty literal array -> default.
13195 if (block.default_block != block.next_block)
13196 {
13197 auto &default_block = get<SPIRBlock>(block.default_block);
13198
13199 // We need to slide in the default block somewhere in this chain
13200 // if there are fall-through scenarios since the default is declared separately in OpSwitch.
13201 // Only consider trivial fall-through cases here.
13202 size_t num_blocks = block_declaration_order.size();
13203 bool injected_block = false;
13204
13205 for (size_t i = 0; i < num_blocks; i++)
13206 {
13207 auto &case_block = get<SPIRBlock>(block_declaration_order[i]);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013208 if (execution_is_direct_branch(case_block, default_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013209 {
13210 // Fallthrough to default block, we must inject the default block here.
13211 block_declaration_order.insert(begin(block_declaration_order) + i + 1, block.default_block);
13212 injected_block = true;
13213 break;
13214 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013215 else if (execution_is_direct_branch(default_block, case_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013216 {
13217 // Default case is falling through to another case label, we must inject the default block here.
13218 block_declaration_order.insert(begin(block_declaration_order) + i, block.default_block);
13219 injected_block = true;
13220 break;
13221 }
13222 }
13223
13224 // Order does not matter.
13225 if (!injected_block)
13226 block_declaration_order.push_back(block.default_block);
13227
13228 case_constructs[block.default_block] = {};
13229 }
13230
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013231 size_t num_blocks = block_declaration_order.size();
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013232
Hans-Kristian Arntzenbcec5cb2019-06-21 14:59:51 +020013233 const auto to_case_label = [](uint32_t literal, bool is_unsigned_case) -> string {
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013234 return is_unsigned_case ? convert_to_string(literal) : convert_to_string(int32_t(literal));
13235 };
13236
13237 // We need to deal with a complex scenario for OpPhi. If we have case-fallthrough and Phi in the picture,
13238 // we need to flush phi nodes outside the switch block in a branch,
13239 // and skip any Phi handling inside the case label to make fall-through work as expected.
13240 // This kind of code-gen is super awkward and it's a last resort. Normally we would want to handle this
13241 // inside the case label if at all possible.
13242 for (size_t i = 1; i < num_blocks; i++)
13243 {
13244 if (flush_phi_required(block.self, block_declaration_order[i]) &&
13245 flush_phi_required(block_declaration_order[i - 1], block_declaration_order[i]))
13246 {
13247 uint32_t target_block = block_declaration_order[i];
13248
13249 // Make sure we flush Phi, it might have been marked to be ignored earlier.
13250 get<SPIRBlock>(target_block).ignore_phi_from_block = 0;
13251
13252 auto &literals = case_constructs[target_block];
13253
13254 if (literals.empty())
13255 {
13256 // Oh boy, gotta make a complete negative test instead! o.o
13257 // Find all possible literals that would *not* make us enter the default block.
13258 // If none of those literals match, we flush Phi ...
13259 SmallVector<string> conditions;
13260 for (size_t j = 0; j < num_blocks; j++)
13261 {
13262 auto &negative_literals = case_constructs[block_declaration_order[j]];
13263 for (auto &case_label : negative_literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020013264 conditions.push_back(join(to_enclosed_expression(block.condition),
13265 " != ", to_case_label(case_label, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013266 }
13267
13268 statement("if (", merge(conditions, " && "), ")");
13269 begin_scope();
13270 flush_phi(block.self, target_block);
13271 end_scope();
13272 }
13273 else
13274 {
13275 SmallVector<string> conditions;
13276 conditions.reserve(literals.size());
13277 for (auto &case_label : literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020013278 conditions.push_back(join(to_enclosed_expression(block.condition),
13279 " == ", to_case_label(case_label, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013280 statement("if (", merge(conditions, " || "), ")");
13281 begin_scope();
13282 flush_phi(block.self, target_block);
13283 end_scope();
13284 }
13285
13286 // Mark the block so that we don't flush Phi from header to case label.
13287 get<SPIRBlock>(target_block).ignore_phi_from_block = block.self;
13288 }
13289 }
13290
13291 emit_block_hints(block);
13292 statement("switch (", to_expression(block.condition), ")");
13293 begin_scope();
13294
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013295 for (size_t i = 0; i < num_blocks; i++)
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013296 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013297 uint32_t target_block = block_declaration_order[i];
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013298 auto &literals = case_constructs[target_block];
13299
13300 if (literals.empty())
13301 {
13302 // Default case.
13303 statement("default:");
13304 }
13305 else
13306 {
13307 for (auto &case_literal : literals)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020013308 {
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010013309 // The case label value must be sign-extended properly in SPIR-V, so we can assume 32-bit values here.
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013310 statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020013311 }
13312 }
13313
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013314 auto &case_block = get<SPIRBlock>(target_block);
Hans-Kristian Arntzen581ed0f2019-06-27 15:10:17 +020013315 if (backend.support_case_fallthrough && i + 1 < num_blocks &&
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020013316 execution_is_direct_branch(case_block, get<SPIRBlock>(block_declaration_order[i + 1])))
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013317 {
13318 // We will fall through here, so just terminate the block chain early.
13319 // We still need to deal with Phi potentially.
13320 // No need for a stack-like thing here since we only do fall-through when there is a
13321 // single trivial branch to fall-through target..
13322 current_emitting_switch_fallthrough = true;
13323 }
13324 else
13325 current_emitting_switch_fallthrough = false;
13326
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013327 begin_scope();
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013328 branch(block.self, target_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013329 end_scope();
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013330
13331 current_emitting_switch_fallthrough = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013332 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013333
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013334 // Might still have to flush phi variables if we branch from loop header directly to merge target.
13335 if (flush_phi_required(block.self, block.next_block))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013336 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013337 if (block.default_block == block.next_block || !literals_to_merge.empty())
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020013338 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013339 for (auto &case_literal : literals_to_merge)
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013340 statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020013341
13342 if (block.default_block == block.next_block)
13343 statement("default:");
13344
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020013345 begin_scope();
13346 flush_phi(block.self, block.next_block);
13347 statement("break;");
13348 end_scope();
13349 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013350 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013352 end_scope();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020013353
13354 if (block.need_ladder_break)
13355 {
13356 statement("if (_", block.self, "_ladder_break)");
13357 begin_scope();
13358 statement("break;");
13359 end_scope();
13360 }
13361
13362 current_emitting_switch = old_emitting_switch;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013363 break;
13364 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013365
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013366 case SPIRBlock::Return:
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013367 {
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020013368 for (auto &line : current_function->fixup_hooks_out)
13369 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040013370
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013371 if (processing_entry_point)
13372 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013373
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013374 auto &cfg = get_cfg_for_current_function();
13375
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013376 if (block.return_value)
13377 {
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013378 auto &type = expression_type(block.return_value);
13379 if (!type.array.empty() && !backend.can_return_array)
13380 {
13381 // If we cannot return arrays, we will have a special out argument we can write to instead.
13382 // The backend is responsible for setting this up, and redirection the return values as appropriate.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010013383 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020013384 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020013385 emit_array_copy("SPIRV_Cross_return_value", block.return_value, StorageClassFunction,
13386 get_backing_variable_storage(block.return_value));
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020013387 }
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013388
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013389 if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013390 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013391 {
13392 statement("return;");
13393 }
13394 }
13395 else
13396 {
13397 // OpReturnValue can return Undef, so don't emit anything for this case.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010013398 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013399 statement("return ", to_expression(block.return_value), ";");
13400 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013401 }
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013402 else if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013403 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013404 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013405 // If this block is the very final block and not called from control flow,
13406 // we do not need an explicit return which looks out of place. Just end the function here.
13407 // In the very weird case of for(;;) { return; } executing return is unconditional,
13408 // but we actually need a return here ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013409 statement("return;");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013410 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013411 break;
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013412 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013413
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013414 case SPIRBlock::Kill:
Bill Hollings943191a2016-10-27 10:20:01 -040013415 statement(backend.discard_literal, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013416 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013417
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010013418 case SPIRBlock::Unreachable:
13419 emit_next_block = false;
13420 break;
13421
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013422 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010013423 SPIRV_CROSS_THROW("Unimplemented block terminator.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013424 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013425
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013426 if (block.next_block && emit_next_block)
13427 {
13428 // If we hit this case, we're dealing with an unconditional branch, which means we will output
13429 // that block after this. If we had selection merge, we already flushed phi variables.
13430 if (block.merge != SPIRBlock::MergeSelection)
13431 flush_phi(block.self, block.next_block);
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013432
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013433 // For switch fallthrough cases, we terminate the chain here, but we still need to handle Phi.
13434 if (!current_emitting_switch_fallthrough)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013435 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013436 // For merge selects we might have ignored the fact that a merge target
13437 // could have been a break; or continue;
13438 // We will need to deal with it here.
13439 if (is_loop_break(block.next_block))
13440 {
13441 // Cannot check for just break, because switch statements will also use break.
13442 assert(block.merge == SPIRBlock::MergeSelection);
13443 statement("break;");
13444 }
13445 else if (is_continue(block.next_block))
13446 {
13447 assert(block.merge == SPIRBlock::MergeSelection);
13448 branch_to_continue(block.self, block.next_block);
13449 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013450 else if (BlockID(block.self) != block.next_block)
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020013451 emit_block_chain(get<SPIRBlock>(block.next_block));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013452 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013453 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013455 if (block.merge == SPIRBlock::MergeLoop)
13456 {
13457 if (continue_type == SPIRBlock::DoWhileLoop)
13458 {
13459 // Make sure that we run the continue block to get the expressions set, but this
13460 // should become an empty string.
13461 // We have no fallbacks if we cannot forward everything to temporaries ...
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013462 const auto &continue_block = get<SPIRBlock>(block.continue_block);
Hans-Kristian Arntzen8bfb04d2019-03-06 12:20:13 +010013463 bool positive_test = execution_is_noop(get<SPIRBlock>(continue_block.true_block),
13464 get<SPIRBlock>(continue_block.loop_dominator));
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013465
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013466 uint32_t current_count = statement_count;
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013467 auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013468 if (statement_count != current_count)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013469 {
13470 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
13471 get<SPIRBlock>(block.continue_block).complex_continue = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013472 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013473 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013474
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013475 // Might have to invert the do-while test here.
13476 auto condition = to_expression(continue_block.condition);
13477 if (!positive_test)
13478 condition = join("!", enclose_expression(condition));
13479
13480 end_scope_decl(join("while (", condition, ")"));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013481 }
13482 else
13483 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013484
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013485 // We cannot break out of two loops at once, so don't check for break; here.
13486 // Using block.self as the "from" block isn't quite right, but it has the same scope
13487 // and dominance structure, so it's fine.
13488 if (is_continue(block.merge_block))
13489 branch_to_continue(block.self, block.merge_block);
13490 else
13491 emit_block_chain(get<SPIRBlock>(block.merge_block));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013492 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013493
13494 // Forget about control dependent expressions now.
13495 block.invalidate_expressions.clear();
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020013496
13497 // After we return, we must be out of scope, so if we somehow have to re-emit this function,
13498 // re-declare variables if necessary.
13499 assert(rearm_dominated_variables.size() == block.dominated_variables.size());
13500 for (size_t i = 0; i < block.dominated_variables.size(); i++)
13501 {
13502 uint32_t var = block.dominated_variables[i];
13503 get<SPIRVariable>(var).deferred_declaration = rearm_dominated_variables[i];
13504 }
Hans-Kristian Arntzen25c74b32019-07-10 12:57:12 +020013505
13506 // Just like for deferred declaration, we need to forget about loop variable enable
13507 // if our block chain is reinstantiated later.
13508 for (auto &var_id : block.loop_variables)
13509 get<SPIRVariable>(var_id).loop_variable_enable = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013510}
13511
13512void CompilerGLSL::begin_scope()
13513{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013514 statement("{");
13515 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013516}
13517
13518void CompilerGLSL::end_scope()
13519{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013520 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010013521 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013522 indent--;
13523 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013524}
13525
Chip Daviscb359342019-09-05 23:14:12 -050013526void CompilerGLSL::end_scope(const string &trailer)
13527{
13528 if (!indent)
13529 SPIRV_CROSS_THROW("Popping empty indent stack.");
13530 indent--;
13531 statement("}", trailer);
13532}
13533
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013534void CompilerGLSL::end_scope_decl()
13535{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013536 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010013537 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013538 indent--;
13539 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013540}
13541
13542void CompilerGLSL::end_scope_decl(const string &decl)
13543{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013544 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010013545 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013546 indent--;
13547 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013548}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020013549
13550void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
13551{
13552 // If our variable is remapped, and we rely on type-remapping information as
13553 // well, then we cannot pass the variable as a function parameter.
13554 // Fixing this is non-trivial without stamping out variants of the same function,
13555 // so for now warn about this and suggest workarounds instead.
13556 for (uint32_t i = 0; i < length; i++)
13557 {
13558 auto *var = maybe_get<SPIRVariable>(args[i]);
13559 if (!var || !var->remapped_variable)
13560 continue;
13561
13562 auto &type = get<SPIRType>(var->basetype);
13563 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
13564 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010013565 SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
13566 "This will not work correctly because type-remapping information is lost. "
13567 "To workaround, please consider not passing the subpass input as a function parameter, "
13568 "or use in/out variables instead which do not need type remapping information.");
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020013569 }
13570 }
13571}
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010013572
13573const Instruction *CompilerGLSL::get_next_instruction_in_block(const Instruction &instr)
13574{
13575 // FIXME: This is kind of hacky. There should be a cleaner way.
13576 auto offset = uint32_t(&instr - current_emitting_block->ops.data());
13577 if ((offset + 1) < current_emitting_block->ops.size())
13578 return &current_emitting_block->ops[offset + 1];
13579 else
13580 return nullptr;
13581}
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010013582
13583uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
13584{
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010013585 return semantics & (MemorySemanticsAtomicCounterMemoryMask | MemorySemanticsImageMemoryMask |
13586 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask |
13587 MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010013588}
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013589
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020013590void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageClass, StorageClass)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010013591{
13592 statement(lhs, " = ", to_expression(rhs_id), ";");
13593}
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020013594
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013595void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013596{
13597 if (!backend.force_gl_in_out_block)
13598 return;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013599 // This path is only relevant for GL backends.
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013600
13601 auto *var = maybe_get<SPIRVariable>(source_id);
13602 if (!var)
13603 return;
13604
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013605 if (var->storage != StorageClassInput)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013606 return;
13607
13608 auto &type = get_variable_data_type(*var);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013609 if (type.array.empty())
13610 return;
13611
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013612 auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013613 bool is_builtin = is_builtin_variable(*var) && (builtin == BuiltInPointSize || builtin == BuiltInPosition);
13614 bool is_tess = is_tessellation_shader();
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010013615 bool is_patch = has_decoration(var->self, DecorationPatch);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013616
13617 // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
13618 // We must unroll the array load.
13619 // For builtins, we couldn't catch this case normally,
13620 // because this is resolved in the OpAccessChain in most cases.
13621 // If we load the entire array, we have no choice but to unroll here.
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010013622 if (!is_patch && (is_builtin || is_tess))
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013623 {
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013624 auto new_expr = join("_", target_id, "_unrolled");
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013625 statement(variable_decl(type, new_expr, target_id), ";");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013626 string array_expr;
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010013627 if (type.array_size_literal.back())
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013628 {
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010013629 array_expr = convert_to_string(type.array.back());
13630 if (type.array.back() == 0)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013631 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
13632 }
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013633 else
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010013634 array_expr = to_expression(type.array.back());
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013635
13636 // The array size might be a specialization constant, so use a for-loop instead.
13637 statement("for (int i = 0; i < int(", array_expr, "); i++)");
13638 begin_scope();
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010013639 if (is_builtin)
13640 statement(new_expr, "[i] = gl_in[i].", expr, ";");
13641 else
13642 statement(new_expr, "[i] = ", expr, "[i];");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010013643 end_scope();
13644
13645 expr = move(new_expr);
13646 }
13647}
13648
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020013649void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020013650{
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020013651 auto *var = maybe_get_backing_variable(source_id);
13652 if (var)
13653 source_id = var->self;
13654
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020013655 // Only interested in standalone builtin variables.
13656 if (!has_decoration(source_id, DecorationBuiltIn))
13657 return;
13658
13659 auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
13660 auto expected_type = expr_type.basetype;
13661
13662 // TODO: Fill in for more builtins.
13663 switch (builtin)
13664 {
13665 case BuiltInLayer:
13666 case BuiltInPrimitiveId:
13667 case BuiltInViewportIndex:
13668 case BuiltInInstanceId:
13669 case BuiltInInstanceIndex:
13670 case BuiltInVertexId:
13671 case BuiltInVertexIndex:
13672 case BuiltInSampleId:
Chip Davisfcad0192018-08-28 13:47:29 -050013673 case BuiltInBaseVertex:
13674 case BuiltInBaseInstance:
13675 case BuiltInDrawIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020013676 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020013677 case BuiltInInstanceCustomIndexNV:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020013678 expected_type = SPIRType::Int;
13679 break;
13680
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020013681 case BuiltInGlobalInvocationId:
13682 case BuiltInLocalInvocationId:
13683 case BuiltInWorkgroupId:
13684 case BuiltInLocalInvocationIndex:
13685 case BuiltInWorkgroupSize:
13686 case BuiltInNumWorkgroups:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020013687 case BuiltInIncomingRayFlagsNV:
13688 case BuiltInLaunchIdNV:
13689 case BuiltInLaunchSizeNV:
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020013690 expected_type = SPIRType::UInt;
13691 break;
13692
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020013693 default:
13694 break;
13695 }
13696
13697 if (expected_type != expr_type.basetype)
13698 expr = bitcast_expression(expr_type, expected_type, expr);
13699}
13700
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020013701void CompilerGLSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020013702{
13703 // Only interested in standalone builtin variables.
13704 if (!has_decoration(target_id, DecorationBuiltIn))
13705 return;
13706
13707 auto builtin = static_cast<BuiltIn>(get_decoration(target_id, DecorationBuiltIn));
13708 auto expected_type = expr_type.basetype;
13709
13710 // TODO: Fill in for more builtins.
13711 switch (builtin)
13712 {
13713 case BuiltInLayer:
13714 case BuiltInPrimitiveId:
13715 case BuiltInViewportIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020013716 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020013717 expected_type = SPIRType::Int;
13718 break;
13719
13720 default:
13721 break;
13722 }
13723
13724 if (expected_type != expr_type.basetype)
13725 {
13726 auto type = expr_type;
13727 type.basetype = expected_type;
13728 expr = bitcast_expression(type, expr_type.basetype, expr);
13729 }
13730}
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020013731
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020013732void CompilerGLSL::convert_non_uniform_expression(const SPIRType &type, std::string &expr)
13733{
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020013734 if (*backend.nonuniform_qualifier == '\0')
13735 return;
13736
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020013737 // Handle SPV_EXT_descriptor_indexing.
13738 if (type.basetype == SPIRType::Sampler || type.basetype == SPIRType::SampledImage ||
13739 type.basetype == SPIRType::Image)
13740 {
13741 // The image/sampler ID must be declared as non-uniform.
13742 // However, it is not legal GLSL to have
13743 // nonuniformEXT(samplers[index]), so we must move the nonuniform qualifier
13744 // to the array indexing, like
13745 // samplers[nonuniformEXT(index)].
13746 // While the access chain will generally be nonuniformEXT, it's not necessarily so,
13747 // so we might have to fixup the OpLoad-ed expression late.
13748
13749 auto start_array_index = expr.find_first_of('[');
13750 auto end_array_index = expr.find_last_of(']');
13751 // Doesn't really make sense to declare a non-arrayed image with nonuniformEXT, but there's
13752 // nothing we can do here to express that.
13753 if (start_array_index == string::npos || end_array_index == string::npos || end_array_index < start_array_index)
13754 return;
13755
13756 start_array_index++;
13757
13758 expr = join(expr.substr(0, start_array_index), backend.nonuniform_qualifier, "(",
13759 expr.substr(start_array_index, end_array_index - start_array_index), ")",
13760 expr.substr(end_array_index, string::npos));
13761 }
13762}
13763
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020013764void CompilerGLSL::emit_block_hints(const SPIRBlock &)
13765{
13766}
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +010013767
13768void CompilerGLSL::preserve_alias_on_reset(uint32_t id)
13769{
13770 preserved_aliases[id] = get_name(id);
13771}
13772
13773void CompilerGLSL::reset_name_caches()
13774{
13775 for (auto &preserved : preserved_aliases)
13776 set_name(preserved.first, preserved.second);
13777
13778 preserved_aliases.clear();
13779 resource_names.clear();
13780 block_input_names.clear();
13781 block_output_names.clear();
13782 block_ubo_names.clear();
13783 block_ssbo_names.clear();
13784 block_names.clear();
13785 function_overloads.clear();
13786}
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020013787
13788void CompilerGLSL::fixup_type_alias()
13789{
13790 // Due to how some backends work, the "master" type of type_alias must be a block-like type if it exists.
13791 // FIXME: Multiple alias types which are both block-like will be awkward, for now, it's best to just drop the type
13792 // alias if the slave type is a block type.
13793 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
13794 if (type.type_alias && type_is_block_like(type))
13795 {
13796 // Become the master.
13797 ir.for_each_typed_id<SPIRType>([&](uint32_t other_id, SPIRType &other_type) {
13798 if (other_id == type.self)
13799 return;
13800
13801 if (other_type.type_alias == type.type_alias)
13802 other_type.type_alias = type.self;
13803 });
13804
13805 this->get<SPIRType>(type.type_alias).type_alias = self;
13806 type.type_alias = 0;
13807 }
13808 });
13809
13810 ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
13811 if (type.type_alias && type_is_block_like(type))
13812 {
13813 // This is not allowed, drop the type_alias.
13814 type.type_alias = 0;
13815 }
Hans-Kristian Arntzenf59688b2019-10-07 12:40:21 +020013816 else if (type.type_alias && !type_is_block_like(this->get<SPIRType>(type.type_alias)))
Hans-Kristian Arntzena0c13e42019-10-07 10:31:42 +020013817 {
13818 // If the alias master is not a block-like type, there is no reason to use type aliasing.
13819 // This case can happen if two structs are declared with the same name, but they are unrelated.
13820 // Aliases are only used to deal with aliased types for structs which are used in different buffer types
13821 // which all create a variant of the same struct with different DecorationOffset values.
13822 type.type_alias = 0;
13823 }
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020013824 });
13825}
13826
13827void CompilerGLSL::reorder_type_alias()
13828{
13829 // Reorder declaration of types so that the master of the type alias is always emitted first.
13830 // We need this in case a type B depends on type A (A must come before in the vector), but A is an alias of a type Abuffer, which
13831 // means declaration of A doesn't happen (yet), and order would be B, ABuffer and not ABuffer, B. Fix this up here.
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +020013832 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020013833
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020013834 auto &type_ids = ir.ids_for_type[TypeType];
13835 for (auto alias_itr = begin(type_ids); alias_itr != end(type_ids); ++alias_itr)
13836 {
13837 auto &type = get<SPIRType>(*alias_itr);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013838 if (type.type_alias != TypeID(0) &&
13839 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020013840 {
13841 // We will skip declaring this type, so make sure the type_alias type comes before.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013842 auto master_itr = find(begin(type_ids), end(type_ids), ID(type.type_alias));
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020013843 assert(master_itr != end(type_ids));
13844
13845 if (alias_itr < master_itr)
13846 {
13847 // Must also swap the type order for the constant-type joined array.
13848 auto &joined_types = ir.ids_for_constant_or_type;
13849 auto alt_alias_itr = find(begin(joined_types), end(joined_types), *alias_itr);
13850 auto alt_master_itr = find(begin(joined_types), end(joined_types), *master_itr);
13851 assert(alt_alias_itr != end(joined_types));
13852 assert(alt_master_itr != end(joined_types));
13853
13854 swap(*alias_itr, *master_itr);
13855 swap(*alt_alias_itr, *alt_master_itr);
13856 }
13857 }
13858 }
13859}
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020013860
13861void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
13862{
13863 // If we are redirecting statements, ignore the line directive.
13864 // Common case here is continue blocks.
13865 if (redirect_statement)
13866 return;
13867
13868 if (options.emit_line_directives)
13869 {
13870 require_extension_internal("GL_GOOGLE_cpp_style_line_directive");
13871 statement_no_indent("#line ", line_literal, " \"", get<SPIRString>(file_id).str, "\"");
13872 }
13873}
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020013874
13875void CompilerGLSL::propagate_nonuniform_qualifier(uint32_t id)
13876{
13877 // SPIR-V might only tag the very last ID with NonUniformEXT, but for codegen,
13878 // we need to know NonUniformEXT a little earlier, when the resource is actually loaded.
13879 // Back-propagate the qualifier based on the expression dependency chain.
13880
13881 if (!has_decoration(id, DecorationNonUniformEXT))
13882 {
13883 set_decoration(id, DecorationNonUniformEXT);
13884 force_recompile();
13885 }
13886
13887 auto *e = maybe_get<SPIRExpression>(id);
13888 auto *combined = maybe_get<SPIRCombinedImageSampler>(id);
13889 auto *chain = maybe_get<SPIRAccessChain>(id);
13890 if (e)
13891 {
13892 for (auto &expr : e->expression_dependencies)
13893 propagate_nonuniform_qualifier(expr);
13894 for (auto &expr : e->implied_read_expressions)
13895 propagate_nonuniform_qualifier(expr);
13896 }
13897 else if (combined)
13898 {
13899 propagate_nonuniform_qualifier(combined->image);
13900 propagate_nonuniform_qualifier(combined->sampler);
13901 }
13902 else if (chain)
13903 {
13904 for (auto &expr : chain->implied_read_expressions)
13905 propagate_nonuniform_qualifier(expr);
13906 }
13907}
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013908
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010013909void CompilerGLSL::emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id,
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013910 SmallVector<uint32_t> chain)
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013911{
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013912 // Fully unroll all member/array indices one by one.
13913
13914 auto &lhs_type = get<SPIRType>(lhs_type_id);
13915 auto &rhs_type = get<SPIRType>(rhs_type_id);
13916
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013917 if (!lhs_type.array.empty())
13918 {
13919 // Could use a loop here to support specialization constants, but it gets rather complicated with nested array types,
13920 // and this is a rather obscure opcode anyways, keep it simple unless we are forced to.
13921 uint32_t array_size = to_array_size_literal(lhs_type);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013922 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013923
13924 for (uint32_t i = 0; i < array_size; i++)
13925 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013926 chain.back() = i;
13927 emit_copy_logical_type(lhs_id, lhs_type.parent_type, rhs_id, rhs_type.parent_type, chain);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013928 }
13929 }
13930 else if (lhs_type.basetype == SPIRType::Struct)
13931 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013932 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013933 uint32_t member_count = uint32_t(lhs_type.member_types.size());
13934 for (uint32_t i = 0; i < member_count; i++)
13935 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013936 chain.back() = i;
13937 emit_copy_logical_type(lhs_id, lhs_type.member_types[i], rhs_id, rhs_type.member_types[i], chain);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013938 }
13939 }
13940 else
13941 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013942 // Need to handle unpack/packing fixups since this can differ wildly between the logical types,
13943 // particularly in MSL.
13944 // To deal with this, we emit access chains and go through emit_store_statement
13945 // to deal with all the special cases we can encounter.
13946
13947 AccessChainMeta lhs_meta, rhs_meta;
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010013948 auto lhs = access_chain_internal(lhs_id, chain.data(), uint32_t(chain.size()),
13949 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &lhs_meta);
13950 auto rhs = access_chain_internal(rhs_id, chain.data(), uint32_t(chain.size()),
13951 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &rhs_meta);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010013952
13953 uint32_t id = ir.increase_bound_by(2);
13954 lhs_id = id;
13955 rhs_id = id + 1;
13956
13957 {
13958 auto &lhs_expr = set<SPIRExpression>(lhs_id, move(lhs), lhs_type_id, true);
13959 lhs_expr.need_transpose = lhs_meta.need_transpose;
13960
13961 if (lhs_meta.storage_is_packed)
13962 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypePacked);
13963 if (lhs_meta.storage_physical_type != 0)
13964 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID, lhs_meta.storage_physical_type);
13965
13966 forwarded_temporaries.insert(lhs_id);
13967 suppressed_usage_tracking.insert(lhs_id);
13968 }
13969
13970 {
13971 auto &rhs_expr = set<SPIRExpression>(rhs_id, move(rhs), rhs_type_id, true);
13972 rhs_expr.need_transpose = rhs_meta.need_transpose;
13973
13974 if (rhs_meta.storage_is_packed)
13975 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypePacked);
13976 if (rhs_meta.storage_physical_type != 0)
13977 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID, rhs_meta.storage_physical_type);
13978
13979 forwarded_temporaries.insert(rhs_id);
13980 suppressed_usage_tracking.insert(rhs_id);
13981 }
13982
13983 emit_store_statement(lhs_id, rhs_id);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010013984 }
13985}
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010013986
13987bool CompilerGLSL::subpass_input_is_framebuffer_fetch(uint32_t id) const
13988{
13989 if (!has_decoration(id, DecorationInputAttachmentIndex))
13990 return false;
13991
13992 uint32_t input_attachment_index = get_decoration(id, DecorationInputAttachmentIndex);
13993 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
13994 if (remap.first == input_attachment_index)
13995 return true;
13996
13997 return false;
13998}
13999
14000const SPIRVariable *CompilerGLSL::find_subpass_input_by_attachment_index(uint32_t index) const
14001{
14002 const SPIRVariable *ret = nullptr;
14003 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
14004 if (has_decoration(var.self, DecorationInputAttachmentIndex) &&
14005 get_decoration(var.self, DecorationInputAttachmentIndex) == index)
14006 {
14007 ret = &var;
14008 }
14009 });
14010 return ret;
14011}
14012
14013const SPIRVariable *CompilerGLSL::find_color_output_by_location(uint32_t location) const
14014{
14015 const SPIRVariable *ret = nullptr;
14016 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
14017 if (var.storage == StorageClassOutput && get_decoration(var.self, DecorationLocation) == location)
14018 ret = &var;
14019 });
14020 return ret;
14021}
14022
14023void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs()
14024{
14025 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
14026 {
14027 auto *subpass_var = find_subpass_input_by_attachment_index(remap.first);
14028 auto *output_var = find_color_output_by_location(remap.second);
14029 if (!subpass_var)
14030 continue;
14031 if (!output_var)
14032 SPIRV_CROSS_THROW("Need to declare the corresponding fragment output variable to be able to read from it.");
14033 if (is_array(get<SPIRType>(output_var->basetype)))
14034 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs.");
14035
14036 auto &func = get<SPIRFunction>(get_entry_point().self);
14037 func.fixup_hooks_in.push_back([=]() {
14038 if (is_legacy())
14039 {
14040 statement(to_expression(subpass_var->self), " = ", "gl_LastFragData[",
14041 get_decoration(output_var->self, DecorationLocation), "];");
14042 }
14043 else
14044 {
14045 uint32_t num_rt_components = this->get<SPIRType>(output_var->basetype).vecsize;
14046 statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ",
14047 to_expression(output_var->self), ";");
14048 }
14049 });
14050 }
14051}
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020014052
14053bool CompilerGLSL::variable_is_depth_or_compare(VariableID id) const
14054{
14055 return image_is_comparison(get<SPIRType>(get<SPIRVariable>(id).basetype), id);
14056}