blob: a96c9671478586b15bcb247aea76abe3c1a3da89 [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzen47044822021-01-14 16:07:49 +01002 * Copyright 2015-2021 Arm Limited
Jon Leechf2a65542021-05-08 01:47:48 -07003 * SPDX-License-Identifier: Apache-2.0 OR MIT
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010018/*
19 * At your option, you may choose to accept this material under either:
20 * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
21 * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010022 */
23
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020024#include "spirv_glsl.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010025#include "GLSL.std.450.h"
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +020026#include "spirv_common.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010027#include <algorithm>
28#include <assert.h>
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010029#include <cmath>
Hans-Kristian Arntzencc7679e2018-07-17 00:10:12 +020030#include <limits>
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +010031#include <locale.h>
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +010032#include <utility>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010033
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +010034#ifndef _WIN32
35#include <langinfo.h>
36#endif
37#include <locale.h>
38
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010039using namespace spv;
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010040using namespace SPIRV_CROSS_NAMESPACE;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010041using namespace std;
42
Hans-Kristian Arntzen4ca06c72021-03-08 14:09:32 +010043enum ExtraSubExpressionType
44{
45 // Create masks above any legal ID range to allow multiple address spaces into the extra_sub_expressions map.
46 EXTRA_SUB_EXPRESSION_TYPE_STREAM_OFFSET = 0x10000000,
47 EXTRA_SUB_EXPRESSION_TYPE_AUX = 0x20000000
48};
49
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020050static bool is_unsigned_opcode(Op op)
51{
52 // Don't have to be exhaustive, only relevant for legacy target checking ...
53 switch (op)
54 {
55 case OpShiftRightLogical:
56 case OpUGreaterThan:
57 case OpUGreaterThanEqual:
58 case OpULessThan:
59 case OpULessThanEqual:
60 case OpUConvert:
61 case OpUDiv:
62 case OpUMod:
63 case OpUMulExtended:
64 case OpConvertUToF:
65 case OpConvertFToU:
66 return true;
67
68 default:
69 return false;
70 }
71}
72
73static bool is_unsigned_glsl_opcode(GLSLstd450 op)
74{
75 // Don't have to be exhaustive, only relevant for legacy target checking ...
76 switch (op)
77 {
78 case GLSLstd450UClamp:
79 case GLSLstd450UMin:
80 case GLSLstd450UMax:
81 case GLSLstd450FindUMsb:
82 return true;
83
84 default:
85 return false;
86 }
87}
88
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +020089static bool packing_is_vec4_padded(BufferPackingStandard packing)
90{
91 switch (packing)
92 {
93 case BufferPackingHLSLCbuffer:
94 case BufferPackingHLSLCbufferPackOffset:
95 case BufferPackingStd140:
96 case BufferPackingStd140EnhancedLayout:
97 return true;
98
99 default:
100 return false;
101 }
102}
103
104static bool packing_is_hlsl(BufferPackingStandard packing)
105{
106 switch (packing)
107 {
108 case BufferPackingHLSLCbuffer:
109 case BufferPackingHLSLCbufferPackOffset:
110 return true;
111
112 default:
113 return false;
114 }
115}
116
117static bool packing_has_flexible_offset(BufferPackingStandard packing)
118{
119 switch (packing)
120 {
121 case BufferPackingStd140:
122 case BufferPackingStd430:
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200123 case BufferPackingScalar:
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200124 case BufferPackingHLSLCbuffer:
125 return false;
126
127 default:
128 return true;
129 }
130}
131
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200132static bool packing_is_scalar(BufferPackingStandard packing)
133{
134 switch (packing)
135 {
136 case BufferPackingScalar:
137 case BufferPackingScalarEnhancedLayout:
138 return true;
139
140 default:
141 return false;
142 }
143}
144
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200145static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard packing)
146{
147 switch (packing)
148 {
149 case BufferPackingStd140EnhancedLayout:
150 return BufferPackingStd140;
151 case BufferPackingStd430EnhancedLayout:
152 return BufferPackingStd430;
153 case BufferPackingHLSLCbufferPackOffset:
154 return BufferPackingHLSLCbuffer;
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200155 case BufferPackingScalarEnhancedLayout:
156 return BufferPackingScalar;
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200157 default:
158 return packing;
159 }
160}
161
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100162void CompilerGLSL::init()
163{
164 if (ir.source.known)
165 {
166 options.es = ir.source.es;
167 options.version = ir.source.version;
168 }
169
170 // Query the locale to see what the decimal point is.
171 // We'll rely on fixing it up ourselves in the rare case we have a comma-as-decimal locale
172 // rather than setting locales ourselves. Settings locales in a safe and isolated way is rather
173 // tricky.
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100174#ifdef _WIN32
175 // On Windows, localeconv uses thread-local storage, so it should be fine.
176 const struct lconv *conv = localeconv();
177 if (conv && conv->decimal_point)
178 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen73102742019-03-18 10:13:33 +0100179#elif defined(__ANDROID__) && __ANDROID_API__ < 26
180 // nl_langinfo is not supported on this platform, fall back to the worse alternative.
181 const struct lconv *conv = localeconv();
182 if (conv && conv->decimal_point)
183 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100184#else
185 // localeconv, the portable function is not MT safe ...
Hans-Kristian Arntzen40965522019-02-28 12:32:52 +0100186 const char *decimal_point = nl_langinfo(RADIXCHAR);
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100187 if (decimal_point && *decimal_point != '\0')
188 current_locale_radix_character = *decimal_point;
189#endif
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100190}
191
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200192static const char *to_pls_layout(PlsFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100193{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200194 switch (format)
195 {
196 case PlsR11FG11FB10F:
197 return "layout(r11f_g11f_b10f) ";
198 case PlsR32F:
199 return "layout(r32f) ";
200 case PlsRG16F:
201 return "layout(rg16f) ";
202 case PlsRGB10A2:
203 return "layout(rgb10_a2) ";
204 case PlsRGBA8:
205 return "layout(rgba8) ";
206 case PlsRG16:
207 return "layout(rg16) ";
208 case PlsRGBA8I:
209 return "layout(rgba8i)";
210 case PlsRG16I:
211 return "layout(rg16i) ";
212 case PlsRGB10A2UI:
213 return "layout(rgb10_a2ui) ";
214 case PlsRGBA8UI:
215 return "layout(rgba8ui) ";
216 case PlsRG16UI:
217 return "layout(rg16ui) ";
218 case PlsR32UI:
219 return "layout(r32ui) ";
220 default:
221 return "";
222 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100223}
224
225static SPIRType::BaseType pls_format_to_basetype(PlsFormat format)
226{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200227 switch (format)
228 {
229 default:
230 case PlsR11FG11FB10F:
231 case PlsR32F:
232 case PlsRG16F:
233 case PlsRGB10A2:
234 case PlsRGBA8:
235 case PlsRG16:
236 return SPIRType::Float;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200238 case PlsRGBA8I:
239 case PlsRG16I:
240 return SPIRType::Int;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100241
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200242 case PlsRGB10A2UI:
243 case PlsRGBA8UI:
244 case PlsRG16UI:
245 case PlsR32UI:
246 return SPIRType::UInt;
247 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100248}
249
250static uint32_t pls_format_to_components(PlsFormat format)
251{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200252 switch (format)
253 {
254 default:
255 case PlsR32F:
256 case PlsR32UI:
257 return 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100258
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200259 case PlsRG16F:
260 case PlsRG16:
261 case PlsRG16UI:
262 case PlsRG16I:
263 return 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100264
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200265 case PlsR11FG11FB10F:
266 return 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200268 case PlsRGB10A2:
269 case PlsRGBA8:
270 case PlsRGBA8I:
271 case PlsRGB10A2UI:
272 case PlsRGBA8UI:
273 return 4;
274 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100275}
276
Hans-Kristian Arntzen93f32652020-01-07 14:05:55 +0100277const char *CompilerGLSL::vector_swizzle(int vecsize, int index)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800278{
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +0200279 static const char *const swizzle[4][4] = {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +0200280 { ".x", ".y", ".z", ".w" },
281 { ".xy", ".yz", ".zw", nullptr },
282 { ".xyz", ".yzw", nullptr, nullptr },
Hans-Kristian Arntzen7557ff52019-06-24 10:17:25 +0200283#if defined(__GNUC__) && (__GNUC__ == 9)
284 // This works around a GCC 9 bug, see details in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90947.
285 // This array ends up being compiled as all nullptrs, tripping the assertions below.
286 { "", nullptr, nullptr, "$" },
287#else
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +0200288 { "", nullptr, nullptr, nullptr },
Hans-Kristian Arntzen7557ff52019-06-24 10:17:25 +0200289#endif
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800290 };
291
292 assert(vecsize >= 1 && vecsize <= 4);
293 assert(index >= 0 && index < 4);
294 assert(swizzle[vecsize - 1][index]);
295
296 return swizzle[vecsize - 1][index];
297}
298
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100299void CompilerGLSL::reset()
300{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200301 // We do some speculative optimizations which should pretty much always work out,
302 // but just in case the SPIR-V is rather weird, recompile until it's happy.
303 // This typically only means one extra pass.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200304 clear_force_recompile();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100305
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200306 // Clear invalid expression tracking.
307 invalid_expressions.clear();
308 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100309
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200310 // Clear temporary usage tracking.
311 expression_usage_counts.clear();
312 forwarded_temporaries.clear();
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +0200313 suppressed_usage_tracking.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100314
Lukas Hermanns50ac6862019-09-18 14:03:54 -0400315 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -0400316 flushed_phi_variables.clear();
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400317
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +0100318 reset_name_caches();
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200319
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100320 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, SPIRFunction &func) {
321 func.active = false;
322 func.flush_undeclared = true;
323 });
324
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +0100325 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) { var.dependees.clear(); });
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100326
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400327 ir.reset_all_of_type<SPIRExpression>();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100328 ir.reset_all_of_type<SPIRAccessChain>();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100329
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200330 statement_count = 0;
331 indent = 0;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +0200332 current_loop_level = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100333}
334
335void CompilerGLSL::remap_pls_variables()
336{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200337 for (auto &input : pls_inputs)
338 {
339 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 bool input_is_target = false;
342 if (var.storage == StorageClassUniformConstant)
343 {
344 auto &type = get<SPIRType>(var.basetype);
345 input_is_target = type.image.dim == DimSubpassData;
346 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100347
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200348 if (var.storage != StorageClassInput && !input_is_target)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100349 SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200350 var.remapped_variable = true;
351 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100352
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200353 for (auto &output : pls_outputs)
354 {
355 auto &var = get<SPIRVariable>(output.id);
356 if (var.storage != StorageClassOutput)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100357 SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200358 var.remapped_variable = true;
359 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100360}
361
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200362void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100363{
364 subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200365 inout_color_attachments.push_back({ color_location, coherent });
366}
367
368bool CompilerGLSL::location_is_framebuffer_fetch(uint32_t location) const
369{
370 return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
371 [&](const std::pair<uint32_t, bool> &elem) {
372 return elem.first == location;
373 }) != end(inout_color_attachments);
374}
375
376bool CompilerGLSL::location_is_non_coherent_framebuffer_fetch(uint32_t location) const
377{
378 return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
379 [&](const std::pair<uint32_t, bool> &elem) {
380 return elem.first == location && !elem.second;
381 }) != end(inout_color_attachments);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100382}
383
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200384void CompilerGLSL::find_static_extensions()
385{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100386 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
387 if (type.basetype == SPIRType::Double)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200388 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100389 if (options.es)
390 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
391 if (!options.es && options.version < 400)
392 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200393 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100394 else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100395 {
396 if (options.es)
397 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
398 if (!options.es)
399 require_extension_internal("GL_ARB_gpu_shader_int64");
400 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100401 else if (type.basetype == SPIRType::Half)
402 {
403 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_float16");
404 if (options.vulkan_semantics)
405 require_extension_internal("GL_EXT_shader_16bit_storage");
406 }
407 else if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
408 {
409 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int8");
410 if (options.vulkan_semantics)
411 require_extension_internal("GL_EXT_shader_8bit_storage");
412 }
413 else if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
414 {
415 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int16");
416 if (options.vulkan_semantics)
417 require_extension_internal("GL_EXT_shader_16bit_storage");
418 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100419 });
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200420
421 auto &execution = get_entry_point();
422 switch (execution.model)
423 {
424 case ExecutionModelGLCompute:
425 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200426 require_extension_internal("GL_ARB_compute_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200427 if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100428 SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200429 break;
430
431 case ExecutionModelGeometry:
432 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200433 require_extension_internal("GL_EXT_geometry_shader");
robfb1820e2017-06-17 10:06:46 +0900434 if (!options.es && options.version < 150)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200435 require_extension_internal("GL_ARB_geometry_shader4");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200436
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100437 if (execution.flags.get(ExecutionModeInvocations) && execution.invocations != 1)
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200438 {
439 // Instanced GS is part of 400 core or this extension.
440 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200441 require_extension_internal("GL_ARB_gpu_shader5");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200442 }
443 break;
444
445 case ExecutionModelTessellationEvaluation:
446 case ExecutionModelTessellationControl:
447 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200448 require_extension_internal("GL_EXT_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200449 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200450 require_extension_internal("GL_ARB_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200451 break;
452
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100453 case ExecutionModelRayGenerationKHR:
454 case ExecutionModelIntersectionKHR:
455 case ExecutionModelAnyHitKHR:
456 case ExecutionModelClosestHitKHR:
457 case ExecutionModelMissKHR:
458 case ExecutionModelCallableKHR:
459 // NV enums are aliases.
Patrick Moursc74d7a42019-03-25 15:06:01 +0100460 if (options.es || options.version < 460)
461 SPIRV_CROSS_THROW("Ray tracing shaders require non-es profile with version 460 or above.");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100462 if (!options.vulkan_semantics)
463 SPIRV_CROSS_THROW("Ray tracing requires Vulkan semantics.");
464
465 // Need to figure out if we should target KHR or NV extension based on capabilities.
466 for (auto &cap : ir.declared_capabilities)
467 {
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +0200468 if (cap == CapabilityRayTracingKHR || cap == CapabilityRayQueryKHR ||
469 cap == CapabilityRayTraversalPrimitiveCullingKHR)
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100470 {
471 ray_tracing_is_khr = true;
472 break;
473 }
474 }
475
476 if (ray_tracing_is_khr)
477 {
478 // In KHR ray tracing we pass payloads by pointer instead of location,
479 // so make sure we assign locations properly.
480 ray_tracing_khr_fixup_locations();
481 require_extension_internal("GL_EXT_ray_tracing");
482 }
483 else
484 require_extension_internal("GL_NV_ray_tracing");
Patrick Moursc74d7a42019-03-25 15:06:01 +0100485 break;
486
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200487 default:
488 break;
489 }
490
491 if (!pls_inputs.empty() || !pls_outputs.empty())
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100492 {
493 if (execution.model != ExecutionModelFragment)
494 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_pixel_local_storage in fragment shaders.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200495 require_extension_internal("GL_EXT_shader_pixel_local_storage");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100496 }
497
498 if (!inout_color_attachments.empty())
499 {
500 if (execution.model != ExecutionModelFragment)
501 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
502 if (options.vulkan_semantics)
503 SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200504
505 bool has_coherent = false;
506 bool has_incoherent = false;
507
508 for (auto &att : inout_color_attachments)
509 {
510 if (att.second)
511 has_coherent = true;
512 else
513 has_incoherent = true;
514 }
515
516 if (has_coherent)
517 require_extension_internal("GL_EXT_shader_framebuffer_fetch");
518 if (has_incoherent)
519 require_extension_internal("GL_EXT_shader_framebuffer_fetch_non_coherent");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100520 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +0200521
522 if (options.separate_shader_objects && !options.es && options.version < 410)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200523 require_extension_internal("GL_ARB_separate_shader_objects");
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200524
525 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
526 {
527 if (!options.vulkan_semantics)
528 SPIRV_CROSS_THROW("GL_EXT_buffer_reference is only supported in Vulkan GLSL.");
529 if (options.es && options.version < 320)
530 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires ESSL 320.");
531 else if (!options.es && options.version < 450)
532 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires GLSL 450.");
533 require_extension_internal("GL_EXT_buffer_reference");
534 }
535 else if (ir.addressing_model != AddressingModelLogical)
536 {
537 SPIRV_CROSS_THROW("Only Logical and PhysicalStorageBuffer64EXT addressing models are supported.");
538 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200539
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100540 // Check for nonuniform qualifier and passthrough.
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200541 // Instead of looping over all decorations to find this, just look at capabilities.
542 for (auto &cap : ir.declared_capabilities)
543 {
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200544 switch (cap)
545 {
546 case CapabilityShaderNonUniformEXT:
Mateusz Kielan127224d2020-04-18 21:21:43 +0200547 if (!options.vulkan_semantics)
548 require_extension_internal("GL_NV_gpu_shader5");
549 else
550 require_extension_internal("GL_EXT_nonuniform_qualifier");
551 break;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200552 case CapabilityRuntimeDescriptorArrayEXT:
553 if (!options.vulkan_semantics)
554 SPIRV_CROSS_THROW("GL_EXT_nonuniform_qualifier is only supported in Vulkan GLSL.");
555 require_extension_internal("GL_EXT_nonuniform_qualifier");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100556 break;
557
558 case CapabilityGeometryShaderPassthroughNV:
559 if (execution.model == ExecutionModelGeometry)
560 {
561 require_extension_internal("GL_NV_geometry_shader_passthrough");
562 execution.geometry_passthrough = true;
563 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200564 break;
565
Hans-Kristian Arntzendc940842020-12-07 12:16:02 +0100566 case CapabilityVariablePointers:
567 case CapabilityVariablePointersStorageBuffer:
568 SPIRV_CROSS_THROW("VariablePointers capability is not supported in GLSL.");
569
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200570 case CapabilityMultiView:
571 if (options.vulkan_semantics)
572 require_extension_internal("GL_EXT_multiview");
573 else
574 {
575 require_extension_internal("GL_OVR_multiview2");
576 if (options.ovr_multiview_view_count == 0)
577 SPIRV_CROSS_THROW("ovr_multiview_view_count must be non-zero when using GL_OVR_multiview2.");
578 if (get_execution_model() != ExecutionModelVertex)
579 SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
580 }
581 break;
582
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +0200583 case CapabilityRayQueryKHR:
584 if (options.es || options.version < 460 || !options.vulkan_semantics)
585 SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
586 require_extension_internal("GL_EXT_ray_query");
587 ray_tracing_is_khr = true;
588 break;
589
590 case CapabilityRayTraversalPrimitiveCullingKHR:
591 if (options.es || options.version < 460 || !options.vulkan_semantics)
592 SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
593 require_extension_internal("GL_EXT_ray_flags_primitive_culling");
594 ray_tracing_is_khr = true;
595 break;
596
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200597 default:
598 break;
599 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200600 }
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200601
602 if (options.ovr_multiview_view_count)
603 {
604 if (options.vulkan_semantics)
605 SPIRV_CROSS_THROW("OVR_multiview2 cannot be used with Vulkan semantics.");
606 if (get_execution_model() != ExecutionModelVertex)
607 SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
608 require_extension_internal("GL_OVR_multiview2");
609 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200610}
611
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100612void CompilerGLSL::ray_tracing_khr_fixup_locations()
613{
614 uint32_t location = 0;
615 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen66fb0bd2021-01-22 11:22:10 +0100616 // Incoming payload storage can also be used for tracing.
617 if (var.storage != StorageClassRayPayloadKHR && var.storage != StorageClassCallableDataKHR &&
618 var.storage != StorageClassIncomingRayPayloadKHR && var.storage != StorageClassIncomingCallableDataKHR)
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100619 return;
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +0100620 if (is_hidden_variable(var))
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100621 return;
622 set_decoration(var.self, DecorationLocation, location++);
623 });
624}
625
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100626string CompilerGLSL::compile()
627{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200628 ir.fixup_reserved_names();
629
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200630 if (!options.vulkan_semantics)
Mateusz Kielan127224d2020-04-18 21:21:43 +0200631 {
632 // only NV_gpu_shader5 supports divergent indexing on OpenGL, and it does so without extra qualifiers
633 backend.nonuniform_qualifier = "";
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +0200634 backend.needs_row_major_load_workaround = true;
Mateusz Kielan127224d2020-04-18 21:21:43 +0200635 }
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200636 backend.allow_precision_qualifiers = options.vulkan_semantics || options.es;
Hans-Kristian Arntzenf708b492018-01-09 09:16:33 +0100637 backend.force_gl_in_out_block = true;
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +0100638 backend.supports_extensions = true;
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +0200639 backend.use_array_constructor = true;
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100640 backend.workgroup_size_is_hidden = true;
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100641
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200642 backend.support_precise_qualifier = (!options.es && options.version >= 400) || (options.es && options.version >= 320);
643
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +0200644 if (is_legacy_es())
645 backend.support_case_fallthrough = false;
646
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200647 // Scan the SPIR-V to find trivial uses of extensions.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200648 fixup_type_alias();
649 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200650 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200651 find_static_extensions();
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +0100652 fixup_image_load_store_access();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100653 update_active_builtins();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +0100654 analyze_image_and_sampler_usage();
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200655 analyze_interlocked_resource_usage();
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100656 if (!inout_color_attachments.empty())
657 emit_inout_fragment_outputs_copy_to_subpass_inputs();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200658
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200659 // Shaders might cast unrelated data to pointers of non-block types.
660 // Find all such instances and make sure we can cast the pointers to a synthesized block type.
661 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
662 analyze_non_block_pointer_types();
663
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200664 uint32_t pass_count = 0;
665 do
666 {
667 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100668 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100669
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200670 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100671
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200672 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100673
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200674 emit_header();
675 emit_resources();
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200676 emit_extension_workarounds(get_execution_model());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100677
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200678 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200680 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200681 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100682
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200683 // Implement the interlocked wrapper function at the end.
684 // The body was implemented in lieu of main().
685 if (interlocked_is_complex)
686 {
687 statement("void main()");
688 begin_scope();
689 statement("// Interlocks were used in a way not compatible with GLSL, this is very slow.");
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330690 statement("SPIRV_Cross_beginInvocationInterlock();");
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200691 statement("spvMainInterlockedBody();");
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330692 statement("SPIRV_Cross_endInvocationInterlock();");
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200693 end_scope();
694 }
695
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100696 // Entry point in GLSL is always main().
697 get_entry_point().name = "main";
698
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200699 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100700}
701
Bill Hollingsc5c07362016-11-27 12:34:04 -0500702std::string CompilerGLSL::get_partial_source()
703{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200704 return buffer.str();
Bill Hollingsc5c07362016-11-27 12:34:04 -0500705}
706
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200707void CompilerGLSL::build_workgroup_size(SmallVector<string> &arguments, const SpecializationConstant &wg_x,
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +0100708 const SpecializationConstant &wg_y, const SpecializationConstant &wg_z)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100709{
710 auto &execution = get_entry_point();
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100711 bool builtin_workgroup = execution.workgroup_size.constant != 0;
712 bool use_local_size_id = !builtin_workgroup && execution.flags.get(ExecutionModeLocalSizeId);
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100713
714 if (wg_x.id)
715 {
716 if (options.vulkan_semantics)
717 arguments.push_back(join("local_size_x_id = ", wg_x.constant_id));
718 else
719 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(wg_x.id).specialization_constant_macro_name));
720 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100721 else if (use_local_size_id && execution.workgroup_size.id_x)
722 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(execution.workgroup_size.id_x).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100723 else
724 arguments.push_back(join("local_size_x = ", execution.workgroup_size.x));
725
726 if (wg_y.id)
727 {
728 if (options.vulkan_semantics)
729 arguments.push_back(join("local_size_y_id = ", wg_y.constant_id));
730 else
731 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(wg_y.id).specialization_constant_macro_name));
732 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100733 else if (use_local_size_id && execution.workgroup_size.id_y)
734 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(execution.workgroup_size.id_y).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100735 else
736 arguments.push_back(join("local_size_y = ", execution.workgroup_size.y));
737
738 if (wg_z.id)
739 {
740 if (options.vulkan_semantics)
741 arguments.push_back(join("local_size_z_id = ", wg_z.constant_id));
742 else
743 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(wg_z.id).specialization_constant_macro_name));
744 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100745 else if (use_local_size_id && execution.workgroup_size.id_z)
746 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(execution.workgroup_size.id_z).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100747 else
748 arguments.push_back(join("local_size_z = ", execution.workgroup_size.z));
749}
750
crissdb52e272020-10-08 12:14:52 +0200751void CompilerGLSL::request_subgroup_feature(ShaderSubgroupSupportHelper::Feature feature)
752{
753 if (options.vulkan_semantics)
754 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200755 auto khr_extension = ShaderSubgroupSupportHelper::get_KHR_extension_for_feature(feature);
756 require_extension_internal(ShaderSubgroupSupportHelper::get_extension_name(khr_extension));
crissdb52e272020-10-08 12:14:52 +0200757 }
758 else
759 {
760 if (!shader_subgroup_supporter.is_feature_requested(feature))
761 force_recompile();
762 shader_subgroup_supporter.request_feature(feature);
763 }
764}
765
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100766void CompilerGLSL::emit_header()
767{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200768 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200769 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100770
Ben Claytone9621822017-10-09 10:33:42 +0100771 if (!options.es && options.version < 420)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200772 {
Ben Claytone9621822017-10-09 10:33:42 +0100773 // Needed for binding = # on UBOs, etc.
774 if (options.enable_420pack_extension)
775 {
776 statement("#ifdef GL_ARB_shading_language_420pack");
777 statement("#extension GL_ARB_shading_language_420pack : require");
778 statement("#endif");
779 }
780 // Needed for: layout(early_fragment_tests) in;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100781 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200782 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200783 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100784
Chip Davis1df47db2019-07-10 22:42:39 -0500785 // Needed for: layout(post_depth_coverage) in;
786 if (execution.flags.get(ExecutionModePostDepthCoverage))
787 require_extension_internal("GL_ARB_post_depth_coverage");
788
Chip Davis2eff4202019-08-04 00:07:20 -0500789 // Needed for: layout({pixel,sample}_interlock_[un]ordered) in;
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330790 bool interlock_used = execution.flags.get(ExecutionModePixelInterlockOrderedEXT) ||
791 execution.flags.get(ExecutionModePixelInterlockUnorderedEXT) ||
792 execution.flags.get(ExecutionModeSampleInterlockOrderedEXT) ||
793 execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT);
794
795 if (interlock_used)
Chip Davis2eff4202019-08-04 00:07:20 -0500796 {
797 if (options.es)
798 {
799 if (options.version < 310)
800 SPIRV_CROSS_THROW("At least ESSL 3.10 required for fragment shader interlock.");
801 require_extension_internal("GL_NV_fragment_shader_interlock");
802 }
803 else
804 {
805 if (options.version < 420)
806 require_extension_internal("GL_ARB_shader_image_load_store");
807 require_extension_internal("GL_ARB_fragment_shader_interlock");
808 }
809 }
810
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200811 for (auto &ext : forced_extensions)
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200812 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100813 if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16")
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200814 {
815 // Special case, this extension has a potential fallback to another vendor extension in normal GLSL.
816 // GL_AMD_gpu_shader_half_float is a superset, so try that first.
817 statement("#if defined(GL_AMD_gpu_shader_half_float)");
818 statement("#extension GL_AMD_gpu_shader_half_float : require");
Chip Davis1fb27b42018-10-31 09:43:03 -0500819 if (!options.vulkan_semantics)
820 {
821 statement("#elif defined(GL_NV_gpu_shader5)");
822 statement("#extension GL_NV_gpu_shader5 : require");
823 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100824 else
825 {
826 statement("#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)");
827 statement("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
828 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200829 statement("#else");
830 statement("#error No extension available for FP16.");
831 statement("#endif");
832 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100833 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16")
Chip Davis1fb27b42018-10-31 09:43:03 -0500834 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100835 if (options.vulkan_semantics)
836 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
837 else
838 {
839 statement("#if defined(GL_AMD_gpu_shader_int16)");
840 statement("#extension GL_AMD_gpu_shader_int16 : require");
Przemog10408c592021-05-05 21:41:53 +0200841 statement("#elif defined(GL_NV_gpu_shader5)");
842 statement("#extension GL_NV_gpu_shader5 : require");
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100843 statement("#else");
844 statement("#error No extension available for Int16.");
845 statement("#endif");
846 }
Chip Davis1fb27b42018-10-31 09:43:03 -0500847 }
Chip Davis5fe1ecc2019-08-02 21:02:05 -0500848 else if (ext == "GL_ARB_post_depth_coverage")
849 {
850 if (options.es)
851 statement("#extension GL_EXT_post_depth_coverage : require");
852 else
853 {
854 statement("#if defined(GL_ARB_post_depth_coverge)");
855 statement("#extension GL_ARB_post_depth_coverage : require");
856 statement("#else");
857 statement("#extension GL_EXT_post_depth_coverage : require");
858 statement("#endif");
859 }
860 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +0200861 else if (!options.vulkan_semantics && ext == "GL_ARB_shader_draw_parameters")
862 {
863 // Soft-enable this extension on plain GLSL.
864 statement("#ifdef ", ext);
865 statement("#extension ", ext, " : enable");
866 statement("#endif");
867 }
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +0200868 else if (ext == "GL_EXT_control_flow_attributes")
869 {
870 // These are just hints so we can conditionally enable and fallback in the shader.
871 statement("#if defined(GL_EXT_control_flow_attributes)");
872 statement("#extension GL_EXT_control_flow_attributes : require");
873 statement("#define SPIRV_CROSS_FLATTEN [[flatten]]");
874 statement("#define SPIRV_CROSS_BRANCH [[dont_flatten]]");
875 statement("#define SPIRV_CROSS_UNROLL [[unroll]]");
876 statement("#define SPIRV_CROSS_LOOP [[dont_unroll]]");
877 statement("#else");
878 statement("#define SPIRV_CROSS_FLATTEN");
879 statement("#define SPIRV_CROSS_BRANCH");
880 statement("#define SPIRV_CROSS_UNROLL");
881 statement("#define SPIRV_CROSS_LOOP");
882 statement("#endif");
883 }
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330884 else if (ext == "GL_NV_fragment_shader_interlock")
885 {
886 statement("#extension GL_NV_fragment_shader_interlock : require");
887 statement("#define SPIRV_Cross_beginInvocationInterlock() beginInvocationInterlockNV()");
888 statement("#define SPIRV_Cross_endInvocationInterlock() endInvocationInterlockNV()");
889 }
890 else if (ext == "GL_ARB_fragment_shader_interlock")
891 {
892 statement("#ifdef GL_ARB_fragment_shader_interlock");
893 statement("#extension GL_ARB_fragment_shader_interlock : enable");
894 statement("#define SPIRV_Cross_beginInvocationInterlock() beginInvocationInterlockARB()");
895 statement("#define SPIRV_Cross_endInvocationInterlock() endInvocationInterlockARB()");
896 statement("#elif defined(GL_INTEL_fragment_shader_ordering)");
897 statement("#extension GL_INTEL_fragment_shader_ordering : enable");
898 statement("#define SPIRV_Cross_beginInvocationInterlock() beginFragmentShaderOrderingINTEL()");
899 statement("#define SPIRV_Cross_endInvocationInterlock()");
900 statement("#endif");
901 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200902 else
903 statement("#extension ", ext, " : require");
904 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100905
crissdb52e272020-10-08 12:14:52 +0200906 if (!options.vulkan_semantics)
907 {
908 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200909 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +0200910
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200911 for (uint32_t feature_index = 0; feature_index < Supp::FeatureCount; feature_index++)
crissdb52e272020-10-08 12:14:52 +0200912 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200913 auto feature = static_cast<Supp::Feature>(feature_index);
crissdb52e272020-10-08 12:14:52 +0200914 if (!shader_subgroup_supporter.is_feature_requested(feature))
915 continue;
916
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200917 auto exts = Supp::get_candidates_for_feature(feature, result);
crissdb52e272020-10-08 12:14:52 +0200918 if (exts.empty())
919 continue;
920
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200921 statement("");
crissdb52e272020-10-08 12:14:52 +0200922
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200923 for (auto &ext : exts)
924 {
925 const char *name = Supp::get_extension_name(ext);
926 const char *extra_predicate = Supp::get_extra_required_extension_predicate(ext);
927 auto extra_names = Supp::get_extra_required_extension_names(ext);
928 statement(&ext != &exts.front() ? "#elif" : "#if", " defined(", name, ")",
929 (*extra_predicate != '\0' ? " && " : ""), extra_predicate);
930 for (const auto &e : extra_names)
crissdb52e272020-10-08 12:14:52 +0200931 statement("#extension ", e, " : enable");
932 statement("#extension ", name, " : require");
933 }
934
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200935 if (!Supp::can_feature_be_implemented_without_extensions(feature))
crissdb52e272020-10-08 12:14:52 +0200936 {
937 statement("#else");
938 statement("#error No extensions available to emulate requested subgroup feature.");
939 }
940
941 statement("#endif");
942 }
943 }
944
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200945 for (auto &header : header_lines)
946 statement(header);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100947
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200948 SmallVector<string> inputs;
949 SmallVector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100950
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200951 switch (execution.model)
952 {
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200953 case ExecutionModelVertex:
954 if (options.ovr_multiview_view_count)
955 inputs.push_back(join("num_views = ", options.ovr_multiview_view_count));
956 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200957 case ExecutionModelGeometry:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100958 if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200959 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100960 if (execution.flags.get(ExecutionModeInputPoints))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200961 inputs.push_back("points");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100962 if (execution.flags.get(ExecutionModeInputLines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200963 inputs.push_back("lines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100964 if (execution.flags.get(ExecutionModeInputLinesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200965 inputs.push_back("lines_adjacency");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100966 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200967 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100968 if (execution.flags.get(ExecutionModeInputTrianglesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200969 inputs.push_back("triangles_adjacency");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100970
971 if (!execution.geometry_passthrough)
972 {
973 // For passthrough, these are implies and cannot be declared in shader.
974 outputs.push_back(join("max_vertices = ", execution.output_vertices));
975 if (execution.flags.get(ExecutionModeOutputTriangleStrip))
976 outputs.push_back("triangle_strip");
977 if (execution.flags.get(ExecutionModeOutputPoints))
978 outputs.push_back("points");
979 if (execution.flags.get(ExecutionModeOutputLineStrip))
980 outputs.push_back("line_strip");
981 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200982 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100983
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200984 case ExecutionModelTessellationControl:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100985 if (execution.flags.get(ExecutionModeOutputVertices))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200986 outputs.push_back(join("vertices = ", execution.output_vertices));
987 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100988
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200989 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100990 if (execution.flags.get(ExecutionModeQuads))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200991 inputs.push_back("quads");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100992 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200993 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100994 if (execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200995 inputs.push_back("isolines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100996 if (execution.flags.get(ExecutionModePointMode))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200997 inputs.push_back("point_mode");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200998
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100999 if (!execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001000 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001001 if (execution.flags.get(ExecutionModeVertexOrderCw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001002 inputs.push_back("cw");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001003 if (execution.flags.get(ExecutionModeVertexOrderCcw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001004 inputs.push_back("ccw");
1005 }
1006
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001007 if (execution.flags.get(ExecutionModeSpacingFractionalEven))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001008 inputs.push_back("fractional_even_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001009 if (execution.flags.get(ExecutionModeSpacingFractionalOdd))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001010 inputs.push_back("fractional_odd_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001011 if (execution.flags.get(ExecutionModeSpacingEqual))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001012 inputs.push_back("equal_spacing");
1013 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001014
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001015 case ExecutionModelGLCompute:
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001016 {
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01001017 if (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId))
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001018 {
1019 SpecializationConstant wg_x, wg_y, wg_z;
1020 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
1021
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001022 // If there are any spec constants on legacy GLSL, defer declaration, we need to set up macro
1023 // declarations before we can emit the work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001024 if (options.vulkan_semantics ||
1025 ((wg_x.id == ConstantID(0)) && (wg_y.id == ConstantID(0)) && (wg_z.id == ConstantID(0))))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001026 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001027 }
1028 else
1029 {
1030 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
1031 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
1032 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
1033 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001034 break;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001035 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001036
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001037 case ExecutionModelFragment:
1038 if (options.es)
1039 {
1040 switch (options.fragment.default_float_precision)
1041 {
1042 case Options::Lowp:
1043 statement("precision lowp float;");
1044 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001045
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001046 case Options::Mediump:
1047 statement("precision mediump float;");
1048 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001049
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001050 case Options::Highp:
1051 statement("precision highp float;");
1052 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001053
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001054 default:
1055 break;
1056 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001057
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001058 switch (options.fragment.default_int_precision)
1059 {
1060 case Options::Lowp:
1061 statement("precision lowp int;");
1062 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001063
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001064 case Options::Mediump:
1065 statement("precision mediump int;");
1066 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001067
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001068 case Options::Highp:
1069 statement("precision highp int;");
1070 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001072 default:
1073 break;
1074 }
1075 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001076
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001077 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001078 inputs.push_back("early_fragment_tests");
Chip Davis1df47db2019-07-10 22:42:39 -05001079 if (execution.flags.get(ExecutionModePostDepthCoverage))
1080 inputs.push_back("post_depth_coverage");
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +01001081
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301082 if (interlock_used)
1083 statement("#if defined(GL_ARB_fragment_shader_interlock)");
1084
Chip Davis2eff4202019-08-04 00:07:20 -05001085 if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301086 statement("layout(pixel_interlock_ordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001087 else if (execution.flags.get(ExecutionModePixelInterlockUnorderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301088 statement("layout(pixel_interlock_unordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001089 else if (execution.flags.get(ExecutionModeSampleInterlockOrderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301090 statement("layout(sample_interlock_ordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001091 else if (execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301092 statement("layout(sample_interlock_unordered) in;");
1093
1094 if (interlock_used)
1095 {
1096 statement("#elif !defined(GL_INTEL_fragment_shader_ordering)");
1097 statement("#error Fragment Shader Interlock/Ordering extension missing!");
1098 statement("#endif");
1099 }
Chip Davis2eff4202019-08-04 00:07:20 -05001100
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +01001101 if (!options.es && execution.flags.get(ExecutionModeDepthGreater))
1102 statement("layout(depth_greater) out float gl_FragDepth;");
1103 else if (!options.es && execution.flags.get(ExecutionModeDepthLess))
1104 statement("layout(depth_less) out float gl_FragDepth;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001105
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001106 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001107
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001108 default:
1109 break;
1110 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001111
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +02001112 for (auto &cap : ir.declared_capabilities)
1113 if (cap == CapabilityRayTraversalPrimitiveCullingKHR)
1114 statement("layout(primitive_culling);");
1115
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001116 if (!inputs.empty())
1117 statement("layout(", merge(inputs), ") in;");
1118 if (!outputs.empty())
1119 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001120
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001121 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001122}
1123
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +01001124bool CompilerGLSL::type_is_empty(const SPIRType &type)
1125{
1126 return type.basetype == SPIRType::Struct && type.member_types.empty();
1127}
1128
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001129void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001130{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001131 // Struct types can be stamped out multiple times
1132 // with just different offsets, matrix layouts, etc ...
1133 // Type-punning with these types is legal, which complicates things
1134 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzen294259e2018-03-05 16:27:04 +01001135 // 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 +02001136 if (type.type_alias != TypeID(0) &&
1137 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001138 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001139
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001140 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001141 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001142
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001143 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001144 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001145
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001146 type.member_name_cache.clear();
1147
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001148 uint32_t i = 0;
1149 bool emitted = false;
1150 for (auto &member : type.member_types)
1151 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001152 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05001153 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001154 i++;
1155 emitted = true;
1156 }
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02001157
1158 // Don't declare empty structs in GLSL, this is not allowed.
1159 if (type_is_empty(type) && !backend.supports_empty_struct)
1160 {
1161 statement("int empty_struct_member;");
1162 emitted = true;
1163 }
1164
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +02001165 if (has_extended_decoration(type.self, SPIRVCrossDecorationPaddingTarget))
1166 emit_struct_padding_target(type);
1167
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001168 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001169
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001170 if (emitted)
1171 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001172}
1173
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001174string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001175{
1176 string res;
1177 //if (flags & (1ull << DecorationSmooth))
1178 // res += "smooth ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001179 if (flags.get(DecorationFlat))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001180 res += "flat ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001181 if (flags.get(DecorationNoPerspective))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001182 res += "noperspective ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001183 if (flags.get(DecorationCentroid))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001184 res += "centroid ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001185 if (flags.get(DecorationPatch))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001186 res += "patch ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001187 if (flags.get(DecorationSample))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001188 res += "sample ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001189 if (flags.get(DecorationInvariant))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001190 res += "invariant ";
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001191
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001192 if (flags.get(DecorationExplicitInterpAMD))
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001193 {
1194 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +01001195 res += "__explicitInterpAMD ";
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001196 }
1197
1198 if (flags.get(DecorationPerVertexNV))
1199 {
1200 if (options.es && options.version < 320)
1201 SPIRV_CROSS_THROW("pervertexNV requires ESSL 320.");
1202 else if (!options.es && options.version < 450)
1203 SPIRV_CROSS_THROW("pervertexNV requires GLSL 450.");
1204 require_extension_internal("GL_NV_fragment_shader_barycentric");
1205 res += "pervertexNV ";
1206 }
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001207
1208 return res;
1209}
1210
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001211string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
1212{
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001213 if (is_legacy())
1214 return "";
1215
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001216 bool is_block = has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001217 if (!is_block)
1218 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001219
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001220 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001221 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +02001222 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001223 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001224
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001225 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001226
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001227 if (has_member_decoration(type.self, index, DecorationPassthroughNV))
1228 attr.push_back("passthrough");
1229
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001230 // We can only apply layouts on members in block interfaces.
1231 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
1232 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
1233 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
1234 //
1235 // We would like to go from (SPIR-V style):
1236 //
1237 // struct Foo { layout(row_major) mat4 matrix; };
1238 // buffer UBO { Foo foo; };
1239 //
1240 // to
1241 //
1242 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
1243 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
1244 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001245
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001246 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001247 attr.push_back("row_major");
1248 // We don't emit any global layouts, so column_major is default.
1249 //if (flags & (1ull << DecorationColMajor))
1250 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001251
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001252 if (dec.decoration_flags.get(DecorationLocation) && can_use_io_location(type.storage, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001253 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001254
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001255 // Can only declare component if we can declare location.
1256 if (dec.decoration_flags.get(DecorationComponent) && can_use_io_location(type.storage, true))
1257 {
1258 if (!options.es)
1259 {
1260 if (options.version < 440 && options.version >= 140)
1261 require_extension_internal("GL_ARB_enhanced_layouts");
1262 else if (options.version < 140)
1263 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
1264 attr.push_back(join("component = ", dec.component));
1265 }
1266 else
1267 SPIRV_CROSS_THROW("Component decoration is not supported in ES targets.");
1268 }
1269
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001270 // 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 +02001271 // This is only done selectively in GLSL as needed.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02001272 if (has_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset) &&
1273 dec.decoration_flags.get(DecorationOffset))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001274 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001275 else if (type.storage == StorageClassOutput && dec.decoration_flags.get(DecorationOffset))
1276 attr.push_back(join("xfb_offset = ", dec.offset));
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001277
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001278 if (attr.empty())
1279 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001280
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001281 string res = "layout(";
1282 res += merge(attr);
1283 res += ") ";
1284 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001285}
1286
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001287const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001288{
Brad Davis76204002018-06-20 10:25:38 -07001289 if (options.es && is_desktop_only_format(format))
1290 SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001291
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001292 switch (format)
1293 {
1294 case ImageFormatRgba32f:
1295 return "rgba32f";
1296 case ImageFormatRgba16f:
1297 return "rgba16f";
1298 case ImageFormatR32f:
1299 return "r32f";
1300 case ImageFormatRgba8:
1301 return "rgba8";
1302 case ImageFormatRgba8Snorm:
1303 return "rgba8_snorm";
1304 case ImageFormatRg32f:
1305 return "rg32f";
1306 case ImageFormatRg16f:
1307 return "rg16f";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001308 case ImageFormatRgba32i:
1309 return "rgba32i";
1310 case ImageFormatRgba16i:
1311 return "rgba16i";
1312 case ImageFormatR32i:
1313 return "r32i";
1314 case ImageFormatRgba8i:
1315 return "rgba8i";
1316 case ImageFormatRg32i:
1317 return "rg32i";
1318 case ImageFormatRg16i:
1319 return "rg16i";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001320 case ImageFormatRgba32ui:
1321 return "rgba32ui";
1322 case ImageFormatRgba16ui:
1323 return "rgba16ui";
1324 case ImageFormatR32ui:
1325 return "r32ui";
1326 case ImageFormatRgba8ui:
1327 return "rgba8ui";
1328 case ImageFormatRg32ui:
1329 return "rg32ui";
1330 case ImageFormatRg16ui:
1331 return "rg16ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001332 case ImageFormatR11fG11fB10f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001333 return "r11f_g11f_b10f";
1334 case ImageFormatR16f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001335 return "r16f";
1336 case ImageFormatRgb10A2:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001337 return "rgb10_a2";
1338 case ImageFormatR8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001339 return "r8";
1340 case ImageFormatRg8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001341 return "rg8";
1342 case ImageFormatR16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001343 return "r16";
1344 case ImageFormatRg16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001345 return "rg16";
1346 case ImageFormatRgba16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001347 return "rgba16";
1348 case ImageFormatR16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001349 return "r16_snorm";
1350 case ImageFormatRg16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001351 return "rg16_snorm";
1352 case ImageFormatRgba16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001353 return "rgba16_snorm";
1354 case ImageFormatR8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001355 return "r8_snorm";
1356 case ImageFormatRg8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001357 return "rg8_snorm";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001358 case ImageFormatR8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001359 return "r8ui";
1360 case ImageFormatRg8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001361 return "rg8ui";
1362 case ImageFormatR16ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001363 return "r16ui";
1364 case ImageFormatRgb10a2ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001365 return "rgb10_a2ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001366 case ImageFormatR8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001367 return "r8i";
1368 case ImageFormatRg8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001369 return "rg8i";
1370 case ImageFormatR16i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001371 return "r16i";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001372 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001373 case ImageFormatUnknown:
1374 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001375 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001376}
1377
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001378uint32_t CompilerGLSL::type_to_packed_base_size(const SPIRType &type, BufferPackingStandard)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001379{
1380 switch (type.basetype)
1381 {
1382 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02001383 case SPIRType::Int64:
1384 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001385 return 8;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001386 case SPIRType::Float:
1387 case SPIRType::Int:
1388 case SPIRType::UInt:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001389 return 4;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001390 case SPIRType::Half:
Chip Davis117ccf42018-11-01 17:20:07 -05001391 case SPIRType::Short:
1392 case SPIRType::UShort:
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001393 return 2;
Chip Davis117ccf42018-11-01 17:20:07 -05001394 case SPIRType::SByte:
1395 case SPIRType::UByte:
1396 return 1;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001397
1398 default:
1399 SPIRV_CROSS_THROW("Unrecognized type in type_to_packed_base_size.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001400 }
1401}
1402
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001403uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bitset &flags,
1404 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001405{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001406 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1407 // and is 64-bit.
1408 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1409 {
1410 if (!type.pointer)
1411 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1412
1413 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1414 {
1415 if (packing_is_vec4_padded(packing) && type_is_array_of_pointers(type))
1416 return 16;
1417 else
1418 return 8;
1419 }
1420 else
1421 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1422 }
1423
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001424 if (!type.array.empty())
1425 {
1426 uint32_t minimum_alignment = 1;
1427 if (packing_is_vec4_padded(packing))
1428 minimum_alignment = 16;
1429
1430 auto *tmp = &get<SPIRType>(type.parent_type);
1431 while (!tmp->array.empty())
1432 tmp = &get<SPIRType>(tmp->parent_type);
1433
1434 // Get the alignment of the base type, then maybe round up.
1435 return max(minimum_alignment, type_to_packed_alignment(*tmp, flags, packing));
1436 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001437
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001438 if (type.basetype == SPIRType::Struct)
1439 {
1440 // Rule 9. Structs alignments are maximum alignment of its members.
Hans-Kristian Arntzen8c632da2019-01-28 11:02:28 +01001441 uint32_t alignment = 1;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001442 for (uint32_t i = 0; i < type.member_types.size(); i++)
1443 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001444 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +02001445 alignment =
1446 max(alignment, type_to_packed_alignment(get<SPIRType>(type.member_types[i]), member_flags, packing));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001447 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001448
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001449 // In std140, struct alignment is rounded up to 16.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001450 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001451 alignment = max(alignment, 16u);
1452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001453 return alignment;
1454 }
1455 else
1456 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001457 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1458
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001459 // Alignment requirement for scalar block layout is always the alignment for the most basic component.
1460 if (packing_is_scalar(packing))
1461 return base_alignment;
1462
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001463 // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle
1464 // a vec4, this is handled outside since that part knows our current offset.
1465 if (type.columns == 1 && packing_is_hlsl(packing))
1466 return base_alignment;
1467
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001468 // From 7.6.2.2 in GL 4.5 core spec.
1469 // Rule 1
1470 if (type.vecsize == 1 && type.columns == 1)
1471 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001472
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001473 // Rule 2
1474 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
1475 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001476
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001477 // Rule 3
1478 if (type.vecsize == 3 && type.columns == 1)
1479 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001480
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001481 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001482
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001483 // Rule 5. Column-major matrices are stored as arrays of
1484 // vectors.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001485 if (flags.get(DecorationColMajor) && type.columns > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001486 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001487 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001488 return 4 * base_alignment;
1489 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001490 return 4 * base_alignment;
1491 else
1492 return type.vecsize * base_alignment;
1493 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001494
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001495 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001496
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001497 // Rule 7.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001498 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001499 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001500 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001501 return 4 * base_alignment;
1502 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001503 return 4 * base_alignment;
1504 else
1505 return type.columns * base_alignment;
1506 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001507
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001508 // Rule 8 implied.
1509 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001510
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001511 SPIRV_CROSS_THROW("Did not find suitable rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001512}
1513
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001514uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, const Bitset &flags,
1515 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001516{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001517 // Array stride is equal to aligned size of the underlying type.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001518 uint32_t parent = type.parent_type;
1519 assert(parent);
1520
1521 auto &tmp = get<SPIRType>(parent);
1522
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001523 uint32_t size = type_to_packed_size(tmp, flags, packing);
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001524 uint32_t alignment = type_to_packed_alignment(type, flags, packing);
1525 return (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001526}
1527
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001528uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001529{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001530 if (!type.array.empty())
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001531 {
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001532 uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing);
1533
1534 // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size,
1535 // so that it is possible to pack other vectors into the last element.
1536 if (packing_is_hlsl(packing) && type.basetype != SPIRType::Struct)
1537 packed_size -= (4 - type.vecsize) * (type.width / 8);
1538
1539 return packed_size;
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001540 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001541
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001542 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1543 // and is 64-bit.
1544 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1545 {
1546 if (!type.pointer)
1547 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1548
1549 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1550 return 8;
1551 else
1552 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1553 }
1554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001555 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001557 if (type.basetype == SPIRType::Struct)
1558 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001559 uint32_t pad_alignment = 1;
1560
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001561 for (uint32_t i = 0; i < type.member_types.size(); i++)
1562 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001563 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001564 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001565
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001566 uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
1567 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001568
1569 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1570 // GL 4.5 spec, 7.6.2.2.
1571 if (member_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001572 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001573 else
1574 pad_alignment = 1;
1575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001576 size = (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001577 size += type_to_packed_size(member_type, member_flags, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001578 }
1579 }
1580 else
1581 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001582 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1583
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001584 if (packing_is_scalar(packing))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001585 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001586 size = type.vecsize * type.columns * base_alignment;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001587 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001588 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001589 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001590 if (type.columns == 1)
1591 size = type.vecsize * base_alignment;
1592
1593 if (flags.get(DecorationColMajor) && type.columns > 1)
1594 {
1595 if (packing_is_vec4_padded(packing))
1596 size = type.columns * 4 * base_alignment;
1597 else if (type.vecsize == 3)
1598 size = type.columns * 4 * base_alignment;
1599 else
1600 size = type.columns * type.vecsize * base_alignment;
1601 }
1602
1603 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
1604 {
1605 if (packing_is_vec4_padded(packing))
1606 size = type.vecsize * 4 * base_alignment;
1607 else if (type.columns == 3)
1608 size = type.vecsize * 4 * base_alignment;
1609 else
1610 size = type.vecsize * type.columns * base_alignment;
1611 }
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001612
1613 // For matrices in HLSL, the last element has a size which depends on its vector size,
1614 // so that it is possible to pack other vectors into the last element.
1615 if (packing_is_hlsl(packing) && type.columns > 1)
1616 size -= (4 - type.vecsize) * (type.width / 8);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001617 }
1618 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001619
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001620 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001621}
1622
msiglreithd096f5c2017-11-27 16:00:56 +01001623bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001624 uint32_t *failed_validation_index, uint32_t start_offset,
1625 uint32_t end_offset)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001626{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001627 // This is very tricky and error prone, but try to be exhaustive and correct here.
1628 // SPIR-V doesn't directly say if we're using std430 or std140.
1629 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
1630 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
1631 // 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).
1632 //
1633 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
1634 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
1635 //
1636 // The only two differences between std140 and std430 are related to padding alignment/array stride
1637 // in arrays and structs. In std140 they take minimum vec4 alignment.
1638 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001639
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001640 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001641 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001642
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001643 bool is_top_level_block =
1644 has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
1645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001646 for (uint32_t i = 0; i < type.member_types.size(); i++)
1647 {
1648 auto &memb_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001649 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001650
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001651 // Verify alignment rules.
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001652 uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001653
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001654 // This is a rather dirty workaround to deal with some cases of OpSpecConstantOp used as array size, e.g:
1655 // layout(constant_id = 0) const int s = 10;
1656 // const int S = s + 5; // SpecConstantOp
1657 // buffer Foo { int data[S]; }; // <-- Very hard for us to deduce a fixed value here,
1658 // we would need full implementation of compile-time constant folding. :(
1659 // If we are the last member of a struct, there might be cases where the actual size of that member is irrelevant
1660 // for our analysis (e.g. unsized arrays).
1661 // This lets us simply ignore that there are spec constant op sized arrays in our buffers.
1662 // Querying size of this member will fail, so just don't call it unless we have to.
1663 //
1664 // This is likely "best effort" we can support without going into unacceptably complicated workarounds.
1665 bool member_can_be_unsized =
1666 is_top_level_block && size_t(i + 1) == type.member_types.size() && !memb_type.array.empty();
1667
1668 uint32_t packed_size = 0;
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001669 if (!member_can_be_unsized || packing_is_hlsl(packing))
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001670 packed_size = type_to_packed_size(memb_type, member_flags, packing);
1671
1672 // 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 +02001673 if (packing_is_hlsl(packing))
1674 {
1675 // If a member straddles across a vec4 boundary, alignment is actually vec4.
1676 uint32_t begin_word = offset / 16;
1677 uint32_t end_word = (offset + packed_size - 1) / 16;
1678 if (begin_word != end_word)
1679 packed_alignment = max(packed_alignment, 16u);
1680 }
1681
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001682 uint32_t actual_offset = type_struct_member_offset(type, i);
1683 // Field is not in the specified range anymore and we can ignore any further fields.
1684 if (actual_offset >= end_offset)
1685 break;
1686
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001687 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001688 offset = (offset + alignment - 1) & ~(alignment - 1);
1689
1690 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1691 // GL 4.5 spec, 7.6.2.2.
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001692 if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001693 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001694 else
1695 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001696
msiglreithd096f5c2017-11-27 16:00:56 +01001697 // Only care about packing if we are in the given range
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001698 if (actual_offset >= start_offset)
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001699 {
msiglreithd096f5c2017-11-27 16:00:56 +01001700 // We only care about offsets in std140, std430, etc ...
1701 // For EnhancedLayout variants, we have the flexibility to choose our own offsets.
1702 if (!packing_has_flexible_offset(packing))
1703 {
msiglreithd096f5c2017-11-27 16:00:56 +01001704 if (actual_offset != offset) // This cannot be the packing we're looking for.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001705 {
1706 if (failed_validation_index)
1707 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001708 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001709 }
msiglreithd096f5c2017-11-27 16:00:56 +01001710 }
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001711 else if ((actual_offset & (alignment - 1)) != 0)
1712 {
1713 // We still need to verify that alignment rules are observed, even if we have explicit offset.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001714 if (failed_validation_index)
1715 *failed_validation_index = i;
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001716 return false;
1717 }
msiglreithd096f5c2017-11-27 16:00:56 +01001718
1719 // Verify array stride rules.
1720 if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
1721 type_struct_member_array_stride(type, i))
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001722 {
1723 if (failed_validation_index)
1724 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001725 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001726 }
msiglreithd096f5c2017-11-27 16:00:56 +01001727
1728 // Verify that sub-structs also follow packing rules.
1729 // We cannot use enhanced layouts on substructs, so they better be up to spec.
1730 auto substruct_packing = packing_to_substruct_packing(packing);
1731
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001732 if (!memb_type.pointer && !memb_type.member_types.empty() &&
1733 !buffer_is_packing_standard(memb_type, substruct_packing))
1734 {
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001735 if (failed_validation_index)
1736 *failed_validation_index = i;
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001737 return false;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001738 }
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001739 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001740
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001741 // Bump size.
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001742 offset = actual_offset + packed_size;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001743 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001745 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001746}
1747
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001748bool CompilerGLSL::can_use_io_location(StorageClass storage, bool block)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001749{
1750 // Location specifiers are must have in SPIR-V, but they aren't really supported in earlier versions of GLSL.
1751 // Be very explicit here about how to solve the issue.
1752 if ((get_execution_model() != ExecutionModelVertex && storage == StorageClassInput) ||
1753 (get_execution_model() != ExecutionModelFragment && storage == StorageClassOutput))
1754 {
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001755 uint32_t minimum_desktop_version = block ? 440 : 410;
1756 // ARB_enhanced_layouts vs ARB_separate_shader_objects ...
1757
1758 if (!options.es && options.version < minimum_desktop_version && !options.separate_shader_objects)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001759 return false;
1760 else if (options.es && options.version < 310)
1761 return false;
1762 }
1763
1764 if ((get_execution_model() == ExecutionModelVertex && storage == StorageClassInput) ||
1765 (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput))
1766 {
1767 if (options.es && options.version < 300)
1768 return false;
1769 else if (!options.es && options.version < 330)
1770 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001771 }
1772
Hans-Kristian Arntzen1389aa32019-03-19 11:20:25 +01001773 if (storage == StorageClassUniform || storage == StorageClassUniformConstant || storage == StorageClassPushConstant)
Andrei Alexeyev4a430242018-04-07 22:14:35 +03001774 {
1775 if (options.es && options.version < 310)
1776 return false;
1777 else if (!options.es && options.version < 430)
1778 return false;
1779 }
1780
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001781 return true;
1782}
1783
1784string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
1785{
Hans-Kristian Arntzen62d223a2016-09-21 08:20:04 +02001786 // FIXME: Come up with a better solution for when to disable layouts.
1787 // Having layouts depend on extensions as well as which types
1788 // of layouts are used. For now, the simple solution is to just disable
1789 // layouts for legacy versions.
1790 if (is_legacy())
rob42fe8c32016-09-18 13:18:33 +09001791 return "";
1792
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01001793 if (subpass_input_is_framebuffer_fetch(var.self))
1794 return "";
1795
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001796 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001797
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001798 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001799 auto &flags = get_decoration_bitset(var.self);
1800 auto &typeflags = get_decoration_bitset(type.self);
1801
1802 if (flags.get(DecorationPassthroughNV))
1803 attr.push_back("passthrough");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001804
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001805 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
1806 attr.push_back("push_constant");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001807 else if (var.storage == StorageClassShaderRecordBufferKHR)
1808 attr.push_back(ray_tracing_is_khr ? "shaderRecordEXT" : "shaderRecordNV");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001809
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001810 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001811 attr.push_back("row_major");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001812 if (flags.get(DecorationColMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001813 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001814
1815 if (options.vulkan_semantics)
1816 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001817 if (flags.get(DecorationInputAttachmentIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001818 attr.push_back(join("input_attachment_index = ", get_decoration(var.self, DecorationInputAttachmentIndex)));
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001819 }
1820
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001821 bool is_block = has_decoration(type.self, DecorationBlock);
1822 if (flags.get(DecorationLocation) && can_use_io_location(var.storage, is_block))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001823 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001824 Bitset combined_decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001825 for (uint32_t i = 0; i < ir.meta[type.self].members.size(); i++)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001826 combined_decoration.merge_or(combined_decoration_for_member(type, i));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001827
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001828 // If our members have location decorations, we don't need to
1829 // emit location decorations at the top as well (looks weird).
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001830 if (!combined_decoration.get(DecorationLocation))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001831 attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation)));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001832 }
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001833
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02001834 if (get_execution_model() == ExecutionModelFragment && var.storage == StorageClassOutput &&
1835 location_is_non_coherent_framebuffer_fetch(get_decoration(var.self, DecorationLocation)))
1836 {
1837 attr.push_back("noncoherent");
1838 }
1839
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001840 // Transform feedback
1841 bool uses_enhanced_layouts = false;
1842 if (is_block && var.storage == StorageClassOutput)
1843 {
1844 // For blocks, there is a restriction where xfb_stride/xfb_buffer must only be declared on the block itself,
1845 // since all members must match the same xfb_buffer. The only thing we will declare for members of the block
1846 // is the xfb_offset.
1847 uint32_t member_count = uint32_t(type.member_types.size());
1848 bool have_xfb_buffer_stride = false;
1849 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001850 bool have_geom_stream = false;
1851 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001852
1853 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride))
1854 {
1855 have_xfb_buffer_stride = true;
1856 xfb_buffer = get_decoration(var.self, DecorationXfbBuffer);
1857 xfb_stride = get_decoration(var.self, DecorationXfbStride);
1858 }
1859
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001860 if (flags.get(DecorationStream))
1861 {
1862 have_geom_stream = true;
1863 geom_stream = get_decoration(var.self, DecorationStream);
1864 }
1865
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001866 // Verify that none of the members violate our assumption.
1867 for (uint32_t i = 0; i < member_count; i++)
1868 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001869 if (has_member_decoration(type.self, i, DecorationStream))
1870 {
1871 uint32_t member_geom_stream = get_member_decoration(type.self, i, DecorationStream);
1872 if (have_geom_stream && member_geom_stream != geom_stream)
1873 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
1874 have_geom_stream = true;
1875 geom_stream = member_geom_stream;
1876 }
1877
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001878 // Only members with an Offset decoration participate in XFB.
1879 if (!has_member_decoration(type.self, i, DecorationOffset))
1880 continue;
1881 have_any_xfb_offset = true;
1882
1883 if (has_member_decoration(type.self, i, DecorationXfbBuffer))
1884 {
1885 uint32_t buffer_index = get_member_decoration(type.self, i, DecorationXfbBuffer);
1886 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
1887 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
1888 have_xfb_buffer_stride = true;
1889 xfb_buffer = buffer_index;
1890 }
1891
1892 if (has_member_decoration(type.self, i, DecorationXfbStride))
1893 {
1894 uint32_t stride = get_member_decoration(type.self, i, DecorationXfbStride);
1895 if (have_xfb_buffer_stride && stride != xfb_stride)
1896 SPIRV_CROSS_THROW("IO block member XfbStride mismatch.");
1897 have_xfb_buffer_stride = true;
1898 xfb_stride = stride;
1899 }
1900 }
1901
1902 if (have_xfb_buffer_stride && have_any_xfb_offset)
1903 {
1904 attr.push_back(join("xfb_buffer = ", xfb_buffer));
1905 attr.push_back(join("xfb_stride = ", xfb_stride));
1906 uses_enhanced_layouts = true;
1907 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001908
1909 if (have_geom_stream)
1910 {
1911 if (get_execution_model() != ExecutionModelGeometry)
1912 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
1913 if (options.es)
1914 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
1915 if (options.version < 400)
1916 require_extension_internal("GL_ARB_transform_feedback3");
1917 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
1918 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001919 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001920 else if (var.storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001921 {
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01001922 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) && flags.get(DecorationOffset))
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001923 {
1924 // XFB for standalone variables, we can emit all decorations.
1925 attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer)));
1926 attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride)));
1927 attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset)));
1928 uses_enhanced_layouts = true;
1929 }
1930
1931 if (flags.get(DecorationStream))
1932 {
1933 if (get_execution_model() != ExecutionModelGeometry)
1934 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
1935 if (options.es)
1936 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
1937 if (options.version < 400)
1938 require_extension_internal("GL_ARB_transform_feedback3");
1939 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
1940 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001941 }
1942
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001943 // Can only declare Component if we can declare location.
1944 if (flags.get(DecorationComponent) && can_use_io_location(var.storage, is_block))
1945 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001946 uses_enhanced_layouts = true;
1947 attr.push_back(join("component = ", get_decoration(var.self, DecorationComponent)));
1948 }
1949
1950 if (uses_enhanced_layouts)
1951 {
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001952 if (!options.es)
1953 {
1954 if (options.version < 440 && options.version >= 140)
1955 require_extension_internal("GL_ARB_enhanced_layouts");
1956 else if (options.version < 140)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001957 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in targets below GLSL 1.40.");
1958 if (!options.es && options.version < 440)
1959 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001960 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001961 else if (options.es)
1962 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in ESSL.");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001963 }
1964
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001965 if (flags.get(DecorationIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001966 attr.push_back(join("index = ", get_decoration(var.self, DecorationIndex)));
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001967
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001968 // Do not emit set = decoration in regular GLSL output, but
1969 // we need to preserve it in Vulkan GLSL mode.
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001970 if (var.storage != StorageClassPushConstant && var.storage != StorageClassShaderRecordBufferKHR)
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001971 {
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001972 if (flags.get(DecorationDescriptorSet) && options.vulkan_semantics)
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001973 attr.push_back(join("set = ", get_decoration(var.self, DecorationDescriptorSet)));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001974 }
1975
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001976 bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001977 bool ssbo_block = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferKHR ||
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001978 (var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
1979 bool emulated_ubo = var.storage == StorageClassPushConstant && options.emit_push_constant_as_uniform_buffer;
1980 bool ubo_block = var.storage == StorageClassUniform && typeflags.get(DecorationBlock);
1981
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001982 // GL 3.0/GLSL 1.30 is not considered legacy, but it doesn't have UBOs ...
1983 bool can_use_buffer_blocks = (options.es && options.version >= 300) || (!options.es && options.version >= 140);
1984
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001985 // pretend no UBOs when options say so
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001986 if (ubo_block && options.emit_uniform_buffer_as_plain_uniforms)
1987 can_use_buffer_blocks = false;
1988
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001989 bool can_use_binding;
1990 if (options.es)
1991 can_use_binding = options.version >= 310;
1992 else
1993 can_use_binding = options.enable_420pack_extension || (options.version >= 420);
1994
Hans-Kristian Arntzen938040b2018-04-03 16:58:05 +02001995 // Make sure we don't emit binding layout for a classic uniform on GLSL 1.30.
1996 if (!can_use_buffer_blocks && var.storage == StorageClassUniform)
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001997 can_use_binding = false;
1998
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001999 if (var.storage == StorageClassShaderRecordBufferKHR)
Patrick Mours8d64d5e2019-06-05 13:29:01 +02002000 can_use_binding = false;
2001
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002002 if (can_use_binding && flags.get(DecorationBinding))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002003 attr.push_back(join("binding = ", get_decoration(var.self, DecorationBinding)));
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02002004
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002005 if (var.storage != StorageClassOutput && flags.get(DecorationOffset))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002006 attr.push_back(join("offset = ", get_decoration(var.self, DecorationOffset)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002007
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002008 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
2009 // If SPIR-V does not comply with either layout, we cannot really work around it.
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01002010 if (can_use_buffer_blocks && (ubo_block || emulated_ubo))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002011 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002012 attr.push_back(buffer_to_packing_standard(type, false));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002013 }
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02002014 else if (can_use_buffer_blocks && (push_constant_block || ssbo_block))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002015 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002016 attr.push_back(buffer_to_packing_standard(type, true));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002017 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002018
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002019 // For images, the type itself adds a layout qualifer.
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02002020 // Only emit the format for storage images.
2021 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002022 {
2023 const char *fmt = format_to_glsl(type.image.format);
2024 if (fmt)
2025 attr.push_back(fmt);
2026 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002027
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002028 if (attr.empty())
2029 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002030
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002031 string res = "layout(";
2032 res += merge(attr);
2033 res += ") ";
2034 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002035}
2036
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002037string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type, bool support_std430_without_scalar_layout)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002038{
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002039 if (support_std430_without_scalar_layout && buffer_is_packing_standard(type, BufferPackingStd430))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002040 return "std430";
2041 else if (buffer_is_packing_standard(type, BufferPackingStd140))
2042 return "std140";
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002043 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalar))
2044 {
2045 require_extension_internal("GL_EXT_scalar_block_layout");
2046 return "scalar";
2047 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002048 else if (support_std430_without_scalar_layout &&
2049 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002050 {
2051 if (options.es && !options.vulkan_semantics)
2052 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
2053 "not support GL_ARB_enhanced_layouts.");
2054 if (!options.es && !options.vulkan_semantics && options.version < 440)
2055 require_extension_internal("GL_ARB_enhanced_layouts");
2056
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002057 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002058 return "std430";
2059 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002060 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
2061 {
2062 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
2063 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
2064 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
2065 if (options.es && !options.vulkan_semantics)
2066 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
2067 "not support GL_ARB_enhanced_layouts.");
2068 if (!options.es && !options.vulkan_semantics && options.version < 440)
2069 require_extension_internal("GL_ARB_enhanced_layouts");
2070
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002071 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002072 return "std140";
2073 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002074 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalarEnhancedLayout))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002075 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002076 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002077 require_extension_internal("GL_EXT_scalar_block_layout");
2078 return "scalar";
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002079 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002080 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
2081 buffer_is_packing_standard(type, BufferPackingStd430))
2082 {
2083 // UBOs can support std430 with GL_EXT_scalar_block_layout.
2084 require_extension_internal("GL_EXT_scalar_block_layout");
2085 return "std430";
2086 }
2087 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
2088 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
2089 {
2090 // UBOs can support std430 with GL_EXT_scalar_block_layout.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002091 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002092 require_extension_internal("GL_EXT_scalar_block_layout");
2093 return "std430";
2094 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002095 else
2096 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002097 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 +02002098 "layouts. You can try flattening this block to support a more flexible layout.");
2099 }
2100}
2101
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002102void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
2103{
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01002104 if (flattened_buffer_blocks.count(var.self))
2105 emit_buffer_block_flattened(var);
2106 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002107 emit_push_constant_block_vulkan(var);
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01002108 else if (options.emit_push_constant_as_uniform_buffer)
2109 emit_buffer_block_native(var);
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002110 else
2111 emit_push_constant_block_glsl(var);
2112}
2113
2114void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
2115{
2116 emit_buffer_block(var);
2117}
2118
2119void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
2120{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002121 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
2122 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002123
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002124 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002125 flags.clear(DecorationBinding);
2126 flags.clear(DecorationDescriptorSet);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002127
2128#if 0
2129 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002130 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002131 "Remap to location with reflection API first or disable these decorations.");
2132#endif
2133
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002134 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
2135 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002136 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002137 bool block_flag = block_flags.get(DecorationBlock);
2138 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002139
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002140 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002141
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002142 if (block_flag)
2143 block_flags.set(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002144
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002145 emit_uniform(var);
2146 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002147}
2148
2149void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
2150{
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002151 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02002152 bool ubo_block = var.storage == StorageClassUniform && has_decoration(type.self, DecorationBlock);
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002153
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002154 if (flattened_buffer_blocks.count(var.self))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002155 emit_buffer_block_flattened(var);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02002156 else if (is_legacy() || (!options.es && options.version == 130) ||
2157 (ubo_block && options.emit_uniform_buffer_as_plain_uniforms))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002158 emit_buffer_block_legacy(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002159 else
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002160 emit_buffer_block_native(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002161}
2162
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002163void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
2164{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002165 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02002166 bool ssbo = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002167 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002168 if (ssbo)
2169 SPIRV_CROSS_THROW("SSBOs not supported in legacy targets.");
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002170
2171 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
2172 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002173 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002174 bool block_flag = block_flags.get(DecorationBlock);
2175 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002176 emit_struct(type);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002177 if (block_flag)
2178 block_flags.set(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002179 emit_uniform(var);
2180 statement("");
2181}
2182
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002183void CompilerGLSL::emit_buffer_reference_block(uint32_t type_id, bool forward_declaration)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002184{
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002185 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002186 string buffer_name;
2187
2188 if (forward_declaration)
2189 {
2190 // Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
2191 // Allow aliased name since we might be declaring the block twice. Once with buffer reference (forward declared) and one proper declaration.
2192 // The names must match up.
2193 buffer_name = to_name(type.self, false);
2194
2195 // Shaders never use the block by interface name, so we don't
2196 // have to track this other than updating name caches.
2197 // If we have a collision for any reason, just fallback immediately.
2198 if (ir.meta[type.self].decoration.alias.empty() ||
2199 block_ssbo_names.find(buffer_name) != end(block_ssbo_names) ||
2200 resource_names.find(buffer_name) != end(resource_names))
2201 {
2202 buffer_name = join("_", type.self);
2203 }
2204
2205 // Make sure we get something unique for both global name scope and block name scope.
2206 // See GLSL 4.5 spec: section 4.3.9 for details.
2207 add_variable(block_ssbo_names, resource_names, buffer_name);
2208
2209 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2210 // This cannot conflict with anything else, so we're safe now.
2211 // We cannot reuse this fallback name in neither global scope (blocked by block_names) nor block name scope.
2212 if (buffer_name.empty())
2213 buffer_name = join("_", type.self);
2214
2215 block_names.insert(buffer_name);
2216 block_ssbo_names.insert(buffer_name);
Hans-Kristian Arntzene07f0a92020-11-23 16:36:49 +01002217
2218 // Ensure we emit the correct name when emitting non-forward pointer type.
2219 ir.meta[type.self].decoration.alias = buffer_name;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002220 }
2221 else if (type.basetype != SPIRType::Struct)
2222 buffer_name = type_to_glsl(type);
2223 else
2224 buffer_name = to_name(type.self, false);
2225
2226 if (!forward_declaration)
2227 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002228 auto itr = physical_storage_type_to_alignment.find(type_id);
2229 uint32_t alignment = 0;
2230 if (itr != physical_storage_type_to_alignment.end())
2231 alignment = itr->second.alignment;
2232
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002233 if (type.basetype == SPIRType::Struct)
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002234 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002235 SmallVector<std::string> attributes;
2236 attributes.push_back("buffer_reference");
2237 if (alignment)
2238 attributes.push_back(join("buffer_reference_align = ", alignment));
2239 attributes.push_back(buffer_to_packing_standard(type, true));
2240
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002241 auto flags = ir.get_buffer_block_type_flags(type);
2242 string decorations;
2243 if (flags.get(DecorationRestrict))
2244 decorations += " restrict";
2245 if (flags.get(DecorationCoherent))
2246 decorations += " coherent";
2247 if (flags.get(DecorationNonReadable))
2248 decorations += " writeonly";
2249 if (flags.get(DecorationNonWritable))
2250 decorations += " readonly";
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002251
2252 statement("layout(", merge(attributes), ")", decorations, " buffer ", buffer_name);
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002253 }
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002254 else if (alignment)
2255 statement("layout(buffer_reference, buffer_reference_align = ", alignment, ") buffer ", buffer_name);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002256 else
2257 statement("layout(buffer_reference) buffer ", buffer_name);
2258
2259 begin_scope();
2260
2261 if (type.basetype == SPIRType::Struct)
2262 {
2263 type.member_name_cache.clear();
2264
2265 uint32_t i = 0;
2266 for (auto &member : type.member_types)
2267 {
2268 add_member_name(type, i);
2269 emit_struct_member(type, member, i);
2270 i++;
2271 }
2272 }
2273 else
2274 {
2275 auto &pointee_type = get_pointee_type(type);
2276 statement(type_to_glsl(pointee_type), " value", type_to_array_glsl(pointee_type), ";");
2277 }
2278
2279 end_scope_decl();
2280 statement("");
2281 }
2282 else
2283 {
2284 statement("layout(buffer_reference) buffer ", buffer_name, ";");
2285 }
2286}
2287
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002288void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002289{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002290 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002291
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002292 Bitset flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002293 bool ssbo = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferKHR ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002294 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002295 bool is_restrict = ssbo && flags.get(DecorationRestrict);
2296 bool is_writeonly = ssbo && flags.get(DecorationNonReadable);
2297 bool is_readonly = ssbo && flags.get(DecorationNonWritable);
2298 bool is_coherent = ssbo && flags.get(DecorationCoherent);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02002299
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002300 // 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 +02002301 auto buffer_name = to_name(type.self, false);
2302
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002303 auto &block_namespace = ssbo ? block_ssbo_names : block_ubo_names;
2304
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002305 // Shaders never use the block by interface name, so we don't
2306 // have to track this other than updating name caches.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002307 // If we have a collision for any reason, just fallback immediately.
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01002308 if (ir.meta[type.self].decoration.alias.empty() || block_namespace.find(buffer_name) != end(block_namespace) ||
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002309 resource_names.find(buffer_name) != end(resource_names))
2310 {
Hans-Kristian Arntzenaab31072017-09-29 12:16:53 +02002311 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002312 }
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002313
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002314 // Make sure we get something unique for both global name scope and block name scope.
2315 // See GLSL 4.5 spec: section 4.3.9 for details.
2316 add_variable(block_namespace, resource_names, buffer_name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002317
2318 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2319 // This cannot conflict with anything else, so we're safe now.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002320 // 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 +01002321 if (buffer_name.empty())
2322 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2323
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002324 block_names.insert(buffer_name);
2325 block_namespace.insert(buffer_name);
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002326
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002327 // Save for post-reflection later.
2328 declared_block_names[var.self] = buffer_name;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002329
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02002330 statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
2331 is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
2332 buffer_name);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002334 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002335
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002336 type.member_name_cache.clear();
2337
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002338 uint32_t i = 0;
2339 for (auto &member : type.member_types)
2340 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002341 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002342 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002343 i++;
2344 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002345
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +01002346 // var.self can be used as a backup name for the block name,
2347 // so we need to make sure we don't disturb the name here on a recompile.
2348 // It will need to be reset if we have to recompile.
2349 preserve_alias_on_reset(var.self);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002350 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002351 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
2352 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002353}
2354
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002355void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002356{
2357 auto &type = get<SPIRType>(var.basetype);
2358
2359 // Block names should never alias.
2360 auto buffer_name = to_name(type.self, false);
2361 size_t buffer_size = (get_declared_struct_size(type) + 15) / 16;
2362
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002363 SPIRType::BaseType basic_type;
2364 if (get_common_basic_type(type, basic_type))
2365 {
2366 SPIRType tmp;
2367 tmp.basetype = basic_type;
Hans-Kristian Arntzenefba6102017-01-22 08:53:52 +01002368 tmp.vecsize = 4;
2369 if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt)
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002370 SPIRV_CROSS_THROW("Basic types in a flattened UBO must be float, int or uint.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002371
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002372 auto flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002373 statement("uniform ", flags_to_qualifiers_glsl(tmp, flags), type_to_glsl(tmp), " ", buffer_name, "[",
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01002374 buffer_size, "];");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002375 }
2376 else
2377 SPIRV_CROSS_THROW("All basic types in a flattened block must be the same.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002378}
2379
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002380const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002381{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002382 auto &execution = get_entry_point();
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002383
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002384 if (subpass_input_is_framebuffer_fetch(var.self))
2385 return "";
2386
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002387 if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
2388 {
2389 if (is_legacy() && execution.model == ExecutionModelVertex)
2390 return var.storage == StorageClassInput ? "attribute " : "varying ";
2391 else if (is_legacy() && execution.model == ExecutionModelFragment)
2392 return "varying "; // Fragment outputs are renamed so they never hit this case.
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002393 else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
2394 {
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02002395 uint32_t loc = get_decoration(var.self, DecorationLocation);
2396 bool is_inout = location_is_framebuffer_fetch(loc);
2397 if (is_inout)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002398 return "inout ";
2399 else
2400 return "out ";
2401 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002402 else
2403 return var.storage == StorageClassInput ? "in " : "out ";
2404 }
2405 else if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
2406 var.storage == StorageClassPushConstant)
2407 {
2408 return "uniform ";
2409 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002410 else if (var.storage == StorageClassRayPayloadKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002411 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002412 return ray_tracing_is_khr ? "rayPayloadEXT " : "rayPayloadNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002413 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002414 else if (var.storage == StorageClassIncomingRayPayloadKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002415 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002416 return ray_tracing_is_khr ? "rayPayloadInEXT " : "rayPayloadInNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002417 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002418 else if (var.storage == StorageClassHitAttributeKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002419 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002420 return ray_tracing_is_khr ? "hitAttributeEXT " : "hitAttributeNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002421 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002422 else if (var.storage == StorageClassCallableDataKHR)
Patrick Mours78917862019-06-03 15:25:21 +02002423 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002424 return ray_tracing_is_khr ? "callableDataEXT " : "callableDataNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002425 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002426 else if (var.storage == StorageClassIncomingCallableDataKHR)
Patrick Mours78917862019-06-03 15:25:21 +02002427 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002428 return ray_tracing_is_khr ? "callableDataInEXT " : "callableDataInNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002429 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002430
2431 return "";
2432}
2433
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002434void CompilerGLSL::emit_flattened_io_block_member(const std::string &basename, const SPIRType &type, const char *qual,
2435 const SmallVector<uint32_t> &indices)
2436{
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002437 uint32_t member_type_id = type.self;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002438 const SPIRType *member_type = &type;
2439 const SPIRType *parent_type = nullptr;
2440 auto flattened_name = basename;
2441 for (auto &index : indices)
2442 {
2443 flattened_name += "_";
2444 flattened_name += to_member_name(*member_type, index);
2445 parent_type = member_type;
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002446 member_type_id = member_type->member_types[index];
2447 member_type = &get<SPIRType>(member_type_id);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002448 }
2449
2450 assert(member_type->basetype != SPIRType::Struct);
2451
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002452 // We're overriding struct member names, so ensure we do so on the primary type.
2453 if (parent_type->type_alias)
2454 parent_type = &get<SPIRType>(parent_type->type_alias);
2455
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002456 // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row,
2457 // which is not allowed.
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02002458 ParsedIR::sanitize_underscores(flattened_name);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002459
2460 uint32_t last_index = indices.back();
2461
2462 // Pass in the varying qualifier here so it will appear in the correct declaration order.
2463 // Replace member name while emitting it so it encodes both struct name and member name.
2464 auto backup_name = get_member_name(parent_type->self, last_index);
2465 auto member_name = to_member_name(*parent_type, last_index);
2466 set_member_name(parent_type->self, last_index, flattened_name);
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002467 emit_struct_member(*parent_type, member_type_id, last_index, qual);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002468 // Restore member name.
2469 set_member_name(parent_type->self, last_index, member_name);
2470}
2471
2472void CompilerGLSL::emit_flattened_io_block_struct(const std::string &basename, const SPIRType &type, const char *qual,
2473 const SmallVector<uint32_t> &indices)
2474{
2475 auto sub_indices = indices;
2476 sub_indices.push_back(0);
2477
2478 const SPIRType *member_type = &type;
2479 for (auto &index : indices)
2480 member_type = &get<SPIRType>(member_type->member_types[index]);
2481
2482 assert(member_type->basetype == SPIRType::Struct);
2483
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002484 if (!member_type->array.empty())
2485 SPIRV_CROSS_THROW("Cannot flatten array of structs in I/O blocks.");
2486
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002487 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
2488 {
2489 sub_indices.back() = i;
2490 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
2491 emit_flattened_io_block_struct(basename, type, qual, sub_indices);
2492 else
2493 emit_flattened_io_block_member(basename, type, qual, sub_indices);
2494 }
2495}
2496
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002497void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual)
2498{
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002499 auto &var_type = get<SPIRType>(var.basetype);
2500 if (!var_type.array.empty())
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002501 SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings.");
2502
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002503 // Emit flattened types based on the type alias. Normally, we are never supposed to emit
2504 // struct declarations for aliased types.
2505 auto &type = var_type.type_alias ? get<SPIRType>(var_type.type_alias) : var_type;
2506
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002507 auto old_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002508 // Emit the members as if they are part of a block to get all qualifiers.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002509 ir.meta[type.self].decoration.decoration_flags.set(DecorationBlock);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002510
Hans-Kristian Arntzena8df0802017-11-22 11:19:54 +01002511 type.member_name_cache.clear();
2512
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002513 SmallVector<uint32_t> member_indices;
2514 member_indices.push_back(0);
2515 auto basename = to_name(var.self);
2516
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002517 uint32_t i = 0;
2518 for (auto &member : type.member_types)
2519 {
2520 add_member_name(type, i);
2521 auto &membertype = get<SPIRType>(member);
2522
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002523 member_indices.back() = i;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002524 if (membertype.basetype == SPIRType::Struct)
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002525 emit_flattened_io_block_struct(basename, type, qual, member_indices);
2526 else
2527 emit_flattened_io_block_member(basename, type, qual, member_indices);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002528 i++;
2529 }
2530
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002531 ir.meta[type.self].decoration.decoration_flags = old_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002532
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002533 // Treat this variable as fully flattened from now on.
2534 flattened_structs[var.self] = true;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002535}
2536
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002537void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
2538{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002539 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002540
rdbdf5e3732020-11-12 22:59:28 +01002541 if (var.storage == StorageClassInput && type.basetype == SPIRType::Double &&
2542 !options.es && options.version < 410)
2543 {
2544 require_extension_internal("GL_ARB_vertex_attrib_64bit");
2545 }
2546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002547 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002548 bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002549 const char *qual = to_storage_qualifiers_glsl(var);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002550
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002551 if (block)
2552 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002553 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2554 // I/O variables which are struct types.
2555 // To support this, flatten the struct into separate varyings instead.
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002556 if (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2557 (!options.es && options.version < 150))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002558 {
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002559 // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320.
2560 // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150).
2561 emit_flattened_io_block(var, qual);
2562 }
2563 else
2564 {
2565 if (options.es && options.version < 320)
2566 {
2567 // Geometry and tessellation extensions imply this extension.
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01002568 if (!has_extension("GL_EXT_geometry_shader") && !has_extension("GL_EXT_tessellation_shader"))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002569 require_extension_internal("GL_EXT_shader_io_blocks");
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002570 }
2571
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +01002572 // Workaround to make sure we can emit "patch in/out" correctly.
2573 fixup_io_block_patch_qualifiers(var);
2574
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002575 // Block names should never alias.
2576 auto block_name = to_name(type.self, false);
2577
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002578 // The namespace for I/O blocks is separate from other variables in GLSL.
2579 auto &block_namespace = type.storage == StorageClassInput ? block_input_names : block_output_names;
2580
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002581 // Shaders never use the block by interface name, so we don't
2582 // have to track this other than updating name caches.
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002583 if (block_name.empty() || block_namespace.find(block_name) != end(block_namespace))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002584 block_name = get_fallback_name(type.self);
2585 else
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002586 block_namespace.insert(block_name);
2587
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002588 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2589 // This cannot conflict with anything else, so we're safe now.
2590 if (block_name.empty())
2591 block_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2592
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002593 // Instance names cannot alias block names.
2594 resource_names.insert(block_name);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002595
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +01002596 bool is_patch = has_decoration(var.self, DecorationPatch);
2597 statement(layout_for_variable(var), (is_patch ? "patch " : ""), qual, block_name);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002598 begin_scope();
2599
2600 type.member_name_cache.clear();
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002601
2602 uint32_t i = 0;
2603 for (auto &member : type.member_types)
2604 {
2605 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002606 emit_struct_member(type, member, i);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002607 i++;
2608 }
2609
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002610 add_resource_name(var.self);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002611 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
2612 statement("");
2613 }
2614 }
2615 else
2616 {
2617 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2618 // I/O variables which are struct types.
2619 // To support this, flatten the struct into separate varyings instead.
2620 if (type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002621 (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2622 (!options.es && options.version < 150)))
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002623 {
2624 emit_flattened_io_block(var, qual);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002625 }
2626 else
2627 {
2628 add_resource_name(var.self);
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002629
2630 // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays.
2631 // Opt for unsized as it's the more "correct" variant to use.
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +01002632 bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() &&
2633 !has_decoration(var.self, DecorationPatch) &&
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002634 (get_entry_point().model == ExecutionModelTessellationControl ||
2635 get_entry_point().model == ExecutionModelTessellationEvaluation);
2636
2637 uint32_t old_array_size = 0;
2638 bool old_array_size_literal = true;
2639
2640 if (control_point_input_array)
2641 {
2642 swap(type.array.back(), old_array_size);
2643 swap(type.array_size_literal.back(), old_array_size_literal);
2644 }
2645
Chip Davis3bfb2f92018-12-03 02:06:33 -06002646 statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
2647 variable_decl(type, to_name(var.self), var.self), ";");
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002648
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002649 if (control_point_input_array)
2650 {
2651 swap(type.array.back(), old_array_size);
2652 swap(type.array_size_literal.back(), old_array_size_literal);
2653 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002654 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002655 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002656}
2657
2658void CompilerGLSL::emit_uniform(const SPIRVariable &var)
2659{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002660 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002661 if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002662 {
2663 if (!options.es && options.version < 420)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002664 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002665 else if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002666 SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002667 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002668
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002669 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002670 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002671}
2672
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002673string CompilerGLSL::constant_value_macro_name(uint32_t id)
2674{
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002675 return join("SPIRV_CROSS_CONSTANT_ID_", id);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002676}
2677
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002678void CompilerGLSL::emit_specialization_constant_op(const SPIRConstantOp &constant)
2679{
2680 auto &type = get<SPIRType>(constant.basetype);
2681 auto name = to_name(constant.self);
2682 statement("const ", variable_decl(type, name), " = ", constant_op_expression(constant), ";");
2683}
2684
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01002685int CompilerGLSL::get_constant_mapping_to_workgroup_component(const SPIRConstant &c) const
2686{
2687 auto &entry_point = get_entry_point();
2688 int index = -1;
2689
2690 // Need to redirect specialization constants which are used as WorkGroupSize to the builtin,
2691 // since the spec constant declarations are never explicitly declared.
2692 if (entry_point.workgroup_size.constant == 0 && entry_point.flags.get(ExecutionModeLocalSizeId))
2693 {
2694 if (c.self == entry_point.workgroup_size.id_x)
2695 index = 0;
2696 else if (c.self == entry_point.workgroup_size.id_y)
2697 index = 1;
2698 else if (c.self == entry_point.workgroup_size.id_z)
2699 index = 2;
2700 }
2701
2702 return index;
2703}
2704
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002705void CompilerGLSL::emit_constant(const SPIRConstant &constant)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002706{
2707 auto &type = get<SPIRType>(constant.constant_type);
2708 auto name = to_name(constant.self);
2709
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002710 SpecializationConstant wg_x, wg_y, wg_z;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002711 ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002712
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002713 // This specialization constant is implicitly declared by emitting layout() in;
2714 if (constant.self == workgroup_size_id)
2715 return;
2716
2717 // These specialization constants are implicitly declared by emitting layout() in;
2718 // In legacy GLSL, we will still need to emit macros for these, so a layout() in; declaration
2719 // later can use macro overrides for work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002720 bool is_workgroup_size_constant = ConstantID(constant.self) == wg_x.id || ConstantID(constant.self) == wg_y.id ||
2721 ConstantID(constant.self) == wg_z.id;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002722
2723 if (options.vulkan_semantics && is_workgroup_size_constant)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002724 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002725 // Vulkan GLSL does not need to declare workgroup spec constants explicitly, it is handled in layout().
2726 return;
2727 }
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002728 else if (!options.vulkan_semantics && is_workgroup_size_constant &&
2729 !has_decoration(constant.self, DecorationSpecId))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002730 {
2731 // 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 +02002732 return;
2733 }
2734
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002735 // Only scalars have constant IDs.
2736 if (has_decoration(constant.self, DecorationSpecId))
2737 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002738 if (options.vulkan_semantics)
2739 {
2740 statement("layout(constant_id = ", get_decoration(constant.self, DecorationSpecId), ") const ",
2741 variable_decl(type, name), " = ", constant_expression(constant), ";");
2742 }
2743 else
2744 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002745 const string &macro_name = constant.specialization_constant_macro_name;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002746 statement("#ifndef ", macro_name);
2747 statement("#define ", macro_name, " ", constant_expression(constant));
2748 statement("#endif");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002749
2750 // For workgroup size constants, only emit the macros.
2751 if (!is_workgroup_size_constant)
2752 statement("const ", variable_decl(type, name), " = ", macro_name, ";");
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002753 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002754 }
2755 else
2756 {
2757 statement("const ", variable_decl(type, name), " = ", constant_expression(constant), ";");
2758 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002759}
2760
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +02002761void CompilerGLSL::emit_entry_point_declarations()
2762{
2763}
2764
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002765void CompilerGLSL::replace_illegal_names(const unordered_set<string> &keywords)
2766{
2767 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
2768 if (is_hidden_variable(var))
2769 return;
2770
2771 auto *meta = ir.find_meta(var.self);
2772 if (!meta)
2773 return;
2774
2775 auto &m = meta->decoration;
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002776 if (keywords.find(m.alias) != end(keywords))
2777 m.alias = join("_", m.alias);
2778 });
2779
2780 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, const SPIRFunction &func) {
2781 auto *meta = ir.find_meta(func.self);
2782 if (!meta)
2783 return;
2784
2785 auto &m = meta->decoration;
2786 if (keywords.find(m.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002787 m.alias = join("_", m.alias);
2788 });
2789
2790 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
2791 auto *meta = ir.find_meta(type.self);
2792 if (!meta)
2793 return;
2794
2795 auto &m = meta->decoration;
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002796 if (keywords.find(m.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002797 m.alias = join("_", m.alias);
2798
2799 for (auto &memb : meta->members)
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002800 if (keywords.find(memb.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002801 memb.alias = join("_", memb.alias);
2802 });
2803}
2804
Robert Konrad76936562016-08-13 00:14:52 +02002805void CompilerGLSL::replace_illegal_names()
2806{
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002807 // clang-format off
2808 static const unordered_set<string> keywords = {
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002809 "abs", "acos", "acosh", "all", "any", "asin", "asinh", "atan", "atanh",
2810 "atomicAdd", "atomicCompSwap", "atomicCounter", "atomicCounterDecrement", "atomicCounterIncrement",
2811 "atomicExchange", "atomicMax", "atomicMin", "atomicOr", "atomicXor",
2812 "bitCount", "bitfieldExtract", "bitfieldInsert", "bitfieldReverse",
2813 "ceil", "cos", "cosh", "cross", "degrees",
2814 "dFdx", "dFdxCoarse", "dFdxFine",
2815 "dFdy", "dFdyCoarse", "dFdyFine",
2816 "distance", "dot", "EmitStreamVertex", "EmitVertex", "EndPrimitive", "EndStreamPrimitive", "equal", "exp", "exp2",
Chip Davis0d949e12018-11-05 14:55:56 -06002817 "faceforward", "findLSB", "findMSB", "float16BitsToInt16", "float16BitsToUint16", "floatBitsToInt", "floatBitsToUint", "floor", "fma", "fract",
2818 "frexp", "fwidth", "fwidthCoarse", "fwidthFine",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002819 "greaterThan", "greaterThanEqual", "groupMemoryBarrier",
2820 "imageAtomicAdd", "imageAtomicAnd", "imageAtomicCompSwap", "imageAtomicExchange", "imageAtomicMax", "imageAtomicMin", "imageAtomicOr", "imageAtomicXor",
Chip Davis0d949e12018-11-05 14:55:56 -06002821 "imageLoad", "imageSamples", "imageSize", "imageStore", "imulExtended", "int16BitsToFloat16", "intBitsToFloat", "interpolateAtOffset", "interpolateAtCentroid", "interpolateAtSample",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002822 "inverse", "inversesqrt", "isinf", "isnan", "ldexp", "length", "lessThan", "lessThanEqual", "log", "log2",
2823 "matrixCompMult", "max", "memoryBarrier", "memoryBarrierAtomicCounter", "memoryBarrierBuffer", "memoryBarrierImage", "memoryBarrierShared",
2824 "min", "mix", "mod", "modf", "noise", "noise1", "noise2", "noise3", "noise4", "normalize", "not", "notEqual",
Chip Davis0d949e12018-11-05 14:55:56 -06002825 "outerProduct", "packDouble2x32", "packHalf2x16", "packInt2x16", "packInt4x16", "packSnorm2x16", "packSnorm4x8",
2826 "packUint2x16", "packUint4x16", "packUnorm2x16", "packUnorm4x8", "pow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002827 "radians", "reflect", "refract", "round", "roundEven", "sign", "sin", "sinh", "smoothstep", "sqrt", "step",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002828 "tan", "tanh", "texelFetch", "texelFetchOffset", "texture", "textureGather", "textureGatherOffset", "textureGatherOffsets",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002829 "textureGrad", "textureGradOffset", "textureLod", "textureLodOffset", "textureOffset", "textureProj", "textureProjGrad",
2830 "textureProjGradOffset", "textureProjLod", "textureProjLodOffset", "textureProjOffset", "textureQueryLevels", "textureQueryLod", "textureSamples", "textureSize",
Chip Davis0d949e12018-11-05 14:55:56 -06002831 "transpose", "trunc", "uaddCarry", "uint16BitsToFloat16", "uintBitsToFloat", "umulExtended", "unpackDouble2x32", "unpackHalf2x16", "unpackInt2x16", "unpackInt4x16",
2832 "unpackSnorm2x16", "unpackSnorm4x8", "unpackUint2x16", "unpackUint4x16", "unpackUnorm2x16", "unpackUnorm4x8", "usubBorrow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002833
Pascal Muetschardaced6052018-05-04 14:53:32 -07002834 "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002835 "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard",
2836 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4",
2837 "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float",
2838 "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray",
2839 "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
2840 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect",
2841 "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant",
2842 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002843 "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp",
2844 "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump",
2845 "namespace", "noinline", "noperspective", "out", "output", "packed", "partition", "patch", "precise", "precision", "public", "readonly",
2846 "resource", "restrict", "return", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002847 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
2848 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002849 "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "shared", "short", "sizeof", "smooth", "static",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002850 "struct", "subroutine", "superp", "switch", "template", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D",
2851 "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube",
2852 "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
2853 "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002854 "usamplerCubeArray", "using", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile",
2855 "while", "writeonly",
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002856 };
2857 // clang-format on
Bas Zalmstraf537adf2016-10-27 12:51:22 +02002858
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002859 replace_illegal_names(keywords);
Robert Konrad76936562016-08-13 00:14:52 +02002860}
2861
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002862void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
2863{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002864 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002865 uint32_t location = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002866 if (m.decoration_flags.get(DecorationLocation))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002867 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002868
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002869 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
2870 // do the access chain part of this for us.
2871 auto &type = get<SPIRType>(var.basetype);
2872
2873 if (type.array.empty())
2874 {
2875 // Redirect the write to a specific render target in legacy GLSL.
2876 m.alias = join("gl_FragData[", location, "]");
Lubos Lenco52158642016-09-17 15:56:23 +02002877
2878 if (is_legacy_es() && location != 0)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002879 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002880 }
2881 else if (type.array.size() == 1)
2882 {
2883 // If location is non-zero, we probably have to add an offset.
2884 // This gets really tricky since we'd have to inject an offset in the access chain.
2885 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
2886 m.alias = "gl_FragData";
2887 if (location != 0)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002888 SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
2889 "This is unimplemented in SPIRV-Cross.");
Hans-Kristian Arntzen6cc96242016-09-17 18:46:10 +02002890
Lubos Lenco80c39412016-09-17 14:33:16 +02002891 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002892 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002893 }
2894 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002895 SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002896
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002897 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 +01002898}
2899
2900void CompilerGLSL::replace_fragment_outputs()
2901{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002902 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002903 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002904
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +01002905 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer && var.storage == StorageClassOutput)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002906 replace_fragment_output(var);
2907 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002908}
2909
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002910string CompilerGLSL::remap_swizzle(const SPIRType &out_type, uint32_t input_components, const string &expr)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002911{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002912 if (out_type.vecsize == input_components)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002913 return expr;
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01002914 else if (input_components == 1 && !backend.can_swizzle_scalar)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002915 return join(type_to_glsl(out_type), "(", expr, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002916 else
2917 {
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02002918 // FIXME: This will not work with packed expressions.
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002919 auto e = enclose_expression(expr) + ".";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002920 // Just clamp the swizzle index if we have more outputs than inputs.
2921 for (uint32_t c = 0; c < out_type.vecsize; c++)
2922 e += index_to_swizzle(min(c, input_components - 1));
2923 if (backend.swizzle_is_function && out_type.vecsize > 1)
2924 e += "()";
Hans-Kristian Arntzenffad50b2017-12-12 13:01:10 +01002925
2926 remove_duplicate_swizzle(e);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002927 return e;
2928 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002929}
2930
2931void CompilerGLSL::emit_pls()
2932{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002933 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002934 if (execution.model != ExecutionModelFragment)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002935 SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002936
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002937 if (!options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002938 SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002939
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002940 if (options.version < 300)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002941 SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002942
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002943 if (!pls_inputs.empty())
2944 {
2945 statement("__pixel_local_inEXT _PLSIn");
2946 begin_scope();
2947 for (auto &input : pls_inputs)
2948 statement(pls_decl(input), ";");
2949 end_scope_decl();
2950 statement("");
2951 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002952
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002953 if (!pls_outputs.empty())
2954 {
2955 statement("__pixel_local_outEXT _PLSOut");
2956 begin_scope();
2957 for (auto &output : pls_outputs)
2958 statement(pls_decl(output), ";");
2959 end_scope_decl();
2960 statement("");
2961 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002962}
2963
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002964void CompilerGLSL::fixup_image_load_store_access()
2965{
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002966 if (!options.enable_storage_image_qualifier_deduction)
2967 return;
2968
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002969 ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002970 auto &vartype = expression_type(var);
Hans-Kristian Arntzenb691b7d2020-04-03 12:26:13 +02002971 if (vartype.basetype == SPIRType::Image && vartype.image.sampled == 2)
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002972 {
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002973 // Very old glslangValidator and HLSL compilers do not emit required qualifiers here.
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002974 // Solve this by making the image access as restricted as possible and loosen up if we need to.
2975 // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
2976
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01002977 auto &flags = ir.meta[var].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002978 if (!flags.get(DecorationNonWritable) && !flags.get(DecorationNonReadable))
2979 {
2980 flags.set(DecorationNonWritable);
2981 flags.set(DecorationNonReadable);
2982 }
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002983 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002984 });
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002985}
2986
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002987static bool is_block_builtin(BuiltIn builtin)
2988{
2989 return builtin == BuiltInPosition || builtin == BuiltInPointSize || builtin == BuiltInClipDistance ||
2990 builtin == BuiltInCullDistance;
2991}
2992
2993bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage)
2994{
2995 // If the builtin block uses XFB, we need to force explicit redeclaration of the builtin block.
2996
2997 if (storage != StorageClassOutput)
2998 return false;
2999 bool should_force = false;
3000
3001 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
3002 if (should_force)
3003 return;
3004
3005 auto &type = this->get<SPIRType>(var.basetype);
3006 bool block = has_decoration(type.self, DecorationBlock);
3007 if (var.storage == storage && block && is_builtin_variable(var))
3008 {
3009 uint32_t member_count = uint32_t(type.member_types.size());
3010 for (uint32_t i = 0; i < member_count; i++)
3011 {
3012 if (has_member_decoration(type.self, i, DecorationBuiltIn) &&
3013 is_block_builtin(BuiltIn(get_member_decoration(type.self, i, DecorationBuiltIn))) &&
3014 has_member_decoration(type.self, i, DecorationOffset))
3015 {
3016 should_force = true;
3017 }
3018 }
3019 }
3020 else if (var.storage == storage && !block && is_builtin_variable(var))
3021 {
3022 if (is_block_builtin(BuiltIn(get_decoration(type.self, DecorationBuiltIn))) &&
3023 has_decoration(var.self, DecorationOffset))
3024 {
3025 should_force = true;
3026 }
3027 }
3028 });
3029
Hans-Kristian Arntzen3776d892021-01-07 12:14:49 +01003030 // If we're declaring clip/cull planes with control points we need to force block declaration.
3031 if (get_execution_model() == ExecutionModelTessellationControl &&
3032 (clip_distance_count || cull_distance_count))
3033 {
3034 should_force = true;
3035 }
3036
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003037 return should_force;
3038}
3039
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003040void CompilerGLSL::fixup_implicit_builtin_block_names()
3041{
3042 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
3043 auto &type = this->get<SPIRType>(var.basetype);
3044 bool block = has_decoration(type.self, DecorationBlock);
3045 if ((var.storage == StorageClassOutput || var.storage == StorageClassInput) && block &&
3046 is_builtin_variable(var))
3047 {
3048 // Make sure the array has a supported name in the code.
3049 if (var.storage == StorageClassOutput)
3050 set_name(var.self, "gl_out");
3051 else if (var.storage == StorageClassInput)
3052 set_name(var.self, "gl_in");
3053 }
3054 });
3055}
3056
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003057void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
3058{
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003059 Bitset emitted_builtins;
3060 Bitset global_builtins;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003061 const SPIRVariable *block_var = nullptr;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003062 bool emitted_block = false;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003063 bool builtin_array = false;
3064
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003065 // Need to use declared size in the type.
3066 // These variables might have been declared, but not statically used, so we haven't deduced their size yet.
3067 uint32_t cull_distance_size = 0;
3068 uint32_t clip_distance_size = 0;
3069
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003070 bool have_xfb_buffer_stride = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003071 bool have_geom_stream = false;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003072 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003073 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzendfffbb12020-01-27 15:56:47 +01003074 std::unordered_map<uint32_t, uint32_t> builtin_xfb_offsets;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003075
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003076 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003077 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003078 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003079 Bitset builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003080
3081 if (var.storage == storage && block && is_builtin_variable(var))
3082 {
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003083 uint32_t index = 0;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003084 for (auto &m : ir.meta[type.self].members)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003085 {
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003086 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003087 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003088 builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003089 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003090 cull_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003091 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003092 clip_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003093
3094 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationOffset))
3095 {
3096 have_any_xfb_offset = true;
3097 builtin_xfb_offsets[m.builtin_type] = m.offset;
3098 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003099
3100 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
3101 {
3102 uint32_t stream = m.stream;
3103 if (have_geom_stream && geom_stream != stream)
3104 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3105 have_geom_stream = true;
3106 geom_stream = stream;
3107 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003108 }
3109 index++;
3110 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003111
3112 if (storage == StorageClassOutput && has_decoration(var.self, DecorationXfbBuffer) &&
3113 has_decoration(var.self, DecorationXfbStride))
3114 {
3115 uint32_t buffer_index = get_decoration(var.self, DecorationXfbBuffer);
3116 uint32_t stride = get_decoration(var.self, DecorationXfbStride);
3117 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
3118 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3119 if (have_xfb_buffer_stride && stride != xfb_stride)
3120 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3121 have_xfb_buffer_stride = true;
3122 xfb_buffer = buffer_index;
3123 xfb_stride = stride;
3124 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003125
3126 if (storage == StorageClassOutput && has_decoration(var.self, DecorationStream))
3127 {
3128 uint32_t stream = get_decoration(var.self, DecorationStream);
3129 if (have_geom_stream && geom_stream != stream)
3130 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3131 have_geom_stream = true;
3132 geom_stream = stream;
3133 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003134 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003135 else if (var.storage == storage && !block && is_builtin_variable(var))
3136 {
3137 // While we're at it, collect all declared global builtins (HLSL mostly ...).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003138 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003139 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003140 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003141 global_builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003142 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003143 cull_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003144 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003145 clip_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003146
3147 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationXfbStride) &&
3148 m.decoration_flags.get(DecorationXfbBuffer) && m.decoration_flags.get(DecorationOffset))
3149 {
3150 have_any_xfb_offset = true;
3151 builtin_xfb_offsets[m.builtin_type] = m.offset;
3152 uint32_t buffer_index = m.xfb_buffer;
3153 uint32_t stride = m.xfb_stride;
3154 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
3155 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3156 if (have_xfb_buffer_stride && stride != xfb_stride)
3157 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3158 have_xfb_buffer_stride = true;
3159 xfb_buffer = buffer_index;
3160 xfb_stride = stride;
3161 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003162
3163 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
3164 {
3165 uint32_t stream = get_decoration(var.self, DecorationStream);
3166 if (have_geom_stream && geom_stream != stream)
3167 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3168 have_geom_stream = true;
3169 geom_stream = stream;
3170 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003171 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003172 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003173
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003174 if (builtins.empty())
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003175 return;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003176
3177 if (emitted_block)
3178 SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
3179
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003180 emitted_builtins = builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003181 emitted_block = true;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003182 builtin_array = !type.array.empty();
3183 block_var = &var;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003184 });
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003185
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01003186 global_builtins =
3187 Bitset(global_builtins.get_lower() & ((1ull << BuiltInPosition) | (1ull << BuiltInPointSize) |
3188 (1ull << BuiltInClipDistance) | (1ull << BuiltInCullDistance)));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003189
3190 // Try to collect all other declared builtins.
3191 if (!emitted_block)
3192 emitted_builtins = global_builtins;
3193
3194 // Can't declare an empty interface block.
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003195 if (emitted_builtins.empty())
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003196 return;
3197
3198 if (storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003199 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003200 SmallVector<string> attr;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003201 if (have_xfb_buffer_stride && have_any_xfb_offset)
3202 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003203 if (!options.es)
3204 {
3205 if (options.version < 440 && options.version >= 140)
3206 require_extension_internal("GL_ARB_enhanced_layouts");
3207 else if (options.version < 140)
3208 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
3209 if (!options.es && options.version < 440)
3210 require_extension_internal("GL_ARB_enhanced_layouts");
3211 }
3212 else if (options.es)
3213 SPIRV_CROSS_THROW("Need GL_ARB_enhanced_layouts for xfb_stride or xfb_buffer.");
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003214 attr.push_back(join("xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003215 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003216
3217 if (have_geom_stream)
3218 {
3219 if (get_execution_model() != ExecutionModelGeometry)
3220 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
3221 if (options.es)
3222 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
3223 if (options.version < 400)
3224 require_extension_internal("GL_ARB_transform_feedback3");
3225 attr.push_back(join("stream = ", geom_stream));
3226 }
3227
3228 if (!attr.empty())
3229 statement("layout(", merge(attr), ") out gl_PerVertex");
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003230 else
3231 statement("out gl_PerVertex");
3232 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003233 else
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01003234 {
3235 // If we have passthrough, there is no way PerVertex cannot be passthrough.
3236 if (get_entry_point().geometry_passthrough)
3237 statement("layout(passthrough) in gl_PerVertex");
3238 else
3239 statement("in gl_PerVertex");
3240 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003241
3242 begin_scope();
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003243 if (emitted_builtins.get(BuiltInPosition))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003244 {
3245 auto itr = builtin_xfb_offsets.find(BuiltInPosition);
3246 if (itr != end(builtin_xfb_offsets))
3247 statement("layout(xfb_offset = ", itr->second, ") vec4 gl_Position;");
3248 else
3249 statement("vec4 gl_Position;");
3250 }
3251
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003252 if (emitted_builtins.get(BuiltInPointSize))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003253 {
3254 auto itr = builtin_xfb_offsets.find(BuiltInPointSize);
3255 if (itr != end(builtin_xfb_offsets))
3256 statement("layout(xfb_offset = ", itr->second, ") float gl_PointSize;");
3257 else
3258 statement("float gl_PointSize;");
3259 }
3260
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003261 if (emitted_builtins.get(BuiltInClipDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003262 {
3263 auto itr = builtin_xfb_offsets.find(BuiltInClipDistance);
3264 if (itr != end(builtin_xfb_offsets))
3265 statement("layout(xfb_offset = ", itr->second, ") float gl_ClipDistance[", clip_distance_size, "];");
3266 else
3267 statement("float gl_ClipDistance[", clip_distance_size, "];");
3268 }
3269
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003270 if (emitted_builtins.get(BuiltInCullDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003271 {
3272 auto itr = builtin_xfb_offsets.find(BuiltInCullDistance);
3273 if (itr != end(builtin_xfb_offsets))
3274 statement("layout(xfb_offset = ", itr->second, ") float gl_CullDistance[", cull_distance_size, "];");
3275 else
3276 statement("float gl_CullDistance[", cull_distance_size, "];");
3277 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003278
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003279 if (builtin_array)
3280 {
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003281 if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
3282 end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]"));
3283 else
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01003284 end_scope_decl(join(to_name(block_var->self), "[]"));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003285 }
3286 else
3287 end_scope_decl();
3288 statement("");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003289}
3290
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003291void CompilerGLSL::declare_undefined_values()
3292{
3293 bool emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003294 ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003295 auto &type = this->get<SPIRType>(undef.basetype);
3296 // OpUndef can be void for some reason ...
3297 if (type.basetype == SPIRType::Void)
3298 return;
3299
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003300 string initializer;
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003301 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003302 initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
3303
crissdb52e272020-10-08 12:14:52 +02003304 statement(variable_decl(type, to_name(undef.self), undef.self), initializer, ";");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003305 emitted = true;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003306 });
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003307
3308 if (emitted)
3309 statement("");
3310}
3311
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003312bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const
3313{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003314 bool statically_assigned = var.statically_assigned && var.static_expression != ID(0) && var.remapped_variable;
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003315
3316 if (statically_assigned)
3317 {
3318 auto *constant = maybe_get<SPIRConstant>(var.static_expression);
3319 if (constant && constant->is_used_as_lut)
3320 return true;
3321 }
3322
3323 return false;
3324}
3325
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003326void CompilerGLSL::emit_resources()
3327{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02003328 auto &execution = get_entry_point();
3329
Robert Konrad76936562016-08-13 00:14:52 +02003330 replace_illegal_names();
3331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003332 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
3333 // with builtins.
3334 if (execution.model == ExecutionModelFragment && is_legacy())
3335 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003337 // Emit PLS blocks if we have such variables.
3338 if (!pls_inputs.empty() || !pls_outputs.empty())
3339 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003340
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003341 switch (execution.model)
3342 {
3343 case ExecutionModelGeometry:
3344 case ExecutionModelTessellationControl:
3345 case ExecutionModelTessellationEvaluation:
3346 fixup_implicit_builtin_block_names();
3347 break;
3348
3349 default:
3350 break;
3351 }
3352
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003353 // Emit custom gl_PerVertex for SSO compatibility.
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003354 if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment)
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003355 {
3356 switch (execution.model)
3357 {
3358 case ExecutionModelGeometry:
3359 case ExecutionModelTessellationControl:
3360 case ExecutionModelTessellationEvaluation:
3361 emit_declared_builtin_block(StorageClassInput, execution.model);
3362 emit_declared_builtin_block(StorageClassOutput, execution.model);
3363 break;
3364
3365 case ExecutionModelVertex:
3366 emit_declared_builtin_block(StorageClassOutput, execution.model);
3367 break;
3368
3369 default:
3370 break;
3371 }
3372 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003373 else if (should_force_emit_builtin_block(StorageClassOutput))
3374 {
3375 emit_declared_builtin_block(StorageClassOutput, execution.model);
3376 }
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01003377 else if (execution.geometry_passthrough)
3378 {
3379 // Need to declare gl_in with Passthrough.
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003380 // 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 +01003381 emit_declared_builtin_block(StorageClassInput, execution.model);
3382 }
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003383 else
3384 {
3385 // Need to redeclare clip/cull distance with explicit size to use them.
3386 // SPIR-V mandates these builtins have a size declared.
3387 const char *storage = execution.model == ExecutionModelFragment ? "in" : "out";
3388 if (clip_distance_count != 0)
3389 statement(storage, " float gl_ClipDistance[", clip_distance_count, "];");
3390 if (cull_distance_count != 0)
3391 statement(storage, " float gl_CullDistance[", cull_distance_count, "];");
3392 if (clip_distance_count != 0 || cull_distance_count != 0)
3393 statement("");
3394 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003395
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003396 if (position_invariant)
3397 {
3398 statement("invariant gl_Position;");
3399 statement("");
3400 }
3401
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003402 bool emitted = false;
3403
3404 // If emitted Vulkan GLSL,
3405 // emit specialization constants as actual floats,
3406 // spec op expressions will redirect to the constant name.
3407 //
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003408 {
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +02003409 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003410 for (auto &id_ : ir.ids_for_constant_or_type)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003411 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003412 auto &id = ir.ids[id_];
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003413
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003414 if (id.get_type() == TypeConstant)
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003415 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003416 auto &c = id.get<SPIRConstant>();
3417
3418 bool needs_declaration = c.specialization || c.is_used_as_lut;
3419
3420 if (needs_declaration)
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003421 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003422 if (!options.vulkan_semantics && c.specialization)
3423 {
3424 c.specialization_constant_macro_name =
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02003425 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003426 }
3427 emit_constant(c);
3428 emitted = true;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003429 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003430 }
3431 else if (id.get_type() == TypeConstantOp)
3432 {
3433 emit_specialization_constant_op(id.get<SPIRConstantOp>());
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003434 emitted = true;
3435 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003436 else if (id.get_type() == TypeType)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003437 {
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003438 auto *type = &id.get<SPIRType>();
3439
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003440 bool is_natural_struct = type->basetype == SPIRType::Struct && type->array.empty() && !type->pointer &&
3441 (!has_decoration(type->self, DecorationBlock) &&
3442 !has_decoration(type->self, DecorationBufferBlock));
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003443
3444 // Special case, ray payload and hit attribute blocks are not really blocks, just regular structs.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003445 if (type->basetype == SPIRType::Struct && type->pointer &&
3446 has_decoration(type->self, DecorationBlock) &&
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003447 (type->storage == StorageClassRayPayloadKHR || type->storage == StorageClassIncomingRayPayloadKHR ||
3448 type->storage == StorageClassHitAttributeKHR))
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003449 {
3450 type = &get<SPIRType>(type->parent_type);
3451 is_natural_struct = true;
3452 }
3453
3454 if (is_natural_struct)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003455 {
3456 if (emitted)
3457 statement("");
3458 emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003459
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003460 emit_struct(*type);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003461 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003462 }
3463 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003464 }
3465
3466 if (emitted)
3467 statement("");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003468
3469 // If we needed to declare work group size late, check here.
3470 // If the work group size depends on a specialization constant, we need to declare the layout() block
3471 // after constants (and their macros) have been declared.
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01003472 if (execution.model == ExecutionModelGLCompute && !options.vulkan_semantics &&
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01003473 (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003474 {
3475 SpecializationConstant wg_x, wg_y, wg_z;
3476 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
3477
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003478 if ((wg_x.id != ConstantID(0)) || (wg_y.id != ConstantID(0)) || (wg_z.id != ConstantID(0)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003479 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02003480 SmallVector<string> inputs;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003481 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
3482 statement("layout(", merge(inputs), ") in;");
3483 statement("");
3484 }
3485 }
3486
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003487 emitted = false;
3488
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003489 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
3490 {
3491 for (auto type : physical_storage_non_block_pointer_types)
3492 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003493 emit_buffer_reference_block(type, false);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003494 }
3495
3496 // Output buffer reference blocks.
3497 // Do this in two stages, one with forward declaration,
3498 // and one without. Buffer reference blocks can reference themselves
3499 // to support things like linked lists.
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003500 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
3501 if (type.basetype == SPIRType::Struct && type.pointer &&
3502 type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003503 type.storage == StorageClassPhysicalStorageBufferEXT)
3504 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003505 emit_buffer_reference_block(self, true);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003506 }
3507 });
3508
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003509 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
3510 if (type.basetype == SPIRType::Struct &&
3511 type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003512 type.storage == StorageClassPhysicalStorageBufferEXT)
3513 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003514 emit_buffer_reference_block(self, false);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003515 }
3516 });
3517 }
3518
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003519 // Output UBOs and SSBOs
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003520 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003521 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003522
Patrick Mours78917862019-06-03 15:25:21 +02003523 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform ||
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003524 type.storage == StorageClassShaderRecordBufferKHR;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003525 bool has_block_flags = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
3526 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
3527
3528 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
3529 has_block_flags)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003530 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003531 emit_buffer_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003532 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003533 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003534
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003535 // Output push constant blocks
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003536 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003537 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003538 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
3539 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003540 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003541 emit_push_constant_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003542 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003543 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003544
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02003545 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003547 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003548 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003549 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003550
3551 // If we're remapping separate samplers and images, only emit the combined samplers.
3552 if (skip_separate_image_sampler)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003553 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003554 // Sampler buffers are always used without a sampler, and they will also work in regular GL.
3555 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
3556 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
3557 bool separate_sampler = type.basetype == SPIRType::Sampler;
3558 if (!sampler_buffer && (separate_image || separate_sampler))
3559 return;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003560 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003561
3562 if (var.storage != StorageClassFunction && type.pointer &&
Patrick Moursda39a7b2019-02-26 15:43:03 +01003563 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter ||
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003564 type.storage == StorageClassRayPayloadKHR || type.storage == StorageClassIncomingRayPayloadKHR ||
3565 type.storage == StorageClassCallableDataKHR || type.storage == StorageClassIncomingCallableDataKHR ||
3566 type.storage == StorageClassHitAttributeKHR) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003567 !is_hidden_variable(var))
3568 {
3569 emit_uniform(var);
3570 emitted = true;
3571 }
3572 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003574 if (emitted)
3575 statement("");
3576 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003577
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003578 bool emitted_base_instance = false;
3579
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003580 // Output in/out interfaces.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003581 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003582 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003583
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003584 bool is_hidden = is_hidden_variable(var);
3585
3586 // Unused output I/O variables might still be required to implement framebuffer fetch.
3587 if (var.storage == StorageClassOutput && !is_legacy() &&
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02003588 location_is_framebuffer_fetch(get_decoration(var.self, DecorationLocation)) != 0)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003589 {
3590 is_hidden = false;
3591 }
3592
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003593 if (var.storage != StorageClassFunction && type.pointer &&
3594 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003595 interface_variable_exists_in_entry_point(var.self) && !is_hidden)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003596 {
xinhou4b0584c2021-11-26 10:06:42 +08003597 if (options.es && get_execution_model() == ExecutionModelVertex && var.storage == StorageClassInput &&
3598 type.array.size() == 1)
3599 {
3600 SPIRV_CROSS_THROW("OpenGL ES doesn't support array input variables in vertex shader.");
3601 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003602 emit_interface_block(var);
3603 emitted = true;
3604 }
3605 else if (is_builtin_variable(var))
3606 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003607 auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003608 // For gl_InstanceIndex emulation on GLES, the API user needs to
3609 // supply this uniform.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003610
3611 // The draw parameter extension is soft-enabled on GL with some fallbacks.
3612 if (!options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003613 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003614 if (!emitted_base_instance &&
3615 ((options.vertex.support_nonzero_base_instance && builtin == BuiltInInstanceIndex) ||
3616 (builtin == BuiltInBaseInstance)))
3617 {
3618 statement("#ifdef GL_ARB_shader_draw_parameters");
3619 statement("#define SPIRV_Cross_BaseInstance gl_BaseInstanceARB");
3620 statement("#else");
3621 // A crude, but simple workaround which should be good enough for non-indirect draws.
3622 statement("uniform int SPIRV_Cross_BaseInstance;");
3623 statement("#endif");
3624 emitted = true;
3625 emitted_base_instance = true;
3626 }
3627 else if (builtin == BuiltInBaseVertex)
3628 {
3629 statement("#ifdef GL_ARB_shader_draw_parameters");
3630 statement("#define SPIRV_Cross_BaseVertex gl_BaseVertexARB");
3631 statement("#else");
3632 // A crude, but simple workaround which should be good enough for non-indirect draws.
3633 statement("uniform int SPIRV_Cross_BaseVertex;");
3634 statement("#endif");
3635 }
3636 else if (builtin == BuiltInDrawIndex)
3637 {
3638 statement("#ifndef GL_ARB_shader_draw_parameters");
3639 // Cannot really be worked around.
3640 statement("#error GL_ARB_shader_draw_parameters is not supported.");
3641 statement("#endif");
3642 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003643 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003644 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003645 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003646
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003647 // Global variables.
3648 for (auto global : global_variables)
3649 {
3650 auto &var = get<SPIRVariable>(global);
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +01003651 if (is_hidden_variable(var, true))
3652 continue;
3653
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003654 if (var.storage != StorageClassOutput)
3655 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003656 if (!variable_is_lut(var))
3657 {
3658 add_resource_name(var.self);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003659
3660 string initializer;
3661 if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate &&
3662 !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var)))
3663 {
3664 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var)));
3665 }
3666
3667 statement(variable_decl(var), initializer, ";");
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003668 emitted = true;
3669 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003670 }
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +01003671 else if (var.initializer && maybe_get<SPIRConstant>(var.initializer) != nullptr)
3672 {
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003673 emit_output_variable_initializer(var);
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +01003674 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003675 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003676
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003677 if (emitted)
3678 statement("");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003679
3680 declare_undefined_values();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003681}
3682
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003683void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var)
3684{
3685 // If a StorageClassOutput variable has an initializer, we need to initialize it in main().
3686 auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
3687 auto &type = get<SPIRType>(var.basetype);
3688 bool is_patch = has_decoration(var.self, DecorationPatch);
3689 bool is_block = has_decoration(type.self, DecorationBlock);
3690 bool is_control_point = get_execution_model() == ExecutionModelTessellationControl && !is_patch;
3691
3692 if (is_block)
3693 {
3694 uint32_t member_count = uint32_t(type.member_types.size());
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003695 bool type_is_array = type.array.size() == 1;
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003696 uint32_t array_size = 1;
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003697 if (type_is_array)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003698 array_size = to_array_size_literal(type);
3699 uint32_t iteration_count = is_control_point ? 1 : array_size;
3700
3701 // If the initializer is a block, we must initialize each block member one at a time.
3702 for (uint32_t i = 0; i < member_count; i++)
3703 {
3704 // These outputs might not have been properly declared, so don't initialize them in that case.
3705 if (has_member_decoration(type.self, i, DecorationBuiltIn))
3706 {
3707 if (get_member_decoration(type.self, i, DecorationBuiltIn) == BuiltInCullDistance &&
3708 !cull_distance_count)
3709 continue;
3710
3711 if (get_member_decoration(type.self, i, DecorationBuiltIn) == BuiltInClipDistance &&
3712 !clip_distance_count)
3713 continue;
3714 }
3715
3716 // We need to build a per-member array first, essentially transposing from AoS to SoA.
3717 // This code path hits when we have an array of blocks.
3718 string lut_name;
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003719 if (type_is_array)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003720 {
3721 lut_name = join("_", var.self, "_", i, "_init");
3722 uint32_t member_type_id = get<SPIRType>(var.basetype).member_types[i];
3723 auto &member_type = get<SPIRType>(member_type_id);
3724 auto array_type = member_type;
3725 array_type.parent_type = member_type_id;
3726 array_type.array.push_back(array_size);
3727 array_type.array_size_literal.push_back(true);
3728
3729 SmallVector<string> exprs;
3730 exprs.reserve(array_size);
3731 auto &c = get<SPIRConstant>(var.initializer);
3732 for (uint32_t j = 0; j < array_size; j++)
3733 exprs.push_back(to_expression(get<SPIRConstant>(c.subconstants[j]).subconstants[i]));
3734 statement("const ", type_to_glsl(array_type), " ", lut_name, type_to_array_glsl(array_type), " = ",
3735 type_to_glsl_constructor(array_type), "(", merge(exprs, ", "), ");");
3736 }
3737
3738 for (uint32_t j = 0; j < iteration_count; j++)
3739 {
3740 entry_func.fixup_hooks_in.push_back([=, &var]() {
3741 AccessChainMeta meta;
3742 auto &c = this->get<SPIRConstant>(var.initializer);
3743
3744 uint32_t invocation_id = 0;
3745 uint32_t member_index_id = 0;
3746 if (is_control_point)
3747 {
3748 uint32_t ids = ir.increase_bound_by(3);
3749 SPIRType uint_type;
3750 uint_type.basetype = SPIRType::UInt;
3751 uint_type.width = 32;
3752 set<SPIRType>(ids, uint_type);
3753 set<SPIRExpression>(ids + 1, builtin_to_glsl(BuiltInInvocationId, StorageClassInput), ids, true);
3754 set<SPIRConstant>(ids + 2, ids, i, false);
3755 invocation_id = ids + 1;
3756 member_index_id = ids + 2;
3757 }
3758
3759 if (is_patch)
3760 {
3761 statement("if (gl_InvocationID == 0)");
3762 begin_scope();
3763 }
3764
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003765 if (type_is_array && !is_control_point)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003766 {
3767 uint32_t indices[2] = { j, i };
3768 auto chain = access_chain_internal(var.self, indices, 2, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
3769 statement(chain, " = ", lut_name, "[", j, "];");
3770 }
3771 else if (is_control_point)
3772 {
3773 uint32_t indices[2] = { invocation_id, member_index_id };
3774 auto chain = access_chain_internal(var.self, indices, 2, 0, &meta);
3775 statement(chain, " = ", lut_name, "[", builtin_to_glsl(BuiltInInvocationId, StorageClassInput), "];");
3776 }
3777 else
3778 {
3779 auto chain =
3780 access_chain_internal(var.self, &i, 1, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
3781 statement(chain, " = ", to_expression(c.subconstants[i]), ";");
3782 }
3783
3784 if (is_patch)
3785 end_scope();
3786 });
3787 }
3788 }
3789 }
3790 else if (is_control_point)
3791 {
3792 auto lut_name = join("_", var.self, "_init");
3793 statement("const ", type_to_glsl(type), " ", lut_name, type_to_array_glsl(type),
3794 " = ", to_expression(var.initializer), ";");
3795 entry_func.fixup_hooks_in.push_back([&, lut_name]() {
3796 statement(to_expression(var.self), "[gl_InvocationID] = ", lut_name, "[gl_InvocationID];");
3797 });
3798 }
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01003799 else if (has_decoration(var.self, DecorationBuiltIn) &&
3800 BuiltIn(get_decoration(var.self, DecorationBuiltIn)) == BuiltInSampleMask)
3801 {
3802 // We cannot copy the array since gl_SampleMask is unsized in GLSL. Unroll time! <_<
3803 entry_func.fixup_hooks_in.push_back([&] {
3804 auto &c = this->get<SPIRConstant>(var.initializer);
3805 uint32_t num_constants = uint32_t(c.subconstants.size());
3806 for (uint32_t i = 0; i < num_constants; i++)
3807 {
3808 // Don't use to_expression on constant since it might be uint, just fish out the raw int.
3809 statement(to_expression(var.self), "[", i, "] = ",
3810 convert_to_string(this->get<SPIRConstant>(c.subconstants[i]).scalar_i32()), ";");
3811 }
3812 });
3813 }
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003814 else
3815 {
3816 auto lut_name = join("_", var.self, "_init");
3817 statement("const ", type_to_glsl(type), " ", lut_name,
3818 type_to_array_glsl(type), " = ", to_expression(var.initializer), ";");
3819 entry_func.fixup_hooks_in.push_back([&, lut_name, is_patch]() {
3820 if (is_patch)
3821 {
3822 statement("if (gl_InvocationID == 0)");
3823 begin_scope();
3824 }
3825 statement(to_expression(var.self), " = ", lut_name, ";");
3826 if (is_patch)
3827 end_scope();
3828 });
3829 }
3830}
3831
crissdb52e272020-10-08 12:14:52 +02003832void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
3833{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01003834 static const char *workaround_types[] = { "int", "ivec2", "ivec3", "ivec4", "uint", "uvec2", "uvec3", "uvec4",
3835 "float", "vec2", "vec3", "vec4", "double", "dvec2", "dvec3", "dvec4" };
crissdb52e272020-10-08 12:14:52 +02003836
3837 if (!options.vulkan_semantics)
3838 {
3839 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003840 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +02003841
3842 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMask))
3843 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003844 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupMask, result);
crissdb52e272020-10-08 12:14:52 +02003845
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003846 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003847 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003848 const char *name = Supp::get_extension_name(e);
3849 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003850
crissdb52e272020-10-08 12:14:52 +02003851 switch (e)
3852 {
3853 case Supp::NV_shader_thread_group:
3854 statement("#define gl_SubgroupEqMask uvec4(gl_ThreadEqMaskNV, 0u, 0u, 0u)");
3855 statement("#define gl_SubgroupGeMask uvec4(gl_ThreadGeMaskNV, 0u, 0u, 0u)");
3856 statement("#define gl_SubgroupGtMask uvec4(gl_ThreadGtMaskNV, 0u, 0u, 0u)");
3857 statement("#define gl_SubgroupLeMask uvec4(gl_ThreadLeMaskNV, 0u, 0u, 0u)");
3858 statement("#define gl_SubgroupLtMask uvec4(gl_ThreadLtMaskNV, 0u, 0u, 0u)");
3859 break;
3860 case Supp::ARB_shader_ballot:
3861 statement("#define gl_SubgroupEqMask uvec4(unpackUint2x32(gl_SubGroupEqMaskARB), 0u, 0u)");
3862 statement("#define gl_SubgroupGeMask uvec4(unpackUint2x32(gl_SubGroupGeMaskARB), 0u, 0u)");
3863 statement("#define gl_SubgroupGtMask uvec4(unpackUint2x32(gl_SubGroupGtMaskARB), 0u, 0u)");
3864 statement("#define gl_SubgroupLeMask uvec4(unpackUint2x32(gl_SubGroupLeMaskARB), 0u, 0u)");
3865 statement("#define gl_SubgroupLtMask uvec4(unpackUint2x32(gl_SubGroupLtMaskARB), 0u, 0u)");
3866 break;
3867 default:
3868 break;
3869 }
3870 }
3871 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003872 statement("");
crissdb52e272020-10-08 12:14:52 +02003873 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003874
crissdb52e272020-10-08 12:14:52 +02003875 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupSize))
3876 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003877 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupSize, result);
crissdb52e272020-10-08 12:14:52 +02003878
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003879 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003880 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003881 const char *name = Supp::get_extension_name(e);
3882 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003883
crissdb52e272020-10-08 12:14:52 +02003884 switch (e)
3885 {
3886 case Supp::NV_shader_thread_group:
3887 statement("#define gl_SubgroupSize gl_WarpSizeNV");
3888 break;
3889 case Supp::ARB_shader_ballot:
3890 statement("#define gl_SubgroupSize gl_SubGroupSizeARB");
3891 break;
3892 case Supp::AMD_gcn_shader:
3893 statement("#define gl_SubgroupSize uint(gl_SIMDGroupSizeAMD)");
3894 break;
3895 default:
3896 break;
3897 }
3898 }
3899 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003900 statement("");
crissdb52e272020-10-08 12:14:52 +02003901 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003902
crissdb52e272020-10-08 12:14:52 +02003903 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInvocationID))
3904 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003905 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupInvocationID, result);
crissdb52e272020-10-08 12:14:52 +02003906
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003907 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003908 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003909 const char *name = Supp::get_extension_name(e);
3910 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003911
crissdb52e272020-10-08 12:14:52 +02003912 switch (e)
3913 {
3914 case Supp::NV_shader_thread_group:
3915 statement("#define gl_SubgroupInvocationID gl_ThreadInWarpNV");
3916 break;
3917 case Supp::ARB_shader_ballot:
3918 statement("#define gl_SubgroupInvocationID gl_SubGroupInvocationARB");
3919 break;
3920 default:
3921 break;
3922 }
3923 }
3924 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003925 statement("");
crissdb52e272020-10-08 12:14:52 +02003926 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003927
crissdb52e272020-10-08 12:14:52 +02003928 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupID))
3929 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003930 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupID, result);
crissdb52e272020-10-08 12:14:52 +02003931
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003932 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003933 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003934 const char *name = Supp::get_extension_name(e);
3935 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003936
crissdb52e272020-10-08 12:14:52 +02003937 switch (e)
3938 {
3939 case Supp::NV_shader_thread_group:
3940 statement("#define gl_SubgroupID gl_WarpIDNV");
3941 break;
3942 default:
3943 break;
3944 }
3945 }
3946 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003947 statement("");
crissdb52e272020-10-08 12:14:52 +02003948 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003949
crissdb52e272020-10-08 12:14:52 +02003950 if (shader_subgroup_supporter.is_feature_requested(Supp::NumSubgroups))
3951 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003952 auto exts = Supp::get_candidates_for_feature(Supp::NumSubgroups, result);
crissdb52e272020-10-08 12:14:52 +02003953
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003954 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003955 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003956 const char *name = Supp::get_extension_name(e);
3957 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003958
crissdb52e272020-10-08 12:14:52 +02003959 switch (e)
3960 {
3961 case Supp::NV_shader_thread_group:
3962 statement("#define gl_NumSubgroups gl_WarpsPerSMNV");
3963 break;
3964 default:
3965 break;
3966 }
3967 }
3968 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003969 statement("");
crissdb52e272020-10-08 12:14:52 +02003970 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003971
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01003972 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBroadcast_First))
crissdb52e272020-10-08 12:14:52 +02003973 {
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01003974 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBroadcast_First, result);
crissdb52e272020-10-08 12:14:52 +02003975
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003976 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003977 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003978 const char *name = Supp::get_extension_name(e);
3979 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003980
crissdb52e272020-10-08 12:14:52 +02003981 switch (e)
3982 {
3983 case Supp::NV_shader_thread_shuffle:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003984 for (const char *t : workaround_types)
3985 {
3986 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02003987 " value) { return shuffleNV(value, findLSB(ballotThreadNV(true)), gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003988 }
3989 for (const char *t : workaround_types)
3990 {
3991 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02003992 " value, uint id) { return shuffleNV(value, id, gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003993 }
crissdb52e272020-10-08 12:14:52 +02003994 break;
3995 case Supp::ARB_shader_ballot:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003996 for (const char *t : workaround_types)
3997 {
3998 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02003999 " value) { return readFirstInvocationARB(value); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004000 }
4001 for (const char *t : workaround_types)
4002 {
4003 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02004004 " value, uint id) { return readInvocationARB(value, id); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004005 }
crissdb52e272020-10-08 12:14:52 +02004006 break;
4007 default:
4008 break;
4009 }
4010 }
4011 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004012 statement("");
crissdb52e272020-10-08 12:14:52 +02004013 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004014
crissdb52e272020-10-08 12:14:52 +02004015 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotFindLSB_MSB))
4016 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004017 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallotFindLSB_MSB, result);
crissdb52e272020-10-08 12:14:52 +02004018
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004019 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004020 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004021 const char *name = Supp::get_extension_name(e);
4022 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004023
crissdb52e272020-10-08 12:14:52 +02004024 switch (e)
4025 {
4026 case Supp::NV_shader_thread_group:
4027 statement("uint subgroupBallotFindLSB(uvec4 value) { return findLSB(value.x); }");
4028 statement("uint subgroupBallotFindMSB(uvec4 value) { return findMSB(value.x); }");
4029 break;
4030 default:
4031 break;
4032 }
4033 }
4034 statement("#else");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004035 statement("uint subgroupBallotFindLSB(uvec4 value)");
4036 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004037 statement("int firstLive = findLSB(value.x);");
4038 statement("return uint(firstLive != -1 ? firstLive : (findLSB(value.y) + 32));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004039 end_scope();
4040 statement("uint subgroupBallotFindMSB(uvec4 value)");
4041 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004042 statement("int firstLive = findMSB(value.y);");
4043 statement("return uint(firstLive != -1 ? (firstLive + 32) : findMSB(value.x));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004044 end_scope();
crissdb52e272020-10-08 12:14:52 +02004045 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004046 statement("");
crissdb52e272020-10-08 12:14:52 +02004047 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004048
crissdb52e272020-10-08 12:14:52 +02004049 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAll_Any_AllEqualBool))
4050 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004051 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupAll_Any_AllEqualBool, result);
crissdb52e272020-10-08 12:14:52 +02004052
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004053 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004054 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004055 const char *name = Supp::get_extension_name(e);
4056 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004057
crissdb52e272020-10-08 12:14:52 +02004058 switch (e)
4059 {
4060 case Supp::NV_gpu_shader_5:
4061 statement("bool subgroupAll(bool value) { return allThreadsNV(value); }");
4062 statement("bool subgroupAny(bool value) { return anyThreadNV(value); }");
4063 statement("bool subgroupAllEqual(bool value) { return allThreadsEqualNV(value); }");
4064 break;
4065 case Supp::ARB_shader_group_vote:
4066 statement("bool subgroupAll(bool v) { return allInvocationsARB(v); }");
4067 statement("bool subgroupAny(bool v) { return anyInvocationARB(v); }");
4068 statement("bool subgroupAllEqual(bool v) { return allInvocationsEqualARB(v); }");
4069 break;
4070 case Supp::AMD_gcn_shader:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004071 statement("bool subgroupAll(bool value) { return ballotAMD(value) == ballotAMD(true); }");
4072 statement("bool subgroupAny(bool value) { return ballotAMD(value) != 0ull; }");
4073 statement("bool subgroupAllEqual(bool value) { uint64_t b = ballotAMD(value); return b == 0ull || "
4074 "b == ballotAMD(true); }");
crissdb52e272020-10-08 12:14:52 +02004075 break;
4076 default:
4077 break;
4078 }
4079 }
4080 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004081 statement("");
crissdb52e272020-10-08 12:14:52 +02004082 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004083
crissdb52e272020-10-08 12:14:52 +02004084 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAllEqualT))
4085 {
4086 statement("#ifndef GL_KHR_shader_subgroup_vote");
4087 statement(
4088 "#define _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(type) bool subgroupAllEqual(type value) { return "
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004089 "subgroupAllEqual(subgroupBroadcastFirst(value) == value); }");
4090 for (const char *t : workaround_types)
4091 statement("_SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(", t, ")");
crissdb52e272020-10-08 12:14:52 +02004092 statement("#undef _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND");
4093 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004094 statement("");
crissdb52e272020-10-08 12:14:52 +02004095 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004096
crissdb52e272020-10-08 12:14:52 +02004097 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallot))
4098 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004099 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallot, result);
crissdb52e272020-10-08 12:14:52 +02004100
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004101 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004102 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004103 const char *name = Supp::get_extension_name(e);
4104 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004105
crissdb52e272020-10-08 12:14:52 +02004106 switch (e)
4107 {
4108 case Supp::NV_shader_thread_group:
4109 statement("uvec4 subgroupBallot(bool v) { return uvec4(ballotThreadNV(v), 0u, 0u, 0u); }");
4110 break;
4111 case Supp::ARB_shader_ballot:
4112 statement("uvec4 subgroupBallot(bool v) { return uvec4(unpackUint2x32(ballotARB(v)), 0u, 0u); }");
4113 break;
4114 default:
4115 break;
4116 }
4117 }
4118 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004119 statement("");
crissdb52e272020-10-08 12:14:52 +02004120 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004121
crissdb52e272020-10-08 12:14:52 +02004122 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupElect))
4123 {
4124 statement("#ifndef GL_KHR_shader_subgroup_basic");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004125 statement("bool subgroupElect()");
4126 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004127 statement("uvec4 activeMask = subgroupBallot(true);");
4128 statement("uint firstLive = subgroupBallotFindLSB(activeMask);");
4129 statement("return gl_SubgroupInvocationID == firstLive;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004130 end_scope();
crissdb52e272020-10-08 12:14:52 +02004131 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004132 statement("");
crissdb52e272020-10-08 12:14:52 +02004133 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004134
crissdb52e272020-10-08 12:14:52 +02004135 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBarrier))
4136 {
4137 // Extensions we're using in place of GL_KHR_shader_subgroup_basic state
4138 // that subgroup execute in lockstep so this barrier is implicit.
devsh6c5f3942020-10-31 21:46:59 +01004139 // However the GL 4.6 spec also states that `barrier` implies a shared memory barrier,
4140 // and a specific test of optimizing scans by leveraging lock-step invocation execution,
4141 // has shown that a `memoryBarrierShared` is needed in place of a `subgroupBarrier`.
4142 // https://github.com/buildaworldnet/IrrlichtBAW/commit/d8536857991b89a30a6b65d29441e51b64c2c7ad#diff-9f898d27be1ea6fc79b03d9b361e299334c1a347b6e4dc344ee66110c6aa596aR19
crissdb52e272020-10-08 12:14:52 +02004143 statement("#ifndef GL_KHR_shader_subgroup_basic");
devsh6c5f3942020-10-31 21:46:59 +01004144 statement("void subgroupBarrier() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02004145 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004146 statement("");
crissdb52e272020-10-08 12:14:52 +02004147 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004148
crissdb52e272020-10-08 12:14:52 +02004149 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMemBarrier))
4150 {
4151 if (model == spv::ExecutionModelGLCompute)
4152 {
4153 statement("#ifndef GL_KHR_shader_subgroup_basic");
4154 statement("void subgroupMemoryBarrier() { groupMemoryBarrier(); }");
4155 statement("void subgroupMemoryBarrierBuffer() { groupMemoryBarrier(); }");
devsh6c5f3942020-10-31 21:46:59 +01004156 statement("void subgroupMemoryBarrierShared() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02004157 statement("void subgroupMemoryBarrierImage() { groupMemoryBarrier(); }");
4158 statement("#endif");
4159 }
4160 else
4161 {
4162 statement("#ifndef GL_KHR_shader_subgroup_basic");
4163 statement("void subgroupMemoryBarrier() { memoryBarrier(); }");
4164 statement("void subgroupMemoryBarrierBuffer() { memoryBarrierBuffer(); }");
4165 statement("void subgroupMemoryBarrierImage() { memoryBarrierImage(); }");
4166 statement("#endif");
4167 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004168 statement("");
crissdb52e272020-10-08 12:14:52 +02004169 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004170
crissdb52e272020-10-08 12:14:52 +02004171 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInverseBallot_InclBitCount_ExclBitCout))
4172 {
4173 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4174 statement("bool subgroupInverseBallot(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004175 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004176 statement("return any(notEqual(value.xy & gl_SubgroupEqMask.xy, uvec2(0u)));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004177 end_scope();
crissdb52e272020-10-08 12:14:52 +02004178
4179 statement("uint subgroupBallotInclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004180 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004181 statement("uvec2 v = value.xy & gl_SubgroupLeMask.xy;");
4182 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004183 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004184 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004185 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004186 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004187 statement_no_indent("#endif");
4188 end_scope();
crissdb52e272020-10-08 12:14:52 +02004189
4190 statement("uint subgroupBallotExclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004191 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004192 statement("uvec2 v = value.xy & gl_SubgroupLtMask.xy;");
4193 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004194 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004195 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004196 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004197 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004198 statement_no_indent("#endif");
4199 end_scope();
crissdb52e272020-10-08 12:14:52 +02004200 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004201 statement("");
crissdb52e272020-10-08 12:14:52 +02004202 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004203
crissdb52e272020-10-08 12:14:52 +02004204 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitCount))
4205 {
4206 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4207 statement("uint subgroupBallotBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004208 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004209 statement("ivec2 c = bitCount(value.xy);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004210 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004211 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004212 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004213 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004214 statement_no_indent("#endif");
4215 end_scope();
crissdb52e272020-10-08 12:14:52 +02004216 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004217 statement("");
crissdb52e272020-10-08 12:14:52 +02004218 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004219
crissdb52e272020-10-08 12:14:52 +02004220 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitExtract))
4221 {
4222 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4223 statement("bool subgroupBallotBitExtract(uvec4 value, uint index)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004224 begin_scope();
4225 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004226 statement("uint shifted = value.x >> index;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004227 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004228 statement("uint shifted = value[index >> 5u] >> (index & 0x1fu);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004229 statement_no_indent("#endif");
crissdb52e272020-10-08 12:14:52 +02004230 statement("return (shifted & 1u) != 0u;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004231 end_scope();
crissdb52e272020-10-08 12:14:52 +02004232 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004233 statement("");
crissdb52e272020-10-08 12:14:52 +02004234 }
4235 }
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02004236
4237 if (!workaround_ubo_load_overload_types.empty())
4238 {
4239 for (auto &type_id : workaround_ubo_load_overload_types)
4240 {
4241 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004242 statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type),
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02004243 " wrap) { return wrap; }");
4244 }
4245 statement("");
4246 }
rdbbf719942020-11-05 17:09:33 +01004247
4248 if (requires_transpose_2x2)
4249 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004250 statement("mat2 spvTranspose(mat2 m)");
rdbbf719942020-11-05 17:09:33 +01004251 begin_scope();
4252 statement("return mat2(m[0][0], m[1][0], m[0][1], m[1][1]);");
4253 end_scope();
4254 statement("");
4255 }
4256
4257 if (requires_transpose_3x3)
4258 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004259 statement("mat3 spvTranspose(mat3 m)");
rdbbf719942020-11-05 17:09:33 +01004260 begin_scope();
4261 statement("return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]);");
4262 end_scope();
4263 statement("");
4264 }
4265
4266 if (requires_transpose_4x4)
4267 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004268 statement("mat4 spvTranspose(mat4 m)");
rdbbf719942020-11-05 17:09:33 +01004269 begin_scope();
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01004270 statement("return mat4(m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], "
4271 "m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3]);");
rdbbf719942020-11-05 17:09:33 +01004272 end_scope();
4273 statement("");
4274 }
crissdb52e272020-10-08 12:14:52 +02004275}
4276
Bill Hollingsb321b832016-07-06 20:30:47 -04004277// Returns a string representation of the ID, usable as a function arg.
4278// Default is to simply return the expression representation fo the arg ID.
4279// Subclasses may override to modify the return value.
Chip Davis39dce882019-08-02 15:11:19 -05004280string CompilerGLSL::to_func_call_arg(const SPIRFunction::Parameter &, uint32_t id)
Bill Hollingsb321b832016-07-06 20:30:47 -04004281{
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +02004282 // Make sure that we use the name of the original variable, and not the parameter alias.
4283 uint32_t name_id = id;
4284 auto *var = maybe_get<SPIRVariable>(id);
4285 if (var && var->basevariable)
4286 name_id = var->basevariable;
4287 return to_expression(name_id);
Bill Hollingsb321b832016-07-06 20:30:47 -04004288}
4289
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004290void CompilerGLSL::handle_invalid_expression(uint32_t id)
4291{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004292 // We tried to read an invalidated expression.
4293 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
4294 forced_temporaries.insert(id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02004295 force_recompile();
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004296}
4297
Bill Hollingsb332bae2017-03-01 13:07:40 -05004298// Converts the format of the current expression from packed to unpacked,
4299// by wrapping the expression in a constructor of the appropriate type.
4300// GLSL does not support packed formats, so simply return the expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004301// Subclasses that do will override.
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004302string CompilerGLSL::unpack_expression_type(string expr_str, const SPIRType &, uint32_t, bool, bool)
Bill Hollingsb332bae2017-03-01 13:07:40 -05004303{
4304 return expr_str;
4305}
4306
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01004307// Sometimes we proactively enclosed an expression where it turns out we might have not needed it after all.
4308void CompilerGLSL::strip_enclosed_expression(string &expr)
4309{
4310 if (expr.size() < 2 || expr.front() != '(' || expr.back() != ')')
4311 return;
4312
4313 // Have to make sure that our first and last parens actually enclose everything inside it.
4314 uint32_t paren_count = 0;
4315 for (auto &c : expr)
4316 {
4317 if (c == '(')
4318 paren_count++;
4319 else if (c == ')')
4320 {
4321 paren_count--;
4322
4323 // If we hit 0 and this is not the final char, our first and final parens actually don't
4324 // enclose the expression, and we cannot strip, e.g.: (a + b) * (c + d).
4325 if (paren_count == 0 && &c != &expr.back())
4326 return;
4327 }
4328 }
Corentin Walleze88c88c2017-01-18 17:22:19 -05004329 expr.erase(expr.size() - 1, 1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01004330 expr.erase(begin(expr));
4331}
4332
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004333string CompilerGLSL::enclose_expression(const string &expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004334{
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004335 bool need_parens = false;
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004336
4337 // If the expression starts with a unary we need to enclose to deal with cases where we have back-to-back
4338 // unary expressions.
4339 if (!expr.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004340 {
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004341 auto c = expr.front();
Chip Davis3bfb2f92018-12-03 02:06:33 -06004342 if (c == '-' || c == '+' || c == '!' || c == '~' || c == '&' || c == '*')
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004343 need_parens = true;
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004344 }
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004345
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004346 if (!need_parens)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004347 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004348 uint32_t paren_count = 0;
4349 for (auto c : expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004350 {
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02004351 if (c == '(' || c == '[')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004352 paren_count++;
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02004353 else if (c == ')' || c == ']')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004354 {
4355 assert(paren_count);
4356 paren_count--;
4357 }
4358 else if (c == ' ' && paren_count == 0)
4359 {
4360 need_parens = true;
4361 break;
4362 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004363 }
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004364 assert(paren_count == 0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004365 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004366
4367 // If this expression contains any spaces which are not enclosed by parentheses,
4368 // we need to enclose it so we can treat the whole string as an expression.
4369 // This happens when two expressions have been part of a binary op earlier.
4370 if (need_parens)
4371 return join('(', expr, ')');
4372 else
4373 return expr;
4374}
4375
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02004376string CompilerGLSL::dereference_expression(const SPIRType &expr_type, const std::string &expr)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004377{
4378 // If this expression starts with an address-of operator ('&'), then
4379 // just return the part after the operator.
4380 // TODO: Strip parens if unnecessary?
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01004381 if (expr.front() == '&')
Chip Davis3bfb2f92018-12-03 02:06:33 -06004382 return expr.substr(1);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004383 else if (backend.native_pointers)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004384 return join('*', expr);
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02004385 else if (expr_type.storage == StorageClassPhysicalStorageBufferEXT && expr_type.basetype != SPIRType::Struct &&
4386 expr_type.pointer_depth == 1)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004387 {
4388 return join(enclose_expression(expr), ".value");
4389 }
4390 else
4391 return expr;
Chip Davis3bfb2f92018-12-03 02:06:33 -06004392}
4393
4394string CompilerGLSL::address_of_expression(const std::string &expr)
4395{
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004396 if (expr.size() > 3 && expr[0] == '(' && expr[1] == '*' && expr.back() == ')')
4397 {
4398 // If we have an expression which looks like (*foo), taking the address of it is the same as stripping
4399 // the first two and last characters. We might have to enclose the expression.
4400 // This doesn't work for cases like (*foo + 10),
4401 // but this is an r-value expression which we cannot take the address of anyways.
4402 return enclose_expression(expr.substr(2, expr.size() - 3));
4403 }
4404 else if (expr.front() == '*')
4405 {
4406 // If this expression starts with a dereference operator ('*'), then
4407 // just return the part after the operator.
Chip Davis3bfb2f92018-12-03 02:06:33 -06004408 return expr.substr(1);
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004409 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06004410 else
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004411 return join('&', enclose_expression(expr));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004412}
4413
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004414// Just like to_expression except that we enclose the expression inside parentheses if needed.
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004415string CompilerGLSL::to_enclosed_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004416{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004417 return enclose_expression(to_expression(id, register_expression_read));
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004418}
4419
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004420// Used explicitly when we want to read a row-major expression, but without any transpose shenanigans.
4421// need_transpose must be forced to false.
4422string CompilerGLSL::to_unpacked_row_major_matrix_expression(uint32_t id)
4423{
4424 return unpack_expression_type(to_expression(id), expression_type(id),
4425 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
4426 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), true);
4427}
4428
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004429string CompilerGLSL::to_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004430{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02004431 // If we need to transpose, it will also take care of unpacking rules.
4432 auto *e = maybe_get<SPIRExpression>(id);
4433 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004434 bool is_remapped = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4435 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004436
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004437 if (!need_transpose && (is_remapped || is_packed))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004438 {
Hans-Kristian Arntzen1ece67a2019-07-23 17:06:37 +02004439 return unpack_expression_type(to_expression(id, register_expression_read),
4440 get_pointee_type(expression_type_id(id)),
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004441 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004442 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), false);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004443 }
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004444 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004445 return to_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004446}
4447
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004448string CompilerGLSL::to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004449{
Bill Hollings974a0812021-10-21 16:11:33 -04004450 return enclose_expression(to_unpacked_expression(id, register_expression_read));
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004451}
4452
Chip Davis3bfb2f92018-12-03 02:06:33 -06004453string CompilerGLSL::to_dereferenced_expression(uint32_t id, bool register_expression_read)
4454{
4455 auto &type = expression_type(id);
4456 if (type.pointer && should_dereference(id))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004457 return dereference_expression(type, to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004458 else
4459 return to_expression(id, register_expression_read);
4460}
4461
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004462string CompilerGLSL::to_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004463{
4464 auto &type = expression_type(id);
4465 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004466 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004467 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004468 return to_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004469}
4470
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004471string CompilerGLSL::to_enclosed_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004472{
4473 auto &type = expression_type(id);
4474 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004475 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004476 else
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01004477 return to_enclosed_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004478}
4479
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004480string CompilerGLSL::to_extract_component_expression(uint32_t id, uint32_t index)
4481{
4482 auto expr = to_enclosed_expression(id);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004483 if (has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004484 return join(expr, "[", index, "]");
4485 else
4486 return join(expr, ".", index_to_swizzle(index));
4487}
4488
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +01004489string CompilerGLSL::to_extract_constant_composite_expression(uint32_t result_type, const SPIRConstant &c,
4490 const uint32_t *chain, uint32_t length)
4491{
4492 // It is kinda silly if application actually enter this path since they know the constant up front.
4493 // It is useful here to extract the plain constant directly.
4494 SPIRConstant tmp;
4495 tmp.constant_type = result_type;
4496 auto &composite_type = get<SPIRType>(c.constant_type);
4497 assert(composite_type.basetype != SPIRType::Struct && composite_type.array.empty());
4498 assert(!c.specialization);
4499
4500 if (is_matrix(composite_type))
4501 {
4502 if (length == 2)
4503 {
4504 tmp.m.c[0].vecsize = 1;
4505 tmp.m.columns = 1;
4506 tmp.m.c[0].r[0] = c.m.c[chain[0]].r[chain[1]];
4507 }
4508 else
4509 {
4510 assert(length == 1);
4511 tmp.m.c[0].vecsize = composite_type.vecsize;
4512 tmp.m.columns = 1;
4513 tmp.m.c[0] = c.m.c[chain[0]];
4514 }
4515 }
4516 else
4517 {
4518 assert(length == 1);
4519 tmp.m.c[0].vecsize = 1;
4520 tmp.m.columns = 1;
4521 tmp.m.c[0].r[0] = c.m.c[0].r[chain[0]];
4522 }
4523
4524 return constant_expression(tmp);
4525}
4526
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004527string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
4528{
4529 uint32_t size = to_array_size_literal(type);
4530 auto &parent = get<SPIRType>(type.parent_type);
4531 string expr = "{ ";
4532
4533 for (uint32_t i = 0; i < size; i++)
4534 {
4535 auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
4536 if (parent.array.empty())
4537 expr += subexpr;
4538 else
4539 expr += to_rerolled_array_expression(subexpr, parent);
4540
4541 if (i + 1 < size)
4542 expr += ", ";
4543 }
4544
4545 expr += " }";
4546 return expr;
4547}
4548
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004549string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool uses_buffer_offset)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004550{
4551 auto &type = expression_type(id);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004552
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004553 bool reroll_array = !type.array.empty() && (!backend.array_is_value_type ||
4554 (uses_buffer_offset && !backend.buffer_offset_array_is_value_type));
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004555
4556 if (reroll_array)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004557 {
4558 // For this case, we need to "re-roll" an array initializer from a temporary.
4559 // We cannot simply pass the array directly, since it decays to a pointer and it cannot
4560 // participate in a struct initializer. E.g.
4561 // float arr[2] = { 1.0, 2.0 };
4562 // Foo foo = { arr }; must be transformed to
4563 // Foo foo = { { arr[0], arr[1] } };
4564 // The array sizes cannot be deduced from specialization constants since we cannot use any loops.
4565
4566 // We're only triggering one read of the array expression, but this is fine since arrays have to be declared
4567 // as temporaries anyways.
4568 return to_rerolled_array_expression(to_enclosed_expression(id), type);
4569 }
4570 else
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02004571 return to_unpacked_expression(id);
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004572}
4573
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004574string CompilerGLSL::to_non_uniform_aware_expression(uint32_t id)
4575{
4576 string expr = to_expression(id);
4577
4578 if (has_decoration(id, DecorationNonUniform))
4579 convert_non_uniform_expression(expr, id);
4580
4581 return expr;
4582}
4583
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004584string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004585{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004586 auto itr = invalid_expressions.find(id);
4587 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004588 handle_invalid_expression(id);
4589
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004590 if (ir.ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004591 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004592 // We might have a more complex chain of dependencies.
4593 // A possible scenario is that we
4594 //
4595 // %1 = OpLoad
4596 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
4597 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
4598 // 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.
4599 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
4600 //
4601 // 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,
4602 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004603 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004604 for (uint32_t dep : expr.expression_dependencies)
4605 if (invalid_expressions.find(dep) != end(invalid_expressions))
4606 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004607 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004608
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004609 if (register_expression_read)
4610 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004611
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004612 switch (ir.ids[id].get_type())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004613 {
4614 case TypeExpression:
4615 {
4616 auto &e = get<SPIRExpression>(id);
4617 if (e.base_expression)
Hans-Kristian Arntzenea781e62016-12-06 17:19:34 +01004618 return to_enclosed_expression(e.base_expression) + e.expression;
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02004619 else if (e.need_transpose)
Bill Hollings607b0d62018-02-11 16:52:57 -05004620 {
Hans-Kristian Arntzen2172b192019-07-22 16:27:47 +02004621 // This should not be reached for access chains, since we always deal explicitly with transpose state
4622 // when consuming an access chain expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004623 uint32_t physical_type_id = get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4624 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02004625 return convert_row_major_matrix(e.expression, get<SPIRType>(e.expression_type), physical_type_id,
4626 is_packed);
Bill Hollings607b0d62018-02-11 16:52:57 -05004627 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004628 else if (flattened_structs.count(id))
4629 {
4630 return load_flattened_struct(e.expression, get<SPIRType>(e.expression_type));
4631 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004632 else
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004633 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02004634 if (is_forcing_recompilation())
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004635 {
4636 // During first compilation phase, certain expression patterns can trigger exponential growth of memory.
4637 // Avoid this by returning dummy expressions during this phase.
4638 // Do not use empty expressions here, because those are sentinels for other cases.
4639 return "_";
4640 }
4641 else
4642 return e.expression;
4643 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004644 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004646 case TypeConstant:
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004647 {
4648 auto &c = get<SPIRConstant>(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004649 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02004650
4651 // WorkGroupSize may be a constant.
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004652 if (has_decoration(c.self, DecorationBuiltIn))
4653 return builtin_to_glsl(BuiltIn(get_decoration(c.self, DecorationBuiltIn)), StorageClassGeneric);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004654 else if (c.specialization)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004655 {
4656 if (backend.workgroup_size_is_hidden)
4657 {
4658 int wg_index = get_constant_mapping_to_workgroup_component(c);
4659 if (wg_index >= 0)
4660 {
4661 auto wg_size = join(builtin_to_glsl(BuiltInWorkgroupSize, StorageClassInput), vector_swizzle(1, wg_index));
4662 if (type.basetype != SPIRType::UInt)
4663 wg_size = bitcast_expression(type, SPIRType::UInt, wg_size);
4664 return wg_size;
4665 }
4666 }
4667
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004668 return to_name(id);
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004669 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02004670 else if (c.is_used_as_lut)
4671 return to_name(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004672 else if (type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
4673 return to_name(id);
4674 else if (!type.array.empty() && !backend.can_declare_arrays_inline)
4675 return to_name(id);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004676 else
4677 return constant_expression(c);
4678 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004679
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004680 case TypeConstantOp:
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01004681 return to_name(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004683 case TypeVariable:
4684 {
4685 auto &var = get<SPIRVariable>(id);
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01004686 // If we try to use a loop variable before the loop header, we have to redirect it to the static expression,
4687 // the variable has not been declared yet.
4688 if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004689 return to_expression(var.static_expression);
4690 else if (var.deferred_declaration)
4691 {
4692 var.deferred_declaration = false;
4693 return variable_decl(var);
4694 }
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004695 else if (flattened_structs.count(id))
4696 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004697 return load_flattened_struct(to_name(id), get<SPIRType>(var.basetype));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004698 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004699 else
4700 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004701 auto &dec = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004702 if (dec.builtin)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004703 return builtin_to_glsl(dec.builtin_type, var.storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004704 else
4705 return to_name(id);
4706 }
4707 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004708
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02004709 case TypeCombinedImageSampler:
4710 // This type should never be taken the expression of directly.
4711 // The intention is that texture sampling functions will extract the image and samplers
4712 // separately and take their expressions as needed.
4713 // GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
4714 // expression ala sampler2D(texture, sampler).
4715 SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
4716
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004717 case TypeAccessChain:
4718 // We cannot express this type. They only have meaning in other OpAccessChains, OpStore or OpLoad.
4719 SPIRV_CROSS_THROW("Access chains have no default expression representation.");
4720
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004721 default:
4722 return to_name(id);
4723 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004724}
4725
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004726string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
4727{
4728 auto &type = get<SPIRType>(cop.basetype);
4729 bool binary = false;
4730 bool unary = false;
4731 string op;
4732
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004733 if (is_legacy() && is_unsigned_opcode(cop.opcode))
4734 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
4735
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004736 // TODO: Find a clean way to reuse emit_instruction.
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004737 switch (cop.opcode)
4738 {
4739 case OpSConvert:
4740 case OpUConvert:
4741 case OpFConvert:
4742 op = type_to_glsl_constructor(type);
4743 break;
4744
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004745#define GLSL_BOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004746 case Op##opname: \
4747 binary = true; \
4748 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004749 break
4750
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004751#define GLSL_UOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004752 case Op##opname: \
4753 unary = true; \
4754 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004755 break
4756
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004757 GLSL_UOP(SNegate, "-");
4758 GLSL_UOP(Not, "~");
4759 GLSL_BOP(IAdd, "+");
4760 GLSL_BOP(ISub, "-");
4761 GLSL_BOP(IMul, "*");
4762 GLSL_BOP(SDiv, "/");
4763 GLSL_BOP(UDiv, "/");
4764 GLSL_BOP(UMod, "%");
4765 GLSL_BOP(SMod, "%");
4766 GLSL_BOP(ShiftRightLogical, ">>");
4767 GLSL_BOP(ShiftRightArithmetic, ">>");
4768 GLSL_BOP(ShiftLeftLogical, "<<");
4769 GLSL_BOP(BitwiseOr, "|");
4770 GLSL_BOP(BitwiseXor, "^");
4771 GLSL_BOP(BitwiseAnd, "&");
4772 GLSL_BOP(LogicalOr, "||");
4773 GLSL_BOP(LogicalAnd, "&&");
4774 GLSL_UOP(LogicalNot, "!");
4775 GLSL_BOP(LogicalEqual, "==");
4776 GLSL_BOP(LogicalNotEqual, "!=");
4777 GLSL_BOP(IEqual, "==");
4778 GLSL_BOP(INotEqual, "!=");
4779 GLSL_BOP(ULessThan, "<");
4780 GLSL_BOP(SLessThan, "<");
4781 GLSL_BOP(ULessThanEqual, "<=");
4782 GLSL_BOP(SLessThanEqual, "<=");
4783 GLSL_BOP(UGreaterThan, ">");
4784 GLSL_BOP(SGreaterThan, ">");
4785 GLSL_BOP(UGreaterThanEqual, ">=");
4786 GLSL_BOP(SGreaterThanEqual, ">=");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004787
Bill Hollings5fb1ca42021-09-03 18:20:49 -04004788 case OpSRem:
4789 {
4790 uint32_t op0 = cop.arguments[0];
4791 uint32_t op1 = cop.arguments[1];
4792 return join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
4793 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
4794 }
4795
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004796 case OpSelect:
4797 {
4798 if (cop.arguments.size() < 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004799 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004800
4801 // This one is pretty annoying. It's triggered from
4802 // uint(bool), int(bool) from spec constants.
4803 // In order to preserve its compile-time constness in Vulkan GLSL,
4804 // we need to reduce the OpSelect expression back to this simplified model.
4805 // If we cannot, fail.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004806 if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004807 {
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004808 // Implement as a simple cast down below.
4809 }
4810 else
4811 {
4812 // Implement a ternary and pray the compiler understands it :)
4813 return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004814 }
4815 break;
4816 }
4817
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02004818 case OpVectorShuffle:
4819 {
4820 string expr = type_to_glsl_constructor(type);
4821 expr += "(";
4822
4823 uint32_t left_components = expression_type(cop.arguments[0]).vecsize;
4824 string left_arg = to_enclosed_expression(cop.arguments[0]);
4825 string right_arg = to_enclosed_expression(cop.arguments[1]);
4826
4827 for (uint32_t i = 2; i < uint32_t(cop.arguments.size()); i++)
4828 {
4829 uint32_t index = cop.arguments[i];
4830 if (index >= left_components)
4831 expr += right_arg + "." + "xyzw"[index - left_components];
4832 else
4833 expr += left_arg + "." + "xyzw"[index];
4834
4835 if (i + 1 < uint32_t(cop.arguments.size()))
4836 expr += ", ";
4837 }
4838
4839 expr += ")";
4840 return expr;
4841 }
4842
4843 case OpCompositeExtract:
4844 {
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01004845 auto expr = access_chain_internal(cop.arguments[0], &cop.arguments[1], uint32_t(cop.arguments.size() - 1),
4846 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02004847 return expr;
4848 }
4849
4850 case OpCompositeInsert:
4851 SPIRV_CROSS_THROW("OpCompositeInsert spec constant op is not supported.");
4852
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004853 default:
4854 // Some opcodes are unimplemented here, these are currently not possible to test from glslang.
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004855 SPIRV_CROSS_THROW("Unimplemented spec constant op.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004856 }
4857
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004858 uint32_t bit_width = 0;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004859 if (unary || binary || cop.opcode == OpSConvert || cop.opcode == OpUConvert)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004860 bit_width = expression_type(cop.arguments[0]).width;
4861
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004862 SPIRType::BaseType input_type;
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004863 bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004864
4865 switch (cop.opcode)
4866 {
4867 case OpIEqual:
4868 case OpINotEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004869 input_type = to_signed_basetype(bit_width);
4870 break;
4871
4872 case OpSLessThan:
4873 case OpSLessThanEqual:
4874 case OpSGreaterThan:
4875 case OpSGreaterThanEqual:
4876 case OpSMod:
4877 case OpSDiv:
4878 case OpShiftRightArithmetic:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004879 case OpSConvert:
4880 case OpSNegate:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004881 input_type = to_signed_basetype(bit_width);
4882 break;
4883
4884 case OpULessThan:
4885 case OpULessThanEqual:
4886 case OpUGreaterThan:
4887 case OpUGreaterThanEqual:
4888 case OpUMod:
4889 case OpUDiv:
4890 case OpShiftRightLogical:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004891 case OpUConvert:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004892 input_type = to_unsigned_basetype(bit_width);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004893 break;
4894
4895 default:
4896 input_type = type.basetype;
4897 break;
4898 }
4899
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004900#undef GLSL_BOP
4901#undef GLSL_UOP
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004902 if (binary)
4903 {
4904 if (cop.arguments.size() < 2)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004905 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004906
4907 string cast_op0;
4908 string cast_op1;
4909 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, cop.arguments[0],
4910 cop.arguments[1], skip_cast_if_equal_type);
4911
4912 if (type.basetype != input_type && type.basetype != SPIRType::Boolean)
4913 {
4914 expected_type.basetype = input_type;
4915 auto expr = bitcast_glsl_op(type, expected_type);
4916 expr += '(';
4917 expr += join(cast_op0, " ", op, " ", cast_op1);
4918 expr += ')';
4919 return expr;
4920 }
4921 else
4922 return join("(", cast_op0, " ", op, " ", cast_op1, ")");
4923 }
4924 else if (unary)
4925 {
4926 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004927 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004928
4929 // Auto-bitcast to result type as needed.
4930 // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
4931 return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")");
4932 }
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004933 else if (cop.opcode == OpSConvert || cop.opcode == OpUConvert)
4934 {
4935 if (cop.arguments.size() < 1)
4936 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
4937
4938 auto &arg_type = expression_type(cop.arguments[0]);
4939 if (arg_type.width < type.width && input_type != arg_type.basetype)
4940 {
4941 auto expected = arg_type;
4942 expected.basetype = input_type;
4943 return join(op, "(", bitcast_glsl(expected, cop.arguments[0]), ")");
4944 }
4945 else
4946 return join(op, "(", to_expression(cop.arguments[0]), ")");
4947 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004948 else
4949 {
4950 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004951 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004952 return join(op, "(", to_expression(cop.arguments[0]), ")");
4953 }
4954}
4955
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004956string CompilerGLSL::constant_expression(const SPIRConstant &c)
4957{
Chip Davis3bfb2f92018-12-03 02:06:33 -06004958 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004959
Chip Davis3bfb2f92018-12-03 02:06:33 -06004960 if (type.pointer)
4961 {
4962 return backend.null_pointer_literal;
4963 }
4964 else if (!c.subconstants.empty())
4965 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004966 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004967 string res;
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004968
Lukas Hermanns50ac6862019-09-18 14:03:54 -04004969 // Allow Metal to use the array<T> template to make arrays a value type
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004970 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen57a15df2018-09-10 10:08:02 +02004971 if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004972 type.array.empty())
4973 {
4974 res = type_to_glsl_constructor(type) + "{ ";
4975 }
Hans-Kristian Arntzenc2655ab2020-03-19 14:21:42 +01004976 else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
4977 !type.array.empty())
Mark Satterthwaited50659a2019-08-13 18:18:48 -04004978 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02004979 res = type_to_glsl_constructor(type) + "({ ";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004980 needs_trailing_tracket = true;
Mark Satterthwaited50659a2019-08-13 18:18:48 -04004981 }
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004982 else if (backend.use_initializer_list)
4983 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004984 res = "{ ";
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004985 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004986 else
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004987 {
4988 res = type_to_glsl_constructor(type) + "(";
4989 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004990
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004991 for (auto &elem : c.subconstants)
4992 {
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004993 auto &subc = get<SPIRConstant>(elem);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004994 if (subc.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004995 res += to_name(elem);
4996 else
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02004997 res += constant_expression(subc);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004998
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004999 if (&elem != &c.subconstants.back())
5000 res += ", ";
5001 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005002
5003 res += backend.use_initializer_list ? " }" : ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005004 if (needs_trailing_tracket)
Mark Satterthwaited50659a2019-08-13 18:18:48 -04005005 res += ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005006
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005007 return res;
5008 }
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04005009 else if (type.basetype == SPIRType::Struct && type.member_types.size() == 0)
5010 {
5011 // Metal tessellation likes empty structs which are then constant expressions.
Hans-Kristian Arntzen3b5c4c72019-10-24 17:05:55 +02005012 if (backend.supports_empty_struct)
5013 return "{ }";
5014 else if (backend.use_typed_initializer_list)
5015 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "{ 0 }");
5016 else if (backend.use_initializer_list)
5017 return "{ 0 }";
5018 else
5019 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "(0)");
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04005020 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005021 else if (c.columns() == 1)
5022 {
5023 return constant_expression_vector(c, 0);
5024 }
5025 else
5026 {
5027 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
5028 for (uint32_t col = 0; col < c.columns(); col++)
5029 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005030 if (c.specialization_constant_id(col) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005031 res += to_name(c.specialization_constant_id(col));
5032 else
5033 res += constant_expression_vector(c, col);
5034
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005035 if (col + 1 < c.columns())
5036 res += ", ";
5037 }
5038 res += ")";
5039 return res;
5040 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005041}
5042
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005043#ifdef _MSC_VER
5044// sprintf warning.
5045// We cannot rely on snprintf existing because, ..., MSVC.
5046#pragma warning(push)
5047#pragma warning(disable : 4996)
5048#endif
5049
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005050string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5051{
5052 string res;
5053 float float_value = c.scalar_f16(col, row);
5054
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005055 // There is no literal "hf" in GL_NV_gpu_shader5, so to avoid lots
5056 // of complicated workarounds, just value-cast to the half type always.
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005057 if (std::isnan(float_value) || std::isinf(float_value))
5058 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005059 SPIRType type;
5060 type.basetype = SPIRType::Half;
5061 type.vecsize = 1;
5062 type.columns = 1;
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005063
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005064 if (float_value == numeric_limits<float>::infinity())
5065 res = join(type_to_glsl(type), "(1.0 / 0.0)");
5066 else if (float_value == -numeric_limits<float>::infinity())
5067 res = join(type_to_glsl(type), "(-1.0 / 0.0)");
5068 else if (std::isnan(float_value))
5069 res = join(type_to_glsl(type), "(0.0 / 0.0)");
5070 else
5071 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005072 }
5073 else
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005074 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005075 SPIRType type;
5076 type.basetype = SPIRType::Half;
5077 type.vecsize = 1;
5078 type.columns = 1;
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005079 res = join(type_to_glsl(type), "(", convert_to_string(float_value, current_locale_radix_character), ")");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005080 }
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005081
5082 return res;
5083}
5084
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005085string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5086{
5087 string res;
5088 float float_value = c.scalar_f32(col, row);
5089
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005090 if (std::isnan(float_value) || std::isinf(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005091 {
5092 // Use special representation.
5093 if (!is_legacy())
5094 {
5095 SPIRType out_type;
5096 SPIRType in_type;
5097 out_type.basetype = SPIRType::Float;
5098 in_type.basetype = SPIRType::UInt;
5099 out_type.vecsize = 1;
5100 in_type.vecsize = 1;
5101 out_type.width = 32;
5102 in_type.width = 32;
5103
5104 char print_buffer[32];
5105 sprintf(print_buffer, "0x%xu", c.scalar(col, row));
xndcn02fb8f22021-05-26 22:43:26 +08005106
5107 const char *comment = "inf";
5108 if (float_value == -numeric_limits<float>::infinity())
5109 comment = "-inf";
5110 else if (std::isnan(float_value))
5111 comment = "nan";
5112 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005113 }
5114 else
5115 {
5116 if (float_value == numeric_limits<float>::infinity())
5117 {
5118 if (backend.float_literal_suffix)
5119 res = "(1.0f / 0.0f)";
5120 else
5121 res = "(1.0 / 0.0)";
5122 }
5123 else if (float_value == -numeric_limits<float>::infinity())
5124 {
5125 if (backend.float_literal_suffix)
5126 res = "(-1.0f / 0.0f)";
5127 else
5128 res = "(-1.0 / 0.0)";
5129 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005130 else if (std::isnan(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005131 {
5132 if (backend.float_literal_suffix)
5133 res = "(0.0f / 0.0f)";
5134 else
5135 res = "(0.0 / 0.0)";
5136 }
5137 else
5138 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
5139 }
5140 }
5141 else
5142 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005143 res = convert_to_string(float_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005144 if (backend.float_literal_suffix)
5145 res += "f";
5146 }
5147
5148 return res;
5149}
5150
5151std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5152{
5153 string res;
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005154 double double_value = c.scalar_f64(col, row);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005155
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005156 if (std::isnan(double_value) || std::isinf(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005157 {
5158 // Use special representation.
5159 if (!is_legacy())
5160 {
5161 SPIRType out_type;
5162 SPIRType in_type;
5163 out_type.basetype = SPIRType::Double;
5164 in_type.basetype = SPIRType::UInt64;
5165 out_type.vecsize = 1;
5166 in_type.vecsize = 1;
5167 out_type.width = 64;
5168 in_type.width = 64;
5169
5170 uint64_t u64_value = c.scalar_u64(col, row);
5171
5172 if (options.es)
5173 SPIRV_CROSS_THROW("64-bit integers/float not supported in ES profile.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005174 require_extension_internal("GL_ARB_gpu_shader_int64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005175
5176 char print_buffer[64];
5177 sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
5178 backend.long_long_literal_suffix ? "ull" : "ul");
xndcn02fb8f22021-05-26 22:43:26 +08005179
5180 const char *comment = "inf";
5181 if (double_value == -numeric_limits<double>::infinity())
5182 comment = "-inf";
5183 else if (std::isnan(double_value))
5184 comment = "nan";
5185 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005186 }
5187 else
5188 {
5189 if (options.es)
5190 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
5191 if (options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005192 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005193
5194 if (double_value == numeric_limits<double>::infinity())
5195 {
5196 if (backend.double_literal_suffix)
5197 res = "(1.0lf / 0.0lf)";
5198 else
5199 res = "(1.0 / 0.0)";
5200 }
5201 else if (double_value == -numeric_limits<double>::infinity())
5202 {
5203 if (backend.double_literal_suffix)
5204 res = "(-1.0lf / 0.0lf)";
5205 else
5206 res = "(-1.0 / 0.0)";
5207 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005208 else if (std::isnan(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005209 {
5210 if (backend.double_literal_suffix)
5211 res = "(0.0lf / 0.0lf)";
5212 else
5213 res = "(0.0 / 0.0)";
5214 }
5215 else
5216 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
5217 }
5218 }
5219 else
5220 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005221 res = convert_to_string(double_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005222 if (backend.double_literal_suffix)
5223 res += "lf";
5224 }
5225
5226 return res;
5227}
5228
5229#ifdef _MSC_VER
5230#pragma warning(pop)
5231#endif
5232
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005233string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
5234{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005235 auto type = get<SPIRType>(c.constant_type);
5236 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005237
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005238 auto scalar_type = type;
5239 scalar_type.vecsize = 1;
5240
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005241 string res;
Robert Konradea24ee82016-09-23 18:57:18 +02005242 bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005243 bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005244
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005245 if (!type_is_floating_point(type))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005246 {
5247 // Cannot swizzle literal integers as a special case.
5248 swizzle_splat = false;
5249 }
5250
5251 if (splat || swizzle_splat)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005252 {
5253 // Cannot use constant splatting if we have specialization constants somewhere in the vector.
5254 for (uint32_t i = 0; i < c.vector_size(); i++)
5255 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005256 if (c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005257 {
5258 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005259 swizzle_splat = false;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005260 break;
5261 }
5262 }
5263 }
5264
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005265 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005266 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02005267 if (type.width == 64)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005268 {
5269 uint64_t ident = c.scalar_u64(vector, 0);
5270 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005271 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005272 if (ident != c.scalar_u64(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005273 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005274 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005275 swizzle_splat = false;
5276 break;
5277 }
5278 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005279 }
5280 else
5281 {
5282 uint32_t ident = c.scalar(vector, 0);
5283 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005284 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005285 if (ident != c.scalar(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005286 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005287 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005288 swizzle_splat = false;
5289 }
5290 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005291 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005292 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005293
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005294 if (c.vector_size() > 1 && !swizzle_splat)
5295 res += type_to_glsl(type) + "(";
5296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005297 switch (type.basetype)
5298 {
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005299 case SPIRType::Half:
5300 if (splat || swizzle_splat)
5301 {
5302 res += convert_half_to_string(c, vector, 0);
5303 if (swizzle_splat)
5304 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
5305 }
5306 else
5307 {
5308 for (uint32_t i = 0; i < c.vector_size(); i++)
5309 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005310 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005311 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005312 else
5313 res += convert_half_to_string(c, vector, i);
5314
5315 if (i + 1 < c.vector_size())
5316 res += ", ";
5317 }
5318 }
5319 break;
5320
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005321 case SPIRType::Float:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005322 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005323 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005324 res += convert_float_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005325 if (swizzle_splat)
5326 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005327 }
5328 else
5329 {
5330 for (uint32_t i = 0; i < c.vector_size(); i++)
5331 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005332 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005333 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005334 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005335 res += convert_float_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005337 if (i + 1 < c.vector_size())
5338 res += ", ";
5339 }
5340 }
5341 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005342
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005343 case SPIRType::Double:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005344 if (splat || swizzle_splat)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005345 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005346 res += convert_double_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005347 if (swizzle_splat)
5348 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005349 }
5350 else
5351 {
5352 for (uint32_t i = 0; i < c.vector_size(); i++)
5353 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005354 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005355 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005356 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005357 res += convert_double_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005358
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005359 if (i + 1 < c.vector_size())
5360 res += ", ";
5361 }
5362 }
5363 break;
5364
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005365 case SPIRType::Int64:
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005366 {
5367 auto tmp = type;
5368 tmp.vecsize = 1;
5369 tmp.columns = 1;
5370 auto int64_type = type_to_glsl(tmp);
5371
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005372 if (splat)
5373 {
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005374 res += convert_to_string(c.scalar_i64(vector, 0), int64_type, backend.long_long_literal_suffix);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005375 }
5376 else
5377 {
5378 for (uint32_t i = 0; i < c.vector_size(); i++)
5379 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005380 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005381 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005382 else
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005383 res += convert_to_string(c.scalar_i64(vector, i), int64_type, backend.long_long_literal_suffix);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005384
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005385 if (i + 1 < c.vector_size())
5386 res += ", ";
5387 }
5388 }
5389 break;
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005390 }
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005391
5392 case SPIRType::UInt64:
5393 if (splat)
5394 {
5395 res += convert_to_string(c.scalar_u64(vector, 0));
5396 if (backend.long_long_literal_suffix)
5397 res += "ull";
5398 else
5399 res += "ul";
5400 }
5401 else
5402 {
5403 for (uint32_t i = 0; i < c.vector_size(); i++)
5404 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005405 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005406 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005407 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005408 {
5409 res += convert_to_string(c.scalar_u64(vector, i));
5410 if (backend.long_long_literal_suffix)
5411 res += "ull";
5412 else
5413 res += "ul";
5414 }
5415
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005416 if (i + 1 < c.vector_size())
5417 res += ", ";
5418 }
5419 }
5420 break;
5421
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005422 case SPIRType::UInt:
5423 if (splat)
5424 {
5425 res += convert_to_string(c.scalar(vector, 0));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005426 if (is_legacy())
5427 {
5428 // Fake unsigned constant literals with signed ones if possible.
5429 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
5430 if (c.scalar_i32(vector, 0) < 0)
5431 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative.");
5432 }
5433 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005434 res += "u";
5435 }
5436 else
5437 {
5438 for (uint32_t i = 0; i < c.vector_size(); i++)
5439 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005440 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005441 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005442 else
5443 {
5444 res += convert_to_string(c.scalar(vector, i));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005445 if (is_legacy())
5446 {
5447 // Fake unsigned constant literals with signed ones if possible.
5448 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
5449 if (c.scalar_i32(vector, i) < 0)
crissdb52e272020-10-08 12:14:52 +02005450 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made "
5451 "the literal negative.");
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005452 }
5453 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005454 res += "u";
5455 }
5456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005457 if (i + 1 < c.vector_size())
5458 res += ", ";
5459 }
5460 }
5461 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005462
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005463 case SPIRType::Int:
5464 if (splat)
5465 res += convert_to_string(c.scalar_i32(vector, 0));
5466 else
5467 {
5468 for (uint32_t i = 0; i < c.vector_size(); i++)
5469 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005470 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005471 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005472 else
5473 res += convert_to_string(c.scalar_i32(vector, i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005474 if (i + 1 < c.vector_size())
5475 res += ", ";
5476 }
5477 }
5478 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005479
Chip Davisca4744a2018-11-02 14:39:55 -05005480 case SPIRType::UShort:
5481 if (splat)
5482 {
5483 res += convert_to_string(c.scalar(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005484 }
5485 else
5486 {
5487 for (uint32_t i = 0; i < c.vector_size(); i++)
5488 {
5489 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005490 res += to_expression(c.specialization_constant_id(vector, i));
Chip Davisca4744a2018-11-02 14:39:55 -05005491 else
5492 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005493 if (*backend.uint16_t_literal_suffix)
Chip Davisca4744a2018-11-02 14:39:55 -05005494 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005495 res += convert_to_string(c.scalar_u16(vector, i));
5496 res += backend.uint16_t_literal_suffix;
Chip Davisca4744a2018-11-02 14:39:55 -05005497 }
Bill Hollingsc48702d2019-03-28 14:23:32 -04005498 else
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005499 {
5500 // If backend doesn't have a literal suffix, we need to value cast.
5501 res += type_to_glsl(scalar_type);
5502 res += "(";
5503 res += convert_to_string(c.scalar_u16(vector, i));
5504 res += ")";
5505 }
Chip Davisca4744a2018-11-02 14:39:55 -05005506 }
5507
5508 if (i + 1 < c.vector_size())
5509 res += ", ";
5510 }
5511 }
5512 break;
5513
5514 case SPIRType::Short:
5515 if (splat)
5516 {
5517 res += convert_to_string(c.scalar_i16(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005518 }
5519 else
5520 {
5521 for (uint32_t i = 0; i < c.vector_size(); i++)
5522 {
5523 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005524 res += to_expression(c.specialization_constant_id(vector, i));
Chip Davisca4744a2018-11-02 14:39:55 -05005525 else
5526 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005527 if (*backend.int16_t_literal_suffix)
5528 {
5529 res += convert_to_string(c.scalar_i16(vector, i));
5530 res += backend.int16_t_literal_suffix;
5531 }
5532 else
5533 {
5534 // If backend doesn't have a literal suffix, we need to value cast.
5535 res += type_to_glsl(scalar_type);
5536 res += "(";
5537 res += convert_to_string(c.scalar_i16(vector, i));
5538 res += ")";
5539 }
Chip Davisca4744a2018-11-02 14:39:55 -05005540 }
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005541
Chip Davisca4744a2018-11-02 14:39:55 -05005542 if (i + 1 < c.vector_size())
5543 res += ", ";
5544 }
5545 }
5546 break;
5547
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005548 case SPIRType::UByte:
5549 if (splat)
5550 {
5551 res += convert_to_string(c.scalar_u8(vector, 0));
5552 }
5553 else
5554 {
5555 for (uint32_t i = 0; i < c.vector_size(); i++)
5556 {
5557 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005558 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005559 else
5560 {
5561 res += type_to_glsl(scalar_type);
5562 res += "(";
5563 res += convert_to_string(c.scalar_u8(vector, i));
5564 res += ")";
5565 }
5566
5567 if (i + 1 < c.vector_size())
5568 res += ", ";
5569 }
5570 }
5571 break;
5572
5573 case SPIRType::SByte:
5574 if (splat)
5575 {
5576 res += convert_to_string(c.scalar_i8(vector, 0));
5577 }
5578 else
5579 {
5580 for (uint32_t i = 0; i < c.vector_size(); i++)
5581 {
5582 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005583 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005584 else
5585 {
5586 res += type_to_glsl(scalar_type);
5587 res += "(";
5588 res += convert_to_string(c.scalar_i8(vector, i));
5589 res += ")";
5590 }
5591
5592 if (i + 1 < c.vector_size())
5593 res += ", ";
5594 }
5595 }
5596 break;
5597
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005598 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005599 if (splat)
5600 res += c.scalar(vector, 0) ? "true" : "false";
5601 else
5602 {
5603 for (uint32_t i = 0; i < c.vector_size(); i++)
5604 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005605 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005606 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005607 else
5608 res += c.scalar(vector, i) ? "true" : "false";
5609
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005610 if (i + 1 < c.vector_size())
5611 res += ", ";
5612 }
5613 }
5614 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005615
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005616 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005617 SPIRV_CROSS_THROW("Invalid constant expression basetype.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005618 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005619
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005620 if (c.vector_size() > 1 && !swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005621 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005622
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005623 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005624}
5625
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005626SPIRExpression &CompilerGLSL::emit_uninitialized_temporary_expression(uint32_t type, uint32_t id)
5627{
5628 forced_temporaries.insert(id);
5629 emit_uninitialized_temporary(type, id);
5630 return set<SPIRExpression>(id, to_name(id), type, true);
5631}
5632
5633void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t result_id)
5634{
5635 // If we're declaring temporaries inside continue blocks,
5636 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
5637 if (current_continue_block && !hoisted_temporaries.count(result_id))
5638 {
5639 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5640 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
5641 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
5642 return tmp.first == result_type && tmp.second == result_id;
5643 }) == end(header.declare_temporary))
5644 {
5645 header.declare_temporary.emplace_back(result_type, result_id);
5646 hoisted_temporaries.insert(result_id);
5647 force_recompile();
5648 }
5649 }
5650 else if (hoisted_temporaries.count(result_id) == 0)
5651 {
5652 auto &type = get<SPIRType>(result_type);
5653 auto &flags = ir.meta[result_id].decoration.decoration_flags;
5654
5655 // The result_id has not been made into an expression yet, so use flags interface.
5656 add_local_variable_name(result_id);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01005657
5658 string initializer;
5659 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
5660 initializer = join(" = ", to_zero_initialized_expression(result_type));
5661
5662 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), initializer, ";");
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005663 }
5664}
5665
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005666string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
5667{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005668 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01005669 auto &flags = ir.meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005671 // If we're declaring temporaries inside continue blocks,
5672 // 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 +01005673 if (current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005674 {
5675 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5676 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005677 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005678 return tmp.first == result_type && tmp.second == result_id;
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01005679 }) == end(header.declare_temporary))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005680 {
5681 header.declare_temporary.emplace_back(result_type, result_id);
Hans-Kristian Arntzen7d223b82018-01-18 12:07:10 +01005682 hoisted_temporaries.insert(result_id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02005683 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005684 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005686 return join(to_name(result_id), " = ");
5687 }
Hans-Kristian Arntzenb629ca12017-11-21 09:27:49 +01005688 else if (hoisted_temporaries.count(result_id))
5689 {
5690 // The temporary has already been declared earlier, so just "declare" the temporary by writing to it.
5691 return join(to_name(result_id), " = ");
5692 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005693 else
5694 {
5695 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen35f64d02018-03-24 01:53:08 +01005696 add_local_variable_name(result_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02005697 return join(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005698 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005699}
5700
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005701bool CompilerGLSL::expression_is_forwarded(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005702{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005703 return forwarded_temporaries.count(id) != 0;
5704}
5705
5706bool CompilerGLSL::expression_suppresses_usage_tracking(uint32_t id) const
5707{
5708 return suppressed_usage_tracking.count(id) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005709}
5710
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02005711bool CompilerGLSL::expression_read_implies_multiple_reads(uint32_t id) const
5712{
5713 auto *expr = maybe_get<SPIRExpression>(id);
5714 if (!expr)
5715 return false;
5716
5717 // If we're emitting code at a deeper loop level than when we emitted the expression,
5718 // we're probably reading the same expression over and over.
5719 return current_loop_level > expr->emitted_loop_level;
5720}
5721
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005722SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005723 bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005724{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005725 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
5726 {
5727 // Just forward it without temporary.
5728 // If the forward is trivial, we do not force flushing to temporary for this expression.
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005729 forwarded_temporaries.insert(result_id);
5730 if (suppress_usage_tracking)
5731 suppressed_usage_tracking.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005732
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005733 return set<SPIRExpression>(result_id, rhs, result_type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005734 }
5735 else
5736 {
5737 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
5738 statement(declare_temporary(result_type, result_id), rhs, ";");
5739 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
5740 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005741}
5742
5743void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
5744{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005745 bool forward = should_forward(op0);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005746 emit_op(result_type, result_id, join(op, to_enclosed_unpacked_expression(op0)), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005747 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005748}
5749
5750void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
5751{
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +02005752 // Various FP arithmetic opcodes such as add, sub, mul will hit this.
5753 bool force_temporary_precise = backend.support_precise_qualifier &&
5754 has_decoration(result_id, DecorationNoContraction) &&
5755 type_is_floating_point(get<SPIRType>(result_type));
5756 bool forward = should_forward(op0) && should_forward(op1) && !force_temporary_precise;
5757
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005758 emit_op(result_type, result_id,
5759 join(to_enclosed_unpacked_expression(op0), " ", op, " ", to_enclosed_unpacked_expression(op1)), forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005760
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005761 inherit_expression_dependencies(result_id, op0);
5762 inherit_expression_dependencies(result_id, op1);
5763}
5764
Robert Konradf3a82772017-03-24 15:00:48 +01005765void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
5766{
5767 auto &type = get<SPIRType>(result_type);
5768 auto expr = type_to_glsl_constructor(type);
5769 expr += '(';
5770 for (uint32_t i = 0; i < type.vecsize; i++)
5771 {
5772 // Make sure to call to_expression multiple times to ensure
5773 // that these expressions are properly flushed to temporaries if needed.
5774 expr += op;
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02005775 expr += to_extract_component_expression(operand, i);
Robert Konradf3a82772017-03-24 15:00:48 +01005776
5777 if (i + 1 < type.vecsize)
5778 expr += ", ";
5779 }
5780 expr += ')';
5781 emit_op(result_type, result_id, expr, should_forward(operand));
5782
5783 inherit_expression_dependencies(result_id, operand);
5784}
5785
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005786void 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 +02005787 const char *op, bool negate, SPIRType::BaseType expected_type)
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005788{
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005789 auto &type0 = expression_type(op0);
5790 auto &type1 = expression_type(op1);
5791
5792 SPIRType target_type0 = type0;
5793 SPIRType target_type1 = type1;
5794 target_type0.basetype = expected_type;
5795 target_type1.basetype = expected_type;
5796 target_type0.vecsize = 1;
5797 target_type1.vecsize = 1;
5798
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005799 auto &type = get<SPIRType>(result_type);
5800 auto expr = type_to_glsl_constructor(type);
5801 expr += '(';
5802 for (uint32_t i = 0; i < type.vecsize; i++)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005803 {
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005804 // Make sure to call to_expression multiple times to ensure
5805 // that these expressions are properly flushed to temporaries if needed.
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005806 if (negate)
5807 expr += "!(";
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005808
5809 if (expected_type != SPIRType::Unknown && type0.basetype != expected_type)
5810 expr += bitcast_expression(target_type0, type0.basetype, to_extract_component_expression(op0, i));
5811 else
5812 expr += to_extract_component_expression(op0, i);
5813
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005814 expr += ' ';
5815 expr += op;
5816 expr += ' ';
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005817
5818 if (expected_type != SPIRType::Unknown && type1.basetype != expected_type)
5819 expr += bitcast_expression(target_type1, type1.basetype, to_extract_component_expression(op1, i));
5820 else
5821 expr += to_extract_component_expression(op1, i);
5822
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005823 if (negate)
5824 expr += ")";
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005825
5826 if (i + 1 < type.vecsize)
5827 expr += ", ";
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005828 }
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005829 expr += ')';
5830 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
5831
5832 inherit_expression_dependencies(result_id, op0);
5833 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005834}
5835
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005836SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
5837 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
5838{
5839 auto &type0 = expression_type(op0);
5840 auto &type1 = expression_type(op1);
5841
5842 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
5843 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
5844 // since equality test is exactly the same.
5845 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
5846
5847 // Create a fake type so we can bitcast to it.
5848 // We only deal with regular arithmetic types here like int, uints and so on.
5849 SPIRType expected_type;
5850 expected_type.basetype = input_type;
5851 expected_type.vecsize = type0.vecsize;
5852 expected_type.columns = type0.columns;
5853 expected_type.width = type0.width;
5854
5855 if (cast)
5856 {
5857 cast_op0 = bitcast_glsl(expected_type, op0);
5858 cast_op1 = bitcast_glsl(expected_type, op1);
5859 }
5860 else
5861 {
5862 // 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 +02005863 cast_op0 = to_enclosed_unpacked_expression(op0);
5864 cast_op1 = to_enclosed_unpacked_expression(op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005865 input_type = type0.basetype;
5866 }
5867
5868 return expected_type;
5869}
5870
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02005871bool CompilerGLSL::emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0)
5872{
5873 // Some bitcasts may require complex casting sequences, and are implemented here.
5874 // Otherwise a simply unary function will do with bitcast_glsl_op.
5875
5876 auto &output_type = get<SPIRType>(result_type);
5877 auto &input_type = expression_type(op0);
5878 string expr;
5879
5880 if (output_type.basetype == SPIRType::Half && input_type.basetype == SPIRType::Float && input_type.vecsize == 1)
5881 expr = join("unpackFloat2x16(floatBitsToUint(", to_unpacked_expression(op0), "))");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02005882 else if (output_type.basetype == SPIRType::Float && input_type.basetype == SPIRType::Half &&
5883 input_type.vecsize == 2)
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02005884 expr = join("uintBitsToFloat(packFloat2x16(", to_unpacked_expression(op0), "))");
5885 else
5886 return false;
5887
5888 emit_op(result_type, id, expr, should_forward(op0));
5889 return true;
5890}
5891
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005892void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5893 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
5894{
5895 string cast_op0, cast_op1;
5896 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
5897 auto &out_type = get<SPIRType>(result_type);
5898
5899 // We might have casted away from the result type, so bitcast again.
5900 // For example, arithmetic right shift with uint inputs.
5901 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005902 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005903 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005904 {
5905 expected_type.basetype = input_type;
5906 expr = bitcast_glsl_op(out_type, expected_type);
5907 expr += '(';
5908 expr += join(cast_op0, " ", op, " ", cast_op1);
5909 expr += ')';
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005910 }
5911 else
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005912 expr += join(cast_op0, " ", op, " ", cast_op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005913
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005914 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005915 inherit_expression_dependencies(result_id, op0);
5916 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005917}
5918
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005919void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
5920{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005921 bool forward = should_forward(op0);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005922 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005923 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005924}
5925
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005926void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5927 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005928{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005929 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005930 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ")"),
5931 forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005932 inherit_expression_dependencies(result_id, op0);
5933 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005934}
5935
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005936void CompilerGLSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5937 const char *op)
5938{
5939 forced_temporaries.insert(result_id);
5940 emit_op(result_type, result_id,
5941 join(op, "(", to_non_uniform_aware_expression(op0), ", ",
5942 to_unpacked_expression(op1), ")"), false);
5943 flush_all_atomic_capable_variables();
5944}
5945
5946void CompilerGLSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id,
5947 uint32_t op0, uint32_t op1, uint32_t op2,
5948 const char *op)
5949{
5950 forced_temporaries.insert(result_id);
5951 emit_op(result_type, result_id,
5952 join(op, "(", to_non_uniform_aware_expression(op0), ", ",
5953 to_unpacked_expression(op1), ", ", to_unpacked_expression(op2), ")"), false);
5954 flush_all_atomic_capable_variables();
5955}
5956
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005957void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op,
5958 SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type)
5959{
5960 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005961 auto &expr_type = expression_type(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005962 auto expected_type = out_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005963
5964 // 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 +01005965 expected_type.basetype = input_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005966 expected_type.width = expr_type.width;
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01005967
5968 string cast_op;
5969 if (expr_type.basetype != input_type)
5970 {
5971 if (expr_type.basetype == SPIRType::Boolean)
5972 cast_op = join(type_to_glsl(expected_type), "(", to_unpacked_expression(op0), ")");
5973 else
5974 cast_op = bitcast_glsl(expected_type, op0);
5975 }
5976 else
5977 cast_op = to_unpacked_expression(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005978
5979 string expr;
5980 if (out_type.basetype != expected_result_type)
5981 {
5982 expected_type.basetype = expected_result_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005983 expected_type.width = out_type.width;
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01005984 if (out_type.basetype == SPIRType::Boolean)
5985 expr = type_to_glsl(out_type);
5986 else
5987 expr = bitcast_glsl_op(out_type, expected_type);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005988 expr += '(';
5989 expr += join(op, "(", cast_op, ")");
5990 expr += ')';
5991 }
5992 else
5993 {
5994 expr += join(op, "(", cast_op, ")");
5995 }
5996
5997 emit_op(result_type, result_id, expr, should_forward(op0));
5998 inherit_expression_dependencies(result_id, op0);
5999}
6000
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006001// Very special case. Handling bitfieldExtract requires us to deal with different bitcasts of different signs
6002// and different vector sizes all at once. Need a special purpose method here.
6003void CompilerGLSL::emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6004 uint32_t op2, const char *op,
6005 SPIRType::BaseType expected_result_type,
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006006 SPIRType::BaseType input_type0, SPIRType::BaseType input_type1,
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006007 SPIRType::BaseType input_type2)
6008{
6009 auto &out_type = get<SPIRType>(result_type);
6010 auto expected_type = out_type;
6011 expected_type.basetype = input_type0;
6012
6013 string cast_op0 =
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006014 expression_type(op0).basetype != input_type0 ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006015
6016 auto op1_expr = to_unpacked_expression(op1);
6017 auto op2_expr = to_unpacked_expression(op2);
6018
6019 // Use value casts here instead. Input must be exactly int or uint, but SPIR-V might be 16-bit.
6020 expected_type.basetype = input_type1;
6021 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006022 string cast_op1 = expression_type(op1).basetype != input_type1 ?
6023 join(type_to_glsl_constructor(expected_type), "(", op1_expr, ")") :
6024 op1_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006025
6026 expected_type.basetype = input_type2;
6027 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006028 string cast_op2 = expression_type(op2).basetype != input_type2 ?
6029 join(type_to_glsl_constructor(expected_type), "(", op2_expr, ")") :
6030 op2_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006031
6032 string expr;
6033 if (out_type.basetype != expected_result_type)
6034 {
6035 expected_type.vecsize = out_type.vecsize;
6036 expected_type.basetype = expected_result_type;
6037 expr = bitcast_glsl_op(out_type, expected_type);
6038 expr += '(';
6039 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6040 expr += ')';
6041 }
6042 else
6043 {
6044 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6045 }
6046
6047 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
6048 inherit_expression_dependencies(result_id, op0);
6049 inherit_expression_dependencies(result_id, op1);
6050 inherit_expression_dependencies(result_id, op2);
6051}
6052
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006053void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6054 uint32_t op2, const char *op, SPIRType::BaseType input_type)
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006055{
6056 auto &out_type = get<SPIRType>(result_type);
6057 auto expected_type = out_type;
6058 expected_type.basetype = input_type;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006059 string cast_op0 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006060 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006061 string cast_op1 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006062 expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_unpacked_expression(op1);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006063 string cast_op2 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006064 expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_unpacked_expression(op2);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006065
6066 string expr;
6067 if (out_type.basetype != input_type)
6068 {
6069 expr = bitcast_glsl_op(out_type, expected_type);
6070 expr += '(';
6071 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6072 expr += ')';
6073 }
6074 else
6075 {
6076 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6077 }
6078
6079 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
6080 inherit_expression_dependencies(result_id, op0);
6081 inherit_expression_dependencies(result_id, op1);
6082 inherit_expression_dependencies(result_id, op2);
6083}
6084
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01006085void CompilerGLSL::emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0,
6086 uint32_t op1, const char *op, SPIRType::BaseType input_type)
6087{
6088 // Special purpose method for implementing clustered subgroup opcodes.
6089 // Main difference is that op1 does not participate in any casting, it needs to be a literal.
6090 auto &out_type = get<SPIRType>(result_type);
6091 auto expected_type = out_type;
6092 expected_type.basetype = input_type;
6093 string cast_op0 =
6094 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
6095
6096 string expr;
6097 if (out_type.basetype != input_type)
6098 {
6099 expr = bitcast_glsl_op(out_type, expected_type);
6100 expr += '(';
6101 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
6102 expr += ')';
6103 }
6104 else
6105 {
6106 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
6107 }
6108
6109 emit_op(result_type, result_id, expr, should_forward(op0));
6110 inherit_expression_dependencies(result_id, op0);
6111}
6112
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006113void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6114 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
6115{
6116 string cast_op0, cast_op1;
6117 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
6118 auto &out_type = get<SPIRType>(result_type);
6119
6120 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
6121 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02006122 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006123 {
6124 expected_type.basetype = input_type;
6125 expr = bitcast_glsl_op(out_type, expected_type);
6126 expr += '(';
6127 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
6128 expr += ')';
6129 }
6130 else
6131 {
6132 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
6133 }
6134
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006135 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006136 inherit_expression_dependencies(result_id, op0);
6137 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006138}
6139
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006140void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6141 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006142{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006143 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006144 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006145 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
6146 to_unpacked_expression(op2), ")"),
6147 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006148
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006149 inherit_expression_dependencies(result_id, op0);
6150 inherit_expression_dependencies(result_id, op1);
6151 inherit_expression_dependencies(result_id, op2);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006152}
6153
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006154void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6155 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006156{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006157 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01006158 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006159 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
6160 to_unpacked_expression(op2), ", ", to_unpacked_expression(op3), ")"),
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006161 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006162
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006163 inherit_expression_dependencies(result_id, op0);
6164 inherit_expression_dependencies(result_id, op1);
6165 inherit_expression_dependencies(result_id, op2);
6166 inherit_expression_dependencies(result_id, op3);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006167}
6168
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006169void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6170 uint32_t op2, uint32_t op3, const char *op,
6171 SPIRType::BaseType offset_count_type)
6172{
6173 // Only need to cast offset/count arguments. Types of base/insert must be same as result type,
6174 // and bitfieldInsert is sign invariant.
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006175 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006176
6177 auto op0_expr = to_unpacked_expression(op0);
6178 auto op1_expr = to_unpacked_expression(op1);
6179 auto op2_expr = to_unpacked_expression(op2);
6180 auto op3_expr = to_unpacked_expression(op3);
6181
6182 SPIRType target_type;
6183 target_type.vecsize = 1;
6184 target_type.basetype = offset_count_type;
6185
6186 if (expression_type(op2).basetype != offset_count_type)
6187 {
6188 // Value-cast here. Input might be 16-bit. GLSL requires int.
6189 op2_expr = join(type_to_glsl_constructor(target_type), "(", op2_expr, ")");
6190 }
6191
6192 if (expression_type(op3).basetype != offset_count_type)
6193 {
6194 // Value-cast here. Input might be 16-bit. GLSL requires int.
6195 op3_expr = join(type_to_glsl_constructor(target_type), "(", op3_expr, ")");
6196 }
6197
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006198 emit_op(result_type, result_id, join(op, "(", op0_expr, ", ", op1_expr, ", ", op2_expr, ", ", op3_expr, ")"),
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006199 forward);
6200
6201 inherit_expression_dependencies(result_id, op0);
6202 inherit_expression_dependencies(result_id, op1);
6203 inherit_expression_dependencies(result_id, op2);
6204 inherit_expression_dependencies(result_id, op3);
6205}
6206
rdbb3bd6742020-11-07 12:43:53 +01006207string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t tex)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006208{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006209 const char *type;
6210 switch (imgtype.image.dim)
6211 {
6212 case spv::Dim1D:
Rob Fischer21990632016-09-17 17:01:50 +09006213 type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006214 break;
6215 case spv::Dim2D:
Rob Fischer21990632016-09-17 17:01:50 +09006216 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006217 break;
6218 case spv::Dim3D:
6219 type = "3D";
6220 break;
6221 case spv::DimCube:
6222 type = "Cube";
6223 break;
Sidney Justfbb4df32019-01-06 12:21:59 -08006224 case spv::DimRect:
6225 type = "2DRect";
6226 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006227 case spv::DimBuffer:
6228 type = "Buffer";
6229 break;
6230 case spv::DimSubpassData:
6231 type = "2D";
6232 break;
6233 default:
6234 type = "";
6235 break;
6236 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006237
rdbe8c500c2020-11-05 22:55:44 +01006238 // In legacy GLSL, an extension is required for textureLod in the fragment
6239 // shader or textureGrad anywhere.
6240 bool legacy_lod_ext = false;
6241 auto &execution = get_entry_point();
6242 if (op == "textureGrad" || op == "textureProjGrad" ||
6243 ((op == "textureLod" || op == "textureProjLod") && execution.model != ExecutionModelVertex))
Lubos Lenco0028b4f2016-11-21 22:37:20 +01006244 {
Robert Konradedfc2972017-03-23 13:25:24 +01006245 if (is_legacy_es())
6246 {
rdbe8c500c2020-11-05 22:55:44 +01006247 legacy_lod_ext = true;
6248 require_extension_internal("GL_EXT_shader_texture_lod");
Robert Konradedfc2972017-03-23 13:25:24 +01006249 }
rdbe8c500c2020-11-05 22:55:44 +01006250 else if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02006251 require_extension_internal("GL_ARB_shader_texture_lod");
Lubos Lenco0028b4f2016-11-21 22:37:20 +01006252 }
Lubos Lenco52158642016-09-17 15:56:23 +02006253
Sidney Just5ac55ee2018-06-25 02:11:46 -07006254 if (op == "textureLodOffset" || op == "textureProjLodOffset")
6255 {
6256 if (is_legacy_es())
6257 SPIRV_CROSS_THROW(join(op, " not allowed in legacy ES"));
6258
6259 require_extension_internal("GL_EXT_gpu_shader4");
6260 }
6261
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02006262 // GLES has very limited support for shadow samplers.
Sidney Just5ac55ee2018-06-25 02:11:46 -07006263 // Basically shadow2D and shadow2DProj work through EXT_shadow_samplers,
6264 // everything else can just throw
Bill Hollingsfd252b22021-11-08 15:59:45 -05006265 bool is_comparison = is_depth_image(imgtype, tex);
rdb10fa5f62020-11-09 15:26:46 +01006266 if (is_comparison && is_legacy_es())
Sidney Just5ac55ee2018-06-25 02:11:46 -07006267 {
6268 if (op == "texture" || op == "textureProj")
6269 require_extension_internal("GL_EXT_shadow_samplers");
6270 else
6271 SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
6272 }
6273
rdb10fa5f62020-11-09 15:26:46 +01006274 if (op == "textureSize")
6275 {
6276 if (is_legacy_es())
6277 SPIRV_CROSS_THROW("textureSize not supported in legacy ES");
6278 if (is_comparison)
6279 SPIRV_CROSS_THROW("textureSize not supported on shadow sampler in legacy GLSL");
6280 require_extension_internal("GL_EXT_gpu_shader4");
6281 }
6282
6283 if (op == "texelFetch" && is_legacy_es())
6284 SPIRV_CROSS_THROW("texelFetch not supported in legacy ES");
6285
6286 bool is_es_and_depth = is_legacy_es() && is_comparison;
6287 std::string type_prefix = is_comparison ? "shadow" : "texture";
Sidney Just0f62b5d2018-06-22 01:40:01 -07006288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006289 if (op == "texture")
Sidney Just5ac55ee2018-06-25 02:11:46 -07006290 return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
Robert Konradedfc2972017-03-23 13:25:24 +01006291 else if (op == "textureLod")
rdbe8c500c2020-11-05 22:55:44 +01006292 return join(type_prefix, type, legacy_lod_ext ? "LodEXT" : "Lod");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006293 else if (op == "textureProj")
Sidney Just5ac55ee2018-06-25 02:11:46 -07006294 return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
Sidney Juste66fd6c2018-03-12 00:59:06 +10006295 else if (op == "textureGrad")
Sidney Just0f62b5d2018-06-22 01:40:01 -07006296 return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006297 else if (op == "textureProjLod")
rdbe8c500c2020-11-05 22:55:44 +01006298 return join(type_prefix, type, legacy_lod_ext ? "ProjLodEXT" : "ProjLod");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006299 else if (op == "textureLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01006300 return join(type_prefix, type, "LodOffset");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006301 else if (op == "textureProjGrad")
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02006302 return join(type_prefix, type,
6303 is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006304 else if (op == "textureProjLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01006305 return join(type_prefix, type, "ProjLodOffset");
rdb10fa5f62020-11-09 15:26:46 +01006306 else if (op == "textureSize")
6307 return join("textureSize", type);
6308 else if (op == "texelFetch")
6309 return join("texelFetch", type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006310 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006311 {
6312 SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
6313 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006314}
6315
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006316bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
6317{
6318 auto *cleft = maybe_get<SPIRConstant>(left);
6319 auto *cright = maybe_get<SPIRConstant>(right);
6320 auto &lerptype = expression_type(lerp);
6321
6322 // If our targets aren't constants, we cannot use construction.
6323 if (!cleft || !cright)
6324 return false;
6325
6326 // If our targets are spec constants, we cannot use construction.
6327 if (cleft->specialization || cright->specialization)
6328 return false;
6329
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006330 auto &value_type = get<SPIRType>(cleft->constant_type);
6331
6332 if (lerptype.basetype != SPIRType::Boolean)
6333 return false;
6334 if (value_type.basetype == SPIRType::Struct || is_array(value_type))
6335 return false;
6336 if (!backend.use_constructor_splatting && value_type.vecsize != lerptype.vecsize)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006337 return false;
6338
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006339 // Only valid way in SPIR-V 1.4 to use matrices in select is a scalar select.
6340 // matrix(scalar) constructor fills in diagnonals, so gets messy very quickly.
6341 // Just avoid this case.
6342 if (value_type.columns > 1)
6343 return false;
6344
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006345 // If our bool selects between 0 and 1, we can cast from bool instead, making our trivial constructor.
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006346 bool ret = true;
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006347 for (uint32_t row = 0; ret && row < value_type.vecsize; row++)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006348 {
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006349 switch (type.basetype)
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006350 {
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006351 case SPIRType::Short:
6352 case SPIRType::UShort:
6353 ret = cleft->scalar_u16(0, row) == 0 && cright->scalar_u16(0, row) == 1;
6354 break;
Chip Davis117ccf42018-11-01 17:20:07 -05006355
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006356 case SPIRType::Int:
6357 case SPIRType::UInt:
6358 ret = cleft->scalar(0, row) == 0 && cright->scalar(0, row) == 1;
6359 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006360
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006361 case SPIRType::Half:
6362 ret = cleft->scalar_f16(0, row) == 0.0f && cright->scalar_f16(0, row) == 1.0f;
6363 break;
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01006364
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006365 case SPIRType::Float:
6366 ret = cleft->scalar_f32(0, row) == 0.0f && cright->scalar_f32(0, row) == 1.0f;
6367 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006368
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006369 case SPIRType::Double:
6370 ret = cleft->scalar_f64(0, row) == 0.0 && cright->scalar_f64(0, row) == 1.0;
6371 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006372
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006373 case SPIRType::Int64:
6374 case SPIRType::UInt64:
6375 ret = cleft->scalar_u64(0, row) == 0 && cright->scalar_u64(0, row) == 1;
6376 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006377
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006378 default:
6379 ret = false;
6380 break;
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006381 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006382 }
6383
6384 if (ret)
6385 op = type_to_glsl_constructor(type);
6386 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006387}
6388
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006389string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
6390 uint32_t false_value)
6391{
6392 string expr;
6393 auto &lerptype = expression_type(select);
6394
6395 if (lerptype.vecsize == 1)
Chip Davis3bfb2f92018-12-03 02:06:33 -06006396 expr = join(to_enclosed_expression(select), " ? ", to_enclosed_pointer_expression(true_value), " : ",
6397 to_enclosed_pointer_expression(false_value));
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006398 else
6399 {
6400 auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
6401
6402 expr = type_to_glsl_constructor(restype);
6403 expr += "(";
6404 for (uint32_t i = 0; i < restype.vecsize; i++)
6405 {
6406 expr += swiz(select, i);
6407 expr += " ? ";
6408 expr += swiz(true_value, i);
6409 expr += " : ";
6410 expr += swiz(false_value, i);
6411 if (i + 1 < restype.vecsize)
6412 expr += ", ";
6413 }
6414 expr += ")";
6415 }
6416
6417 return expr;
6418}
6419
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006420void 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 +01006421{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006422 auto &lerptype = expression_type(lerp);
6423 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006424
Chip Davis3bfb2f92018-12-03 02:06:33 -06006425 // If this results in a variable pointer, assume it may be written through.
6426 if (restype.pointer)
6427 {
6428 register_write(left);
6429 register_write(right);
6430 }
6431
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006432 string mix_op;
Chip Davis6628ea62019-07-10 23:46:40 -05006433 bool has_boolean_mix = *backend.boolean_mix_function &&
Hans-Kristian Arntzen851acf32017-05-04 10:28:30 +02006434 ((options.es && options.version >= 310) || (!options.es && options.version >= 450));
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006435 bool trivial_mix = to_trivial_mix_op(restype, mix_op, left, right, lerp);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006436
Hans-Kristian Arntzen0e7c33f2017-02-11 10:52:34 +01006437 // Cannot use boolean mix when the lerp argument is just one boolean,
6438 // fall back to regular trinary statements.
6439 if (lerptype.vecsize == 1)
6440 has_boolean_mix = false;
6441
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006442 // If we can reduce the mix to a simple cast, do so.
6443 // This helps for cases like int(bool), uint(bool) which is implemented with
6444 // OpSelect bool 1 0.
6445 if (trivial_mix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006446 {
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006447 emit_unary_func_op(result_type, id, lerp, mix_op.c_str());
6448 }
6449 else if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
6450 {
6451 // Boolean mix not supported on desktop without extension.
6452 // Was added in OpenGL 4.5 with ES 3.1 compat.
6453 //
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006454 // Could use GL_EXT_shader_integer_mix on desktop at least,
6455 // but Apple doesn't support it. :(
6456 // Just implement it as ternary expressions.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006457 auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006458 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006459 inherit_expression_dependencies(id, left);
6460 inherit_expression_dependencies(id, right);
6461 inherit_expression_dependencies(id, lerp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006462 }
Chip Davis6628ea62019-07-10 23:46:40 -05006463 else if (lerptype.basetype == SPIRType::Boolean)
6464 emit_trinary_func_op(result_type, id, left, right, lerp, backend.boolean_mix_function);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006465 else
6466 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006467}
6468
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006469string CompilerGLSL::to_combined_image_sampler(VariableID image_id, VariableID samp_id)
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006470{
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006471 // Keep track of the array indices we have used to load the image.
6472 // We'll need to use the same array index into the combined image sampler array.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006473 auto image_expr = to_non_uniform_aware_expression(image_id);
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006474 string array_expr;
6475 auto array_index = image_expr.find_first_of('[');
6476 if (array_index != string::npos)
6477 array_expr = image_expr.substr(array_index, string::npos);
6478
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006479 auto &args = current_function->arguments;
6480
6481 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
6482 // all possible combinations into new sampler2D uniforms.
6483 auto *image = maybe_get_backing_variable(image_id);
6484 auto *samp = maybe_get_backing_variable(samp_id);
6485 if (image)
6486 image_id = image->self;
6487 if (samp)
6488 samp_id = samp->self;
6489
6490 auto image_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006491 [image_id](const SPIRFunction::Parameter &param) { return image_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006492
6493 auto sampler_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006494 [samp_id](const SPIRFunction::Parameter &param) { return samp_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006495
6496 if (image_itr != end(args) || sampler_itr != end(args))
6497 {
6498 // If any parameter originates from a parameter, we will find it in our argument list.
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02006499 bool global_image = image_itr == end(args);
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006500 bool global_sampler = sampler_itr == end(args);
Hans-Kristian Arntzenc3ff67c2019-09-17 10:16:47 +02006501 VariableID iid = global_image ? image_id : VariableID(uint32_t(image_itr - begin(args)));
6502 VariableID sid = global_sampler ? samp_id : VariableID(uint32_t(sampler_itr - begin(args)));
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006503
6504 auto &combined = current_function->combined_parameters;
6505 auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02006506 return p.global_image == global_image && p.global_sampler == global_sampler && p.image_id == iid &&
6507 p.sampler_id == sid;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006508 });
6509
6510 if (itr != end(combined))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006511 return to_expression(itr->id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006512 else
6513 {
crissdb52e272020-10-08 12:14:52 +02006514 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler parameter, was "
6515 "build_combined_image_samplers() used "
6516 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006517 }
6518 }
6519 else
6520 {
6521 // For global sampler2D, look directly at the global remapping table.
6522 auto &mapping = combined_image_samplers;
6523 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
6524 return combined.image_id == image_id && combined.sampler_id == samp_id;
6525 });
6526
6527 if (itr != end(combined_image_samplers))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006528 return to_expression(itr->combined_id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006529 else
6530 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006531 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
6532 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006533 }
6534 }
6535}
6536
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02006537bool CompilerGLSL::is_supported_subgroup_op_in_opengl(spv::Op op)
crissdb52e272020-10-08 12:14:52 +02006538{
6539 switch (op)
6540 {
6541 case OpGroupNonUniformElect:
6542 case OpGroupNonUniformBallot:
6543 case OpGroupNonUniformBallotFindLSB:
6544 case OpGroupNonUniformBallotFindMSB:
6545 case OpGroupNonUniformBroadcast:
6546 case OpGroupNonUniformBroadcastFirst:
6547 case OpGroupNonUniformAll:
6548 case OpGroupNonUniformAny:
6549 case OpGroupNonUniformAllEqual:
6550 case OpControlBarrier:
6551 case OpMemoryBarrier:
6552 case OpGroupNonUniformBallotBitCount:
6553 case OpGroupNonUniformBallotBitExtract:
6554 case OpGroupNonUniformInverseBallot:
6555 return true;
6556 default:
6557 return false;
6558 }
6559}
6560
Bill Hollings5aafb282016-04-23 21:47:41 -04006561void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
6562{
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006563 if (options.vulkan_semantics && combined_image_samplers.empty())
6564 {
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006565 emit_binary_func_op(result_type, result_id, image_id, samp_id,
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02006566 type_to_glsl(get<SPIRType>(result_type), result_id).c_str());
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006567 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006568 else
Hans-Kristian Arntzen02808002018-04-27 09:34:13 +02006569 {
6570 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
6571 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true);
6572 }
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02006573
6574 // Make sure to suppress usage tracking and any expression invalidation.
6575 // It is illegal to create temporaries of opaque types.
6576 forwarded_temporaries.erase(result_id);
Bill Hollings5aafb282016-04-23 21:47:41 -04006577}
6578
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006579static inline bool image_opcode_is_sample_no_dref(Op op)
6580{
6581 switch (op)
6582 {
6583 case OpImageSampleExplicitLod:
6584 case OpImageSampleImplicitLod:
6585 case OpImageSampleProjExplicitLod:
6586 case OpImageSampleProjImplicitLod:
6587 case OpImageFetch:
6588 case OpImageRead:
6589 case OpImageSparseSampleExplicitLod:
6590 case OpImageSparseSampleImplicitLod:
6591 case OpImageSparseSampleProjExplicitLod:
6592 case OpImageSparseSampleProjImplicitLod:
6593 case OpImageSparseFetch:
6594 case OpImageSparseRead:
6595 return true;
6596
6597 default:
6598 return false;
6599 }
6600}
6601
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006602void CompilerGLSL::emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id, uint32_t &feedback_id,
6603 uint32_t &texel_id)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006604{
6605 // Need to allocate two temporaries.
6606 if (options.es)
6607 SPIRV_CROSS_THROW("Sparse texture feedback is not supported on ESSL.");
6608 require_extension_internal("GL_ARB_sparse_texture2");
6609
6610 auto &temps = extra_sub_expressions[id];
6611 if (temps == 0)
6612 temps = ir.increase_bound_by(2);
6613
6614 feedback_id = temps + 0;
6615 texel_id = temps + 1;
6616
6617 auto &return_type = get<SPIRType>(result_type_id);
6618 if (return_type.basetype != SPIRType::Struct || return_type.member_types.size() != 2)
6619 SPIRV_CROSS_THROW("Invalid return type for sparse feedback.");
6620 emit_uninitialized_temporary(return_type.member_types[0], feedback_id);
6621 emit_uninitialized_temporary(return_type.member_types[1], texel_id);
6622}
6623
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006624uint32_t CompilerGLSL::get_sparse_feedback_texel_id(uint32_t id) const
6625{
6626 auto itr = extra_sub_expressions.find(id);
6627 if (itr == extra_sub_expressions.end())
6628 return 0;
6629 else
6630 return itr->second + 1;
6631}
6632
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006633void CompilerGLSL::emit_texture_op(const Instruction &i, bool sparse)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006634{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02006635 auto *ops = stream(i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006636 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006637
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006638 SmallVector<uint32_t> inherited_expressions;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006639
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006640 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006641 uint32_t id = ops[1];
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006642 auto &return_type = get<SPIRType>(result_type_id);
6643
6644 uint32_t sparse_code_id = 0;
6645 uint32_t sparse_texel_id = 0;
6646 if (sparse)
6647 emit_sparse_feedback_temporaries(result_type_id, id, sparse_code_id, sparse_texel_id);
Chip Davis39dce882019-08-02 15:11:19 -05006648
6649 bool forward = false;
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006650 string expr = to_texture_op(i, sparse, &forward, inherited_expressions);
6651
6652 if (sparse)
6653 {
6654 statement(to_expression(sparse_code_id), " = ", expr, ";");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006655 expr = join(type_to_glsl(return_type), "(", to_expression(sparse_code_id), ", ", to_expression(sparse_texel_id),
6656 ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006657 forward = true;
6658 inherited_expressions.clear();
6659 }
6660
Chip Davis39dce882019-08-02 15:11:19 -05006661 emit_op(result_type_id, id, expr, forward);
6662 for (auto &inherit : inherited_expressions)
6663 inherit_expression_dependencies(id, inherit);
6664
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006665 // Do not register sparse ops as control dependent as they are always lowered to a temporary.
Chip Davis39dce882019-08-02 15:11:19 -05006666 switch (op)
6667 {
6668 case OpImageSampleDrefImplicitLod:
6669 case OpImageSampleImplicitLod:
6670 case OpImageSampleProjImplicitLod:
6671 case OpImageSampleProjDrefImplicitLod:
6672 register_control_dependent_expression(id);
6673 break;
6674
6675 default:
6676 break;
6677 }
6678}
6679
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006680std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool *forward,
Chip Davis39dce882019-08-02 15:11:19 -05006681 SmallVector<uint32_t> &inherited_expressions)
6682{
6683 auto *ops = stream(i);
6684 auto op = static_cast<Op>(i.op);
6685 uint32_t length = i.length;
6686
6687 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006688 VariableID img = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006689 uint32_t coord = ops[3];
6690 uint32_t dref = 0;
6691 uint32_t comp = 0;
6692 bool gather = false;
6693 bool proj = false;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006694 bool fetch = false;
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01006695 bool nonuniform_expression = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006696 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006697
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006698 auto &result_type = get<SPIRType>(result_type_id);
6699
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006700 inherited_expressions.push_back(coord);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006701 if (has_decoration(img, DecorationNonUniform) && !maybe_get_backing_variable(img))
6702 nonuniform_expression = true;
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02006703
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006704 switch (op)
6705 {
6706 case OpImageSampleDrefImplicitLod:
6707 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006708 case OpImageSparseSampleDrefImplicitLod:
6709 case OpImageSparseSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006710 dref = ops[4];
6711 opt = &ops[5];
6712 length -= 5;
6713 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006714
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006715 case OpImageSampleProjDrefImplicitLod:
6716 case OpImageSampleProjDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006717 case OpImageSparseSampleProjDrefImplicitLod:
6718 case OpImageSparseSampleProjDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006719 dref = ops[4];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006720 opt = &ops[5];
6721 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006722 proj = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006723 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006724
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006725 case OpImageDrefGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006726 case OpImageSparseDrefGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006727 dref = ops[4];
6728 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006729 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006730 gather = true;
rdb509908d2020-11-07 00:01:57 +01006731 if (options.es && options.version < 310)
6732 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6733 else if (!options.es && options.version < 400)
6734 SPIRV_CROSS_THROW("textureGather with depth compare requires GLSL 400.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006735 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006736
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006737 case OpImageGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006738 case OpImageSparseGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006739 comp = ops[4];
6740 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006741 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006742 gather = true;
rdb509908d2020-11-07 00:01:57 +01006743 if (options.es && options.version < 310)
6744 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6745 else if (!options.es && options.version < 400)
6746 {
6747 if (!expression_is_constant_null(comp))
6748 SPIRV_CROSS_THROW("textureGather with component requires GLSL 400.");
6749 require_extension_internal("GL_ARB_texture_gather");
6750 }
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006751 break;
6752
6753 case OpImageFetch:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006754 case OpImageSparseFetch:
Bill Hollings8f6df772017-05-19 18:14:08 -04006755 case OpImageRead: // Reads == fetches in Metal (other langs will not get here)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006756 opt = &ops[4];
6757 length -= 4;
6758 fetch = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006759 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006760
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006761 case OpImageSampleProjImplicitLod:
6762 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006763 case OpImageSparseSampleProjImplicitLod:
6764 case OpImageSparseSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006765 opt = &ops[4];
6766 length -= 4;
6767 proj = true;
6768 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006769
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006770 default:
6771 opt = &ops[4];
6772 length -= 4;
6773 break;
6774 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006775
Bill Hollings8f6df772017-05-19 18:14:08 -04006776 // Bypass pointers because we need the real image struct
6777 auto &type = expression_type(img);
6778 auto &imgtype = get<SPIRType>(type.self);
6779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006780 uint32_t coord_components = 0;
6781 switch (imgtype.image.dim)
6782 {
6783 case spv::Dim1D:
6784 coord_components = 1;
6785 break;
6786 case spv::Dim2D:
6787 coord_components = 2;
6788 break;
6789 case spv::Dim3D:
6790 coord_components = 3;
6791 break;
6792 case spv::DimCube:
6793 coord_components = 3;
6794 break;
6795 case spv::DimBuffer:
6796 coord_components = 1;
6797 break;
6798 default:
6799 coord_components = 2;
6800 break;
6801 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006802
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006803 if (dref)
6804 inherited_expressions.push_back(dref);
6805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006806 if (proj)
6807 coord_components++;
6808 if (imgtype.image.arrayed)
6809 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006810
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006811 uint32_t bias = 0;
6812 uint32_t lod = 0;
6813 uint32_t grad_x = 0;
6814 uint32_t grad_y = 0;
6815 uint32_t coffset = 0;
6816 uint32_t offset = 0;
6817 uint32_t coffsets = 0;
6818 uint32_t sample = 0;
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006819 uint32_t minlod = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006820 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006821
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006822 if (length)
6823 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006824 flags = *opt++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006825 length--;
6826 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006827
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02006828 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006829 if (length && (flags & flag))
6830 {
6831 v = *opt++;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006832 inherited_expressions.push_back(v);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006833 length--;
6834 }
6835 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006836
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006837 test(bias, ImageOperandsBiasMask);
6838 test(lod, ImageOperandsLodMask);
6839 test(grad_x, ImageOperandsGradMask);
6840 test(grad_y, ImageOperandsGradMask);
6841 test(coffset, ImageOperandsConstOffsetMask);
6842 test(offset, ImageOperandsOffsetMask);
6843 test(coffsets, ImageOperandsConstOffsetsMask);
6844 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006845 test(minlod, ImageOperandsMinLodMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006846
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006847 TextureFunctionBaseArguments base_args = {};
6848 base_args.img = img;
6849 base_args.imgtype = &imgtype;
6850 base_args.is_fetch = fetch != 0;
6851 base_args.is_gather = gather != 0;
6852 base_args.is_proj = proj != 0;
6853
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006854 string expr;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006855 TextureFunctionNameArguments name_args = {};
6856
6857 name_args.base = base_args;
6858 name_args.has_array_offsets = coffsets != 0;
6859 name_args.has_offset = coffset != 0 || offset != 0;
6860 name_args.has_grad = grad_x != 0 || grad_y != 0;
6861 name_args.has_dref = dref != 0;
6862 name_args.is_sparse_feedback = sparse;
6863 name_args.has_min_lod = minlod != 0;
6864 name_args.lod = lod;
6865 expr += to_function_name(name_args);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006866 expr += "(";
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006867
6868 uint32_t sparse_texel_id = 0;
6869 if (sparse)
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006870 sparse_texel_id = get_sparse_feedback_texel_id(ops[1]);
6871
6872 TextureFunctionArguments args = {};
6873 args.base = base_args;
6874 args.coord = coord;
6875 args.coord_components = coord_components;
6876 args.dref = dref;
6877 args.grad_x = grad_x;
6878 args.grad_y = grad_y;
6879 args.lod = lod;
6880 args.coffset = coffset;
6881 args.offset = offset;
6882 args.bias = bias;
6883 args.component = comp;
6884 args.sample = sample;
6885 args.sparse_texel = sparse_texel_id;
6886 args.min_lod = minlod;
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01006887 args.nonuniform_expression = nonuniform_expression;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006888 expr += to_function_args(args, forward);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006889 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006890
Sidney Justf6dad782018-06-22 00:28:40 -07006891 // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here.
Bill Hollingsfd252b22021-11-08 15:59:45 -05006892 if (is_legacy() && is_depth_image(imgtype, img))
Sidney Justf6dad782018-06-22 00:28:40 -07006893 expr += ".r";
6894
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006895 // Sampling from a texture which was deduced to be a depth image, might actually return 1 component here.
6896 // Remap back to 4 components as sampling opcodes expect.
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006897 if (backend.comparison_image_samples_scalar && image_opcode_is_sample_no_dref(op))
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006898 {
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006899 bool image_is_depth = false;
6900 const auto *combined = maybe_get<SPIRCombinedImageSampler>(img);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006901 VariableID image_id = combined ? combined->image : img;
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006902
Bill Hollingsfd252b22021-11-08 15:59:45 -05006903 if (combined && is_depth_image(imgtype, combined->image))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006904 image_is_depth = true;
Bill Hollingsfd252b22021-11-08 15:59:45 -05006905 else if (is_depth_image(imgtype, img))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006906 image_is_depth = true;
6907
6908 // We must also check the backing variable for the image.
6909 // We might have loaded an OpImage, and used that handle for two different purposes.
6910 // Once with comparison, once without.
6911 auto *image_variable = maybe_get_backing_variable(image_id);
Bill Hollingsfd252b22021-11-08 15:59:45 -05006912 if (image_variable && is_depth_image(get<SPIRType>(image_variable->basetype), image_variable->self))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006913 image_is_depth = true;
6914
6915 if (image_is_depth)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006916 expr = remap_swizzle(result_type, 1, expr);
6917 }
6918
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006919 if (!sparse && !backend.support_small_type_sampling_result && result_type.width < 32)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006920 {
6921 // Just value cast (narrowing) to expected type since we cannot rely on narrowing to work automatically.
6922 // Hopefully compiler picks this up and converts the texturing instruction to the appropriate precision.
6923 expr = join(type_to_glsl_constructor(result_type), "(", expr, ")");
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006924 }
6925
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01006926 // Deals with reads from MSL. We might need to downconvert to fewer components.
6927 if (op == OpImageRead)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006928 expr = remap_swizzle(result_type, 4, expr);
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01006929
Chip Davis39dce882019-08-02 15:11:19 -05006930 return expr;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006931}
6932
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006933bool CompilerGLSL::expression_is_constant_null(uint32_t id) const
6934{
6935 auto *c = maybe_get<SPIRConstant>(id);
6936 if (!c)
6937 return false;
6938 return c->constant_is_null();
6939}
6940
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02006941bool CompilerGLSL::expression_is_non_value_type_array(uint32_t ptr)
6942{
6943 auto &type = expression_type(ptr);
6944 if (type.array.empty())
6945 return false;
6946
6947 if (!backend.array_is_value_type)
6948 return true;
6949
6950 auto *var = maybe_get_backing_variable(ptr);
6951 if (!var)
6952 return false;
6953
6954 auto &backed_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006955 return !backend.buffer_offset_array_is_value_type && backed_type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02006956 has_member_decoration(backed_type.self, 0, DecorationOffset);
6957}
6958
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006959// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
6960// For some subclasses, the function is a method on the specified image.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006961string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006962{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006963 if (args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006964 {
6965 if (options.es)
6966 SPIRV_CROSS_THROW("Sparse residency is not supported in ESSL.");
6967 require_extension_internal("GL_ARB_sparse_texture_clamp");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006968 }
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006969
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006970 string fname;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006971 auto &imgtype = *args.base.imgtype;
6972 VariableID tex = args.base.img;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006973
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006974 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006975 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
6976 // 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 +02006977 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006978 bool workaround_lod_array_shadow_as_grad = false;
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006979 if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Bill Hollingsfd252b22021-11-08 15:59:45 -05006980 is_depth_image(imgtype, tex) && args.lod)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006981 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006982 if (!expression_is_constant_null(args.lod))
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006983 {
crissdb52e272020-10-08 12:14:52 +02006984 SPIRV_CROSS_THROW("textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be "
6985 "expressed in GLSL.");
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006986 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006987 workaround_lod_array_shadow_as_grad = true;
6988 }
6989
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006990 if (args.is_sparse_feedback)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006991 fname += "sparse";
6992
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006993 if (args.base.is_fetch)
6994 fname += args.is_sparse_feedback ? "TexelFetch" : "texelFetch";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006995 else
6996 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006997 fname += args.is_sparse_feedback ? "Texture" : "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006998
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006999 if (args.base.is_gather)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007000 fname += "Gather";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007001 if (args.has_array_offsets)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007002 fname += "Offsets";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007003 if (args.base.is_proj)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007004 fname += "Proj";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007005 if (args.has_grad || workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007006 fname += "Grad";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007007 if (args.lod != 0 && !workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007008 fname += "Lod";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007009 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007010
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007011 if (args.has_offset)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007012 fname += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007013
Hans-Kristian Arntzenf383cc92020-06-08 13:39:02 +02007014 if (args.has_min_lod)
7015 fname += "Clamp";
7016
7017 if (args.is_sparse_feedback || args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007018 fname += "ARB";
7019
rdb509908d2020-11-07 00:01:57 +01007020 return (is_legacy() && !args.base.is_gather) ? legacy_tex_op(fname, imgtype, tex) : fname;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007021}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007022
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007023std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id)
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007024{
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007025 auto *var = maybe_get_backing_variable(id);
7026
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007027 // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler in GLSL.
7028 // In Vulkan GLSL, we can make use of the newer GL_EXT_samplerless_texture_functions.
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007029 if (var)
7030 {
7031 auto &type = get<SPIRType>(var->basetype);
7032 if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer)
7033 {
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007034 if (options.vulkan_semantics)
7035 {
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007036 if (dummy_sampler_id)
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02007037 {
7038 // Don't need to consider Shadow state since the dummy sampler is always non-shadow.
7039 auto sampled_type = type;
7040 sampled_type.basetype = SPIRType::SampledImage;
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007041 return join(type_to_glsl(sampled_type), "(", to_non_uniform_aware_expression(id), ", ",
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02007042 to_expression(dummy_sampler_id), ")");
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02007043 }
7044 else
7045 {
7046 // Newer glslang supports this extension to deal with texture2D as argument to texture functions.
7047 require_extension_internal("GL_EXT_samplerless_texture_functions");
7048 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007049 }
7050 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007051 {
7052 if (!dummy_sampler_id)
crissdb52e272020-10-08 12:14:52 +02007053 SPIRV_CROSS_THROW("Cannot find dummy sampler ID. Was "
7054 "build_dummy_sampler_for_combined_images() called?");
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007055
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007056 return to_combined_image_sampler(id, dummy_sampler_id);
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007057 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007058 }
7059 }
7060
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007061 return to_non_uniform_aware_expression(id);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007062}
7063
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007064// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007065string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool *p_forward)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007066{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007067 VariableID img = args.base.img;
7068 auto &imgtype = *args.base.imgtype;
7069
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007070 string farg_str;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007071 if (args.base.is_fetch)
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007072 farg_str = convert_separate_image_to_expression(img);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007073 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007074 farg_str = to_non_uniform_aware_expression(img);
Hans-Kristian Arntzen1a2e4de2018-02-21 13:43:16 +01007075
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01007076 if (args.nonuniform_expression && farg_str.find_first_of('[') != string::npos)
7077 {
7078 // Only emit nonuniformEXT() wrapper if the underlying expression is arrayed in some way.
7079 farg_str = join(backend.nonuniform_qualifier, "(", farg_str, ")");
7080 }
7081
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007082 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02007083 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007084 if (comps == in_comps)
7085 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007087 switch (comps)
7088 {
7089 case 1:
7090 return ".x";
7091 case 2:
7092 return swizz_func ? ".xy()" : ".xy";
7093 case 3:
7094 return swizz_func ? ".xyz()" : ".xyz";
7095 default:
7096 return "";
7097 }
7098 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007099
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007100 bool forward = should_forward(args.coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007102 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007103 auto swizzle_expr = swizzle(args.coord_components, expression_type(args.coord).vecsize);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01007104 // Only enclose the UV expression if needed.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02007105 auto coord_expr =
7106 (*swizzle_expr == '\0') ? to_expression(args.coord) : (to_enclosed_expression(args.coord) + swizzle_expr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007107
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007108 // texelFetch only takes int, not uint.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007109 auto &coord_type = expression_type(args.coord);
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007110 if (coord_type.basetype == SPIRType::UInt)
7111 {
7112 auto expected_type = coord_type;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007113 expected_type.vecsize = args.coord_components;
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007114 expected_type.basetype = SPIRType::Int;
7115 coord_expr = bitcast_expression(expected_type, coord_type.basetype, coord_expr);
7116 }
7117
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007118 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007119 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
7120 // 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 +02007121 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02007122 bool workaround_lod_array_shadow_as_grad =
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007123 ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Bill Hollingsfd252b22021-11-08 15:59:45 -05007124 is_depth_image(imgtype, img) && args.lod != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007125
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007126 if (args.dref)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007127 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007128 forward = forward && should_forward(args.dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007129
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007130 // SPIR-V splits dref and coordinate.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02007131 if (args.base.is_gather ||
7132 args.coord_components == 4) // GLSL also splits the arguments in two. Same for textureGather.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007133 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007134 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007135 farg_str += to_expression(args.coord);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007136 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007137 farg_str += to_expression(args.dref);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007138 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007139 else if (args.base.is_proj)
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007140 {
7141 // Have to reshuffle so we get vec4(coord, dref, proj), special case.
7142 // Other shading languages splits up the arguments for coord and compare value like SPIR-V.
7143 // The coordinate type for textureProj shadow is always vec4 even for sampler1DShadow.
7144 farg_str += ", vec4(";
7145
7146 if (imgtype.image.dim == Dim1D)
7147 {
7148 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007149 farg_str += to_enclosed_expression(args.coord) + ".x";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007150 farg_str += ", ";
7151 farg_str += "0.0, ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007152 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007153 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007154 farg_str += to_enclosed_expression(args.coord) + ".y)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007155 }
7156 else if (imgtype.image.dim == Dim2D)
7157 {
7158 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007159 farg_str += to_enclosed_expression(args.coord) + (swizz_func ? ".xy()" : ".xy");
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007160 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007161 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007162 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007163 farg_str += to_enclosed_expression(args.coord) + ".z)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007164 }
7165 else
7166 SPIRV_CROSS_THROW("Invalid type for textureProj with shadow.");
7167 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007168 else
7169 {
7170 // Create a composite which merges coord/dref into a single vector.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007171 auto type = expression_type(args.coord);
7172 type.vecsize = args.coord_components + 1;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007173 farg_str += ", ";
7174 farg_str += type_to_glsl_constructor(type);
7175 farg_str += "(";
7176 farg_str += coord_expr;
7177 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007178 farg_str += to_expression(args.dref);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007179 farg_str += ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007180 }
7181 }
7182 else
7183 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007184 farg_str += ", ";
7185 farg_str += coord_expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007186 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007187
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007188 if (args.grad_x || args.grad_y)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007189 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007190 forward = forward && should_forward(args.grad_x);
7191 forward = forward && should_forward(args.grad_y);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007192 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007193 farg_str += to_expression(args.grad_x);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007194 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007195 farg_str += to_expression(args.grad_y);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007196 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007197
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007198 if (args.lod)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007199 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007200 if (workaround_lod_array_shadow_as_grad)
Robert Konrad3f745032017-03-23 09:55:32 +01007201 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007202 // Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
7203 // Implementing this as plain texture() is not safe on some implementations.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007204 if (imgtype.image.dim == Dim2D)
7205 farg_str += ", vec2(0.0), vec2(0.0)";
7206 else if (imgtype.image.dim == DimCube)
7207 farg_str += ", vec3(0.0), vec3(0.0)";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007208 }
7209 else
7210 {
rdbe8c500c2020-11-05 22:55:44 +01007211 forward = forward && should_forward(args.lod);
7212 farg_str += ", ";
7213
7214 auto &lod_expr_type = expression_type(args.lod);
7215
7216 // Lod expression for TexelFetch in GLSL must be int, and only int.
7217 if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms &&
7218 lod_expr_type.basetype != SPIRType::Int)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007219 {
rdbe8c500c2020-11-05 22:55:44 +01007220 farg_str += join("int(", to_expression(args.lod), ")");
7221 }
7222 else
7223 {
7224 farg_str += to_expression(args.lod);
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007225 }
Robert Konrad3f745032017-03-23 09:55:32 +01007226 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007227 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007228 else if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms)
Hans-Kristian Arntzend93807a2018-04-30 10:53:21 +02007229 {
7230 // Lod argument is optional in OpImageFetch, but we require a LOD value, pick 0 as the default.
7231 farg_str += ", 0";
7232 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007233
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007234 if (args.coffset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007235 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007236 forward = forward && should_forward(args.coffset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007237 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007238 farg_str += to_expression(args.coffset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007239 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007240 else if (args.offset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007241 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007242 forward = forward && should_forward(args.offset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007243 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007244 farg_str += to_expression(args.offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007245 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007246
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007247 if (args.sample)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007248 {
7249 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007250 farg_str += to_expression(args.sample);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007251 }
7252
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007253 if (args.min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007254 {
7255 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007256 farg_str += to_expression(args.min_lod);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007257 }
7258
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007259 if (args.sparse_texel)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007260 {
7261 // Sparse texel output parameter comes after everything else, except it's before the optional, component/bias arguments.
7262 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007263 farg_str += to_expression(args.sparse_texel);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007264 }
7265
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007266 if (args.bias)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007267 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007268 forward = forward && should_forward(args.bias);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007269 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007270 farg_str += to_expression(args.bias);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007271 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007272
rdb509908d2020-11-07 00:01:57 +01007273 if (args.component && !expression_is_constant_null(args.component))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007274 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007275 forward = forward && should_forward(args.component);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007276 farg_str += ", ";
Hans-Kristian Arntzen165dbff2021-06-03 11:37:45 +02007277 auto &component_type = expression_type(args.component);
7278 if (component_type.basetype == SPIRType::Int)
7279 farg_str += to_expression(args.component);
7280 else
7281 farg_str += join("int(", to_expression(args.component), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007282 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007283
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007284 *p_forward = forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007285
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007286 return farg_str;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007287}
7288
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007289void 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 +01007290{
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02007291 auto op = static_cast<GLSLstd450>(eop);
7292
7293 if (is_legacy() && is_unsigned_glsl_opcode(op))
7294 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy GLSL targets.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007295
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007296 // If we need to do implicit bitcasts, make sure we do it with the correct type.
7297 uint32_t integer_width = get_integer_width_for_glsl_instruction(op, args, length);
7298 auto int_type = to_signed_basetype(integer_width);
7299 auto uint_type = to_unsigned_basetype(integer_width);
7300
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007301 switch (op)
7302 {
7303 // FP fiddling
7304 case GLSLstd450Round:
rdb9e6e5d22020-11-06 17:34:38 +01007305 if (!is_legacy())
7306 emit_unary_func_op(result_type, id, args[0], "round");
7307 else
7308 {
7309 auto op0 = to_enclosed_expression(args[0]);
7310 auto &op0_type = expression_type(args[0]);
7311 auto expr = join("floor(", op0, " + ", type_to_glsl_constructor(op0_type), "(0.5))");
7312 bool forward = should_forward(args[0]);
7313 emit_op(result_type, id, expr, forward);
7314 inherit_expression_dependencies(id, args[0]);
7315 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007316 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007317
7318 case GLSLstd450RoundEven:
rdb9e6e5d22020-11-06 17:34:38 +01007319 if (!is_legacy())
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007320 emit_unary_func_op(result_type, id, args[0], "roundEven");
rdb9e6e5d22020-11-06 17:34:38 +01007321 else if (!options.es)
7322 {
7323 // This extension provides round() with round-to-even semantics.
7324 require_extension_internal("GL_EXT_gpu_shader4");
7325 emit_unary_func_op(result_type, id, args[0], "round");
7326 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007327 else
rdb9e6e5d22020-11-06 17:34:38 +01007328 SPIRV_CROSS_THROW("roundEven supported only in ESSL 300.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007329 break;
7330
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007331 case GLSLstd450Trunc:
7332 emit_unary_func_op(result_type, id, args[0], "trunc");
7333 break;
7334 case GLSLstd450SAbs:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007335 emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type);
7336 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007337 case GLSLstd450FAbs:
7338 emit_unary_func_op(result_type, id, args[0], "abs");
7339 break;
7340 case GLSLstd450SSign:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007341 emit_unary_func_op_cast(result_type, id, args[0], "sign", int_type, int_type);
7342 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007343 case GLSLstd450FSign:
7344 emit_unary_func_op(result_type, id, args[0], "sign");
7345 break;
7346 case GLSLstd450Floor:
7347 emit_unary_func_op(result_type, id, args[0], "floor");
7348 break;
7349 case GLSLstd450Ceil:
7350 emit_unary_func_op(result_type, id, args[0], "ceil");
7351 break;
7352 case GLSLstd450Fract:
7353 emit_unary_func_op(result_type, id, args[0], "fract");
7354 break;
7355 case GLSLstd450Radians:
7356 emit_unary_func_op(result_type, id, args[0], "radians");
7357 break;
7358 case GLSLstd450Degrees:
7359 emit_unary_func_op(result_type, id, args[0], "degrees");
7360 break;
7361 case GLSLstd450Fma:
Hans-Kristian Arntzen3ca8bc52019-04-08 10:33:34 +02007362 if ((!options.es && options.version < 400) || (options.es && options.version < 320))
7363 {
7364 auto expr = join(to_enclosed_expression(args[0]), " * ", to_enclosed_expression(args[1]), " + ",
7365 to_enclosed_expression(args[2]));
7366
7367 emit_op(result_type, id, expr,
7368 should_forward(args[0]) && should_forward(args[1]) && should_forward(args[2]));
7369 for (uint32_t i = 0; i < 3; i++)
7370 inherit_expression_dependencies(id, args[i]);
7371 }
7372 else
7373 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007374 break;
7375 case GLSLstd450Modf:
7376 register_call_out_argument(args[1]);
7377 forced_temporaries.insert(id);
7378 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
7379 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007380
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007381 case GLSLstd450ModfStruct:
7382 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007383 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02007384 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007385 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
7386 to_expression(id), ".", to_member_name(type, 1), ");");
7387 break;
7388 }
7389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007390 // Minmax
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007391 case GLSLstd450UMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007392 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", uint_type, false);
7393 break;
7394
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007395 case GLSLstd450SMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007396 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", int_type, false);
7397 break;
7398
7399 case GLSLstd450FMin:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007400 emit_binary_func_op(result_type, id, args[0], args[1], "min");
7401 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007402
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007403 case GLSLstd450FMax:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007404 emit_binary_func_op(result_type, id, args[0], args[1], "max");
7405 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007406
7407 case GLSLstd450UMax:
7408 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", uint_type, false);
7409 break;
7410
7411 case GLSLstd450SMax:
7412 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", int_type, false);
7413 break;
7414
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007415 case GLSLstd450FClamp:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007416 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
7417 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007418
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007419 case GLSLstd450UClamp:
7420 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", uint_type);
7421 break;
7422
7423 case GLSLstd450SClamp:
7424 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", int_type);
7425 break;
7426
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007427 // Trig
7428 case GLSLstd450Sin:
7429 emit_unary_func_op(result_type, id, args[0], "sin");
7430 break;
7431 case GLSLstd450Cos:
7432 emit_unary_func_op(result_type, id, args[0], "cos");
7433 break;
7434 case GLSLstd450Tan:
7435 emit_unary_func_op(result_type, id, args[0], "tan");
7436 break;
7437 case GLSLstd450Asin:
7438 emit_unary_func_op(result_type, id, args[0], "asin");
7439 break;
7440 case GLSLstd450Acos:
7441 emit_unary_func_op(result_type, id, args[0], "acos");
7442 break;
7443 case GLSLstd450Atan:
7444 emit_unary_func_op(result_type, id, args[0], "atan");
7445 break;
7446 case GLSLstd450Sinh:
7447 emit_unary_func_op(result_type, id, args[0], "sinh");
7448 break;
7449 case GLSLstd450Cosh:
7450 emit_unary_func_op(result_type, id, args[0], "cosh");
7451 break;
7452 case GLSLstd450Tanh:
7453 emit_unary_func_op(result_type, id, args[0], "tanh");
7454 break;
7455 case GLSLstd450Asinh:
7456 emit_unary_func_op(result_type, id, args[0], "asinh");
7457 break;
7458 case GLSLstd450Acosh:
7459 emit_unary_func_op(result_type, id, args[0], "acosh");
7460 break;
7461 case GLSLstd450Atanh:
7462 emit_unary_func_op(result_type, id, args[0], "atanh");
7463 break;
7464 case GLSLstd450Atan2:
7465 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
7466 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007467
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007468 // Exponentials
7469 case GLSLstd450Pow:
7470 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
7471 break;
7472 case GLSLstd450Exp:
7473 emit_unary_func_op(result_type, id, args[0], "exp");
7474 break;
7475 case GLSLstd450Log:
7476 emit_unary_func_op(result_type, id, args[0], "log");
7477 break;
7478 case GLSLstd450Exp2:
7479 emit_unary_func_op(result_type, id, args[0], "exp2");
7480 break;
7481 case GLSLstd450Log2:
7482 emit_unary_func_op(result_type, id, args[0], "log2");
7483 break;
7484 case GLSLstd450Sqrt:
7485 emit_unary_func_op(result_type, id, args[0], "sqrt");
7486 break;
7487 case GLSLstd450InverseSqrt:
7488 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
7489 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007491 // Matrix math
7492 case GLSLstd450Determinant:
7493 emit_unary_func_op(result_type, id, args[0], "determinant");
7494 break;
7495 case GLSLstd450MatrixInverse:
7496 emit_unary_func_op(result_type, id, args[0], "inverse");
7497 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007498
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007499 // Lerping
7500 case GLSLstd450FMix:
7501 case GLSLstd450IMix:
7502 {
7503 emit_mix_op(result_type, id, args[0], args[1], args[2]);
7504 break;
7505 }
7506 case GLSLstd450Step:
7507 emit_binary_func_op(result_type, id, args[0], args[1], "step");
7508 break;
7509 case GLSLstd450SmoothStep:
7510 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
7511 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007512
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007513 // Packing
7514 case GLSLstd450Frexp:
7515 register_call_out_argument(args[1]);
7516 forced_temporaries.insert(id);
7517 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
7518 break;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007519
7520 case GLSLstd450FrexpStruct:
7521 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007522 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02007523 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007524 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
7525 to_expression(id), ".", to_member_name(type, 1), ");");
7526 break;
7527 }
7528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007529 case GLSLstd450Ldexp:
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007530 {
7531 bool forward = should_forward(args[0]) && should_forward(args[1]);
7532
7533 auto op0 = to_unpacked_expression(args[0]);
7534 auto op1 = to_unpacked_expression(args[1]);
7535 auto &op1_type = expression_type(args[1]);
7536 if (op1_type.basetype != SPIRType::Int)
7537 {
7538 // Need a value cast here.
7539 auto target_type = op1_type;
7540 target_type.basetype = SPIRType::Int;
7541 op1 = join(type_to_glsl_constructor(target_type), "(", op1, ")");
7542 }
7543
7544 auto expr = join("ldexp(", op0, ", ", op1, ")");
7545
7546 emit_op(result_type, id, expr, forward);
7547 inherit_expression_dependencies(id, args[0]);
7548 inherit_expression_dependencies(id, args[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007549 break;
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007550 }
7551
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007552 case GLSLstd450PackSnorm4x8:
7553 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
7554 break;
7555 case GLSLstd450PackUnorm4x8:
7556 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
7557 break;
7558 case GLSLstd450PackSnorm2x16:
7559 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
7560 break;
7561 case GLSLstd450PackUnorm2x16:
7562 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
7563 break;
7564 case GLSLstd450PackHalf2x16:
7565 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
7566 break;
7567 case GLSLstd450UnpackSnorm4x8:
7568 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
7569 break;
7570 case GLSLstd450UnpackUnorm4x8:
7571 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
7572 break;
7573 case GLSLstd450UnpackSnorm2x16:
7574 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
7575 break;
7576 case GLSLstd450UnpackUnorm2x16:
7577 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
7578 break;
7579 case GLSLstd450UnpackHalf2x16:
7580 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
7581 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007582
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007583 case GLSLstd450PackDouble2x32:
7584 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
7585 break;
7586 case GLSLstd450UnpackDouble2x32:
7587 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
7588 break;
7589
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007590 // Vector math
7591 case GLSLstd450Length:
7592 emit_unary_func_op(result_type, id, args[0], "length");
7593 break;
7594 case GLSLstd450Distance:
7595 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
7596 break;
7597 case GLSLstd450Cross:
7598 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
7599 break;
7600 case GLSLstd450Normalize:
7601 emit_unary_func_op(result_type, id, args[0], "normalize");
7602 break;
7603 case GLSLstd450FaceForward:
7604 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
7605 break;
7606 case GLSLstd450Reflect:
7607 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
7608 break;
7609 case GLSLstd450Refract:
7610 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
7611 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007613 // Bit-fiddling
7614 case GLSLstd450FindILsb:
Hans-Kristian Arntzen932ee0e2019-07-12 10:57:56 +02007615 // findLSB always returns int.
7616 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 +02007617 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007618
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007619 case GLSLstd450FindSMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007620 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", int_type, int_type);
7621 break;
7622
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007623 case GLSLstd450FindUMsb:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02007624 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type,
7625 int_type); // findMSB always returns int.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007626 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007628 // Multisampled varying
7629 case GLSLstd450InterpolateAtCentroid:
7630 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
7631 break;
7632 case GLSLstd450InterpolateAtSample:
7633 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
7634 break;
7635 case GLSLstd450InterpolateAtOffset:
7636 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
7637 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007638
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007639 case GLSLstd450NMin:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007640 case GLSLstd450NMax:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007641 {
7642 emit_nminmax_op(result_type, id, args[0], args[1], op);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007643 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007644 }
7645
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007646 case GLSLstd450NClamp:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007647 {
7648 // Make sure we have a unique ID here to avoid aliasing the extra sub-expressions between clamp and NMin sub-op.
7649 // IDs cannot exceed 24 bits, so we can make use of the higher bits for some unique flags.
Hans-Kristian Arntzen4ca06c72021-03-08 14:09:32 +01007650 uint32_t &max_id = extra_sub_expressions[id | EXTRA_SUB_EXPRESSION_TYPE_AUX];
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007651 if (!max_id)
7652 max_id = ir.increase_bound_by(1);
7653
7654 // Inherit precision qualifiers.
7655 ir.meta[max_id] = ir.meta[id];
7656
7657 emit_nminmax_op(result_type, max_id, args[0], args[1], GLSLstd450NMax);
7658 emit_nminmax_op(result_type, id, max_id, args[2], GLSLstd450NMin);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007659 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007660 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007661
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007662 default:
7663 statement("// unimplemented GLSL op ", eop);
7664 break;
7665 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007666}
7667
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007668void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op)
7669{
7670 // Need to emulate this call.
7671 uint32_t &ids = extra_sub_expressions[id];
7672 if (!ids)
7673 {
7674 ids = ir.increase_bound_by(5);
7675 auto btype = get<SPIRType>(result_type);
7676 btype.basetype = SPIRType::Boolean;
7677 set<SPIRType>(ids, btype);
7678 }
7679
7680 uint32_t btype_id = ids + 0;
7681 uint32_t left_nan_id = ids + 1;
7682 uint32_t right_nan_id = ids + 2;
7683 uint32_t tmp_id = ids + 3;
7684 uint32_t mixed_first_id = ids + 4;
7685
7686 // Inherit precision qualifiers.
7687 ir.meta[tmp_id] = ir.meta[id];
7688 ir.meta[mixed_first_id] = ir.meta[id];
7689
7690 emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
7691 emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
7692 emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max");
7693 emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id);
7694 emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id);
7695}
7696
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007697void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
7698 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007699{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007700 require_extension_internal("GL_AMD_shader_ballot");
Lou Kramer6671f522017-11-21 14:04:57 +01007701
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007702 enum AMDShaderBallot
7703 {
Lou Kramer6671f522017-11-21 14:04:57 +01007704 SwizzleInvocationsAMD = 1,
7705 SwizzleInvocationsMaskedAMD = 2,
7706 WriteInvocationAMD = 3,
7707 MbcntAMD = 4
7708 };
7709
7710 auto op = static_cast<AMDShaderBallot>(eop);
7711
7712 switch (op)
7713 {
7714 case SwizzleInvocationsAMD:
7715 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007716 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007717 break;
7718
7719 case SwizzleInvocationsMaskedAMD:
7720 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsMaskedAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007721 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007722 break;
7723
7724 case WriteInvocationAMD:
7725 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "writeInvocationAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007726 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007727 break;
7728
7729 case MbcntAMD:
7730 emit_unary_func_op(result_type, id, args[0], "mbcntAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007731 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007732 break;
7733
7734 default:
7735 statement("// unimplemented SPV AMD shader ballot op ", eop);
7736 break;
7737 }
7738}
7739
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007740void CompilerGLSL::emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t id, uint32_t eop,
7741 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007742{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007743 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Lou Kramer6671f522017-11-21 14:04:57 +01007744
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007745 enum AMDShaderExplicitVertexParameter
7746 {
Lou Kramer6671f522017-11-21 14:04:57 +01007747 InterpolateAtVertexAMD = 1
7748 };
7749
7750 auto op = static_cast<AMDShaderExplicitVertexParameter>(eop);
7751
7752 switch (op)
7753 {
7754 case InterpolateAtVertexAMD:
7755 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtVertexAMD");
7756 break;
7757
7758 default:
7759 statement("// unimplemented SPV AMD shader explicit vertex parameter op ", eop);
7760 break;
7761 }
7762}
7763
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007764void CompilerGLSL::emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t id, uint32_t eop,
7765 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007766{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007767 require_extension_internal("GL_AMD_shader_trinary_minmax");
Lou Kramer6671f522017-11-21 14:04:57 +01007768
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007769 enum AMDShaderTrinaryMinMax
7770 {
Lou Kramer6671f522017-11-21 14:04:57 +01007771 FMin3AMD = 1,
7772 UMin3AMD = 2,
7773 SMin3AMD = 3,
7774 FMax3AMD = 4,
7775 UMax3AMD = 5,
7776 SMax3AMD = 6,
7777 FMid3AMD = 7,
7778 UMid3AMD = 8,
7779 SMid3AMD = 9
7780 };
7781
7782 auto op = static_cast<AMDShaderTrinaryMinMax>(eop);
7783
7784 switch (op)
7785 {
7786 case FMin3AMD:
7787 case UMin3AMD:
7788 case SMin3AMD:
7789 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "min3");
7790 break;
7791
7792 case FMax3AMD:
7793 case UMax3AMD:
7794 case SMax3AMD:
7795 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "max3");
7796 break;
7797
7798 case FMid3AMD:
7799 case UMid3AMD:
7800 case SMid3AMD:
7801 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mid3");
7802 break;
7803
7804 default:
7805 statement("// unimplemented SPV AMD shader trinary minmax op ", eop);
7806 break;
7807 }
7808}
7809
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007810void CompilerGLSL::emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
7811 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007812{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007813 require_extension_internal("GL_AMD_gcn_shader");
Lou Kramer6671f522017-11-21 14:04:57 +01007814
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007815 enum AMDGCNShader
7816 {
Lou Kramer6671f522017-11-21 14:04:57 +01007817 CubeFaceIndexAMD = 1,
7818 CubeFaceCoordAMD = 2,
7819 TimeAMD = 3
7820 };
7821
7822 auto op = static_cast<AMDGCNShader>(eop);
7823
7824 switch (op)
7825 {
7826 case CubeFaceIndexAMD:
7827 emit_unary_func_op(result_type, id, args[0], "cubeFaceIndexAMD");
7828 break;
7829 case CubeFaceCoordAMD:
7830 emit_unary_func_op(result_type, id, args[0], "cubeFaceCoordAMD");
7831 break;
7832 case TimeAMD:
7833 {
7834 string expr = "timeAMD()";
7835 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007836 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007837 break;
7838 }
7839
7840 default:
7841 statement("// unimplemented SPV AMD gcn shader op ", eop);
7842 break;
7843 }
7844}
7845
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007846void CompilerGLSL::emit_subgroup_op(const Instruction &i)
7847{
7848 const uint32_t *ops = stream(i);
7849 auto op = static_cast<Op>(i.op);
7850
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02007851 if (!options.vulkan_semantics && !is_supported_subgroup_op_in_opengl(op))
crissdb52e272020-10-08 12:14:52 +02007852 SPIRV_CROSS_THROW("This subgroup operation is only supported in Vulkan semantics.");
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007853
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01007854 // If we need to do implicit bitcasts, make sure we do it with the correct type.
7855 uint32_t integer_width = get_integer_width_for_instruction(i);
7856 auto int_type = to_signed_basetype(integer_width);
7857 auto uint_type = to_unsigned_basetype(integer_width);
7858
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007859 switch (op)
7860 {
7861 case OpGroupNonUniformElect:
crissdb52e272020-10-08 12:14:52 +02007862 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupElect);
7863 break;
7864
7865 case OpGroupNonUniformBallotBitCount:
7866 {
7867 const GroupOperation operation = static_cast<GroupOperation>(ops[3]);
7868 if (operation == GroupOperationReduce)
7869 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitCount);
7870 else if (operation == GroupOperationInclusiveScan || operation == GroupOperationExclusiveScan)
7871 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
7872 }
7873 break;
7874
7875 case OpGroupNonUniformBallotBitExtract:
7876 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitExtract);
7877 break;
7878
7879 case OpGroupNonUniformInverseBallot:
7880 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
7881 break;
7882
7883 case OpGroupNonUniformBallot:
7884 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallot);
7885 break;
7886
7887 case OpGroupNonUniformBallotFindLSB:
7888 case OpGroupNonUniformBallotFindMSB:
7889 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotFindLSB_MSB);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007890 break;
7891
7892 case OpGroupNonUniformBroadcast:
7893 case OpGroupNonUniformBroadcastFirst:
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01007894 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBroadcast_First);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007895 break;
7896
7897 case OpGroupNonUniformShuffle:
7898 case OpGroupNonUniformShuffleXor:
7899 require_extension_internal("GL_KHR_shader_subgroup_shuffle");
7900 break;
7901
7902 case OpGroupNonUniformShuffleUp:
7903 case OpGroupNonUniformShuffleDown:
7904 require_extension_internal("GL_KHR_shader_subgroup_shuffle_relative");
7905 break;
7906
7907 case OpGroupNonUniformAll:
7908 case OpGroupNonUniformAny:
7909 case OpGroupNonUniformAllEqual:
crissdb52e272020-10-08 12:14:52 +02007910 {
7911 const SPIRType &type = expression_type(ops[3]);
7912 if (type.basetype == SPIRType::BaseType::Boolean && type.vecsize == 1u)
7913 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAll_Any_AllEqualBool);
7914 else
7915 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAllEqualT);
7916 }
7917 break;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007918
7919 case OpGroupNonUniformFAdd:
7920 case OpGroupNonUniformFMul:
7921 case OpGroupNonUniformFMin:
7922 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007923 case OpGroupNonUniformIAdd:
7924 case OpGroupNonUniformIMul:
7925 case OpGroupNonUniformSMin:
7926 case OpGroupNonUniformSMax:
7927 case OpGroupNonUniformUMin:
7928 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007929 case OpGroupNonUniformBitwiseAnd:
7930 case OpGroupNonUniformBitwiseOr:
7931 case OpGroupNonUniformBitwiseXor:
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +01007932 case OpGroupNonUniformLogicalAnd:
7933 case OpGroupNonUniformLogicalOr:
7934 case OpGroupNonUniformLogicalXor:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007935 {
7936 auto operation = static_cast<GroupOperation>(ops[3]);
7937 if (operation == GroupOperationClusteredReduce)
7938 {
7939 require_extension_internal("GL_KHR_shader_subgroup_clustered");
7940 }
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02007941 else if (operation == GroupOperationExclusiveScan || operation == GroupOperationInclusiveScan ||
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007942 operation == GroupOperationReduce)
7943 {
7944 require_extension_internal("GL_KHR_shader_subgroup_arithmetic");
7945 }
7946 else
7947 SPIRV_CROSS_THROW("Invalid group operation.");
7948 break;
7949 }
7950
7951 case OpGroupNonUniformQuadSwap:
7952 case OpGroupNonUniformQuadBroadcast:
7953 require_extension_internal("GL_KHR_shader_subgroup_quad");
7954 break;
7955
7956 default:
7957 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
7958 }
7959
7960 uint32_t result_type = ops[0];
7961 uint32_t id = ops[1];
7962
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02007963 auto scope = static_cast<Scope>(evaluate_constant_u32(ops[2]));
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007964 if (scope != ScopeSubgroup)
7965 SPIRV_CROSS_THROW("Only subgroup scope is supported.");
7966
7967 switch (op)
7968 {
7969 case OpGroupNonUniformElect:
7970 emit_op(result_type, id, "subgroupElect()", true);
7971 break;
7972
7973 case OpGroupNonUniformBroadcast:
7974 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBroadcast");
7975 break;
7976
7977 case OpGroupNonUniformBroadcastFirst:
7978 emit_unary_func_op(result_type, id, ops[3], "subgroupBroadcastFirst");
7979 break;
7980
7981 case OpGroupNonUniformBallot:
7982 emit_unary_func_op(result_type, id, ops[3], "subgroupBallot");
7983 break;
7984
7985 case OpGroupNonUniformInverseBallot:
7986 emit_unary_func_op(result_type, id, ops[3], "subgroupInverseBallot");
7987 break;
7988
7989 case OpGroupNonUniformBallotBitExtract:
7990 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBallotBitExtract");
7991 break;
7992
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007993 case OpGroupNonUniformBallotFindLSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007994 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindLSB");
7995 break;
7996
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007997 case OpGroupNonUniformBallotFindMSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007998 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindMSB");
7999 break;
8000
8001 case OpGroupNonUniformBallotBitCount:
8002 {
8003 auto operation = static_cast<GroupOperation>(ops[3]);
8004 if (operation == GroupOperationReduce)
8005 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotBitCount");
8006 else if (operation == GroupOperationInclusiveScan)
8007 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotInclusiveBitCount");
8008 else if (operation == GroupOperationExclusiveScan)
8009 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotExclusiveBitCount");
8010 else
8011 SPIRV_CROSS_THROW("Invalid BitCount operation.");
8012 break;
8013 }
8014
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008015 case OpGroupNonUniformShuffle:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008016 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffle");
8017 break;
8018
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008019 case OpGroupNonUniformShuffleXor:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008020 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleXor");
8021 break;
8022
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008023 case OpGroupNonUniformShuffleUp:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008024 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleUp");
8025 break;
8026
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008027 case OpGroupNonUniformShuffleDown:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008028 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleDown");
8029 break;
8030
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008031 case OpGroupNonUniformAll:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008032 emit_unary_func_op(result_type, id, ops[3], "subgroupAll");
8033 break;
8034
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008035 case OpGroupNonUniformAny:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008036 emit_unary_func_op(result_type, id, ops[3], "subgroupAny");
8037 break;
8038
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008039 case OpGroupNonUniformAllEqual:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008040 emit_unary_func_op(result_type, id, ops[3], "subgroupAllEqual");
8041 break;
8042
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008043 // clang-format off
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008044#define GLSL_GROUP_OP(op, glsl_op) \
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008045case OpGroupNonUniform##op: \
8046 { \
8047 auto operation = static_cast<GroupOperation>(ops[3]); \
8048 if (operation == GroupOperationReduce) \
8049 emit_unary_func_op(result_type, id, ops[4], "subgroup" #glsl_op); \
8050 else if (operation == GroupOperationInclusiveScan) \
8051 emit_unary_func_op(result_type, id, ops[4], "subgroupInclusive" #glsl_op); \
8052 else if (operation == GroupOperationExclusiveScan) \
8053 emit_unary_func_op(result_type, id, ops[4], "subgroupExclusive" #glsl_op); \
8054 else if (operation == GroupOperationClusteredReduce) \
8055 emit_binary_func_op(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op); \
8056 else \
8057 SPIRV_CROSS_THROW("Invalid group operation."); \
8058 break; \
8059 }
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008060
8061#define GLSL_GROUP_OP_CAST(op, glsl_op, type) \
8062case OpGroupNonUniform##op: \
8063 { \
8064 auto operation = static_cast<GroupOperation>(ops[3]); \
8065 if (operation == GroupOperationReduce) \
8066 emit_unary_func_op_cast(result_type, id, ops[4], "subgroup" #glsl_op, type, type); \
8067 else if (operation == GroupOperationInclusiveScan) \
8068 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupInclusive" #glsl_op, type, type); \
8069 else if (operation == GroupOperationExclusiveScan) \
8070 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupExclusive" #glsl_op, type, type); \
8071 else if (operation == GroupOperationClusteredReduce) \
8072 emit_binary_func_op_cast_clustered(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op, type); \
8073 else \
8074 SPIRV_CROSS_THROW("Invalid group operation."); \
8075 break; \
8076 }
8077
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008078 GLSL_GROUP_OP(FAdd, Add)
8079 GLSL_GROUP_OP(FMul, Mul)
8080 GLSL_GROUP_OP(FMin, Min)
8081 GLSL_GROUP_OP(FMax, Max)
8082 GLSL_GROUP_OP(IAdd, Add)
8083 GLSL_GROUP_OP(IMul, Mul)
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008084 GLSL_GROUP_OP_CAST(SMin, Min, int_type)
8085 GLSL_GROUP_OP_CAST(SMax, Max, int_type)
8086 GLSL_GROUP_OP_CAST(UMin, Min, uint_type)
8087 GLSL_GROUP_OP_CAST(UMax, Max, uint_type)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008088 GLSL_GROUP_OP(BitwiseAnd, And)
8089 GLSL_GROUP_OP(BitwiseOr, Or)
8090 GLSL_GROUP_OP(BitwiseXor, Xor)
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +01008091 GLSL_GROUP_OP(LogicalAnd, And)
8092 GLSL_GROUP_OP(LogicalOr, Or)
8093 GLSL_GROUP_OP(LogicalXor, Xor)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008094#undef GLSL_GROUP_OP
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008095#undef GLSL_GROUP_OP_CAST
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008096 // clang-format on
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008097
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008098 case OpGroupNonUniformQuadSwap:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008099 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008100 uint32_t direction = evaluate_constant_u32(ops[4]);
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008101 if (direction == 0)
8102 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapHorizontal");
8103 else if (direction == 1)
8104 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapVertical");
8105 else if (direction == 2)
8106 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapDiagonal");
8107 else
8108 SPIRV_CROSS_THROW("Invalid quad swap direction.");
8109 break;
8110 }
8111
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008112 case OpGroupNonUniformQuadBroadcast:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008113 {
8114 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupQuadBroadcast");
8115 break;
8116 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008117
8118 default:
8119 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
8120 }
8121
8122 register_control_dependent_expression(id);
8123}
8124
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008125string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008126{
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008127 // OpBitcast can deal with pointers.
8128 if (out_type.pointer || in_type.pointer)
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +02008129 {
8130 if (out_type.vecsize == 2 || in_type.vecsize == 2)
8131 require_extension_internal("GL_EXT_buffer_reference_uvec2");
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008132 return type_to_glsl(out_type);
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +02008133 }
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008134
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008135 if (out_type.basetype == in_type.basetype)
8136 return "";
8137
Chip Davisef0b1fc2019-01-30 20:19:05 -06008138 assert(out_type.basetype != SPIRType::Boolean);
8139 assert(in_type.basetype != SPIRType::Boolean);
8140
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008141 bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
8142 bool same_size_cast = out_type.width == in_type.width;
8143
8144 // Trivial bitcast case, casts between integers.
8145 if (integral_cast && same_size_cast)
Chip Davis0d949e12018-11-05 14:55:56 -06008146 return type_to_glsl(out_type);
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008147
8148 // Catch-all 8-bit arithmetic casts (GL_EXT_shader_explicit_arithmetic_types).
8149 if (out_type.width == 8 && in_type.width >= 16 && integral_cast && in_type.vecsize == 1)
8150 return "unpack8";
8151 else if (in_type.width == 8 && out_type.width == 16 && integral_cast && out_type.vecsize == 1)
8152 return "pack16";
8153 else if (in_type.width == 8 && out_type.width == 32 && integral_cast && out_type.vecsize == 1)
8154 return "pack32";
8155
8156 // Floating <-> Integer special casts. Just have to enumerate all cases. :(
8157 // 16-bit, 32-bit and 64-bit floats.
8158 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008159 {
8160 if (is_legacy_es())
8161 SPIRV_CROSS_THROW("Float -> Uint bitcast not supported on legacy ESSL.");
8162 else if (!options.es && options.version < 330)
8163 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008164 return "floatBitsToUint";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008165 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008166 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008167 {
8168 if (is_legacy_es())
8169 SPIRV_CROSS_THROW("Float -> Int bitcast not supported on legacy ESSL.");
8170 else if (!options.es && options.version < 330)
8171 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008172 return "floatBitsToInt";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008173 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008174 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008175 {
8176 if (is_legacy_es())
8177 SPIRV_CROSS_THROW("Uint -> Float bitcast not supported on legacy ESSL.");
8178 else if (!options.es && options.version < 330)
8179 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008180 return "uintBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008181 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008182 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008183 {
8184 if (is_legacy_es())
8185 SPIRV_CROSS_THROW("Int -> Float bitcast not supported on legacy ESSL.");
8186 else if (!options.es && options.version < 330)
8187 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008188 return "intBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008189 }
8190
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02008191 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
8192 return "doubleBitsToInt64";
8193 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
8194 return "doubleBitsToUint64";
8195 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
8196 return "int64BitsToDouble";
8197 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
8198 return "uint64BitsToDouble";
Chip Davis0d949e12018-11-05 14:55:56 -06008199 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Half)
8200 return "float16BitsToInt16";
8201 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half)
8202 return "float16BitsToUint16";
8203 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Short)
8204 return "int16BitsToFloat16";
8205 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
8206 return "uint16BitsToFloat16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008207
8208 // And finally, some even more special purpose casts.
8209 if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
Lou Kramer6671f522017-11-21 14:04:57 +01008210 return "packUint2x32";
Asuka55dfbea2020-04-17 22:46:06 +08008211 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UInt64 && out_type.vecsize == 2)
8212 return "unpackUint2x32";
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008213 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
8214 return "unpackFloat2x16";
8215 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)
8216 return "packFloat2x16";
Chip Davis0d949e12018-11-05 14:55:56 -06008217 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Short && in_type.vecsize == 2)
8218 return "packInt2x16";
8219 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int && in_type.vecsize == 1)
8220 return "unpackInt2x16";
8221 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UShort && in_type.vecsize == 2)
8222 return "packUint2x16";
8223 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
8224 return "unpackUint2x16";
8225 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Short && in_type.vecsize == 4)
8226 return "packInt4x16";
8227 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int64 && in_type.vecsize == 1)
8228 return "unpackInt4x16";
8229 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UShort && in_type.vecsize == 4)
8230 return "packUint4x16";
8231 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt64 && in_type.vecsize == 1)
8232 return "unpackUint4x16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008233
8234 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008235}
8236
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008237string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008238{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008239 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008240 if (op.empty())
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02008241 return to_enclosed_unpacked_expression(argument);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008242 else
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02008243 return join(op, "(", to_unpacked_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008244}
8245
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008246std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg)
8247{
8248 auto expr = to_expression(arg);
8249 auto &src_type = expression_type(arg);
8250 if (src_type.basetype != target_type)
8251 {
8252 auto target = src_type;
8253 target.basetype = target_type;
8254 expr = join(bitcast_glsl_op(target, src_type), "(", expr, ")");
8255 }
8256
8257 return expr;
8258}
8259
8260std::string CompilerGLSL::bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type,
8261 const std::string &expr)
8262{
8263 if (target_type.basetype == expr_type)
8264 return expr;
8265
8266 auto src_type = target_type;
8267 src_type.basetype = expr_type;
8268 return join(bitcast_glsl_op(target_type, src_type), "(", expr, ")");
8269}
8270
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008271string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008272{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008273 switch (builtin)
8274 {
8275 case BuiltInPosition:
8276 return "gl_Position";
8277 case BuiltInPointSize:
8278 return "gl_PointSize";
Bill Hollingse73e8e42016-12-17 17:07:53 -05008279 case BuiltInClipDistance:
8280 return "gl_ClipDistance";
Hans-Kristian Arntzen7f2e1792017-03-05 12:44:29 +01008281 case BuiltInCullDistance:
8282 return "gl_CullDistance";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008283 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008284 if (options.vulkan_semantics)
crissdb52e272020-10-08 12:14:52 +02008285 SPIRV_CROSS_THROW("Cannot implement gl_VertexID in Vulkan GLSL. This shader was created "
8286 "with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008287 return "gl_VertexID";
8288 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008289 if (options.vulkan_semantics)
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02008290 {
8291 auto model = get_entry_point().model;
8292 switch (model)
8293 {
8294 case spv::ExecutionModelIntersectionKHR:
8295 case spv::ExecutionModelAnyHitKHR:
8296 case spv::ExecutionModelClosestHitKHR:
8297 // gl_InstanceID is allowed in these shaders.
8298 break;
8299
8300 default:
crissdb52e272020-10-08 12:14:52 +02008301 SPIRV_CROSS_THROW("Cannot implement gl_InstanceID in Vulkan GLSL. This shader was "
8302 "created with GL semantics.");
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02008303 }
8304 }
rdb031cbaa2020-06-12 22:42:26 +02008305 if (!options.es && options.version < 140)
8306 {
8307 require_extension_internal("GL_ARB_draw_instanced");
8308 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008309 return "gl_InstanceID";
8310 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008311 if (options.vulkan_semantics)
8312 return "gl_VertexIndex";
8313 else
8314 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008315 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008316 if (options.vulkan_semantics)
8317 return "gl_InstanceIndex";
rdb031cbaa2020-06-12 22:42:26 +02008318
8319 if (!options.es && options.version < 140)
8320 {
8321 require_extension_internal("GL_ARB_draw_instanced");
8322 }
8323
8324 if (options.vertex.support_nonzero_base_instance)
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008325 {
8326 if (!options.vulkan_semantics)
8327 {
8328 // This is a soft-enable. We will opt-in to using gl_BaseInstanceARB if supported.
8329 require_extension_internal("GL_ARB_shader_draw_parameters");
8330 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008331 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008332 }
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02008333 else
8334 return "gl_InstanceID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008335 case BuiltInPrimitiveId:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02008336 if (storage == StorageClassInput && get_entry_point().model == ExecutionModelGeometry)
8337 return "gl_PrimitiveIDIn";
8338 else
8339 return "gl_PrimitiveID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008340 case BuiltInInvocationId:
8341 return "gl_InvocationID";
8342 case BuiltInLayer:
8343 return "gl_Layer";
Hans-Kristian Arntzenf825bd92018-01-04 12:41:25 +01008344 case BuiltInViewportIndex:
8345 return "gl_ViewportIndex";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008346 case BuiltInTessLevelOuter:
8347 return "gl_TessLevelOuter";
8348 case BuiltInTessLevelInner:
8349 return "gl_TessLevelInner";
8350 case BuiltInTessCoord:
8351 return "gl_TessCoord";
8352 case BuiltInFragCoord:
8353 return "gl_FragCoord";
8354 case BuiltInPointCoord:
8355 return "gl_PointCoord";
8356 case BuiltInFrontFacing:
8357 return "gl_FrontFacing";
8358 case BuiltInFragDepth:
8359 return "gl_FragDepth";
8360 case BuiltInNumWorkgroups:
8361 return "gl_NumWorkGroups";
8362 case BuiltInWorkgroupSize:
8363 return "gl_WorkGroupSize";
8364 case BuiltInWorkgroupId:
8365 return "gl_WorkGroupID";
8366 case BuiltInLocalInvocationId:
8367 return "gl_LocalInvocationID";
8368 case BuiltInGlobalInvocationId:
8369 return "gl_GlobalInvocationID";
8370 case BuiltInLocalInvocationIndex:
8371 return "gl_LocalInvocationIndex";
Hans-Kristian Arntzen61f1d8b2018-11-28 15:18:43 +01008372 case BuiltInHelperInvocation:
8373 return "gl_HelperInvocation";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008374
Chip Davisfcad0192018-08-28 13:47:29 -05008375 case BuiltInBaseVertex:
8376 if (options.es)
8377 SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008378
8379 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008380 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008381 if (options.version < 460)
8382 {
8383 require_extension_internal("GL_ARB_shader_draw_parameters");
8384 return "gl_BaseVertexARB";
8385 }
8386 return "gl_BaseVertex";
Chip Davisfcad0192018-08-28 13:47:29 -05008387 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008388 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8389 require_extension_internal("GL_ARB_shader_draw_parameters");
8390 return "SPIRV_Cross_BaseVertex";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008391
Chip Davisfcad0192018-08-28 13:47:29 -05008392 case BuiltInBaseInstance:
8393 if (options.es)
8394 SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008395
8396 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008397 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008398 if (options.version < 460)
8399 {
8400 require_extension_internal("GL_ARB_shader_draw_parameters");
8401 return "gl_BaseInstanceARB";
8402 }
8403 return "gl_BaseInstance";
Chip Davisfcad0192018-08-28 13:47:29 -05008404 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008405 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8406 require_extension_internal("GL_ARB_shader_draw_parameters");
8407 return "SPIRV_Cross_BaseInstance";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008408
Chip Davisfcad0192018-08-28 13:47:29 -05008409 case BuiltInDrawIndex:
8410 if (options.es)
8411 SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008412
8413 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008414 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008415 if (options.version < 460)
8416 {
8417 require_extension_internal("GL_ARB_shader_draw_parameters");
8418 return "gl_DrawIDARB";
8419 }
8420 return "gl_DrawID";
8421 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008422 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8423 require_extension_internal("GL_ARB_shader_draw_parameters");
8424 return "gl_DrawIDARB";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008425
8426 case BuiltInSampleId:
8427 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008428 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008429 if (!options.es && options.version < 400)
8430 SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
8431 return "gl_SampleID";
8432
8433 case BuiltInSampleMask:
8434 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008435 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008436 if (!options.es && options.version < 400)
8437 SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
8438
8439 if (storage == StorageClassInput)
8440 return "gl_SampleMaskIn";
8441 else
8442 return "gl_SampleMask";
8443
8444 case BuiltInSamplePosition:
8445 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008446 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008447 if (!options.es && options.version < 400)
8448 SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
8449 return "gl_SamplePosition";
8450
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008451 case BuiltInViewIndex:
8452 if (options.vulkan_semantics)
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008453 return "gl_ViewIndex";
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008454 else
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008455 return "gl_ViewID_OVR";
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008456
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008457 case BuiltInNumSubgroups:
crissdb52e272020-10-08 12:14:52 +02008458 request_subgroup_feature(ShaderSubgroupSupportHelper::NumSubgroups);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008459 return "gl_NumSubgroups";
8460
8461 case BuiltInSubgroupId:
crissdb52e272020-10-08 12:14:52 +02008462 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008463 return "gl_SubgroupID";
8464
8465 case BuiltInSubgroupSize:
crissdb52e272020-10-08 12:14:52 +02008466 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupSize);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008467 return "gl_SubgroupSize";
8468
8469 case BuiltInSubgroupLocalInvocationId:
crissdb52e272020-10-08 12:14:52 +02008470 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInvocationID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008471 return "gl_SubgroupInvocationID";
8472
8473 case BuiltInSubgroupEqMask:
crissdb52e272020-10-08 12:14:52 +02008474 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008475 return "gl_SubgroupEqMask";
8476
8477 case BuiltInSubgroupGeMask:
crissdb52e272020-10-08 12:14:52 +02008478 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008479 return "gl_SubgroupGeMask";
8480
8481 case BuiltInSubgroupGtMask:
crissdb52e272020-10-08 12:14:52 +02008482 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008483 return "gl_SubgroupGtMask";
8484
8485 case BuiltInSubgroupLeMask:
crissdb52e272020-10-08 12:14:52 +02008486 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008487 return "gl_SubgroupLeMask";
8488
8489 case BuiltInSubgroupLtMask:
crissdb52e272020-10-08 12:14:52 +02008490 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008491 return "gl_SubgroupLtMask";
8492
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008493 case BuiltInLaunchIdKHR:
8494 return ray_tracing_is_khr ? "gl_LaunchIDEXT" : "gl_LaunchIDNV";
8495 case BuiltInLaunchSizeKHR:
8496 return ray_tracing_is_khr ? "gl_LaunchSizeEXT" : "gl_LaunchSizeNV";
8497 case BuiltInWorldRayOriginKHR:
8498 return ray_tracing_is_khr ? "gl_WorldRayOriginEXT" : "gl_WorldRayOriginNV";
8499 case BuiltInWorldRayDirectionKHR:
8500 return ray_tracing_is_khr ? "gl_WorldRayDirectionEXT" : "gl_WorldRayDirectionNV";
8501 case BuiltInObjectRayOriginKHR:
8502 return ray_tracing_is_khr ? "gl_ObjectRayOriginEXT" : "gl_ObjectRayOriginNV";
8503 case BuiltInObjectRayDirectionKHR:
8504 return ray_tracing_is_khr ? "gl_ObjectRayDirectionEXT" : "gl_ObjectRayDirectionNV";
8505 case BuiltInRayTminKHR:
8506 return ray_tracing_is_khr ? "gl_RayTminEXT" : "gl_RayTminNV";
8507 case BuiltInRayTmaxKHR:
8508 return ray_tracing_is_khr ? "gl_RayTmaxEXT" : "gl_RayTmaxNV";
8509 case BuiltInInstanceCustomIndexKHR:
8510 return ray_tracing_is_khr ? "gl_InstanceCustomIndexEXT" : "gl_InstanceCustomIndexNV";
8511 case BuiltInObjectToWorldKHR:
8512 return ray_tracing_is_khr ? "gl_ObjectToWorldEXT" : "gl_ObjectToWorldNV";
8513 case BuiltInWorldToObjectKHR:
8514 return ray_tracing_is_khr ? "gl_WorldToObjectEXT" : "gl_WorldToObjectNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +01008515 case BuiltInHitTNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008516 // gl_HitTEXT is an alias of RayTMax in KHR.
Patrick Moursda39a7b2019-02-26 15:43:03 +01008517 return "gl_HitTNV";
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008518 case BuiltInHitKindKHR:
8519 return ray_tracing_is_khr ? "gl_HitKindEXT" : "gl_HitKindNV";
8520 case BuiltInIncomingRayFlagsKHR:
8521 return ray_tracing_is_khr ? "gl_IncomingRayFlagsEXT" : "gl_IncomingRayFlagsNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +01008522
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008523 case BuiltInBaryCoordNV:
8524 {
8525 if (options.es && options.version < 320)
8526 SPIRV_CROSS_THROW("gl_BaryCoordNV requires ESSL 320.");
8527 else if (!options.es && options.version < 450)
8528 SPIRV_CROSS_THROW("gl_BaryCoordNV requires GLSL 450.");
8529 require_extension_internal("GL_NV_fragment_shader_barycentric");
8530 return "gl_BaryCoordNV";
8531 }
8532
8533 case BuiltInBaryCoordNoPerspNV:
8534 {
8535 if (options.es && options.version < 320)
8536 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires ESSL 320.");
8537 else if (!options.es && options.version < 450)
8538 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires GLSL 450.");
8539 require_extension_internal("GL_NV_fragment_shader_barycentric");
8540 return "gl_BaryCoordNoPerspNV";
8541 }
8542
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +02008543 case BuiltInFragStencilRefEXT:
8544 {
8545 if (!options.es)
8546 {
8547 require_extension_internal("GL_ARB_shader_stencil_export");
8548 return "gl_FragStencilRefARB";
8549 }
8550 else
8551 SPIRV_CROSS_THROW("Stencil export not supported in GLES.");
8552 }
8553
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +02008554 case BuiltInPrimitiveShadingRateKHR:
8555 {
8556 if (!options.vulkan_semantics)
8557 SPIRV_CROSS_THROW("Can only use PrimitiveShadingRateKHR in Vulkan GLSL.");
8558 require_extension_internal("GL_EXT_fragment_shading_rate");
8559 return "gl_PrimitiveShadingRateEXT";
8560 }
8561
8562 case BuiltInShadingRateKHR:
8563 {
8564 if (!options.vulkan_semantics)
8565 SPIRV_CROSS_THROW("Can only use ShadingRateKHR in Vulkan GLSL.");
8566 require_extension_internal("GL_EXT_fragment_shading_rate");
8567 return "gl_ShadingRateEXT";
8568 }
8569
Chip Davis6a585542019-07-12 21:50:50 -05008570 case BuiltInDeviceIndex:
8571 if (!options.vulkan_semantics)
8572 SPIRV_CROSS_THROW("Need Vulkan semantics for device group support.");
8573 require_extension_internal("GL_EXT_device_group");
8574 return "gl_DeviceIndex";
8575
Hans-Kristian Arntzen3fd14842021-04-20 13:44:52 +02008576 case BuiltInFullyCoveredEXT:
8577 if (!options.es)
8578 require_extension_internal("GL_NV_conservative_raster_underestimation");
8579 else
8580 SPIRV_CROSS_THROW("Need desktop GL to use GL_NV_conservative_raster_underestimation.");
8581 return "gl_FragFullyCoveredNV";
8582
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008583 default:
Bill Hollingse73e8e42016-12-17 17:07:53 -05008584 return join("gl_BuiltIn_", convert_to_string(builtin));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008585 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008586}
8587
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008588const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008589{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008590 switch (index)
8591 {
8592 case 0:
8593 return "x";
8594 case 1:
8595 return "y";
8596 case 2:
8597 return "z";
8598 case 3:
8599 return "w";
8600 default:
Bill Hollings595eb0c2021-10-20 14:46:30 -04008601 return "x"; // Don't crash, but engage the "undefined behavior" described for out-of-bounds logical addressing in spec.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008602 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008603}
8604
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02008605void CompilerGLSL::access_chain_internal_append_index(std::string &expr, uint32_t /*base*/, const SPIRType * /*type*/,
Lukas Hermanns6673a672019-10-22 11:06:16 -04008606 AccessChainFlags flags, bool & /*access_chain_is_arrayed*/,
8607 uint32_t index)
8608{
8609 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
8610 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
8611
8612 expr += "[";
8613
Lukas Hermanns6673a672019-10-22 11:06:16 -04008614 if (index_is_literal)
8615 expr += convert_to_string(index);
8616 else
Bill Hollings974a0812021-10-21 16:11:33 -04008617 expr += to_unpacked_expression(index, register_expression_read);
Lukas Hermanns6673a672019-10-22 11:06:16 -04008618
Lukas Hermanns6673a672019-10-22 11:06:16 -04008619 expr += "]";
8620}
8621
Hans-Kristian Arntzen75ed7382021-04-14 15:10:02 +02008622bool CompilerGLSL::access_chain_needs_stage_io_builtin_translation(uint32_t)
8623{
8624 return true;
8625}
8626
Hans-Kristian Arntzeneb5e09f2017-02-23 19:33:14 +01008627string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008628 AccessChainFlags flags, AccessChainMeta *meta)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008629{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008630 string expr;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008631
8632 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008633 bool msb_is_id = (flags & ACCESS_CHAIN_LITERAL_MSB_FORCE_ID) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008634 bool chain_only = (flags & ACCESS_CHAIN_CHAIN_ONLY_BIT) != 0;
8635 bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0;
8636 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008637 bool flatten_member_reference = (flags & ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008638
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008639 if (!chain_only)
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008640 {
8641 // We handle transpose explicitly, so don't resolve that here.
8642 auto *e = maybe_get<SPIRExpression>(base);
8643 bool old_transpose = e && e->need_transpose;
8644 if (e)
8645 e->need_transpose = false;
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008646 expr = to_enclosed_expression(base, register_expression_read);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008647 if (e)
8648 e->need_transpose = old_transpose;
8649 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008650
Bill Hollings1e84a372017-08-12 00:21:13 -04008651 // Start traversing type hierarchy at the proper non-pointer types,
8652 // but keep type_id referencing the original pointer for use below.
Bill Hollingse0910312018-06-24 15:06:12 -04008653 uint32_t type_id = expression_type_id(base);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02008654
8655 if (!backend.native_pointers)
8656 {
8657 if (ptr_chain)
8658 SPIRV_CROSS_THROW("Backend does not support native pointers and does not support OpPtrAccessChain.");
8659
8660 // Wrapped buffer reference pointer types will need to poke into the internal "value" member before
8661 // continuing the access chain.
8662 if (should_dereference(base))
8663 {
8664 auto &type = get<SPIRType>(type_id);
8665 expr = dereference_expression(type, expr);
8666 }
8667 }
8668
Chip Davisfc02b3d2019-01-08 12:54:40 -06008669 const auto *type = &get_pointee_type(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008670
Hans-Kristian Arntzenb71f5df2018-05-08 15:33:51 +02008671 bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos;
Bill Hollings13583622016-12-14 02:12:52 -05008672 bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008673 bool is_packed = has_extended_decoration(base, SPIRVCrossDecorationPhysicalTypePacked);
8674 uint32_t physical_type = get_extended_decoration(base, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008675 bool is_invariant = has_decoration(base, DecorationInvariant);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008676 bool pending_array_enclose = false;
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008677 bool dimension_flatten = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008678
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008679 const auto append_index = [&](uint32_t index, bool is_literal) {
8680 AccessChainFlags mod_flags = flags;
8681 if (!is_literal)
8682 mod_flags &= ~ACCESS_CHAIN_INDEX_IS_LITERAL_BIT;
8683 access_chain_internal_append_index(expr, base, type, mod_flags, access_chain_is_arrayed, index);
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02008684 };
8685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008686 for (uint32_t i = 0; i < count; i++)
8687 {
8688 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008689
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008690 bool is_literal = index_is_literal;
8691 if (is_literal && msb_is_id && (index >> 31u) != 0u)
8692 {
8693 is_literal = false;
8694 index &= 0x7fffffffu;
8695 }
8696
Chip Davis3bfb2f92018-12-03 02:06:33 -06008697 // Pointer chains
8698 if (ptr_chain && i == 0)
8699 {
8700 // If we are flattening multidimensional arrays, only create opening bracket on first
8701 // array index.
8702 if (options.flatten_multidimensional_arrays)
8703 {
8704 dimension_flatten = type->array.size() >= 1;
8705 pending_array_enclose = dimension_flatten;
8706 if (pending_array_enclose)
8707 expr += "[";
8708 }
8709
8710 if (options.flatten_multidimensional_arrays && dimension_flatten)
8711 {
8712 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008713 if (is_literal)
Chip Davis3bfb2f92018-12-03 02:06:33 -06008714 expr += convert_to_string(index);
8715 else
8716 expr += to_enclosed_expression(index, register_expression_read);
8717
8718 for (auto j = uint32_t(type->array.size()); j; j--)
8719 {
8720 expr += " * ";
8721 expr += enclose_expression(to_array_size(*type, j - 1));
8722 }
8723
8724 if (type->array.empty())
8725 pending_array_enclose = false;
8726 else
8727 expr += " + ";
8728
8729 if (!pending_array_enclose)
8730 expr += "]";
8731 }
8732 else
8733 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008734 append_index(index, is_literal);
Chip Davis3bfb2f92018-12-03 02:06:33 -06008735 }
8736
Chip Davise75add42019-02-05 18:13:26 -06008737 if (type->basetype == SPIRType::ControlPointArray)
8738 {
8739 type_id = type->parent_type;
8740 type = &get<SPIRType>(type_id);
8741 }
8742
Chip Davis3bfb2f92018-12-03 02:06:33 -06008743 access_chain_is_arrayed = true;
8744 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008745 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06008746 else if (!type->array.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008747 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008748 // If we are flattening multidimensional arrays, only create opening bracket on first
8749 // array index.
8750 if (options.flatten_multidimensional_arrays && !pending_array_enclose)
8751 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008752 dimension_flatten = type->array.size() > 1;
8753 pending_array_enclose = dimension_flatten;
8754 if (pending_array_enclose)
8755 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008756 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008757
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01008758 assert(type->parent_type);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008759
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008760 auto *var = maybe_get<SPIRVariable>(base);
Bill Hollings27d4af72018-01-08 16:18:34 -05008761 if (backend.force_gl_in_out_block && i == 0 && var && is_builtin_variable(*var) &&
8762 !has_decoration(type->self, DecorationBlock))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008763 {
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008764 // This deals with scenarios for tesc/geom where arrays of gl_Position[] are declared.
8765 // Normally, these variables live in blocks when compiled from GLSL,
8766 // but HLSL seems to just emit straight arrays here.
8767 // We must pretend this access goes through gl_in/gl_out arrays
8768 // to be able to access certain builtins as arrays.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02008769 auto builtin = ir.meta[base].decoration.builtin_type;
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008770 switch (builtin)
8771 {
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01008772 // case BuiltInCullDistance: // These are already arrays, need to figure out rules for these in tess/geom.
8773 // case BuiltInClipDistance:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008774 case BuiltInPosition:
8775 case BuiltInPointSize:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008776 if (var->storage == StorageClassInput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008777 expr = join("gl_in[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008778 else if (var->storage == StorageClassOutput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008779 expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008780 else
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008781 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008782 break;
8783
8784 default:
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008785 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008786 break;
8787 }
8788 }
8789 else if (options.flatten_multidimensional_arrays && dimension_flatten)
8790 {
8791 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008792 auto &parent_type = get<SPIRType>(type->parent_type);
8793
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008794 if (is_literal)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008795 expr += convert_to_string(index);
8796 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008797 expr += to_enclosed_expression(index, register_expression_read);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008798
8799 for (auto j = uint32_t(parent_type.array.size()); j; j--)
8800 {
8801 expr += " * ";
8802 expr += enclose_expression(to_array_size(parent_type, j - 1));
8803 }
8804
8805 if (parent_type.array.empty())
8806 pending_array_enclose = false;
8807 else
8808 expr += " + ";
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008809
8810 if (!pending_array_enclose)
8811 expr += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008812 }
Hans-Kristian Arntzen9d18c822019-10-24 17:10:22 +02008813 // 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.
8814 // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask.
8815 else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn))))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008816 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008817 append_index(index, is_literal);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008818 }
8819
Bill Hollings1e84a372017-08-12 00:21:13 -04008820 type_id = type->parent_type;
8821 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008823 access_chain_is_arrayed = true;
8824 }
Bill Hollings76cb8072021-10-28 10:16:34 -04008825 // For structs, the index refers to a constant, which indexes into the members, possibly through a redirection mapping.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008826 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
8827 else if (type->basetype == SPIRType::Struct)
8828 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008829 if (!is_literal)
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008830 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008831
Bill Hollings76cb8072021-10-28 10:16:34 -04008832 if (index < uint32_t(type->member_type_index_redirection.size()))
8833 index = type->member_type_index_redirection[index];
8834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008835 if (index >= type->member_types.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008836 SPIRV_CROSS_THROW("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008837
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008838 BuiltIn builtin;
Hans-Kristian Arntzen75ed7382021-04-14 15:10:02 +02008839 if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008840 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008841 if (access_chain_is_arrayed)
8842 {
8843 expr += ".";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008844 expr += builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008845 }
8846 else
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008847 expr = builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008848 }
8849 else
8850 {
Bill Hollingsc1b81542017-05-22 21:41:19 -04008851 // If the member has a qualified name, use it as the entire chain
Bill Hollings1e84a372017-08-12 00:21:13 -04008852 string qual_mbr_name = get_member_qualified_name(type_id, index);
Bill Hollingsc1b81542017-05-22 21:41:19 -04008853 if (!qual_mbr_name.empty())
8854 expr = qual_mbr_name;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008855 else if (flatten_member_reference)
8856 expr += join("_", to_member_name(*type, index));
Bill Hollingsc1b81542017-05-22 21:41:19 -04008857 else
Chip Davis3bfb2f92018-12-03 02:06:33 -06008858 expr += to_member_reference(base, *type, index, ptr_chain);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008859 }
Bill Hollingsb332bae2017-03-01 13:07:40 -05008860
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008861 if (has_member_decoration(type->self, index, DecorationInvariant))
8862 is_invariant = true;
8863
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008864 is_packed = member_is_packed_physical_type(*type, index);
Hans-Kristian Arntzenf6251e42019-07-19 11:21:02 +02008865 if (member_is_remapped_physical_type(*type, index))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008866 physical_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008867 else
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008868 physical_type = 0;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008869
Bill Hollings13583622016-12-14 02:12:52 -05008870 row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008871 type = &get<SPIRType>(type->member_types[index]);
8872 }
8873 // Matrix -> Vector
8874 else if (type->columns > 1)
8875 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008876 // If we have a row-major matrix here, we need to defer any transpose in case this access chain
8877 // is used to store a column. We can resolve it right here and now if we access a scalar directly,
8878 // by flipping indexing order of the matrix.
Bill Hollings343677e2016-12-11 11:01:08 -05008879
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008880 expr += "[";
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008881 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008882 expr += convert_to_string(index);
8883 else
Bill Hollings974a0812021-10-21 16:11:33 -04008884 expr += to_unpacked_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008885 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008886
Bill Hollings1e84a372017-08-12 00:21:13 -04008887 type_id = type->parent_type;
8888 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008889 }
8890 // Vector -> Scalar
8891 else if (type->vecsize > 1)
8892 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008893 string deferred_index;
8894 if (row_major_matrix_needs_conversion)
8895 {
8896 // Flip indexing order.
8897 auto column_index = expr.find_last_of('[');
8898 if (column_index != string::npos)
8899 {
8900 deferred_index = expr.substr(column_index);
8901 expr.resize(column_index);
8902 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008903 }
8904
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008905 // Internally, access chain implementation can also be used on composites,
8906 // ignore scalar access workarounds in this case.
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02008907 StorageClass effective_storage = StorageClassGeneric;
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008908 bool ignore_potential_sliced_writes = false;
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02008909 if ((flags & ACCESS_CHAIN_FORCE_COMPOSITE_BIT) == 0)
8910 {
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +02008911 if (expression_type(base).pointer)
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02008912 effective_storage = get_expression_effective_storage_class(base);
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008913
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008914 // Special consideration for control points.
8915 // Control points can only be written by InvocationID, so there is no need
8916 // to consider scalar access chains here.
8917 // Cleans up some cases where it's very painful to determine the accurate storage class
8918 // since blocks can be partially masked ...
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +02008919 auto *var = maybe_get_backing_variable(base);
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008920 if (var && var->storage == StorageClassOutput &&
8921 get_execution_model() == ExecutionModelTessellationControl &&
8922 !has_decoration(var->self, DecorationPatch))
8923 {
8924 ignore_potential_sliced_writes = true;
8925 }
8926 }
8927 else
8928 ignore_potential_sliced_writes = true;
8929
8930 if (!row_major_matrix_needs_conversion && !ignore_potential_sliced_writes)
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008931 {
8932 // On some backends, we might not be able to safely access individual scalars in a vector.
8933 // To work around this, we might have to cast the access chain reference to something which can,
8934 // like a pointer to scalar, which we can then index into.
8935 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
8936 is_packed);
8937 }
8938
Sebastián Aedo905b8242021-11-11 12:57:57 -03008939 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008940 {
Sebastián Aedo905b8242021-11-11 12:57:57 -03008941 bool out_of_bounds = (index >= type->vecsize);
8942
8943 if (!is_packed && !row_major_matrix_needs_conversion)
8944 {
8945 expr += ".";
8946 expr += index_to_swizzle(out_of_bounds ? 0 : index);
8947 }
8948 else
8949 {
8950 // For packed vectors, we can only access them as an array, not by swizzle.
8951 expr += join("[", out_of_bounds ? 0 : index, "]");
8952 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008953 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008954 else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008955 {
8956 auto &c = get<SPIRConstant>(index);
Sebastián Aedo905b8242021-11-11 12:57:57 -03008957 bool out_of_bounds = (c.scalar() >= type->vecsize);
8958
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02008959 if (c.specialization)
8960 {
8961 // If the index is a spec constant, we cannot turn extract into a swizzle.
Sebastián Aedo905b8242021-11-11 12:57:57 -03008962 expr += join("[", out_of_bounds ? "0" : to_expression(index), "]");
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02008963 }
8964 else
8965 {
8966 expr += ".";
Sebastián Aedo905b8242021-11-11 12:57:57 -03008967 expr += index_to_swizzle(out_of_bounds ? 0 : c.scalar());
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02008968 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008969 }
8970 else
8971 {
8972 expr += "[";
Bill Hollings974a0812021-10-21 16:11:33 -04008973 expr += to_unpacked_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008974 expr += "]";
8975 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008976
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008977 if (row_major_matrix_needs_conversion && !ignore_potential_sliced_writes)
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008978 {
8979 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
8980 is_packed);
8981 }
8982
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008983 expr += deferred_index;
8984 row_major_matrix_needs_conversion = false;
8985
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01008986 is_packed = false;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008987 physical_type = 0;
Bill Hollings1e84a372017-08-12 00:21:13 -04008988 type_id = type->parent_type;
8989 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008990 }
Bill Hollings2964e322018-02-13 14:44:40 -05008991 else if (!backend.allow_truncated_access_chain)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008992 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008993 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008994
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008995 if (pending_array_enclose)
8996 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008997 SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
8998 "but the access chain was terminated in the middle of a multidimensional array. "
8999 "This is not supported.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009000 }
9001
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009002 if (meta)
9003 {
9004 meta->need_transpose = row_major_matrix_needs_conversion;
9005 meta->storage_is_packed = is_packed;
9006 meta->storage_is_invariant = is_invariant;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009007 meta->storage_physical_type = physical_type;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009008 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009009
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009010 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009011}
9012
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02009013void CompilerGLSL::prepare_access_chain_for_scalar_access(std::string &, const SPIRType &, spv::StorageClass, bool &)
9014{
9015}
9016
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009017string CompilerGLSL::to_flattened_struct_member(const string &basename, const SPIRType &type, uint32_t index)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009018{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009019 auto ret = join(basename, "_", to_member_name(type, index));
9020 ParsedIR::sanitize_underscores(ret);
9021 return ret;
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009022}
9023
Bill Hollings2d0d3282017-01-20 11:33:59 -05009024string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
Chip Davis3bfb2f92018-12-03 02:06:33 -06009025 AccessChainMeta *meta, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009026{
Arseny Kapoulkine24c66252017-01-16 14:19:49 -08009027 if (flattened_buffer_blocks.count(base))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009028 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009029 uint32_t matrix_stride = 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009030 uint32_t array_stride = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009031 bool need_transpose = false;
Chip Davis3bfb2f92018-12-03 02:06:33 -06009032 flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009033 &array_stride, ptr_chain);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009034
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009035 if (meta)
9036 {
9037 meta->need_transpose = target_type.columns > 1 && need_transpose;
9038 meta->storage_is_packed = false;
9039 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009040
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01009041 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, array_stride,
9042 need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009043 }
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009044 else if (flattened_structs.count(base) && count > 0)
9045 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009046 AccessChainFlags flags = ACCESS_CHAIN_CHAIN_ONLY_BIT | ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
9047 if (ptr_chain)
9048 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
9049
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009050 if (flattened_structs[base])
9051 {
9052 flags |= ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT;
9053 if (meta)
9054 meta->flattened_struct = target_type.basetype == SPIRType::Struct;
9055 }
9056
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009057 auto chain = access_chain_internal(base, indices, count, flags, nullptr).substr(1);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009058 if (meta)
9059 {
9060 meta->need_transpose = false;
9061 meta->storage_is_packed = false;
9062 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009063
9064 auto basename = to_flattened_access_chain_expression(base);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009065 auto ret = join(basename, "_", chain);
9066 ParsedIR::sanitize_underscores(ret);
9067 return ret;
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009068 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009069 else
9070 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009071 AccessChainFlags flags = ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
9072 if (ptr_chain)
9073 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
9074 return access_chain_internal(base, indices, count, flags, meta);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009075 }
9076}
9077
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009078string CompilerGLSL::load_flattened_struct(const string &basename, const SPIRType &type)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009079{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009080 auto expr = type_to_glsl_constructor(type);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009081 expr += '(';
9082
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009083 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
9084 {
9085 if (i)
9086 expr += ", ";
9087
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009088 auto &member_type = get<SPIRType>(type.member_types[i]);
9089 if (member_type.basetype == SPIRType::Struct)
9090 expr += load_flattened_struct(to_flattened_struct_member(basename, type, i), member_type);
9091 else
9092 expr += to_flattened_struct_member(basename, type, i);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009093 }
9094 expr += ')';
9095 return expr;
9096}
9097
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009098std::string CompilerGLSL::to_flattened_access_chain_expression(uint32_t id)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009099{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009100 // Do not use to_expression as that will unflatten access chains.
9101 string basename;
9102 if (const auto *var = maybe_get<SPIRVariable>(id))
9103 basename = to_name(var->self);
9104 else if (const auto *expr = maybe_get<SPIRExpression>(id))
9105 basename = expr->expression;
9106 else
9107 basename = to_expression(id);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009108
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009109 return basename;
9110}
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009111
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009112void CompilerGLSL::store_flattened_struct(const string &basename, uint32_t rhs_id, const SPIRType &type,
9113 const SmallVector<uint32_t> &indices)
9114{
9115 SmallVector<uint32_t> sub_indices = indices;
9116 sub_indices.push_back(0);
9117
9118 auto *member_type = &type;
9119 for (auto &index : indices)
9120 member_type = &get<SPIRType>(member_type->member_types[index]);
9121
9122 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009123 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009124 sub_indices.back() = i;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009125 auto lhs = join(basename, "_", to_member_name(*member_type, i));
9126 ParsedIR::sanitize_underscores(lhs);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009127
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009128 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
9129 {
9130 store_flattened_struct(lhs, rhs_id, type, sub_indices);
9131 }
9132 else
9133 {
9134 auto rhs = to_expression(rhs_id) + to_multi_member_reference(type, sub_indices);
9135 statement(lhs, " = ", rhs, ";");
9136 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009137 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009138}
9139
9140void CompilerGLSL::store_flattened_struct(uint32_t lhs_id, uint32_t value)
9141{
9142 auto &type = expression_type(lhs_id);
9143 auto basename = to_flattened_access_chain_expression(lhs_id);
9144 store_flattened_struct(basename, value, type, {});
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009145}
9146
Bill Hollings2d0d3282017-01-20 11:33:59 -05009147std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009148 const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009149 uint32_t /* array_stride */, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009150{
9151 if (!target_type.array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009152 SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009153 else if (target_type.basetype == SPIRType::Struct)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009154 return flattened_access_chain_struct(base, indices, count, target_type, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009155 else if (target_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009156 return flattened_access_chain_matrix(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009157 else
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009158 return flattened_access_chain_vector(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009159}
9160
Bill Hollings2d0d3282017-01-20 11:33:59 -05009161std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
9162 const SPIRType &target_type, uint32_t offset)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009163{
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009164 std::string expr;
9165
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01009166 expr += type_to_glsl_constructor(target_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009167 expr += "(";
9168
Henrik Rydgårdbfae0412017-03-07 09:59:26 +01009169 for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009170 {
9171 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08009172 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009173
9174 const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009175 uint32_t member_offset = type_struct_member_offset(target_type, i);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009176
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009177 // The access chain terminates at the struct, so we need to find matrix strides and row-major information
9178 // ahead of time.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009179 bool need_transpose = false;
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009180 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009181 if (member_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009182 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009183 need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009184 matrix_stride = type_struct_member_matrix_stride(target_type, i);
9185 }
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009186
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009187 auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009188 0 /* array_stride */, need_transpose);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009189
9190 // Cannot forward transpositions, so resolve them here.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009191 if (need_transpose)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009192 expr += convert_row_major_matrix(tmp, member_type, 0, false);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009193 else
9194 expr += tmp;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009195 }
9196
9197 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009198
9199 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009200}
9201
Bill Hollings2d0d3282017-01-20 11:33:59 -05009202std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009203 const SPIRType &target_type, uint32_t offset,
9204 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009205{
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009206 assert(matrix_stride);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009207 SPIRType tmp_type = target_type;
9208 if (need_transpose)
9209 swap(tmp_type.vecsize, tmp_type.columns);
9210
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009211 std::string expr;
9212
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009213 expr += type_to_glsl_constructor(tmp_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009214 expr += "(";
9215
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009216 for (uint32_t i = 0; i < tmp_type.columns; i++)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009217 {
9218 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08009219 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009220
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009221 expr += flattened_access_chain_vector(base, indices, count, tmp_type, offset + i * matrix_stride, matrix_stride,
9222 /* need_transpose= */ false);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009223 }
9224
9225 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009226
9227 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009228}
9229
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009230std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
9231 const SPIRType &target_type, uint32_t offset,
9232 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009233{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02009234 auto result = flattened_access_chain_offset(expression_type(base), indices, count, offset, 16);
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009235
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009236 auto buffer_name = to_name(expression_type(base).self);
9237
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009238 if (need_transpose)
9239 {
9240 std::string expr;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009241
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08009242 if (target_type.vecsize > 1)
9243 {
9244 expr += type_to_glsl_constructor(target_type);
9245 expr += "(";
9246 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009247
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009248 for (uint32_t i = 0; i < target_type.vecsize; ++i)
9249 {
9250 if (i != 0)
9251 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009252
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009253 uint32_t component_offset = result.second + i * matrix_stride;
9254
9255 assert(component_offset % (target_type.width / 8) == 0);
9256 uint32_t index = component_offset / (target_type.width / 8);
9257
9258 expr += buffer_name;
9259 expr += "[";
9260 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
9261 expr += convert_to_string(index / 4);
9262 expr += "]";
9263
9264 expr += vector_swizzle(1, index % 4);
9265 }
9266
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08009267 if (target_type.vecsize > 1)
9268 {
9269 expr += ")";
9270 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009271
9272 return expr;
9273 }
9274 else
9275 {
9276 assert(result.second % (target_type.width / 8) == 0);
9277 uint32_t index = result.second / (target_type.width / 8);
9278
9279 std::string expr;
9280
9281 expr += buffer_name;
9282 expr += "[";
9283 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
9284 expr += convert_to_string(index / 4);
9285 expr += "]";
9286
9287 expr += vector_swizzle(target_type.vecsize, index % 4);
9288
9289 return expr;
9290 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009291}
9292
Chip Davis3bfb2f92018-12-03 02:06:33 -06009293std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(
9294 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 +01009295 bool *need_transpose, uint32_t *out_matrix_stride, uint32_t *out_array_stride, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009296{
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01009297 // Start traversing type hierarchy at the proper non-pointer types.
Chip Davisfc02b3d2019-01-08 12:54:40 -06009298 const auto *type = &get_pointee_type(basetype);
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01009299
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009300 std::string expr;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009301
9302 // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout.
9303 bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false;
9304 uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009305 uint32_t array_stride = out_array_stride ? *out_array_stride : 0;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009306
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009307 for (uint32_t i = 0; i < count; i++)
9308 {
9309 uint32_t index = indices[i];
9310
Chip Davis3bfb2f92018-12-03 02:06:33 -06009311 // Pointers
9312 if (ptr_chain && i == 0)
9313 {
9314 // Here, the pointer type will be decorated with an array stride.
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009315 array_stride = get_decoration(basetype.self, DecorationArrayStride);
Chip Davis3bfb2f92018-12-03 02:06:33 -06009316 if (!array_stride)
9317 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
9318
9319 auto *constant = maybe_get<SPIRConstant>(index);
9320 if (constant)
9321 {
9322 // Constant array access.
9323 offset += constant->scalar() * array_stride;
9324 }
9325 else
9326 {
9327 // Dynamic array access.
9328 if (array_stride % word_stride)
9329 {
crissdb52e272020-10-08 12:14:52 +02009330 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
9331 "of a 4-component vector. "
9332 "Likely culprit here is a float or vec2 array inside a push "
9333 "constant block which is std430. "
9334 "This cannot be flattened. Try using std140 layout instead.");
Chip Davis3bfb2f92018-12-03 02:06:33 -06009335 }
9336
9337 expr += to_enclosed_expression(index);
9338 expr += " * ";
9339 expr += convert_to_string(array_stride / word_stride);
9340 expr += " + ";
9341 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06009342 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009343 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06009344 else if (!type->array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009345 {
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009346 auto *constant = maybe_get<SPIRConstant>(index);
9347 if (constant)
9348 {
9349 // Constant array access.
9350 offset += constant->scalar() * array_stride;
9351 }
9352 else
9353 {
9354 // Dynamic array access.
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009355 if (array_stride % word_stride)
9356 {
crissdb52e272020-10-08 12:14:52 +02009357 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
9358 "of a 4-component vector. "
9359 "Likely culprit here is a float or vec2 array inside a push "
9360 "constant block which is std430. "
9361 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009362 }
9363
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009364 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009365 expr += " * ";
9366 expr += convert_to_string(array_stride / word_stride);
9367 expr += " + ";
9368 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009369
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009370 uint32_t parent_type = type->parent_type;
9371 type = &get<SPIRType>(parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01009372
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009373 if (!type->array.empty())
9374 array_stride = get_decoration(parent_type, DecorationArrayStride);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009375 }
9376 // For structs, the index refers to a constant, which indexes into the members.
9377 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
9378 else if (type->basetype == SPIRType::Struct)
9379 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009380 index = evaluate_constant_u32(index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009381
9382 if (index >= type->member_types.size())
9383 SPIRV_CROSS_THROW("Member index is out of bounds!");
9384
9385 offset += type_struct_member_offset(*type, index);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009386
9387 auto &struct_type = *type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009388 type = &get<SPIRType>(type->member_types[index]);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009389
9390 if (type->columns > 1)
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009391 {
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009392 matrix_stride = type_struct_member_matrix_stride(struct_type, index);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009393 row_major_matrix_needs_conversion =
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009394 combined_decoration_for_member(struct_type, index).get(DecorationRowMajor);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009395 }
9396 else
9397 row_major_matrix_needs_conversion = false;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009398
9399 if (!type->array.empty())
9400 array_stride = type_struct_member_array_stride(struct_type, index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009401 }
9402 // Matrix -> Vector
9403 else if (type->columns > 1)
9404 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009405 auto *constant = maybe_get<SPIRConstant>(index);
9406 if (constant)
9407 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009408 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009409 offset += index * (row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride);
9410 }
9411 else
9412 {
9413 uint32_t indexing_stride = row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride;
9414 // Dynamic array access.
9415 if (indexing_stride % word_stride)
9416 {
crissdb52e272020-10-08 12:14:52 +02009417 SPIRV_CROSS_THROW("Matrix stride for dynamic indexing must be divisible by the size of a "
9418 "4-component vector. "
9419 "Likely culprit here is a row-major matrix being accessed dynamically. "
9420 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009421 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009422
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009423 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009424 expr += " * ";
9425 expr += convert_to_string(indexing_stride / word_stride);
9426 expr += " + ";
9427 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009428
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009429 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009430 }
9431 // Vector -> Scalar
9432 else if (type->vecsize > 1)
9433 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009434 auto *constant = maybe_get<SPIRConstant>(index);
9435 if (constant)
9436 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009437 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009438 offset += index * (row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8));
9439 }
9440 else
9441 {
9442 uint32_t indexing_stride = row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009443
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009444 // Dynamic array access.
9445 if (indexing_stride % word_stride)
9446 {
crissdb52e272020-10-08 12:14:52 +02009447 SPIRV_CROSS_THROW("Stride for dynamic vector indexing must be divisible by the "
9448 "size of a 4-component vector. "
9449 "This cannot be flattened in legacy targets.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009450 }
9451
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009452 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009453 expr += " * ";
9454 expr += convert_to_string(indexing_stride / word_stride);
9455 expr += " + ";
9456 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009457
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009458 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009459 }
9460 else
9461 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
9462 }
9463
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08009464 if (need_transpose)
9465 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009466 if (out_matrix_stride)
9467 *out_matrix_stride = matrix_stride;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009468 if (out_array_stride)
9469 *out_array_stride = array_stride;
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08009470
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009471 return std::make_pair(expr, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009472}
9473
Chip Davis3bfb2f92018-12-03 02:06:33 -06009474bool CompilerGLSL::should_dereference(uint32_t id)
9475{
9476 const auto &type = expression_type(id);
9477 // Non-pointer expressions don't need to be dereferenced.
9478 if (!type.pointer)
9479 return false;
9480
9481 // Handles shouldn't be dereferenced either.
9482 if (!expression_is_lvalue(id))
9483 return false;
9484
9485 // If id is a variable but not a phi variable, we should not dereference it.
9486 if (auto *var = maybe_get<SPIRVariable>(id))
9487 return var->phi_variable;
9488
9489 // If id is an access chain, we should not dereference it.
9490 if (auto *expr = maybe_get<SPIRExpression>(id))
9491 return !expr->access_chain;
9492
9493 // Otherwise, we should dereference this pointer expression.
9494 return true;
9495}
9496
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009497bool CompilerGLSL::should_forward(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009498{
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07009499 // If id is a variable we will try to forward it regardless of force_temporary check below
9500 // 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 +02009501 auto *var = maybe_get<SPIRVariable>(id);
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07009502 if (var && var->forwardable)
9503 return true;
9504
9505 // For debugging emit temporary variables for all expressions
9506 if (options.force_temporary)
9507 return false;
9508
9509 // Immutable expression can always be forwarded.
9510 if (is_immutable(id))
9511 return true;
9512
9513 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009514}
9515
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009516bool CompilerGLSL::should_suppress_usage_tracking(uint32_t id) const
9517{
9518 // Used only by opcodes which don't do any real "work", they just swizzle data in some fashion.
9519 return !expression_is_forwarded(id) || expression_suppresses_usage_tracking(id);
9520}
9521
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009522void CompilerGLSL::track_expression_read(uint32_t id)
9523{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009524 switch (ir.ids[id].get_type())
9525 {
9526 case TypeExpression:
9527 {
9528 auto &e = get<SPIRExpression>(id);
9529 for (auto implied_read : e.implied_read_expressions)
9530 track_expression_read(implied_read);
9531 break;
9532 }
9533
9534 case TypeAccessChain:
9535 {
9536 auto &e = get<SPIRAccessChain>(id);
9537 for (auto implied_read : e.implied_read_expressions)
9538 track_expression_read(implied_read);
9539 break;
9540 }
9541
9542 default:
9543 break;
9544 }
9545
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009546 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
9547 // 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 +02009548 if (expression_is_forwarded(id) && !expression_suppresses_usage_tracking(id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009549 {
9550 auto &v = expression_usage_counts[id];
9551 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009552
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02009553 // If we create an expression outside a loop,
9554 // but access it inside a loop, we're implicitly reading it multiple times.
9555 // If the expression in question is expensive, we should hoist it out to avoid relying on loop-invariant code motion
9556 // working inside the backend compiler.
9557 if (expression_read_implies_multiple_reads(id))
9558 v++;
9559
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009560 if (v >= 2)
9561 {
9562 //if (v == 2)
9563 // 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 +01009564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009565 forced_temporaries.insert(id);
9566 // Force a recompile after this pass to avoid forwarding this variable.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009567 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009568 }
9569 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009570}
9571
9572bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
9573{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009574 if (forced_temporaries.find(id) != end(forced_temporaries))
9575 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009576
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009577 for (uint32_t i = 0; i < num_args; i++)
9578 if (!should_forward(args[i]))
9579 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009580
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009581 // We need to forward globals as well.
9582 if (!pure)
9583 {
9584 for (auto global : global_variables)
9585 if (!should_forward(global))
9586 return false;
9587 for (auto aliased : aliased_variables)
9588 if (!should_forward(aliased))
9589 return false;
9590 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009592 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009593}
9594
9595void CompilerGLSL::register_impure_function_call()
9596{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009597 // Impure functions can modify globals and aliased variables, so invalidate them as well.
9598 for (auto global : global_variables)
9599 flush_dependees(get<SPIRVariable>(global));
9600 for (auto aliased : aliased_variables)
9601 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009602}
9603
9604void CompilerGLSL::register_call_out_argument(uint32_t id)
9605{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009606 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009607
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009608 auto *var = maybe_get<SPIRVariable>(id);
9609 if (var)
9610 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009611}
9612
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01009613string CompilerGLSL::variable_decl_function_local(SPIRVariable &var)
9614{
9615 // These variables are always function local,
9616 // so make sure we emit the variable without storage qualifiers.
9617 // Some backends will inject custom variables locally in a function
9618 // with a storage qualifier which is not function-local.
9619 auto old_storage = var.storage;
9620 var.storage = StorageClassFunction;
9621 auto expr = variable_decl(var);
9622 var.storage = old_storage;
9623 return expr;
9624}
9625
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009626void CompilerGLSL::emit_variable_temporary_copies(const SPIRVariable &var)
9627{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04009628 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen3f569ed2019-10-24 17:12:23 +02009629 if (var.allocate_temporary_copy && !flushed_phi_variables.count(var.self))
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009630 {
9631 auto &type = get<SPIRType>(var.basetype);
9632 auto &flags = get_decoration_bitset(var.self);
9633 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, join("_", var.self, "_copy")), ";");
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04009634 flushed_phi_variables.insert(var.self);
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009635 }
9636}
9637
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009638void CompilerGLSL::flush_variable_declaration(uint32_t id)
9639{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04009640 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009641 auto *var = maybe_get<SPIRVariable>(id);
9642 if (var && var->deferred_declaration)
9643 {
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01009644 string initializer;
9645 if (options.force_zero_initialized_variables &&
9646 (var->storage == StorageClassFunction || var->storage == StorageClassGeneric ||
9647 var->storage == StorageClassPrivate) &&
9648 !var->initializer && type_can_zero_initialize(get_variable_data_type(*var)))
9649 {
9650 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(*var)));
9651 }
9652
9653 statement(variable_decl_function_local(*var), initializer, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009654 var->deferred_declaration = false;
9655 }
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04009656 if (var)
9657 {
9658 emit_variable_temporary_copies(*var);
9659 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009660}
9661
9662bool CompilerGLSL::remove_duplicate_swizzle(string &op)
9663{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009664 auto pos = op.find_last_of('.');
9665 if (pos == string::npos || pos == 0)
9666 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009667
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009668 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009669
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009670 if (backend.swizzle_is_function)
9671 {
9672 if (final_swiz.size() < 2)
9673 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009675 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
9676 final_swiz.erase(final_swiz.size() - 2, string::npos);
9677 else
9678 return false;
9679 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009680
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009681 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
9682 // If so, and previous swizzle is of same length,
9683 // we can drop the final swizzle altogether.
9684 for (uint32_t i = 0; i < final_swiz.size(); i++)
9685 {
9686 static const char expected[] = { 'x', 'y', 'z', 'w' };
9687 if (i >= 4 || final_swiz[i] != expected[i])
9688 return false;
9689 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009690
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009691 auto prevpos = op.find_last_of('.', pos - 1);
9692 if (prevpos == string::npos)
9693 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009694
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009695 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009696
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009697 // Make sure there are only swizzles here ...
9698 for (auto i = prevpos; i < pos; i++)
9699 {
9700 if (op[i] < 'w' || op[i] > 'z')
9701 {
9702 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
9703 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
9704 break;
9705 return false;
9706 }
9707 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009709 // If original swizzle is large enough, just carve out the components we need.
9710 // E.g. foobar.wyx.xy will turn into foobar.wy.
9711 if (pos - prevpos >= final_swiz.size())
9712 {
9713 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009714
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009715 // Add back the function call ...
9716 if (backend.swizzle_is_function)
9717 op += "()";
9718 }
9719 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009720}
9721
9722// Optimizes away vector swizzles where we have something like
9723// vec3 foo;
9724// foo.xyz <-- swizzle expression does nothing.
9725// This is a very common pattern after OpCompositeCombine.
9726bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
9727{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009728 auto pos = op.find_last_of('.');
9729 if (pos == string::npos || pos == 0)
9730 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009731
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009732 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009733
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009734 if (backend.swizzle_is_function)
9735 {
9736 if (final_swiz.size() < 2)
9737 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009738
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009739 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
9740 final_swiz.erase(final_swiz.size() - 2, string::npos);
9741 else
9742 return false;
9743 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009745 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
9746 // If so, and previous swizzle is of same length,
9747 // we can drop the final swizzle altogether.
9748 for (uint32_t i = 0; i < final_swiz.size(); i++)
9749 {
9750 static const char expected[] = { 'x', 'y', 'z', 'w' };
9751 if (i >= 4 || final_swiz[i] != expected[i])
9752 return false;
9753 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009754
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009755 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009756
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009757 // Sanity checking ...
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04009758 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009759
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009760 if (type.vecsize == final_swiz.size())
9761 op.erase(pos, string::npos);
9762 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009763}
9764
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009765string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009766{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009767 ID base = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009768 string op;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009769 string subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009770
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009771 // Can only merge swizzles for vectors.
9772 auto &type = get<SPIRType>(return_type);
9773 bool can_apply_swizzle_opt = type.basetype != SPIRType::Struct && type.array.empty() && type.columns == 1;
9774 bool swizzle_optimization = false;
9775
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009776 for (uint32_t i = 0; i < length; i++)
9777 {
9778 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009780 // If we're merging another scalar which belongs to the same base
9781 // 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 +01009782 if (can_apply_swizzle_opt && e && e->base_expression && e->base_expression == base)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009783 {
9784 // Only supposed to be used for vector swizzle -> scalar.
9785 assert(!e->expression.empty() && e->expression.front() == '.');
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009786 subop += e->expression.substr(1, string::npos);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009787 swizzle_optimization = true;
9788 }
9789 else
9790 {
9791 // We'll likely end up with duplicated swizzles, e.g.
9792 // foobar.xyz.xyz from patterns like
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009793 // OpVectorShuffle
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009794 // OpCompositeExtract x 3
9795 // OpCompositeConstruct 3x + other scalar.
9796 // Just modify op in-place.
9797 if (swizzle_optimization)
9798 {
9799 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009800 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009801
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009802 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
9803 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
9804 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
9805 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
9806 // Case 1:
9807 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
9808 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
9809 // Case 2:
9810 // foo.xyz: Duplicate swizzle won't kick in.
9811 // If foo is vec3, we can remove xyz, giving just foo.
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009812 if (!remove_duplicate_swizzle(subop))
9813 remove_unity_swizzle(base, subop);
9814
9815 // Strips away redundant parens if we created them during component extraction.
9816 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009817 swizzle_optimization = false;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009818 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009819 }
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009820 else
9821 op += subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009823 if (i)
9824 op += ", ";
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02009825
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02009826 bool uses_buffer_offset =
9827 type.basetype == SPIRType::Struct && has_member_decoration(type.self, i, DecorationOffset);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02009828 subop = to_composite_constructor_expression(elems[i], uses_buffer_offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009829 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009830
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009831 base = e ? e->base_expression : ID(0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009832 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009833
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009834 if (swizzle_optimization)
9835 {
9836 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009837 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009838
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009839 if (!remove_duplicate_swizzle(subop))
9840 remove_unity_swizzle(base, subop);
9841 // Strips away redundant parens if we created them during component extraction.
9842 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009843 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009844
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009845 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009846 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009847}
9848
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02009849bool CompilerGLSL::skip_argument(uint32_t id) const
9850{
9851 if (!combined_image_samplers.empty() || !options.vulkan_semantics)
9852 {
9853 auto &type = expression_type(id);
9854 if (type.basetype == SPIRType::Sampler || (type.basetype == SPIRType::Image && type.image.sampled == 1))
9855 return true;
9856 }
9857 return false;
9858}
9859
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02009860bool CompilerGLSL::optimize_read_modify_write(const SPIRType &type, const string &lhs, const string &rhs)
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009861{
9862 // Do this with strings because we have a very clear pattern we can check for and it avoids
9863 // adding lots of special cases to the code emission.
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01009864 if (rhs.size() < lhs.size() + 3)
9865 return false;
9866
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02009867 // Do not optimize matrices. They are a bit awkward to reason about in general
9868 // (in which order does operation happen?), and it does not work on MSL anyways.
9869 if (type.vecsize > 1 && type.columns > 1)
9870 return false;
9871
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009872 auto index = rhs.find(lhs);
9873 if (index != 0)
9874 return false;
9875
9876 // TODO: Shift operators, but it's not important for now.
9877 auto op = rhs.find_first_of("+-/*%|&^", lhs.size() + 1);
9878 if (op != lhs.size() + 1)
9879 return false;
9880
David Srbeckye596d402017-09-05 16:05:53 +01009881 // Check that the op is followed by space. This excludes && and ||.
Hans-Kristian Arntzen03db5c42017-09-06 09:15:27 +02009882 if (rhs[op + 1] != ' ')
David Srbeckye596d402017-09-05 16:05:53 +01009883 return false;
9884
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01009885 char bop = rhs[op];
9886 auto expr = rhs.substr(lhs.size() + 3);
9887 // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code.
9888 // Find some common patterns which are equivalent.
9889 if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)"))
9890 statement(lhs, bop, bop, ";");
9891 else
9892 statement(lhs, " ", bop, "= ", expr, ";");
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009893 return true;
9894}
9895
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009896void CompilerGLSL::register_control_dependent_expression(uint32_t expr)
9897{
9898 if (forwarded_temporaries.find(expr) == end(forwarded_temporaries))
9899 return;
9900
9901 assert(current_emitting_block);
9902 current_emitting_block->invalidate_expressions.push_back(expr);
9903}
9904
9905void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02009906{
9907 current_emitting_block = &block;
9908 for (auto &op : block.ops)
9909 emit_instruction(op);
9910 current_emitting_block = nullptr;
9911}
9912
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009913void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression &expr)
9914{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009915 // Allow trivially forwarded expressions like OpLoad or trivial shuffles,
9916 // these will be marked as having suppressed usage tracking.
9917 // Our only concern is to make sure arithmetic operations are done in similar ways.
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009918 if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) &&
9919 forced_invariant_temporaries.count(expr.self) == 0)
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009920 {
9921 forced_temporaries.insert(expr.self);
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009922 forced_invariant_temporaries.insert(expr.self);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009923 force_recompile();
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009924
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009925 for (auto &dependent : expr.expression_dependencies)
9926 disallow_forwarding_in_expression_chain(get<SPIRExpression>(dependent));
9927 }
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009928}
9929
9930void CompilerGLSL::handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id)
9931{
9932 // Variables or access chains marked invariant are complicated. We will need to make sure the code-gen leading up to
9933 // this variable is consistent. The failure case for SPIRV-Cross is when an expression is forced to a temporary
9934 // in one translation unit, but not another, e.g. due to multiple use of an expression.
9935 // This causes variance despite the output variable being marked invariant, so the solution here is to force all dependent
9936 // expressions to be temporaries.
9937 // It is uncertain if this is enough to support invariant in all possible cases, but it should be good enough
9938 // for all reasonable uses of invariant.
9939 if (!has_decoration(store_id, DecorationInvariant))
9940 return;
9941
9942 auto *expr = maybe_get<SPIRExpression>(value_id);
9943 if (!expr)
9944 return;
9945
9946 disallow_forwarding_in_expression_chain(*expr);
9947}
9948
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01009949void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009950{
9951 auto rhs = to_pointer_expression(rhs_expression);
9952
9953 // Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
9954 if (!rhs.empty())
9955 {
9956 handle_store_to_invariant_variable(lhs_expression, rhs_expression);
9957
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01009958 if (!unroll_array_to_complex_store(lhs_expression, rhs_expression))
9959 {
9960 auto lhs = to_dereferenced_expression(lhs_expression);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02009961 if (has_decoration(lhs_expression, DecorationNonUniform))
9962 convert_non_uniform_expression(lhs, lhs_expression);
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009963
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01009964 // We might need to cast in order to store to a builtin.
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +02009965 cast_to_variable_store(lhs_expression, rhs, expression_type(rhs_expression));
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009966
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01009967 // Tries to optimize assignments like "<lhs> = <lhs> op expr".
9968 // While this is purely cosmetic, this is important for legacy ESSL where loop
9969 // variable increments must be in either i++ or i += const-expr.
9970 // Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
9971 if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
9972 statement(lhs, " = ", rhs, ";");
9973 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009974 register_write(lhs_expression);
9975 }
9976}
9977
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009978uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &instr) const
9979{
9980 if (instr.length < 3)
9981 return 32;
9982
9983 auto *ops = stream(instr);
9984
9985 switch (instr.op)
9986 {
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02009987 case OpSConvert:
9988 case OpConvertSToF:
9989 case OpUConvert:
9990 case OpConvertUToF:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009991 case OpIEqual:
9992 case OpINotEqual:
9993 case OpSLessThan:
9994 case OpSLessThanEqual:
9995 case OpSGreaterThan:
9996 case OpSGreaterThanEqual:
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02009997 case OpULessThan:
9998 case OpULessThanEqual:
9999 case OpUGreaterThan:
10000 case OpUGreaterThanEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010001 return expression_type(ops[2]).width;
10002
10003 default:
10004 {
10005 // We can look at result type which is more robust.
10006 auto *type = maybe_get<SPIRType>(ops[0]);
10007 if (type && type_is_integral(*type))
10008 return type->width;
10009 else
10010 return 32;
10011 }
10012 }
10013}
10014
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +010010015uint32_t CompilerGLSL::get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *ops, uint32_t length) const
10016{
10017 if (length < 1)
10018 return 32;
10019
10020 switch (op)
10021 {
10022 case GLSLstd450SAbs:
10023 case GLSLstd450SSign:
10024 case GLSLstd450UMin:
10025 case GLSLstd450SMin:
10026 case GLSLstd450UMax:
10027 case GLSLstd450SMax:
10028 case GLSLstd450UClamp:
10029 case GLSLstd450SClamp:
10030 case GLSLstd450FindSMsb:
10031 case GLSLstd450FindUMsb:
10032 return expression_type(ops[0]).width;
10033
10034 default:
10035 {
10036 // We don't need to care about other opcodes, just return 32.
10037 return 32;
10038 }
10039 }
10040}
10041
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +020010042void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010043{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010044 auto ops = stream(instruction);
10045 auto opcode = static_cast<Op>(instruction.op);
10046 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010047
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010048#define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
10049#define GLSL_BOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010050 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 +020010051#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
10052#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
10053#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
10054#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
10055#define GLSL_BFOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010056 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 +020010057#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
10058#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010059
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010060 // If we need to do implicit bitcasts, make sure we do it with the correct type.
10061 uint32_t integer_width = get_integer_width_for_instruction(instruction);
10062 auto int_type = to_signed_basetype(integer_width);
10063 auto uint_type = to_unsigned_basetype(integer_width);
10064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010065 switch (opcode)
10066 {
10067 // Dealing with memory
10068 case OpLoad:
10069 {
10070 uint32_t result_type = ops[0];
10071 uint32_t id = ops[1];
10072 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010073
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010074 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010076 // If we're loading from memory that cannot be changed by the shader,
10077 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010078 // If an expression is mutable and forwardable, we speculate that it is immutable.
10079 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
10080
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010081 // If loading a non-native row-major matrix, mark the expression as need_transpose.
10082 bool need_transpose = false;
10083 bool old_need_transpose = false;
10084
10085 auto *ptr_expression = maybe_get<SPIRExpression>(ptr);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010086
10087 if (forward)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010088 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010089 // If we're forwarding the load, we're also going to forward transpose state, so don't transpose while
10090 // taking the expression.
10091 if (ptr_expression && ptr_expression->need_transpose)
10092 {
10093 old_need_transpose = true;
10094 ptr_expression->need_transpose = false;
10095 need_transpose = true;
10096 }
10097 else if (is_non_native_row_major_matrix(ptr))
10098 need_transpose = true;
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010099 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010100
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010101 // If we are forwarding this load,
10102 // don't register the read to access chain here, defer that to when we actually use the expression,
10103 // using the add_implied_read_expression mechanism.
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010104 string expr;
10105
10106 bool is_packed = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked);
10107 bool is_remapped = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID);
10108 if (forward || (!is_packed && !is_remapped))
10109 {
10110 // For the simple case, we do not need to deal with repacking.
10111 expr = to_dereferenced_expression(ptr, false);
10112 }
10113 else
10114 {
10115 // If we are not forwarding the expression, we need to unpack and resolve any physical type remapping here before
10116 // storing the expression to a temporary.
10117 expr = to_unpacked_expression(ptr);
10118 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010119
Chip Davis5281d992020-06-13 23:03:30 -050010120 auto &type = get<SPIRType>(result_type);
10121 auto &expr_type = expression_type(ptr);
10122
10123 // If the expression has more vector components than the result type, insert
10124 // a swizzle. This shouldn't happen normally on valid SPIR-V, but it might
10125 // happen with e.g. the MSL backend replacing the type of an input variable.
10126 if (expr_type.vecsize > type.vecsize)
10127 expr = enclose_expression(expr + vector_swizzle(type.vecsize, 0));
10128
Chip Davis3e6010d2020-10-14 15:04:03 -050010129 // We might need to cast in order to load from a builtin.
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020010130 cast_from_variable_load(ptr, expr, type);
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020010131
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010010132 // We might be trying to load a gl_Position[N], where we should be
10133 // doing float4[](gl_in[i].gl_Position, ...) instead.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010010134 // Similar workarounds are required for input arrays in tessellation.
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010010135 // Also, loading from gl_SampleMask array needs special unroll.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010010136 unroll_array_from_complex_load(id, ptr, expr);
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010010137
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010138 if (!type_is_opaque_value(type) && has_decoration(ptr, DecorationNonUniform))
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010139 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010140 // If we're loading something non-opaque, we need to handle non-uniform descriptor access.
10141 convert_non_uniform_expression(expr, ptr);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010142 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020010143
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010144 if (forward && ptr_expression)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010145 ptr_expression->need_transpose = old_need_transpose;
Bill Hollings13583622016-12-14 02:12:52 -050010146
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020010147 bool flattened = ptr_expression && flattened_buffer_blocks.count(ptr_expression->loaded_from) != 0;
10148
10149 if (backend.needs_row_major_load_workaround && !is_non_native_row_major_matrix(ptr) && !flattened)
10150 rewrite_load_for_wrapped_row_major(expr, result_type, ptr);
10151
Hans-Kristian Arntzen18b82ca2018-07-09 14:02:50 +020010152 // 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 +020010153 // However, if we try to load a complex, composite object from a flattened buffer,
10154 // we should avoid emitting the same code over and over and lower the result to a temporary.
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020010155 bool usage_tracking = flattened && (type.basetype == SPIRType::Struct || (type.columns > 1));
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +020010156
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010157 SPIRExpression *e = nullptr;
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +020010158 if (!forward && expression_is_non_value_type_array(ptr))
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010159 {
10160 // Complicated load case where we need to make a copy of ptr, but we cannot, because
10161 // it is an array, and our backend does not support arrays as value types.
10162 // Emit the temporary, and copy it explicitly.
10163 e = &emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020010164 emit_array_copy(to_expression(id), id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010165 }
10166 else
10167 e = &emit_op(result_type, id, expr, forward, !usage_tracking);
10168
10169 e->need_transpose = need_transpose;
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010170 register_read(id, ptr, forward);
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010171
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010172 if (forward)
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +010010173 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010174 // Pass through whether the result is of a packed type and the physical type ID.
10175 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked))
10176 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10177 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID))
10178 {
10179 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID,
10180 get_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID));
10181 }
10182 }
10183 else
10184 {
10185 // This might have been set on an earlier compilation iteration, force it to be unset.
10186 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10187 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +010010188 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010189
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010190 inherit_expression_dependencies(id, ptr);
10191 if (forward)
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010192 add_implied_read_expression(*e, ptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010193 break;
10194 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010195
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010196 case OpInBoundsAccessChain:
10197 case OpAccessChain:
Chip Davis3bfb2f92018-12-03 02:06:33 -060010198 case OpPtrAccessChain:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010199 {
10200 auto *var = maybe_get<SPIRVariable>(ops[2]);
10201 if (var)
10202 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010203
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010204 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010205 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010206 AccessChainMeta meta;
Chip Davis3bfb2f92018-12-03 02:06:33 -060010207 bool ptr_chain = opcode == OpPtrAccessChain;
10208 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 +020010209
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010210 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +020010211
10212 auto *backing_variable = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010213 expr.loaded_from = backing_variable ? backing_variable->self : ID(ops[2]);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010214 expr.need_transpose = meta.need_transpose;
Chip Davis3bfb2f92018-12-03 02:06:33 -060010215 expr.access_chain = true;
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010216
10217 // Mark the result as being packed. Some platforms handled packed vectors differently than non-packed.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010218 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010219 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypePacked);
10220 if (meta.storage_physical_type != 0)
10221 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010222 if (meta.storage_is_invariant)
10223 set_decoration(ops[1], DecorationInvariant);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010224 if (meta.flattened_struct)
10225 flattened_structs[ops[1]] = true;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010226
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010227 // If we have some expression dependencies in our access chain, this access chain is technically a forwarded
10228 // temporary which could be subject to invalidation.
10229 // Need to assume we're forwarded while calling inherit_expression_depdendencies.
10230 forwarded_temporaries.insert(ops[1]);
10231 // The access chain itself is never forced to a temporary, but its dependencies might.
10232 suppressed_usage_tracking.insert(ops[1]);
10233
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010234 for (uint32_t i = 2; i < length; i++)
10235 {
10236 inherit_expression_dependencies(ops[1], ops[i]);
10237 add_implied_read_expression(expr, ops[i]);
10238 }
10239
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010240 // If we have no dependencies after all, i.e., all indices in the access chain are immutable temporaries,
10241 // we're not forwarded after all.
10242 if (expr.expression_dependencies.empty())
10243 forwarded_temporaries.erase(ops[1]);
10244
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010245 break;
10246 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010247
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010248 case OpStore:
10249 {
10250 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010252 if (var && var->statically_assigned)
10253 var->static_expression = ops[1];
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010254 else if (var && var->loop_variable && !var->loop_variable_enable)
10255 var->static_expression = ops[1];
Hans-Kristian Arntzend31bc022020-05-28 11:49:28 +020010256 else if (var && var->remapped_variable && var->static_expression)
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020010257 {
10258 // Skip the write.
10259 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010260 else if (flattened_structs.count(ops[0]))
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +010010261 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010262 store_flattened_struct(ops[0], ops[1]);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +010010263 register_write(ops[0]);
10264 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010265 else
10266 {
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +010010267 emit_store_statement(ops[0], ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010268 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +010010269
Chip Davis3bfb2f92018-12-03 02:06:33 -060010270 // Storing a pointer results in a variable pointer, so we must conservatively assume
10271 // we can write through it.
10272 if (expression_type(ops[1]).pointer)
10273 register_write(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010274 break;
10275 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010276
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010277 case OpArrayLength:
10278 {
10279 uint32_t result_type = ops[0];
10280 uint32_t id = ops[1];
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +010010281 auto e = access_chain_internal(ops[2], &ops[3], length - 3, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010282 if (has_decoration(ops[2], DecorationNonUniform))
10283 convert_non_uniform_expression(e, ops[2]);
Hans-Kristian Arntzenb6f8a202019-05-07 19:02:32 +020010284 set<SPIRExpression>(id, join(type_to_glsl(get<SPIRType>(result_type)), "(", e, ".length())"), result_type,
10285 true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010286 break;
10287 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010289 // Function calls
10290 case OpFunctionCall:
10291 {
10292 uint32_t result_type = ops[0];
10293 uint32_t id = ops[1];
10294 uint32_t func = ops[2];
10295 const auto *arg = &ops[3];
10296 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010297
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010298 auto &callee = get<SPIRFunction>(func);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010299 auto &return_type = get<SPIRType>(callee.return_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010300 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010301
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010302 bool callee_has_out_variables = false;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010303 bool emit_return_value_as_argument = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010304
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010305 // Invalidate out variables passed to functions since they can be OpStore'd to.
10306 for (uint32_t i = 0; i < length; i++)
10307 {
10308 if (callee.arguments[i].write_count)
10309 {
10310 register_call_out_argument(arg[i]);
10311 callee_has_out_variables = true;
10312 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010313
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010314 flush_variable_declaration(arg[i]);
10315 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010316
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010317 if (!return_type.array.empty() && !backend.can_return_array)
10318 {
10319 callee_has_out_variables = true;
10320 emit_return_value_as_argument = true;
10321 }
10322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010323 if (!pure)
10324 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010325
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010326 string funexpr;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020010327 SmallVector<string> arglist;
Bill Hollings1c180782017-11-05 21:34:42 -050010328 funexpr += to_name(func) + "(";
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010329
10330 if (emit_return_value_as_argument)
10331 {
10332 statement(type_to_glsl(return_type), " ", to_name(id), type_to_array_glsl(return_type), ";");
10333 arglist.push_back(to_name(id));
10334 }
10335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010336 for (uint32_t i = 0; i < length; i++)
10337 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010338 // Do not pass in separate images or samplers if we're remapping
10339 // to combined image samplers.
10340 if (skip_argument(arg[i]))
10341 continue;
10342
Chip Davis39dce882019-08-02 15:11:19 -050010343 arglist.push_back(to_func_call_arg(callee.arguments[i], arg[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010344 }
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +020010345
10346 for (auto &combined : callee.combined_parameters)
10347 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010348 auto image_id = combined.global_image ? combined.image_id : VariableID(arg[combined.image_id]);
10349 auto sampler_id = combined.global_sampler ? combined.sampler_id : VariableID(arg[combined.sampler_id]);
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +020010350 arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +020010351 }
Bill Hollingsa759e2c2016-10-19 14:09:51 -070010352
Bill Hollingsac00c602016-10-24 09:24:24 -040010353 append_global_func_args(callee, length, arglist);
Bill Hollingsa759e2c2016-10-19 14:09:51 -070010354
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010355 funexpr += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010356 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010357
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020010358 // Check for function call constraints.
10359 check_function_call_constraints(arg, length);
10360
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010361 if (return_type.basetype != SPIRType::Void)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010362 {
10363 // If the function actually writes to an out variable,
10364 // take the conservative route and do not forward.
10365 // The problem is that we might not read the function
10366 // result (and emit the function) before an out variable
10367 // is read (common case when return value is ignored!
10368 // In order to avoid start tracking invalid variables,
10369 // just avoid the forwarding problem altogether.
10370 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
10371 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010372
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010373 if (emit_return_value_as_argument)
10374 {
10375 statement(funexpr, ";");
10376 set<SPIRExpression>(id, to_name(id), result_type, true);
10377 }
10378 else
10379 emit_op(result_type, id, funexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010380
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010381 // Function calls are implicit loads from all variables in question.
10382 // Set dependencies for them.
10383 for (uint32_t i = 0; i < length; i++)
10384 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010385
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010386 // If we're going to forward the temporary result,
10387 // put dependencies on every variable that must not change.
10388 if (forward)
10389 register_global_read_dependencies(callee, id);
10390 }
10391 else
10392 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010393
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010394 break;
10395 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010396
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010397 // Composite munging
10398 case OpCompositeConstruct:
10399 {
10400 uint32_t result_type = ops[0];
10401 uint32_t id = ops[1];
Hans-Kristian Arntzen9a527132018-03-09 15:26:36 +010010402 const auto *const elems = &ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010403 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010404
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010405 bool forward = true;
10406 for (uint32_t i = 0; i < length; i++)
10407 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010408
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010409 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010410 auto *in_type = length > 0 ? &expression_type(elems[0]) : nullptr;
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020010411
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010412 // Only splat if we have vector constructors.
10413 // Arrays and structs must be initialized properly in full.
10414 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010415
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010416 bool splat = false;
10417 bool swizzle_splat = false;
10418
10419 if (in_type)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +010010420 {
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010421 splat = in_type->vecsize == 1 && in_type->columns == 1 && !composite && backend.use_constructor_splatting;
10422 swizzle_splat = in_type->vecsize == 1 && in_type->columns == 1 && backend.can_swizzle_scalar;
10423
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010424 if (ir.ids[elems[0]].get_type() == TypeConstant && !type_is_floating_point(*in_type))
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010425 {
10426 // Cannot swizzle literal integers as a special case.
10427 swizzle_splat = false;
10428 }
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +010010429 }
10430
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010431 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010432 {
10433 uint32_t input = elems[0];
10434 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010435 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010436 if (input != elems[i])
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010437 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010438 splat = false;
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010439 swizzle_splat = false;
10440 }
10441 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010442 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010443
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010010444 if (out_type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
10445 forward = false;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +010010446 if (!out_type.array.empty() && !backend.can_declare_arrays_inline)
10447 forward = false;
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010448 if (type_is_empty(out_type) && !backend.supports_empty_struct)
10449 forward = false;
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010010450
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010451 string constructor_op;
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +020010452 if (backend.use_initializer_list && composite)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010453 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010454 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010455 // Only use this path if we are building composites.
10456 // This path cannot be used for arithmetic.
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +020010457 if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010010458 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
Hans-Kristian Arntzenc9d4f9c2020-02-24 12:47:14 +010010459 else if (backend.use_typed_initializer_list && backend.array_is_value_type && !out_type.array.empty())
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010460 {
10461 // MSL path. Array constructor is baked into type here, do not use _constructor variant.
10462 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
10463 needs_trailing_tracket = true;
10464 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010465 constructor_op += "{ ";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010466
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010467 if (type_is_empty(out_type) && !backend.supports_empty_struct)
10468 constructor_op += "0";
10469 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020010470 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010471 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010010472 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010473 constructor_op += " }";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010474 if (needs_trailing_tracket)
10475 constructor_op += ")";
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010476 }
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010477 else if (swizzle_splat && !composite)
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +010010478 {
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020010479 constructor_op = remap_swizzle(get<SPIRType>(result_type), 1, to_unpacked_expression(elems[0]));
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +010010480 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010481 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010482 {
10483 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010484 if (type_is_empty(out_type) && !backend.supports_empty_struct)
10485 constructor_op += "0";
10486 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020010487 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010488 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010010489 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010490 constructor_op += ")";
10491 }
10492
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +020010493 if (!constructor_op.empty())
10494 {
10495 emit_op(result_type, id, constructor_op, forward);
10496 for (uint32_t i = 0; i < length; i++)
10497 inherit_expression_dependencies(id, elems[i]);
10498 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010499 break;
10500 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010501
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010502 case OpVectorInsertDynamic:
10503 {
10504 uint32_t result_type = ops[0];
10505 uint32_t id = ops[1];
10506 uint32_t vec = ops[2];
10507 uint32_t comp = ops[3];
10508 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010509
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010510 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010512 // Make a copy, then use access chain to store the variable.
10513 statement(declare_temporary(result_type, id), to_expression(vec), ";");
10514 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010515 auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +020010516 statement(chain, " = ", to_unpacked_expression(comp), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010517 break;
10518 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010519
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010520 case OpVectorExtractDynamic:
10521 {
10522 uint32_t result_type = ops[0];
10523 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010524
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010525 auto expr = access_chain_internal(ops[2], &ops[3], 1, 0, nullptr);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010010526 emit_op(result_type, id, expr, should_forward(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010527 inherit_expression_dependencies(id, ops[2]);
10528 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010529 break;
10530 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010531
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010532 case OpCompositeExtract:
10533 {
10534 uint32_t result_type = ops[0];
10535 uint32_t id = ops[1];
10536 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010538 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010539
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +020010540 // We can only split the expression here if our expression is forwarded as a temporary.
10541 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
10542
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +010010543 // Do not allow base expression for struct members. We risk doing "swizzle" optimizations in this case.
10544 auto &composite_type = expression_type(ops[2]);
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010545 bool composite_type_is_complex = composite_type.basetype == SPIRType::Struct || !composite_type.array.empty();
10546 if (composite_type_is_complex)
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +010010547 allow_base_expression = false;
10548
Hans-Kristian Arntzenc7b75a82020-04-07 18:22:14 +020010549 // Packed expressions or physical ID mapped expressions cannot be split up.
10550 if (has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypePacked) ||
10551 has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypeID))
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +010010552 allow_base_expression = false;
10553
Hans-Kristian Arntzen7ff2db42019-08-27 11:41:54 +020010554 // Cannot use base expression for row-major matrix row-extraction since we need to interleave access pattern
10555 // into the base expression.
10556 if (is_non_native_row_major_matrix(ops[2]))
10557 allow_base_expression = false;
10558
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010559 AccessChainMeta meta;
10560 SPIRExpression *e = nullptr;
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010561 auto *c = maybe_get<SPIRConstant>(ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010562
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010563 if (c && !c->specialization && !composite_type_is_complex)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010564 {
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010565 auto expr = to_extract_constant_composite_expression(result_type, *c, ops + 3, length);
10566 e = &emit_op(result_type, id, expr, true, true);
10567 }
10568 else if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
10569 {
10570 // Only apply this optimization if result is scalar.
10571
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010572 // We want to split the access chain from the base.
10573 // This is so we can later combine different CompositeExtract results
10574 // with CompositeConstruct without emitting code like
10575 //
10576 // vec3 temp = texture(...).xyz
10577 // vec4(temp.x, temp.y, temp.z, 1.0).
10578 //
10579 // when we actually wanted to emit this
10580 // vec4(texture(...).xyz, 1.0).
10581 //
10582 // Including the base will prevent this and would trigger multiple reads
10583 // from expression causing it to be forced to an actual temporary in GLSL.
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010584 auto expr = access_chain_internal(ops[2], &ops[3], length,
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +020010585 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_CHAIN_ONLY_BIT |
10586 ACCESS_CHAIN_FORCE_COMPOSITE_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010587 e = &emit_op(result_type, id, expr, true, should_suppress_usage_tracking(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010588 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010589 e->base_expression = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010590 }
10591 else
10592 {
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +020010593 auto expr = access_chain_internal(ops[2], &ops[3], length,
10594 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_FORCE_COMPOSITE_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010595 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 +010010596 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010597 }
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010598
10599 // Pass through some meta information to the loaded expression.
10600 // We can still end up loading a buffer type to a variable, then CompositeExtract from it
10601 // instead of loading everything through an access chain.
10602 e->need_transpose = meta.need_transpose;
10603 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010604 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10605 if (meta.storage_physical_type != 0)
10606 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010607 if (meta.storage_is_invariant)
10608 set_decoration(id, DecorationInvariant);
10609
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010610 break;
10611 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010613 case OpCompositeInsert:
10614 {
10615 uint32_t result_type = ops[0];
10616 uint32_t id = ops[1];
10617 uint32_t obj = ops[2];
10618 uint32_t composite = ops[3];
10619 const auto *elems = &ops[4];
10620 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010621
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010622 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010623
David Srbecky77b5b442017-06-26 18:32:53 +010010624 // Make a copy, then use access chain to store the variable.
10625 statement(declare_temporary(result_type, id), to_expression(composite), ";");
10626 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010627 auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +020010628 statement(chain, " = ", to_unpacked_expression(obj), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010629
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010630 break;
10631 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010632
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010633 case OpCopyMemory:
10634 {
10635 uint32_t lhs = ops[0];
10636 uint32_t rhs = ops[1];
10637 if (lhs != rhs)
10638 {
Hans-Kristian Arntzen4ca06c72021-03-08 14:09:32 +010010639 uint32_t &tmp_id = extra_sub_expressions[instruction.offset | EXTRA_SUB_EXPRESSION_TYPE_STREAM_OFFSET];
10640 if (!tmp_id)
10641 tmp_id = ir.increase_bound_by(1);
10642 uint32_t tmp_type_id = expression_type(rhs).parent_type;
10643
10644 EmbeddedInstruction fake_load, fake_store;
10645 fake_load.op = OpLoad;
10646 fake_load.length = 3;
10647 fake_load.ops.push_back(tmp_type_id);
10648 fake_load.ops.push_back(tmp_id);
10649 fake_load.ops.push_back(rhs);
10650
10651 fake_store.op = OpStore;
10652 fake_store.length = 2;
10653 fake_store.ops.push_back(lhs);
10654 fake_store.ops.push_back(tmp_id);
10655
10656 // Load and Store do a *lot* of workarounds, and we'd like to reuse them as much as possible.
10657 // Synthesize a fake Load and Store pair for CopyMemory.
10658 emit_instruction(fake_load);
10659 emit_instruction(fake_store);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010660 }
10661 break;
10662 }
10663
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010010664 case OpCopyLogical:
10665 {
10666 // This is used for copying object of different types, arrays and structs.
10667 // We need to unroll the copy, element-by-element.
10668 uint32_t result_type = ops[0];
10669 uint32_t id = ops[1];
10670 uint32_t rhs = ops[2];
10671
10672 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010010673 emit_copy_logical_type(id, result_type, rhs, expression_type_id(rhs), {});
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010010674 break;
10675 }
10676
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010677 case OpCopyObject:
10678 {
10679 uint32_t result_type = ops[0];
10680 uint32_t id = ops[1];
10681 uint32_t rhs = ops[2];
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010682 bool pointer = get<SPIRType>(result_type).pointer;
10683
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010684 auto *chain = maybe_get<SPIRAccessChain>(rhs);
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010685 auto *imgsamp = maybe_get<SPIRCombinedImageSampler>(rhs);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010686 if (chain)
10687 {
10688 // Cannot lower to a SPIRExpression, just copy the object.
10689 auto &e = set<SPIRAccessChain>(id, *chain);
10690 e.self = id;
10691 }
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010692 else if (imgsamp)
10693 {
10694 // Cannot lower to a SPIRExpression, just copy the object.
10695 // GLSL does not currently use this type and will never get here, but MSL does.
Bill Hollings7f67abe2020-10-30 16:05:44 -040010696 // Handled here instead of CompilerMSL for better integration and general handling,
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010697 // and in case GLSL or other subclasses require it in the future.
10698 auto &e = set<SPIRCombinedImageSampler>(id, *imgsamp);
10699 e.self = id;
10700 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010701 else if (expression_is_lvalue(rhs) && !pointer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010702 {
10703 // Need a copy.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010704 // For pointer types, we copy the pointer itself.
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010705 statement(declare_temporary(result_type, id), to_unpacked_expression(rhs), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010706 set<SPIRExpression>(id, to_name(id), result_type, true);
10707 }
10708 else
10709 {
10710 // RHS expression is immutable, so just forward it.
10711 // Copying these things really make no sense, but
10712 // seems to be allowed anyways.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010713 auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
10714 if (pointer)
10715 {
10716 auto *var = maybe_get_backing_variable(rhs);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010717 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010718 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010719
10720 // If we're copying an access chain, need to inherit the read expressions.
10721 auto *rhs_expr = maybe_get<SPIRExpression>(rhs);
10722 if (rhs_expr)
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010723 {
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010724 e.implied_read_expressions = rhs_expr->implied_read_expressions;
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010725 e.expression_dependencies = rhs_expr->expression_dependencies;
10726 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010727 }
10728 break;
10729 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010730
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010731 case OpVectorShuffle:
10732 {
10733 uint32_t result_type = ops[0];
10734 uint32_t id = ops[1];
10735 uint32_t vec0 = ops[2];
10736 uint32_t vec1 = ops[3];
10737 const auto *elems = &ops[4];
10738 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010740 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010741
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010742 // If we have the undefined swizzle index -1, we need to swizzle in undefined data,
10743 // or in our case, T(0).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010744 bool shuffle = false;
10745 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010746 if (elems[i] >= type0.vecsize || elems[i] == 0xffffffffu)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010747 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010748
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010749 // Cannot use swizzles with packed expressions, force shuffle path.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010750 if (!shuffle && has_extended_decoration(vec0, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010751 shuffle = true;
10752
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010753 string expr;
Bill Hollings1845f312017-12-31 18:55:04 -050010754 bool should_fwd, trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010755
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010756 if (shuffle)
10757 {
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +010010758 should_fwd = should_forward(vec0) && should_forward(vec1);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010759 trivial_forward = should_suppress_usage_tracking(vec0) && should_suppress_usage_tracking(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010760
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010761 // Constructor style and shuffling from two different vectors.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020010762 SmallVector<string> args;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010763 for (uint32_t i = 0; i < length; i++)
10764 {
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010765 if (elems[i] == 0xffffffffu)
10766 {
10767 // Use a constant 0 here.
10768 // We could use the first component or similar, but then we risk propagating
10769 // a value we might not need, and bog down codegen.
10770 SPIRConstant c;
10771 c.constant_type = type0.parent_type;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010772 assert(type0.parent_type != ID(0));
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010773 args.push_back(constant_expression(c));
10774 }
10775 else if (elems[i] >= type0.vecsize)
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010776 args.push_back(to_extract_component_expression(vec1, elems[i] - type0.vecsize));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010777 else
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010778 args.push_back(to_extract_component_expression(vec0, elems[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010779 }
10780 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
10781 }
10782 else
10783 {
Bill Hollings1845f312017-12-31 18:55:04 -050010784 should_fwd = should_forward(vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010785 trivial_forward = should_suppress_usage_tracking(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010786
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010787 // We only source from first vector, so can use swizzle.
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010788 // If the vector is packed, unpack it before applying a swizzle (needed for MSL)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +020010789 expr += to_enclosed_unpacked_expression(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010790 expr += ".";
10791 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010792 {
10793 assert(elems[i] != 0xffffffffu);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010794 expr += index_to_swizzle(elems[i]);
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010795 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010796
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010797 if (backend.swizzle_is_function && length > 1)
10798 expr += "()";
10799 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010800
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010801 // A shuffle is trivial in that it doesn't actually *do* anything.
10802 // 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 +010010803
Bill Hollings1845f312017-12-31 18:55:04 -050010804 emit_op(result_type, id, expr, should_fwd, trivial_forward);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010805
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010806 inherit_expression_dependencies(id, vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010807 if (vec0 != vec1)
10808 inherit_expression_dependencies(id, vec1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010809 break;
10810 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010811
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010812 // ALU
10813 case OpIsNan:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010814 GLSL_UFOP(isnan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010815 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010816
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010817 case OpIsInf:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010818 GLSL_UFOP(isinf);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010819 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010820
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010821 case OpSNegate:
10822 case OpFNegate:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010823 GLSL_UOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010824 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010825
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010826 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010827 {
10828 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
10829 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010830 GLSL_BOP_CAST(+, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010831 break;
10832 }
10833
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010834 case OpFAdd:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010835 GLSL_BOP(+);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010836 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010837
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010838 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010839 {
10840 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010841 GLSL_BOP_CAST(-, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010842 break;
10843 }
10844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010845 case OpFSub:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010846 GLSL_BOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010847 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010848
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010849 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010850 {
10851 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010852 GLSL_BOP_CAST(*, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010853 break;
10854 }
10855
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010856 case OpVectorTimesMatrix:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010857 case OpMatrixTimesVector:
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010858 {
10859 // If the matrix needs transpose, just flip the multiply order.
10860 auto *e = maybe_get<SPIRExpression>(ops[opcode == OpMatrixTimesVector ? 2 : 3]);
10861 if (e && e->need_transpose)
10862 {
10863 e->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010864 string expr;
10865
10866 if (opcode == OpMatrixTimesVector)
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020010867 expr = join(to_enclosed_unpacked_expression(ops[3]), " * ",
10868 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010869 else
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020010870 expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
10871 to_enclosed_unpacked_expression(ops[2]));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010872
10873 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
10874 emit_op(ops[0], ops[1], expr, forward);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010875 e->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010876 inherit_expression_dependencies(ops[1], ops[2]);
10877 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010878 }
10879 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010880 GLSL_BOP(*);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010881 break;
10882 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010883
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010884 case OpMatrixTimesMatrix:
10885 {
10886 auto *a = maybe_get<SPIRExpression>(ops[2]);
10887 auto *b = maybe_get<SPIRExpression>(ops[3]);
10888
10889 // If both matrices need transpose, we can multiply in flipped order and tag the expression as transposed.
10890 // a^T * b^T = (b * a)^T.
10891 if (a && b && a->need_transpose && b->need_transpose)
10892 {
10893 a->need_transpose = false;
10894 b->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010895 auto expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
10896 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
10897 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
10898 auto &e = emit_op(ops[0], ops[1], expr, forward);
10899 e.need_transpose = true;
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010900 a->need_transpose = true;
10901 b->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010902 inherit_expression_dependencies(ops[1], ops[2]);
10903 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010904 }
10905 else
10906 GLSL_BOP(*);
10907
10908 break;
10909 }
10910
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010911 case OpFMul:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010912 case OpMatrixTimesScalar:
10913 case OpVectorTimesScalar:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010914 GLSL_BOP(*);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010915 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010916
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010917 case OpOuterProduct:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010918 GLSL_BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010919 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010920
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010921 case OpDot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010922 GLSL_BFOP(dot);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010923 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010924
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010925 case OpTranspose:
rdbbf719942020-11-05 17:09:33 +010010926 if (options.version < 120) // Matches GLSL 1.10 / ESSL 1.00
10927 {
10928 // transpose() is not available, so instead, flip need_transpose,
10929 // which can later be turned into an emulated transpose op by
10930 // convert_row_major_matrix(), if necessary.
10931 uint32_t result_type = ops[0];
10932 uint32_t result_id = ops[1];
10933 uint32_t input = ops[2];
10934
10935 // Force need_transpose to false temporarily to prevent
10936 // to_expression() from doing the transpose.
10937 bool need_transpose = false;
10938 auto *input_e = maybe_get<SPIRExpression>(input);
10939 if (input_e)
10940 swap(need_transpose, input_e->need_transpose);
10941
10942 bool forward = should_forward(input);
10943 auto &e = emit_op(result_type, result_id, to_expression(input), forward);
10944 e.need_transpose = !need_transpose;
10945
10946 // Restore the old need_transpose flag.
10947 if (input_e)
10948 input_e->need_transpose = need_transpose;
10949 }
10950 else
10951 GLSL_UFOP(transpose);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010952 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010953
Jin Zhoue792cd62018-05-22 00:44:34 -040010954 case OpSRem:
Jin Zhou6b144cc2018-05-24 01:17:47 -040010955 {
10956 uint32_t result_type = ops[0];
10957 uint32_t result_id = ops[1];
10958 uint32_t op0 = ops[2];
10959 uint32_t op1 = ops[3];
10960
10961 // Needs special handling.
10962 bool forward = should_forward(op0) && should_forward(op1);
10963 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
10964 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
10965
10966 emit_op(result_type, result_id, expr, forward);
10967 inherit_expression_dependencies(result_id, op0);
10968 inherit_expression_dependencies(result_id, op1);
Jin Zhoue792cd62018-05-22 00:44:34 -040010969 break;
Jin Zhou6b144cc2018-05-24 01:17:47 -040010970 }
Jin Zhoue792cd62018-05-22 00:44:34 -040010971
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010972 case OpSDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010973 GLSL_BOP_CAST(/, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010974 break;
10975
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010976 case OpUDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010977 GLSL_BOP_CAST(/, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010978 break;
10979
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010980 case OpIAddCarry:
10981 case OpISubBorrow:
10982 {
10983 if (options.es && options.version < 310)
10984 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
10985 else if (!options.es && options.version < 400)
10986 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 400.");
10987
10988 uint32_t result_type = ops[0];
10989 uint32_t result_id = ops[1];
10990 uint32_t op0 = ops[2];
10991 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010992 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010993 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010994 const char *op = opcode == OpIAddCarry ? "uaddCarry" : "usubBorrow";
10995
10996 statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", op, "(", to_expression(op0), ", ",
10997 to_expression(op1), ", ", to_expression(result_id), ".", to_member_name(type, 1), ");");
10998 break;
10999 }
11000
11001 case OpUMulExtended:
11002 case OpSMulExtended:
11003 {
11004 if (options.es && options.version < 310)
11005 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
11006 else if (!options.es && options.version < 400)
11007 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 4000.");
11008
11009 uint32_t result_type = ops[0];
11010 uint32_t result_id = ops[1];
11011 uint32_t op0 = ops[2];
11012 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011013 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020011014 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011015 const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended";
11016
11017 statement(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(result_id), ".",
11018 to_member_name(type, 1), ", ", to_expression(result_id), ".", to_member_name(type, 0), ");");
11019 break;
11020 }
11021
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011022 case OpFDiv:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011023 GLSL_BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011024 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011025
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011026 case OpShiftRightLogical:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011027 GLSL_BOP_CAST(>>, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011028 break;
11029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011030 case OpShiftRightArithmetic:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011031 GLSL_BOP_CAST(>>, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011032 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011033
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011034 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020011035 {
11036 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011037 GLSL_BOP_CAST(<<, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011038 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020011039 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011040
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011041 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011042 {
11043 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011044 GLSL_BOP_CAST(|, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011045 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011046 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011047
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011048 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011049 {
11050 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +010011051 GLSL_BOP_CAST(^, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011052 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011053 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011054
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011055 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011056 {
11057 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011058 GLSL_BOP_CAST(&, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011059 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011060 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011061
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011062 case OpNot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011063 GLSL_UOP(~);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011064 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011066 case OpUMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011067 GLSL_BOP_CAST(%, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011068 break;
11069
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011070 case OpSMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011071 GLSL_BOP_CAST(%, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011072 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011073
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011074 case OpFMod:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011075 GLSL_BFOP(mod);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011076 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +020011077
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011078 case OpFRem:
11079 {
11080 if (is_legacy())
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010011081 SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is "
11082 "needed for legacy.");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011083
11084 uint32_t result_type = ops[0];
11085 uint32_t result_id = ops[1];
11086 uint32_t op0 = ops[2];
11087 uint32_t op1 = ops[3];
11088
11089 // Needs special handling.
11090 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010011091 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
11092 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011093
11094 emit_op(result_type, result_id, expr, forward);
11095 inherit_expression_dependencies(result_id, op0);
11096 inherit_expression_dependencies(result_id, op1);
11097 break;
11098 }
11099
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011100 // Relational
11101 case OpAny:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011102 GLSL_UFOP(any);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011103 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011104
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011105 case OpAll:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011106 GLSL_UFOP(all);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011107 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011109 case OpSelect:
11110 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
11111 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011112
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011113 case OpLogicalOr:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011114 {
11115 // No vector variant in GLSL for logical OR.
11116 auto result_type = ops[0];
11117 auto id = ops[1];
11118 auto &type = get<SPIRType>(result_type);
11119
11120 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020011121 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011122 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011123 GLSL_BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011124 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011125 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011126
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011127 case OpLogicalAnd:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011128 {
11129 // No vector variant in GLSL for logical AND.
11130 auto result_type = ops[0];
11131 auto id = ops[1];
11132 auto &type = get<SPIRType>(result_type);
11133
11134 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020011135 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011136 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011137 GLSL_BOP(&&);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011138 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011139 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011140
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011141 case OpLogicalNot:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011142 {
11143 auto &type = get<SPIRType>(ops[0]);
11144 if (type.vecsize > 1)
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010011145 GLSL_UFOP(not );
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011146 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011147 GLSL_UOP(!);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011148 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011149 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011150
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011151 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011152 {
11153 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011154 GLSL_BFOP_CAST(equal, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011155 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011156 GLSL_BOP_CAST(==, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011157 break;
11158 }
11159
11160 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011161 case OpFOrdEqual:
11162 {
11163 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011164 GLSL_BFOP(equal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011165 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011166 GLSL_BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011167 break;
11168 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011169
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011170 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011171 {
11172 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011173 GLSL_BFOP_CAST(notEqual, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011174 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011175 GLSL_BOP_CAST(!=, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011176 break;
11177 }
11178
11179 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011180 case OpFOrdNotEqual:
11181 {
11182 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011183 GLSL_BFOP(notEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011184 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011185 GLSL_BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011186 break;
11187 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011188
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011189 case OpUGreaterThan:
11190 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011191 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011192 auto type = opcode == OpUGreaterThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011193 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011194 GLSL_BFOP_CAST(greaterThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011195 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011196 GLSL_BOP_CAST(>, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011197 break;
11198 }
11199
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011200 case OpFOrdGreaterThan:
11201 {
11202 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011203 GLSL_BFOP(greaterThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011204 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011205 GLSL_BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011206 break;
11207 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011208
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011209 case OpUGreaterThanEqual:
11210 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011211 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011212 auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011213 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011214 GLSL_BFOP_CAST(greaterThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011215 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011216 GLSL_BOP_CAST(>=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011217 break;
11218 }
11219
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011220 case OpFOrdGreaterThanEqual:
11221 {
11222 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011223 GLSL_BFOP(greaterThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011224 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011225 GLSL_BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011226 break;
11227 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011228
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011229 case OpULessThan:
11230 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011231 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011232 auto type = opcode == OpULessThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011233 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011234 GLSL_BFOP_CAST(lessThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011235 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011236 GLSL_BOP_CAST(<, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011237 break;
11238 }
11239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011240 case OpFOrdLessThan:
11241 {
11242 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011243 GLSL_BFOP(lessThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011244 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011245 GLSL_BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011246 break;
11247 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011248
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011249 case OpULessThanEqual:
11250 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011251 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011252 auto type = opcode == OpULessThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011253 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011254 GLSL_BFOP_CAST(lessThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011255 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011256 GLSL_BOP_CAST(<=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011257 break;
11258 }
11259
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011260 case OpFOrdLessThanEqual:
11261 {
11262 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011263 GLSL_BFOP(lessThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011264 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011265 GLSL_BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011266 break;
11267 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011268
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011269 // Conversion
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020011270 case OpSConvert:
11271 case OpConvertSToF:
11272 case OpUConvert:
11273 case OpConvertUToF:
11274 {
11275 auto input_type = opcode == OpSConvert || opcode == OpConvertSToF ? int_type : uint_type;
11276 uint32_t result_type = ops[0];
11277 uint32_t id = ops[1];
11278
11279 auto &type = get<SPIRType>(result_type);
11280 auto &arg_type = expression_type(ops[2]);
11281 auto func = type_to_glsl_constructor(type);
11282
Hans-Kristian Arntzen4edb99d2019-11-28 13:49:53 +010011283 if (arg_type.width < type.width || type_is_floating_point(type))
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020011284 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), input_type, type.basetype);
11285 else
11286 emit_unary_func_op(result_type, id, ops[2], func.c_str());
11287 break;
11288 }
11289
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011290 case OpConvertFToU:
11291 case OpConvertFToS:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020011292 {
11293 // Cast to expected arithmetic type, then potentially bitcast away to desired signedness.
11294 uint32_t result_type = ops[0];
11295 uint32_t id = ops[1];
11296 auto &type = get<SPIRType>(result_type);
11297 auto expected_type = type;
11298 auto &float_type = expression_type(ops[2]);
11299 expected_type.basetype =
11300 opcode == OpConvertFToS ? to_signed_basetype(type.width) : to_unsigned_basetype(type.width);
11301
11302 auto func = type_to_glsl_constructor(expected_type);
11303 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), float_type.basetype, expected_type.basetype);
11304 break;
11305 }
11306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011307 case OpFConvert:
11308 {
11309 uint32_t result_type = ops[0];
11310 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011312 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
11313 emit_unary_func_op(result_type, id, ops[2], func.c_str());
11314 break;
11315 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011316
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011317 case OpBitcast:
11318 {
11319 uint32_t result_type = ops[0];
11320 uint32_t id = ops[1];
11321 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011322
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +020011323 if (!emit_complex_bitcast(result_type, id, arg))
11324 {
11325 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
11326 emit_unary_func_op(result_type, id, arg, op.c_str());
11327 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011328 break;
11329 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011330
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020011331 case OpQuantizeToF16:
11332 {
11333 uint32_t result_type = ops[0];
11334 uint32_t id = ops[1];
11335 uint32_t arg = ops[2];
11336
11337 string op;
11338 auto &type = get<SPIRType>(result_type);
11339
11340 switch (type.vecsize)
11341 {
11342 case 1:
11343 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
11344 break;
11345 case 2:
11346 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
11347 break;
11348 case 3:
11349 {
11350 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
11351 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
11352 op = join("vec3(", op0, ", ", op1, ")");
11353 break;
11354 }
11355 case 4:
11356 {
11357 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
11358 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
11359 op = join("vec4(", op0, ", ", op1, ")");
11360 break;
11361 }
11362 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011363 SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020011364 }
11365
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011366 emit_op(result_type, id, op, should_forward(arg));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010011367 inherit_expression_dependencies(id, arg);
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020011368 break;
11369 }
11370
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011371 // Derivatives
11372 case OpDPdx:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011373 GLSL_UFOP(dFdx);
Lubos Lenco80c39412016-09-17 14:33:16 +020011374 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011375 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011376 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011377 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011378
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011379 case OpDPdy:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011380 GLSL_UFOP(dFdy);
Lubos Lenco80c39412016-09-17 14:33:16 +020011381 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011382 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011383 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011384 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011385
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011386 case OpDPdxFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011387 GLSL_UFOP(dFdxFine);
Robert Konradcb637db2017-03-24 15:58:54 +010011388 if (options.es)
11389 {
11390 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11391 }
11392 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011393 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011394 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011395 break;
11396
11397 case OpDPdyFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011398 GLSL_UFOP(dFdyFine);
Robert Konradcb637db2017-03-24 15:58:54 +010011399 if (options.es)
11400 {
11401 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11402 }
11403 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011404 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011405 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011406 break;
11407
11408 case OpDPdxCoarse:
Robert Konradcb637db2017-03-24 15:58:54 +010011409 if (options.es)
11410 {
11411 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11412 }
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011413 GLSL_UFOP(dFdxCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010011414 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011415 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011416 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011417 break;
11418
11419 case OpDPdyCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011420 GLSL_UFOP(dFdyCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010011421 if (options.es)
11422 {
11423 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11424 }
11425 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011426 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011427 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011428 break;
11429
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011430 case OpFwidth:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011431 GLSL_UFOP(fwidth);
Lubos Lenco80c39412016-09-17 14:33:16 +020011432 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011433 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011434 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011435 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011436
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011437 case OpFwidthCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011438 GLSL_UFOP(fwidthCoarse);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011439 if (options.es)
11440 {
11441 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11442 }
11443 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011444 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011445 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011446 break;
11447
11448 case OpFwidthFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011449 GLSL_UFOP(fwidthFine);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011450 if (options.es)
11451 {
11452 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11453 }
11454 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011455 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011456 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011457 break;
11458
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011459 // Bitfield
11460 case OpBitFieldInsert:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011461 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020011462 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 +020011463 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011464 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011465
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011466 case OpBitFieldSExtract:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011467 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020011468 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 +020011469 SPIRType::Int, SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011470 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011471 }
11472
11473 case OpBitFieldUExtract:
11474 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020011475 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 +020011476 SPIRType::Int, SPIRType::Int);
11477 break;
11478 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011479
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011480 case OpBitReverse:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011481 // BitReverse does not have issues with sign since result type must match input type.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011482 GLSL_UFOP(bitfieldReverse);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011483 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011484
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011485 case OpBitCount:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011486 {
11487 auto basetype = expression_type(ops[2]).basetype;
11488 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "bitCount", basetype, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011489 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011490 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011491
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011492 // Atomics
11493 case OpAtomicExchange:
11494 {
11495 uint32_t result_type = ops[0];
11496 uint32_t id = ops[1];
11497 uint32_t ptr = ops[2];
11498 // Ignore semantics for now, probably only relevant to CL.
11499 uint32_t val = ops[5];
11500 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011501
11502 emit_atomic_func_op(result_type, id, ptr, val, op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011503 break;
11504 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011505
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011506 case OpAtomicCompareExchange:
11507 {
11508 uint32_t result_type = ops[0];
11509 uint32_t id = ops[1];
11510 uint32_t ptr = ops[2];
11511 uint32_t val = ops[6];
11512 uint32_t comp = ops[7];
11513 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011514
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011515 emit_atomic_func_op(result_type, id, ptr, comp, val, op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011516 break;
11517 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011518
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011519 case OpAtomicLoad:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011520 {
11521 // In plain GLSL, we have no atomic loads, so emulate this by fetch adding by 0 and hope compiler figures it out.
11522 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
11523 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen8b236f22019-04-24 09:31:44 +020011524 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011525 bool atomic_image = check_atomic_image(ops[2]);
11526 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
11527 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
11528 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
11529 const char *increment = unsigned_type ? "0u" : "0";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011530 emit_op(ops[0], ops[1],
11531 join(op, "(",
11532 to_non_uniform_aware_expression(ops[2]), ", ", increment, ")"), false);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011533 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011534 break;
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011535 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011536
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010011537 case OpAtomicStore:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011538 {
11539 // In plain GLSL, we have no atomic stores, so emulate this with an atomic exchange where we don't consume the result.
11540 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
11541 uint32_t ptr = ops[0];
11542 // Ignore semantics for now, probably only relevant to CL.
11543 uint32_t val = ops[3];
11544 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011545 statement(op, "(", to_non_uniform_aware_expression(ptr), ", ", to_expression(val), ");");
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011546 flush_all_atomic_capable_variables();
11547 break;
11548 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011549
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011550 case OpAtomicIIncrement:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011551 case OpAtomicIDecrement:
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011552 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011553 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011554 auto &type = expression_type(ops[2]);
11555 if (type.storage == StorageClassAtomicCounter)
11556 {
11557 // Legacy GLSL stuff, not sure if this is relevant to support.
11558 if (opcode == OpAtomicIIncrement)
11559 GLSL_UFOP(atomicCounterIncrement);
11560 else
11561 GLSL_UFOP(atomicCounterDecrement);
11562 }
11563 else
11564 {
11565 bool atomic_image = check_atomic_image(ops[2]);
11566 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
11567 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
11568 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
11569
11570 const char *increment = nullptr;
11571 if (opcode == OpAtomicIIncrement && unsigned_type)
11572 increment = "1u";
11573 else if (opcode == OpAtomicIIncrement)
11574 increment = "1";
11575 else if (unsigned_type)
11576 increment = "uint(-1)";
11577 else
11578 increment = "-1";
11579
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011580 emit_op(ops[0], ops[1],
11581 join(op, "(", to_non_uniform_aware_expression(ops[2]), ", ", increment, ")"), false);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011582 }
11583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011584 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011585 break;
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011586 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011587
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011588 case OpAtomicIAdd:
11589 {
11590 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011591 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011592 break;
11593 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011595 case OpAtomicISub:
11596 {
11597 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
11598 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011599 auto expr = join(op, "(", to_non_uniform_aware_expression(ops[2]), ", -", to_enclosed_expression(ops[5]), ")");
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011600 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011601 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011602 break;
11603 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011604
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011605 case OpAtomicSMin:
11606 case OpAtomicUMin:
11607 {
11608 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011609 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011610 break;
11611 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011613 case OpAtomicSMax:
11614 case OpAtomicUMax:
11615 {
11616 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011617 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011618 break;
11619 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011620
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011621 case OpAtomicAnd:
11622 {
11623 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011624 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011625 break;
11626 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011628 case OpAtomicOr:
11629 {
11630 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011631 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011632 break;
11633 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011634
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011635 case OpAtomicXor:
11636 {
11637 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011638 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011639 break;
11640 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011641
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011642 // Geometry shaders
11643 case OpEmitVertex:
11644 statement("EmitVertex();");
11645 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011646
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011647 case OpEndPrimitive:
11648 statement("EndPrimitive();");
11649 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011650
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011651 case OpEmitStreamVertex:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011652 {
11653 if (options.es)
11654 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
11655 else if (!options.es && options.version < 400)
11656 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
11657
11658 auto stream_expr = to_expression(ops[0]);
11659 if (expression_type(ops[0]).basetype != SPIRType::Int)
11660 stream_expr = join("int(", stream_expr, ")");
11661 statement("EmitStreamVertex(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011662 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011663 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011664
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011665 case OpEndStreamPrimitive:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011666 {
11667 if (options.es)
11668 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
11669 else if (!options.es && options.version < 400)
11670 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
11671
11672 auto stream_expr = to_expression(ops[0]);
11673 if (expression_type(ops[0]).basetype != SPIRType::Int)
11674 stream_expr = join("int(", stream_expr, ")");
11675 statement("EndStreamPrimitive(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011676 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011677 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011678
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011679 // Textures
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011680 case OpImageSampleExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011681 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011682 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011683 case OpImageSampleProjDrefExplicitLod:
Lubos Lenco80c39412016-09-17 14:33:16 +020011684 case OpImageSampleImplicitLod:
11685 case OpImageSampleProjImplicitLod:
11686 case OpImageSampleDrefImplicitLod:
11687 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011688 case OpImageFetch:
11689 case OpImageGather:
11690 case OpImageDrefGather:
11691 // Gets a bit hairy, so move this to a separate instruction.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011692 emit_texture_op(instruction, false);
11693 break;
11694
11695 case OpImageSparseSampleExplicitLod:
11696 case OpImageSparseSampleProjExplicitLod:
11697 case OpImageSparseSampleDrefExplicitLod:
11698 case OpImageSparseSampleProjDrefExplicitLod:
11699 case OpImageSparseSampleImplicitLod:
11700 case OpImageSparseSampleProjImplicitLod:
11701 case OpImageSparseSampleDrefImplicitLod:
11702 case OpImageSparseSampleProjDrefImplicitLod:
11703 case OpImageSparseFetch:
11704 case OpImageSparseGather:
11705 case OpImageSparseDrefGather:
11706 // Gets a bit hairy, so move this to a separate instruction.
11707 emit_texture_op(instruction, true);
11708 break;
11709
11710 case OpImageSparseTexelsResident:
11711 if (options.es)
11712 SPIRV_CROSS_THROW("Sparse feedback is not supported in GLSL.");
11713 require_extension_internal("GL_ARB_sparse_texture2");
Hans-Kristian Arntzen857e1c42020-06-08 11:40:02 +020011714 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "sparseTexelsResidentARB", int_type, SPIRType::Boolean);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011715 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011717 case OpImage:
11718 {
11719 uint32_t result_type = ops[0];
11720 uint32_t id = ops[1];
Hans-Kristian Arntzenaaf397c2018-04-27 11:10:10 +020011721
11722 // Suppress usage tracking.
11723 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011724
11725 // When using the image, we need to know which variable it is actually loaded from.
11726 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020011727 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011728 break;
11729 }
11730
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011731 case OpImageQueryLod:
11732 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011733 const char *op = nullptr;
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011734 if (!options.es && options.version < 400)
11735 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011736 require_extension_internal("GL_ARB_texture_query_lod");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011737 // For some reason, the ARB spec is all-caps.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011738 op = "textureQueryLOD";
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011739 }
11740 else if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011741 SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011742 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011743 op = "textureQueryLod";
11744
11745 auto sampler_expr = to_expression(ops[2]);
11746 if (has_decoration(ops[2], DecorationNonUniform))
11747 {
11748 if (maybe_get_backing_variable(ops[2]))
11749 convert_non_uniform_expression(sampler_expr, ops[2]);
11750 else if (*backend.nonuniform_qualifier != '\0')
11751 sampler_expr = join(backend.nonuniform_qualifier, "(", sampler_expr, ")");
11752 }
11753
11754 bool forward = should_forward(ops[3]);
11755 emit_op(ops[0], ops[1],
11756 join(op, "(", sampler_expr, ", ", to_unpacked_expression(ops[3]), ")"),
11757 forward);
11758 inherit_expression_dependencies(ops[1], ops[2]);
11759 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011760 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011761 break;
11762 }
11763
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011764 case OpImageQueryLevels:
11765 {
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011766 uint32_t result_type = ops[0];
11767 uint32_t id = ops[1];
11768
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011769 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011770 require_extension_internal("GL_ARB_texture_query_levels");
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011771 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011772 SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011773
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020011774 auto expr = join("textureQueryLevels(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011775 auto &restype = get<SPIRType>(ops[0]);
11776 expr = bitcast_expression(restype, SPIRType::Int, expr);
11777 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011778 break;
11779 }
11780
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011781 case OpImageQuerySamples:
11782 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011783 auto &type = expression_type(ops[2]);
11784 uint32_t result_type = ops[0];
11785 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011786
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011787 string expr;
11788 if (type.image.sampled == 2)
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011789 expr = join("imageSamples(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011790 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020011791 expr = join("textureSamples(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011792
11793 auto &restype = get<SPIRType>(ops[0]);
11794 expr = bitcast_expression(restype, SPIRType::Int, expr);
11795 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011796 break;
11797 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011798
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011799 case OpSampledImage:
11800 {
11801 uint32_t result_type = ops[0];
11802 uint32_t id = ops[1];
11803 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011804 inherit_expression_dependencies(id, ops[2]);
11805 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011806 break;
11807 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +020011808
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011809 case OpImageQuerySizeLod:
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011810 {
11811 uint32_t result_type = ops[0];
11812 uint32_t id = ops[1];
rdb10fa5f62020-11-09 15:26:46 +010011813 uint32_t img = ops[2];
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011814
rdb10fa5f62020-11-09 15:26:46 +010011815 std::string fname = "textureSize";
11816 if (is_legacy_desktop())
11817 {
11818 auto &type = expression_type(img);
11819 auto &imgtype = get<SPIRType>(type.self);
11820 fname = legacy_tex_op(fname, imgtype, img);
11821 }
11822 else if (is_legacy_es())
11823 SPIRV_CROSS_THROW("textureSize is not supported in ESSL 100.");
11824
11825 auto expr = join(fname, "(", convert_separate_image_to_expression(img), ", ",
Hans-Kristian Arntzen7e23e692018-04-30 12:46:21 +020011826 bitcast_expression(SPIRType::Int, ops[3]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011827 auto &restype = get<SPIRType>(ops[0]);
11828 expr = bitcast_expression(restype, SPIRType::Int, expr);
11829 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011830 break;
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011831 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011832
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011833 // Image load/store
11834 case OpImageRead:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011835 case OpImageSparseRead:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011836 {
11837 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
11838 // not adding the proper qualifiers.
11839 // If it turns out we need to read the image after all, remove the qualifier and recompile.
11840 auto *var = maybe_get_backing_variable(ops[2]);
11841 if (var)
11842 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010011843 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011844 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011845 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011846 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011847 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011848 }
11849 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011850
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011851 uint32_t result_type = ops[0];
11852 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011853
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011854 bool pure;
11855 string imgexpr;
11856 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011857
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011858 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011859 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011860 if (type.image.ms)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011861 SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011862
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +020011863 auto itr =
11864 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 +010011865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011866 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011867 {
11868 // For non-PLS inputs, we rely on subpass type remapping information to get it right
11869 // since ImageRead always returns 4-component vectors and the backing type is opaque.
11870 if (!var->remapped_components)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011871 SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011872 imgexpr = remap_swizzle(get<SPIRType>(result_type), var->remapped_components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011873 }
11874 else
11875 {
11876 // PLS input could have different number of components than what the SPIR expects, swizzle to
11877 // the appropriate vector size.
11878 uint32_t components = pls_format_to_components(itr->format);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011879 imgexpr = remap_swizzle(get<SPIRType>(result_type), components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011880 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011881 pure = true;
11882 }
11883 else if (type.image.dim == DimSubpassData)
11884 {
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010011885 if (var && subpass_input_is_framebuffer_fetch(var->self))
11886 {
11887 imgexpr = to_expression(var->self);
11888 }
11889 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011890 {
11891 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011892 if (type.image.ms)
11893 {
11894 uint32_t operands = ops[4];
11895 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011896 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11897 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011898
11899 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011900 imgexpr = join("subpassLoad(", to_non_uniform_aware_expression(ops[2]), ", ", to_expression(samples), ")");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011901 }
11902 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011903 imgexpr = join("subpassLoad(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011904 }
11905 else
11906 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011907 if (type.image.ms)
11908 {
11909 uint32_t operands = ops[4];
11910 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011911 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11912 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011913
11914 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011915 imgexpr = join("texelFetch(", to_non_uniform_aware_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011916 to_expression(samples), ")");
11917 }
11918 else
11919 {
11920 // Implement subpass loads via texture barrier style sampling.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011921 imgexpr = join("texelFetch(", to_non_uniform_aware_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011922 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011923 }
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011924 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011925 pure = true;
11926 }
11927 else
11928 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011929 bool sparse = opcode == OpImageSparseRead;
11930 uint32_t sparse_code_id = 0;
11931 uint32_t sparse_texel_id = 0;
11932 if (sparse)
11933 emit_sparse_feedback_temporaries(ops[0], ops[1], sparse_code_id, sparse_texel_id);
11934
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010011935 // imageLoad only accepts int coords, not uint.
11936 auto coord_expr = to_expression(ops[3]);
11937 auto target_coord_type = expression_type(ops[3]);
11938 target_coord_type.basetype = SPIRType::Int;
11939 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
11940
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011941 // Plain image load/store.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011942 if (sparse)
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011943 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011944 if (type.image.ms)
11945 {
11946 uint32_t operands = ops[4];
11947 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011948 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11949 "operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011950
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011951 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011952 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_non_uniform_aware_expression(ops[2]), ", ",
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011953 coord_expr, ", ", to_expression(samples), ", ", to_expression(sparse_texel_id), ");");
11954 }
11955 else
11956 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011957 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_non_uniform_aware_expression(ops[2]), ", ",
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011958 coord_expr, ", ", to_expression(sparse_texel_id), ");");
11959 }
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020011960 imgexpr = join(type_to_glsl(get<SPIRType>(result_type)), "(", to_expression(sparse_code_id), ", ",
11961 to_expression(sparse_texel_id), ")");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011962 }
11963 else
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011964 {
11965 if (type.image.ms)
11966 {
11967 uint32_t operands = ops[4];
11968 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011969 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11970 "operand mask was used.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011971
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011972 uint32_t samples = ops[5];
11973 imgexpr =
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011974 join("imageLoad(", to_non_uniform_aware_expression(ops[2]), ", ", coord_expr, ", ", to_expression(samples), ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011975 }
11976 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011977 imgexpr = join("imageLoad(", to_non_uniform_aware_expression(ops[2]), ", ", coord_expr, ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011978 }
11979
11980 if (!sparse)
11981 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011982 pure = false;
11983 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011985 if (var && var->forwardable)
11986 {
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010011987 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
11988 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011989
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011990 // We only need to track dependencies if we're reading from image load/store.
11991 if (!pure)
11992 {
11993 e.loaded_from = var->self;
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010011994 if (forward)
11995 var->dependees.push_back(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011996 }
11997 }
11998 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011999 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010012000
12001 inherit_expression_dependencies(id, ops[2]);
12002 if (type.image.ms)
12003 inherit_expression_dependencies(id, ops[5]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012004 break;
12005 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012006
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012007 case OpImageTexelPointer:
12008 {
12009 uint32_t result_type = ops[0];
12010 uint32_t id = ops[1];
Mark Satterthwaitec4f97042019-08-26 11:28:13 -040012011
12012 auto coord_expr = to_expression(ops[3]);
12013 auto target_coord_type = expression_type(ops[3]);
12014 target_coord_type.basetype = SPIRType::Int;
12015 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
12016
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010012017 auto expr = join(to_expression(ops[2]), ", ", coord_expr);
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010012018 auto &e = set<SPIRExpression>(id, expr, result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012019
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012020 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012021 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012022 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen6edbf0c2019-10-24 11:30:20 +020012023 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012024 break;
12025 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012026
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012027 case OpImageWrite:
12028 {
12029 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
12030 // not adding the proper qualifiers.
12031 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
12032 auto *var = maybe_get_backing_variable(ops[0]);
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))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012037 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012038 flags.clear(DecorationNonWritable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012039 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012040 }
12041 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012042
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012043 auto &type = expression_type(ops[0]);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012044 auto &value_type = expression_type(ops[2]);
12045 auto store_type = value_type;
12046 store_type.vecsize = 4;
12047
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010012048 // imageStore only accepts int coords, not uint.
12049 auto coord_expr = to_expression(ops[1]);
12050 auto target_coord_type = expression_type(ops[1]);
12051 target_coord_type.basetype = SPIRType::Int;
12052 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
12053
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012054 if (type.image.ms)
12055 {
12056 uint32_t operands = ops[3];
12057 if (operands != ImageOperandsSampleMask || length != 5)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012058 SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012059 uint32_t samples = ops[4];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012060 statement("imageStore(", to_non_uniform_aware_expression(ops[0]), ", ", coord_expr, ", ", to_expression(samples), ", ",
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010012061 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012062 }
12063 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012064 statement("imageStore(", to_non_uniform_aware_expression(ops[0]), ", ", coord_expr, ", ",
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012065 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012066
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012067 if (var && variable_storage_is_aliased(*var))
12068 flush_all_aliased_variables();
12069 break;
12070 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012072 case OpImageQuerySize:
12073 {
12074 auto &type = expression_type(ops[2]);
12075 uint32_t result_type = ops[0];
12076 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012078 if (type.basetype == SPIRType::Image)
12079 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012080 string expr;
12081 if (type.image.sampled == 2)
12082 {
rdb10fa5f62020-11-09 15:26:46 +010012083 if (!options.es && options.version < 430)
12084 require_extension_internal("GL_ARB_shader_image_size");
12085 else if (options.es && options.version < 310)
12086 SPIRV_CROSS_THROW("At least ESSL 3.10 required for imageSize.");
12087
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012088 // The size of an image is always constant.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012089 expr = join("imageSize(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012090 }
12091 else
12092 {
12093 // This path is hit for samplerBuffers and multisampled images which do not have LOD.
rdb10fa5f62020-11-09 15:26:46 +010012094 std::string fname = "textureSize";
12095 if (is_legacy())
12096 {
12097 auto &imgtype = get<SPIRType>(type.self);
12098 fname = legacy_tex_op(fname, imgtype, ops[2]);
12099 }
12100 expr = join(fname, "(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012101 }
12102
12103 auto &restype = get<SPIRType>(ops[0]);
12104 expr = bitcast_expression(restype, SPIRType::Int, expr);
12105 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012106 }
12107 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012108 SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012109 break;
12110 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012111
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012112 // Compute
12113 case OpControlBarrier:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012114 case OpMemoryBarrier:
12115 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012116 uint32_t execution_scope = 0;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012117 uint32_t memory;
12118 uint32_t semantics;
12119
12120 if (opcode == OpMemoryBarrier)
12121 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012122 memory = evaluate_constant_u32(ops[0]);
12123 semantics = evaluate_constant_u32(ops[1]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012124 }
12125 else
12126 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012127 execution_scope = evaluate_constant_u32(ops[0]);
12128 memory = evaluate_constant_u32(ops[1]);
12129 semantics = evaluate_constant_u32(ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012130 }
12131
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012132 if (execution_scope == ScopeSubgroup || memory == ScopeSubgroup)
12133 {
crissdb52e272020-10-08 12:14:52 +020012134 // OpControlBarrier with ScopeSubgroup is subgroupBarrier()
12135 if (opcode != OpControlBarrier)
12136 {
12137 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMemBarrier);
12138 }
12139 else
12140 {
12141 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBarrier);
12142 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012143 }
12144
12145 if (execution_scope != ScopeSubgroup && get_entry_point().model == ExecutionModelTessellationControl)
12146 {
12147 // Control shaders only have barriers, and it implies memory barriers.
12148 if (opcode == OpControlBarrier)
12149 statement("barrier();");
12150 break;
12151 }
12152
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012153 // We only care about these flags, acquire/release and friends are not relevant to GLSL.
12154 semantics = mask_relevant_memory_semantics(semantics);
12155
12156 if (opcode == OpMemoryBarrier)
12157 {
12158 // If we are a memory barrier, and the next instruction is a control barrier, check if that memory barrier
12159 // does what we need, so we avoid redundant barriers.
12160 const Instruction *next = get_next_instruction_in_block(instruction);
12161 if (next && next->op == OpControlBarrier)
12162 {
12163 auto *next_ops = stream(*next);
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012164 uint32_t next_memory = evaluate_constant_u32(next_ops[1]);
12165 uint32_t next_semantics = evaluate_constant_u32(next_ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012166 next_semantics = mask_relevant_memory_semantics(next_semantics);
12167
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010012168 bool memory_scope_covered = false;
12169 if (next_memory == memory)
12170 memory_scope_covered = true;
12171 else if (next_semantics == MemorySemanticsWorkgroupMemoryMask)
12172 {
12173 // If we only care about workgroup memory, either Device or Workgroup scope is fine,
12174 // scope does not have to match.
12175 if ((next_memory == ScopeDevice || next_memory == ScopeWorkgroup) &&
12176 (memory == ScopeDevice || memory == ScopeWorkgroup))
12177 {
12178 memory_scope_covered = true;
12179 }
12180 }
12181 else if (memory == ScopeWorkgroup && next_memory == ScopeDevice)
12182 {
12183 // The control barrier has device scope, but the memory barrier just has workgroup scope.
12184 memory_scope_covered = true;
12185 }
12186
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012187 // If we have the same memory scope, and all memory types are covered, we're good.
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010012188 if (memory_scope_covered && (semantics & next_semantics) == semantics)
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012189 break;
12190 }
12191 }
12192
12193 // We are synchronizing some memory or syncing execution,
12194 // so we cannot forward any loads beyond the memory barrier.
12195 if (semantics || opcode == OpControlBarrier)
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012196 {
12197 assert(current_emitting_block);
12198 flush_control_dependent_expressions(current_emitting_block->self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012199 flush_all_active_variables();
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012200 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012201
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012202 if (memory == ScopeWorkgroup) // Only need to consider memory within a group
12203 {
12204 if (semantics == MemorySemanticsWorkgroupMemoryMask)
Hans-Kristian Arntzen67b29912019-12-04 15:06:19 +010012205 {
12206 // OpControlBarrier implies a memory barrier for shared memory as well.
12207 bool implies_shared_barrier = opcode == OpControlBarrier && execution_scope == ScopeWorkgroup;
12208 if (!implies_shared_barrier)
12209 statement("memoryBarrierShared();");
12210 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012211 else if (semantics != 0)
12212 statement("groupMemoryBarrier();");
12213 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012214 else if (memory == ScopeSubgroup)
12215 {
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +020012216 const uint32_t all_barriers =
12217 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012218
12219 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
12220 {
12221 // These are not relevant for GLSL, but assume it means memoryBarrier().
12222 // memoryBarrier() does everything, so no need to test anything else.
12223 statement("subgroupMemoryBarrier();");
12224 }
12225 else if ((semantics & all_barriers) == all_barriers)
12226 {
12227 // Short-hand instead of emitting 3 barriers.
12228 statement("subgroupMemoryBarrier();");
12229 }
12230 else
12231 {
12232 // Pick out individual barriers.
12233 if (semantics & MemorySemanticsWorkgroupMemoryMask)
12234 statement("subgroupMemoryBarrierShared();");
12235 if (semantics & MemorySemanticsUniformMemoryMask)
12236 statement("subgroupMemoryBarrierBuffer();");
12237 if (semantics & MemorySemanticsImageMemoryMask)
12238 statement("subgroupMemoryBarrierImage();");
12239 }
12240 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012241 else
12242 {
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010012243 const uint32_t all_barriers =
12244 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012245
12246 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
12247 {
12248 // These are not relevant for GLSL, but assume it means memoryBarrier().
12249 // memoryBarrier() does everything, so no need to test anything else.
12250 statement("memoryBarrier();");
12251 }
12252 else if ((semantics & all_barriers) == all_barriers)
12253 {
12254 // Short-hand instead of emitting 4 barriers.
12255 statement("memoryBarrier();");
12256 }
12257 else
12258 {
12259 // Pick out individual barriers.
12260 if (semantics & MemorySemanticsWorkgroupMemoryMask)
12261 statement("memoryBarrierShared();");
12262 if (semantics & MemorySemanticsUniformMemoryMask)
12263 statement("memoryBarrierBuffer();");
12264 if (semantics & MemorySemanticsImageMemoryMask)
12265 statement("memoryBarrierImage();");
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012266 }
12267 }
12268
12269 if (opcode == OpControlBarrier)
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012270 {
12271 if (execution_scope == ScopeSubgroup)
12272 statement("subgroupBarrier();");
12273 else
12274 statement("barrier();");
12275 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012276 break;
12277 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012278
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012279 case OpExtInst:
12280 {
12281 uint32_t extension_set = ops[2];
Lou Kramer6671f522017-11-21 14:04:57 +010012282
12283 if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012284 {
Lou Kramer6671f522017-11-21 14:04:57 +010012285 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12286 }
12287 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_ballot)
12288 {
12289 emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12290 }
12291 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
12292 {
12293 emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12294 }
12295 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_trinary_minmax)
12296 {
12297 emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12298 }
12299 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_gcn_shader)
12300 {
12301 emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12302 }
Lifeng Pan5ca87792019-07-04 16:03:06 +080012303 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_debug_info)
12304 {
12305 break; // Ignore SPIR-V debug information extended instructions.
12306 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012307 else
12308 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012309 statement("// unimplemented ext op ", instruction.op);
12310 break;
12311 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012312
Lou Kramer6671f522017-11-21 14:04:57 +010012313 break;
12314 }
12315
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012316 // Legacy sub-group stuff ...
Lou Kramer6671f522017-11-21 14:04:57 +010012317 case OpSubgroupBallotKHR:
12318 {
Lou Kramer6671f522017-11-21 14:04:57 +010012319 uint32_t result_type = ops[0];
12320 uint32_t id = ops[1];
12321 string expr;
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012322 expr = join("uvec4(unpackUint2x32(ballotARB(" + to_expression(ops[2]) + ")), 0u, 0u)");
Hans-Kristian Arntzen4979d102018-03-12 17:51:14 +010012323 emit_op(result_type, id, expr, should_forward(ops[2]));
Lou Kramer6671f522017-11-21 14:04:57 +010012324
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012325 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzenae2680c2018-03-12 17:42:48 +010012326 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012327 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012328 break;
12329 }
12330
12331 case OpSubgroupFirstInvocationKHR:
12332 {
Lou Kramer6671f522017-11-21 14:04:57 +010012333 uint32_t result_type = ops[0];
12334 uint32_t id = ops[1];
12335 emit_unary_func_op(result_type, id, ops[2], "readFirstInvocationARB");
12336
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012337 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012338 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012339 break;
12340 }
12341
12342 case OpSubgroupReadInvocationKHR:
12343 {
Lou Kramer6671f522017-11-21 14:04:57 +010012344 uint32_t result_type = ops[0];
12345 uint32_t id = ops[1];
12346 emit_binary_func_op(result_type, id, ops[2], ops[3], "readInvocationARB");
12347
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012348 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012349 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012350 break;
12351 }
12352
12353 case OpSubgroupAllKHR:
12354 {
Lou Kramer6671f522017-11-21 14:04:57 +010012355 uint32_t result_type = ops[0];
12356 uint32_t id = ops[1];
12357 emit_unary_func_op(result_type, id, ops[2], "allInvocationsARB");
12358
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012359 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012360 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012361 break;
12362 }
12363
12364 case OpSubgroupAnyKHR:
12365 {
Lou Kramer6671f522017-11-21 14:04:57 +010012366 uint32_t result_type = ops[0];
12367 uint32_t id = ops[1];
12368 emit_unary_func_op(result_type, id, ops[2], "anyInvocationARB");
12369
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012370 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012371 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012372 break;
12373 }
12374
12375 case OpSubgroupAllEqualKHR:
12376 {
Lou Kramer6671f522017-11-21 14:04:57 +010012377 uint32_t result_type = ops[0];
12378 uint32_t id = ops[1];
12379 emit_unary_func_op(result_type, id, ops[2], "allInvocationsEqualARB");
12380
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012381 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012382 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012383 break;
12384 }
12385
12386 case OpGroupIAddNonUniformAMD:
12387 case OpGroupFAddNonUniformAMD:
12388 {
Lou Kramer6671f522017-11-21 14:04:57 +010012389 uint32_t result_type = ops[0];
12390 uint32_t id = ops[1];
12391 emit_unary_func_op(result_type, id, ops[4], "addInvocationsNonUniformAMD");
12392
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012393 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012394 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012395 break;
12396 }
12397
12398 case OpGroupFMinNonUniformAMD:
12399 case OpGroupUMinNonUniformAMD:
12400 case OpGroupSMinNonUniformAMD:
12401 {
Lou Kramer6671f522017-11-21 14:04:57 +010012402 uint32_t result_type = ops[0];
12403 uint32_t id = ops[1];
12404 emit_unary_func_op(result_type, id, ops[4], "minInvocationsNonUniformAMD");
12405
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012406 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012407 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012408 break;
12409 }
12410
12411 case OpGroupFMaxNonUniformAMD:
12412 case OpGroupUMaxNonUniformAMD:
12413 case OpGroupSMaxNonUniformAMD:
12414 {
Lou Kramer6671f522017-11-21 14:04:57 +010012415 uint32_t result_type = ops[0];
12416 uint32_t id = ops[1];
12417 emit_unary_func_op(result_type, id, ops[4], "maxInvocationsNonUniformAMD");
12418
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012419 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012420 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012421 break;
12422 }
12423
12424 case OpFragmentMaskFetchAMD:
12425 {
12426 auto &type = expression_type(ops[2]);
12427 uint32_t result_type = ops[0];
12428 uint32_t id = ops[1];
12429
12430 if (type.image.dim == spv::DimSubpassData)
12431 {
12432 emit_unary_func_op(result_type, id, ops[2], "fragmentMaskFetchAMD");
12433 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012434 else
Lou Kramer6671f522017-11-21 14:04:57 +010012435 {
12436 emit_binary_func_op(result_type, id, ops[2], ops[3], "fragmentMaskFetchAMD");
12437 }
12438
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012439 require_extension_internal("GL_AMD_shader_fragment_mask");
Lou Kramer6671f522017-11-21 14:04:57 +010012440 break;
12441 }
12442
12443 case OpFragmentFetchAMD:
12444 {
12445 auto &type = expression_type(ops[2]);
12446 uint32_t result_type = ops[0];
12447 uint32_t id = ops[1];
12448
12449 if (type.image.dim == spv::DimSubpassData)
12450 {
12451 emit_binary_func_op(result_type, id, ops[2], ops[4], "fragmentFetchAMD");
12452 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012453 else
Lou Kramer6671f522017-11-21 14:04:57 +010012454 {
12455 emit_trinary_func_op(result_type, id, ops[2], ops[3], ops[4], "fragmentFetchAMD");
12456 }
12457
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012458 require_extension_internal("GL_AMD_shader_fragment_mask");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012459 break;
12460 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012461
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012462 // Vulkan 1.1 sub-group stuff ...
12463 case OpGroupNonUniformElect:
12464 case OpGroupNonUniformBroadcast:
12465 case OpGroupNonUniformBroadcastFirst:
12466 case OpGroupNonUniformBallot:
12467 case OpGroupNonUniformInverseBallot:
12468 case OpGroupNonUniformBallotBitExtract:
12469 case OpGroupNonUniformBallotBitCount:
12470 case OpGroupNonUniformBallotFindLSB:
12471 case OpGroupNonUniformBallotFindMSB:
12472 case OpGroupNonUniformShuffle:
12473 case OpGroupNonUniformShuffleXor:
12474 case OpGroupNonUniformShuffleUp:
12475 case OpGroupNonUniformShuffleDown:
12476 case OpGroupNonUniformAll:
12477 case OpGroupNonUniformAny:
12478 case OpGroupNonUniformAllEqual:
12479 case OpGroupNonUniformFAdd:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020012480 case OpGroupNonUniformIAdd:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012481 case OpGroupNonUniformFMul:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020012482 case OpGroupNonUniformIMul:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012483 case OpGroupNonUniformFMin:
12484 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020012485 case OpGroupNonUniformSMin:
12486 case OpGroupNonUniformSMax:
12487 case OpGroupNonUniformUMin:
12488 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012489 case OpGroupNonUniformBitwiseAnd:
12490 case OpGroupNonUniformBitwiseOr:
12491 case OpGroupNonUniformBitwiseXor:
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +010012492 case OpGroupNonUniformLogicalAnd:
12493 case OpGroupNonUniformLogicalOr:
12494 case OpGroupNonUniformLogicalXor:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012495 case OpGroupNonUniformQuadSwap:
12496 case OpGroupNonUniformQuadBroadcast:
12497 emit_subgroup_op(instruction);
12498 break;
12499
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012500 case OpFUnordEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012501 case OpFUnordNotEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012502 case OpFUnordLessThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012503 case OpFUnordGreaterThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012504 case OpFUnordLessThanEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012505 case OpFUnordGreaterThanEqual:
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020012506 {
12507 // GLSL doesn't specify if floating point comparisons are ordered or unordered,
12508 // but glslang always emits ordered floating point compares for GLSL.
12509 // To get unordered compares, we can test the opposite thing and invert the result.
12510 // This way, we force true when there is any NaN present.
12511 uint32_t op0 = ops[2];
12512 uint32_t op1 = ops[3];
12513
12514 string expr;
12515 if (expression_type(op0).vecsize > 1)
12516 {
12517 const char *comp_op = nullptr;
12518 switch (opcode)
12519 {
12520 case OpFUnordEqual:
12521 comp_op = "notEqual";
12522 break;
12523
12524 case OpFUnordNotEqual:
12525 comp_op = "equal";
12526 break;
12527
12528 case OpFUnordLessThan:
12529 comp_op = "greaterThanEqual";
12530 break;
12531
12532 case OpFUnordLessThanEqual:
12533 comp_op = "greaterThan";
12534 break;
12535
12536 case OpFUnordGreaterThan:
12537 comp_op = "lessThanEqual";
12538 break;
12539
12540 case OpFUnordGreaterThanEqual:
12541 comp_op = "lessThan";
12542 break;
12543
12544 default:
12545 assert(0);
12546 break;
12547 }
12548
12549 expr = join("not(", comp_op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), "))");
12550 }
12551 else
12552 {
12553 const char *comp_op = nullptr;
12554 switch (opcode)
12555 {
12556 case OpFUnordEqual:
12557 comp_op = " != ";
12558 break;
12559
12560 case OpFUnordNotEqual:
12561 comp_op = " == ";
12562 break;
12563
12564 case OpFUnordLessThan:
12565 comp_op = " >= ";
12566 break;
12567
12568 case OpFUnordLessThanEqual:
12569 comp_op = " > ";
12570 break;
12571
12572 case OpFUnordGreaterThan:
12573 comp_op = " <= ";
12574 break;
12575
12576 case OpFUnordGreaterThanEqual:
12577 comp_op = " < ";
12578 break;
12579
12580 default:
12581 assert(0);
12582 break;
12583 }
12584
12585 expr = join("!(", to_enclosed_unpacked_expression(op0), comp_op, to_enclosed_unpacked_expression(op1), ")");
12586 }
12587
12588 emit_op(ops[0], ops[1], expr, should_forward(op0) && should_forward(op1));
12589 inherit_expression_dependencies(ops[1], op0);
12590 inherit_expression_dependencies(ops[1], op1);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012591 break;
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020012592 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012593
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012594 case OpReportIntersectionKHR:
12595 // NV is same opcode.
12596 forced_temporaries.insert(ops[1]);
12597 if (ray_tracing_is_khr)
12598 GLSL_BFOP(reportIntersectionEXT);
12599 else
12600 GLSL_BFOP(reportIntersectionNV);
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012601 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012602 break;
12603 case OpIgnoreIntersectionNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012604 // KHR variant is a terminator.
Patrick Moursda39a7b2019-02-26 15:43:03 +010012605 statement("ignoreIntersectionNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012606 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012607 break;
12608 case OpTerminateRayNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012609 // KHR variant is a terminator.
Patrick Moursda39a7b2019-02-26 15:43:03 +010012610 statement("terminateRayNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012611 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012612 break;
12613 case OpTraceNV:
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012614 statement("traceNV(", to_non_uniform_aware_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
Patrick Moursc96bab02019-03-26 14:04:39 +010012615 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
12616 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
12617 to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012618 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012619 break;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012620 case OpTraceRayKHR:
12621 if (!has_decoration(ops[10], DecorationLocation))
12622 SPIRV_CROSS_THROW("A memory declaration object must be used in TraceRayKHR.");
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012623 statement("traceRayEXT(", to_non_uniform_aware_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012624 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
12625 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
12626 to_expression(ops[9]), ", ", get_decoration(ops[10], DecorationLocation), ");");
12627 flush_control_dependent_expressions(current_emitting_block->self);
12628 break;
Patrick Moursda39a7b2019-02-26 15:43:03 +010012629 case OpExecuteCallableNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010012630 statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012631 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012632 break;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012633 case OpExecuteCallableKHR:
12634 if (!has_decoration(ops[1], DecorationLocation))
12635 SPIRV_CROSS_THROW("A memory declaration object must be used in ExecuteCallableKHR.");
12636 statement("executeCallableEXT(", to_expression(ops[0]), ", ", get_decoration(ops[1], DecorationLocation), ");");
12637 flush_control_dependent_expressions(current_emitting_block->self);
12638 break;
12639
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012640 // Don't bother forwarding temporaries. Avoids having to test expression invalidation with ray query objects.
12641 case OpRayQueryInitializeKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012642 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012643 statement("rayQueryInitializeEXT(",
12644 to_expression(ops[0]), ", ", to_expression(ops[1]), ", ",
12645 to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
12646 to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
12647 to_expression(ops[6]), ", ", to_expression(ops[7]), ");");
12648 break;
12649 case OpRayQueryProceedKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012650 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012651 emit_op(ops[0], ops[1], join("rayQueryProceedEXT(", to_expression(ops[2]), ")"), false);
12652 break;
12653 case OpRayQueryTerminateKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012654 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012655 statement("rayQueryTerminateEXT(", to_expression(ops[0]), ");");
12656 break;
12657 case OpRayQueryGenerateIntersectionKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012658 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012659 statement("rayQueryGenerateIntersectionEXT(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
12660 break;
12661 case OpRayQueryConfirmIntersectionKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012662 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012663 statement("rayQueryConfirmIntersectionEXT(", to_expression(ops[0]), ");");
12664 break;
12665#define GLSL_RAY_QUERY_GET_OP(op) \
12666 case OpRayQueryGet##op##KHR: \
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012667 flush_variable_declaration(ops[2]); \
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012668 emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ")"), false); \
12669 break
12670#define GLSL_RAY_QUERY_GET_OP2(op) \
12671 case OpRayQueryGet##op##KHR: \
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012672 flush_variable_declaration(ops[2]); \
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012673 emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ", ", "bool(", to_expression(ops[3]), "))"), false); \
12674 break
12675 GLSL_RAY_QUERY_GET_OP(RayTMin);
12676 GLSL_RAY_QUERY_GET_OP(RayFlags);
12677 GLSL_RAY_QUERY_GET_OP(WorldRayOrigin);
12678 GLSL_RAY_QUERY_GET_OP(WorldRayDirection);
12679 GLSL_RAY_QUERY_GET_OP(IntersectionCandidateAABBOpaque);
12680 GLSL_RAY_QUERY_GET_OP2(IntersectionType);
12681 GLSL_RAY_QUERY_GET_OP2(IntersectionT);
12682 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceCustomIndex);
12683 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceId);
12684 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceShaderBindingTableRecordOffset);
12685 GLSL_RAY_QUERY_GET_OP2(IntersectionGeometryIndex);
12686 GLSL_RAY_QUERY_GET_OP2(IntersectionPrimitiveIndex);
12687 GLSL_RAY_QUERY_GET_OP2(IntersectionBarycentrics);
12688 GLSL_RAY_QUERY_GET_OP2(IntersectionFrontFace);
12689 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayDirection);
12690 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayOrigin);
12691 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectToWorld);
12692 GLSL_RAY_QUERY_GET_OP2(IntersectionWorldToObject);
12693#undef GLSL_RAY_QUERY_GET_OP
12694#undef GLSL_RAY_QUERY_GET_OP2
12695
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012696 case OpConvertUToAccelerationStructureKHR:
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012697 require_extension_internal("GL_EXT_ray_tracing");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012698 GLSL_UFOP(accelerationStructureEXT);
12699 break;
Patrick Moursda39a7b2019-02-26 15:43:03 +010012700
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012701 case OpConvertUToPtr:
12702 {
12703 auto &type = get<SPIRType>(ops[0]);
12704 if (type.storage != StorageClassPhysicalStorageBufferEXT)
12705 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertUToPtr.");
12706
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +020012707 auto &in_type = expression_type(ops[2]);
12708 if (in_type.vecsize == 2)
12709 require_extension_internal("GL_EXT_buffer_reference_uvec2");
12710
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012711 auto op = type_to_glsl(type);
12712 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
12713 break;
12714 }
12715
12716 case OpConvertPtrToU:
12717 {
12718 auto &type = get<SPIRType>(ops[0]);
12719 auto &ptr_type = expression_type(ops[2]);
12720 if (ptr_type.storage != StorageClassPhysicalStorageBufferEXT)
12721 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertPtrToU.");
12722
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +020012723 if (type.vecsize == 2)
12724 require_extension_internal("GL_EXT_buffer_reference_uvec2");
12725
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012726 auto op = type_to_glsl(type);
12727 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
12728 break;
12729 }
12730
lifpan876627d2019-04-08 19:45:31 +080012731 case OpUndef:
12732 // Undefined value has been declared.
12733 break;
12734
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020012735 case OpLine:
12736 {
12737 emit_line_directive(ops[0], ops[1]);
12738 break;
12739 }
12740
Lifeng Pan5ca87792019-07-04 16:03:06 +080012741 case OpNoLine:
12742 break;
12743
Chip Davis50dce102019-07-13 15:57:33 -050012744 case OpDemoteToHelperInvocationEXT:
12745 if (!options.vulkan_semantics)
12746 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
12747 require_extension_internal("GL_EXT_demote_to_helper_invocation");
12748 statement(backend.demote_literal, ";");
12749 break;
12750
12751 case OpIsHelperInvocationEXT:
12752 if (!options.vulkan_semantics)
12753 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
12754 require_extension_internal("GL_EXT_demote_to_helper_invocation");
Chip Davis12a86542019-07-18 17:32:35 -050012755 emit_op(ops[0], ops[1], "helperInvocationEXT()", false);
Chip Davis50dce102019-07-13 15:57:33 -050012756 break;
12757
Chip Davis2eff4202019-08-04 00:07:20 -050012758 case OpBeginInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012759 // If the interlock is complex, we emit this elsewhere.
12760 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050012761 {
Erfan Ahmadi43eecb22021-10-19 09:39:55 +033012762 statement("SPIRV_Cross_beginInvocationInterlock();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020012763 flush_all_active_variables();
12764 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050012765 }
12766 break;
12767
12768 case OpEndInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012769 // If the interlock is complex, we emit this elsewhere.
12770 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050012771 {
Erfan Ahmadi43eecb22021-10-19 09:39:55 +033012772 statement("SPIRV_Cross_endInvocationInterlock();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020012773 flush_all_active_variables();
12774 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050012775 }
12776 break;
12777
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012778 default:
12779 statement("// unimplemented op ", instruction.op);
12780 break;
12781 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012782}
12783
Bill Hollingsa759e2c2016-10-19 14:09:51 -070012784// Appends function arguments, mapped from global variables, beyond the specified arg index.
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012785// This is used when a function call uses fewer arguments than the function defines.
Bill Hollingsa759e2c2016-10-19 14:09:51 -070012786// This situation may occur if the function signature has been dynamically modified to
12787// extract global variables referenced from within the function, and convert them to
12788// function arguments. This is necessary for shader languages that do not support global
12789// access to shader input content from within a function (eg. Metal). Each additional
12790// function args uses the name of the global variable. Function nesting will modify the
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012791// functions and function calls all the way up the nesting chain.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020012792void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<string> &arglist)
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012793{
Bill Hollingsac00c602016-10-24 09:24:24 -040012794 auto &args = func.arguments;
Bill Hollings943191a2016-10-27 10:20:01 -040012795 uint32_t arg_cnt = uint32_t(args.size());
Bill Hollingsac00c602016-10-24 09:24:24 -040012796 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010012797 {
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012798 auto &arg = args[arg_idx];
12799 assert(arg.alias_global_variable);
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012800
12801 // If the underlying variable needs to be declared
12802 // (ie. a local variable with deferred declaration), do so now.
12803 uint32_t var_id = get<SPIRVariable>(arg.id).basevariable;
12804 if (var_id)
12805 flush_variable_declaration(var_id);
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +020012806
Chip Davis39dce882019-08-02 15:11:19 -050012807 arglist.push_back(to_func_call_arg(arg, arg.id));
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010012808 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012809}
12810
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012811string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
12812{
Hans-Kristian Arntzena0c13e42019-10-07 10:31:42 +020012813 if (type.type_alias != TypeID(0) &&
12814 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
12815 {
12816 return to_member_name(get<SPIRType>(type.type_alias), index);
12817 }
12818
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012819 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012820 if (index < memb.size() && !memb[index].alias.empty())
12821 return memb[index].alias;
12822 else
Hans-Kristian Arntzen1c6df1b2017-07-29 21:44:20 +020012823 return join("_m", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012824}
12825
Chip Davis3bfb2f92018-12-03 02:06:33 -060012826string CompilerGLSL::to_member_reference(uint32_t, const SPIRType &type, uint32_t index, bool)
Chip Davis3a9af962018-09-26 20:06:05 -050012827{
12828 return join(".", to_member_name(type, index));
12829}
12830
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020012831string CompilerGLSL::to_multi_member_reference(const SPIRType &type, const SmallVector<uint32_t> &indices)
12832{
12833 string ret;
12834 auto *member_type = &type;
12835 for (auto &index : indices)
12836 {
12837 ret += join(".", to_member_name(*member_type, index));
12838 member_type = &get<SPIRType>(member_type->member_types[index]);
12839 }
12840 return ret;
12841}
12842
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012843void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
12844{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012845 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012846 if (index < memb.size() && !memb[index].alias.empty())
12847 {
12848 auto &name = memb[index].alias;
12849 if (name.empty())
12850 return;
12851
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020012852 ParsedIR::sanitize_identifier(name, true, true);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012853 update_name_cache(type.member_name_cache, name);
12854 }
12855}
12856
Bill Hollingsb332bae2017-03-01 13:07:40 -050012857// Checks whether the ID is a row_major matrix that requires conversion before use
Bill Hollings13583622016-12-14 02:12:52 -050012858bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012859{
Bill Hollings13583622016-12-14 02:12:52 -050012860 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010012861 // Legacy targets do not support row major.
12862 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050012863 return false;
12864
Hans-Kristian Arntzen120af422020-10-14 16:07:10 +020012865 auto *e = maybe_get<SPIRExpression>(id);
12866 if (e)
12867 return e->need_transpose;
12868 else
12869 return has_decoration(id, DecorationRowMajor);
Bill Hollings343677e2016-12-11 11:01:08 -050012870}
12871
Bill Hollings13583622016-12-14 02:12:52 -050012872// Checks whether the member is a row_major matrix that requires conversion before use
12873bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index)
Bill Hollings343677e2016-12-11 11:01:08 -050012874{
Bill Hollings13583622016-12-14 02:12:52 -050012875 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010012876 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050012877 return false;
12878
12879 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +010012880 if (!has_member_decoration(type.self, index, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -050012881 return false;
12882
12883 // Only square row-major matrices can be converted at this time.
12884 // Converting non-square matrices will require defining custom GLSL function that
12885 // swaps matrix elements while retaining the original dimensional form of the matrix.
12886 const auto mbr_type = get<SPIRType>(type.member_types[index]);
12887 if (mbr_type.columns != mbr_type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +010012888 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -050012889
12890 return true;
Bill Hollings343677e2016-12-11 11:01:08 -050012891}
12892
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020012893// Checks if we need to remap physical type IDs when declaring the type in a buffer.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020012894bool CompilerGLSL::member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const
Bill Hollingsb332bae2017-03-01 13:07:40 -050012895{
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020012896 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID);
12897}
12898
12899// Checks whether the member is in packed data type, that might need to be unpacked.
12900bool CompilerGLSL::member_is_packed_physical_type(const SPIRType &type, uint32_t index) const
12901{
12902 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
Bill Hollingsb332bae2017-03-01 13:07:40 -050012903}
12904
Bill Hollings13583622016-12-14 02:12:52 -050012905// Wraps the expression string in a function call that converts the
12906// row_major matrix result of the expression to a column_major matrix.
12907// Base implementation uses the standard library transpose() function.
12908// Subclasses may override to use a different function.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020012909string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t /* physical_type_id */,
12910 bool /*is_packed*/)
Bill Hollings343677e2016-12-11 11:01:08 -050012911{
12912 strip_enclosed_expression(exp_str);
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012913 if (!is_matrix(exp_type))
12914 {
12915 auto column_index = exp_str.find_last_of('[');
12916 if (column_index == string::npos)
12917 return exp_str;
12918
12919 auto column_expr = exp_str.substr(column_index);
12920 exp_str.resize(column_index);
12921
12922 auto transposed_expr = type_to_glsl_constructor(exp_type) + "(";
12923
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020012924 // Loading a column from a row-major matrix. Unroll the load.
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012925 for (uint32_t c = 0; c < exp_type.vecsize; c++)
12926 {
12927 transposed_expr += join(exp_str, '[', c, ']', column_expr);
12928 if (c + 1 < exp_type.vecsize)
12929 transposed_expr += ", ";
12930 }
12931
12932 transposed_expr += ")";
12933 return transposed_expr;
12934 }
rdbbf719942020-11-05 17:09:33 +010012935 else if (options.version < 120)
12936 {
12937 // GLSL 110, ES 100 do not have transpose(), so emulate it. Note that
12938 // these GLSL versions do not support non-square matrices.
12939 if (exp_type.vecsize == 2 && exp_type.columns == 2)
12940 {
12941 if (!requires_transpose_2x2)
12942 {
12943 requires_transpose_2x2 = true;
12944 force_recompile();
12945 }
12946 }
12947 else if (exp_type.vecsize == 3 && exp_type.columns == 3)
12948 {
12949 if (!requires_transpose_3x3)
12950 {
12951 requires_transpose_3x3 = true;
12952 force_recompile();
12953 }
12954 }
12955 else if (exp_type.vecsize == 4 && exp_type.columns == 4)
12956 {
12957 if (!requires_transpose_4x4)
12958 {
12959 requires_transpose_4x4 = true;
12960 force_recompile();
12961 }
12962 }
12963 else
12964 SPIRV_CROSS_THROW("Non-square matrices are not supported in legacy GLSL, cannot transpose.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010012965 return join("spvTranspose(", exp_str, ")");
rdbbf719942020-11-05 17:09:33 +010012966 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012967 else
12968 return join("transpose(", exp_str, ")");
Bill Hollings343677e2016-12-11 11:01:08 -050012969}
12970
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020012971string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012972{
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020012973 string type_name = type_to_glsl(type, id);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +020012974 remap_variable_type_name(type, name, type_name);
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +020012975 return join(type_name, " ", name, type_to_array_glsl(type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012976}
12977
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020012978bool CompilerGLSL::variable_decl_is_remapped_storage(const SPIRVariable &var, StorageClass storage) const
Hans-Kristian Arntzenf2b5fb32021-03-26 17:23:44 +010012979{
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020012980 return var.storage == storage;
Hans-Kristian Arntzenf2b5fb32021-03-26 17:23:44 +010012981}
12982
Bill Hollings484931d2017-02-28 21:44:36 -050012983// Emit a structure member. Subclasses may override to modify output,
12984// or to dynamically add a padding member if needed.
Bill Hollingsdc694272017-03-11 12:17:22 -050012985void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
msiglreithd096f5c2017-11-27 16:00:56 +010012986 const string &qualifier, uint32_t)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012987{
Bill Hollings484931d2017-02-28 21:44:36 -050012988 auto &membertype = get<SPIRType>(member_type_id);
12989
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012990 Bitset memberflags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012991 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012992 if (index < memb.size())
12993 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012994
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020012995 string qualifiers;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012996 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
12997 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012998
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020012999 if (is_block)
13000 qualifiers = to_interpolation_qualifiers(memberflags);
13001
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013002 statement(layout_for_member(type, index), qualifiers, qualifier, flags_to_qualifiers_glsl(membertype, memberflags),
Bill Hollings484931d2017-02-28 21:44:36 -050013003 variable_decl(membertype, to_member_name(type, index)), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013004}
13005
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +020013006void CompilerGLSL::emit_struct_padding_target(const SPIRType &)
13007{
13008}
13009
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013010string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013011{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013012 // GL_EXT_buffer_reference variables can be marked as restrict.
13013 if (flags.get(DecorationRestrictPointerEXT))
13014 return "restrict ";
13015
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013016 string qual;
13017
Hans-Kristian Arntzenac11a912021-07-26 22:05:55 +020013018 if (type_is_floating_point(type) && flags.get(DecorationNoContraction) && backend.support_precise_qualifier)
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013019 qual = "precise ";
13020
Hans-Kristian Arntzenac11a912021-07-26 22:05:55 +020013021 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
13022 bool type_supports_precision =
13023 type.basetype == SPIRType::Float || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
13024 type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
13025 type.basetype == SPIRType::Sampler;
13026
13027 if (!type_supports_precision)
13028 return qual;
13029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013030 if (options.es)
13031 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +020013032 auto &execution = get_entry_point();
13033
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013034 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013035 {
13036 bool implied_fmediump = type.basetype == SPIRType::Float &&
13037 options.fragment.default_float_precision == Options::Mediump &&
13038 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013039
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013040 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
13041 options.fragment.default_int_precision == Options::Mediump &&
13042 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013043
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013044 qual += (implied_fmediump || implied_imediump) ? "" : "mediump ";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013045 }
13046 else
13047 {
13048 bool implied_fhighp =
13049 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
13050 execution.model == ExecutionModelFragment) ||
13051 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013052
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013053 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
13054 ((options.fragment.default_int_precision == Options::Highp &&
13055 execution.model == ExecutionModelFragment) ||
13056 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013057
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013058 qual += (implied_fhighp || implied_ihighp) ? "" : "highp ";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013059 }
13060 }
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010013061 else if (backend.allow_precision_qualifiers)
13062 {
13063 // Vulkan GLSL supports precision qualifiers, even in desktop profiles, which is convenient.
13064 // 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 +010013065 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013066 qual += "mediump ";
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010013067 }
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013068
13069 return qual;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013070}
13071
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013072string CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013073{
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013074 auto &type = expression_type(id);
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013075 bool use_precision_qualifiers = backend.allow_precision_qualifiers;
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013076 if (use_precision_qualifiers && (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage))
13077 {
13078 // Force mediump for the sampler type. We cannot declare 16-bit or smaller image types.
13079 auto &result_type = get<SPIRType>(type.image.type);
13080 if (result_type.width < 32)
13081 return "mediump ";
13082 }
13083 return flags_to_qualifiers_glsl(type, ir.meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013084}
13085
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013086void CompilerGLSL::fixup_io_block_patch_qualifiers(const SPIRVariable &var)
13087{
13088 // Works around weird behavior in glslangValidator where
13089 // a patch out block is translated to just block members getting the decoration.
13090 // To make glslang not complain when we compile again, we have to transform this back to a case where
13091 // the variable itself has Patch decoration, and not members.
13092 auto &type = get<SPIRType>(var.basetype);
13093 if (has_decoration(type.self, DecorationBlock))
13094 {
13095 uint32_t member_count = uint32_t(type.member_types.size());
13096 for (uint32_t i = 0; i < member_count; i++)
13097 {
13098 if (has_member_decoration(type.self, i, DecorationPatch))
13099 {
13100 set_decoration(var.self, DecorationPatch);
13101 break;
13102 }
13103 }
13104
13105 if (has_decoration(var.self, DecorationPatch))
13106 for (uint32_t i = 0; i < member_count; i++)
13107 unset_member_decoration(type.self, i, DecorationPatch);
13108 }
13109}
13110
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013111string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
13112{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013113 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013114 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013115
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013116 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013118 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
13119 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013120
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020013121 res += to_interpolation_qualifiers(flags);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010013122 if (var)
13123 res += to_storage_qualifiers_glsl(*var);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010013124
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013125 auto &type = expression_type(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013126 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
13127 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013128 if (flags.get(DecorationCoherent))
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013129 res += "coherent ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013130 if (flags.get(DecorationRestrict))
Hans-Kristian Arntzen11dfcb62017-08-29 15:54:22 +020013131 res += "restrict ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013132
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013133 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013134 res += "readonly ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013135
13136 bool formatted_load = type.image.format == ImageFormatUnknown;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013137 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013138 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013139 res += "writeonly ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013140 formatted_load = false;
13141 }
13142
13143 if (formatted_load)
13144 {
13145 if (!options.es)
13146 require_extension_internal("GL_EXT_shader_image_load_formatted");
13147 else
13148 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_image_load_formatted in ESSL.");
13149 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013150 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013151
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013152 res += to_precision_qualifiers_glsl(id);
13153
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013154 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013155}
13156
13157string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
13158{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013159 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013160 auto &type = expression_type(arg.id);
13161 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013162
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013163 if (type.pointer)
13164 {
13165 if (arg.write_count && arg.read_count)
13166 direction = "inout ";
13167 else if (arg.write_count)
13168 direction = "out ";
13169 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013170
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020013171 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 +010013172}
13173
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020013174string CompilerGLSL::to_initializer_expression(const SPIRVariable &var)
13175{
Bill Hollings974a0812021-10-21 16:11:33 -040013176 return to_unpacked_expression(var.initializer);
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020013177}
13178
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013179string CompilerGLSL::to_zero_initialized_expression(uint32_t type_id)
13180{
13181#ifndef NDEBUG
13182 auto &type = get<SPIRType>(type_id);
13183 assert(type.storage == StorageClassPrivate || type.storage == StorageClassFunction ||
13184 type.storage == StorageClassGeneric);
13185#endif
13186 uint32_t id = ir.increase_bound_by(1);
13187 ir.make_constant_null(id, type_id, false);
13188 return constant_expression(get<SPIRConstant>(id));
13189}
13190
13191bool CompilerGLSL::type_can_zero_initialize(const SPIRType &type) const
13192{
13193 if (type.pointer)
13194 return false;
13195
13196 if (!type.array.empty() && options.flatten_multidimensional_arrays)
13197 return false;
13198
13199 for (auto &literal : type.array_size_literal)
13200 if (!literal)
13201 return false;
13202
13203 for (auto &memb : type.member_types)
13204 if (!type_can_zero_initialize(get<SPIRType>(memb)))
13205 return false;
13206
13207 return true;
13208}
13209
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013210string CompilerGLSL::variable_decl(const SPIRVariable &variable)
13211{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013212 // Ignore the pointer type since GLSL doesn't have pointers.
Chip Davis3bfb2f92018-12-03 02:06:33 -060013213 auto &type = get_variable_data_type(variable);
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +020013214
Hans-Kristian Arntzen97796e02021-02-26 12:50:24 +010013215 if (type.pointer_depth > 1 && !backend.support_pointer_to_pointer)
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +010013216 SPIRV_CROSS_THROW("Cannot declare pointer-to-pointer types.");
13217
Hans-Kristian Arntzenb0f7dee2017-06-17 10:56:24 +020013218 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 +020013219
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010013220 if (variable.loop_variable && variable.static_expression)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013221 {
13222 uint32_t expr = variable.static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013223 if (ir.ids[expr].get_type() != TypeUndef)
Bill Hollings974a0812021-10-21 16:11:33 -040013224 res += join(" = ", to_unpacked_expression(variable.static_expression));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013225 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
13226 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013227 }
Hans-Kristian Arntzenc9946292021-04-14 11:27:05 +020013228 else if (variable.initializer && !variable_decl_is_remapped_storage(variable, StorageClassWorkgroup))
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013229 {
13230 uint32_t expr = variable.initializer;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013231 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020013232 res += join(" = ", to_initializer_expression(variable));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013233 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
13234 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013235 }
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013236
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013237 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013238}
13239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013240const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013241{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013242 auto &flags = ir.meta[variable.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013243 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013244 return "mediump ";
13245 else
13246 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013247}
13248
13249string CompilerGLSL::pls_decl(const PlsRemap &var)
13250{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013251 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013252
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013253 SPIRType type;
13254 type.vecsize = pls_format_to_components(var.format);
13255 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013257 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
13258 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013259}
13260
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +010013261uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type) const
13262{
13263 return to_array_size_literal(type, uint32_t(type.array.size() - 1));
13264}
13265
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020013266uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t index) const
13267{
13268 assert(type.array.size() == type.array_size_literal.size());
13269
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010013270 if (type.array_size_literal[index])
13271 {
13272 return type.array[index];
13273 }
13274 else
13275 {
13276 // Use the default spec constant value.
13277 // This is the best we can do.
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020013278 return evaluate_constant_u32(type.array[index]);
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010013279 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020013280}
13281
13282string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index)
13283{
13284 assert(type.array.size() == type.array_size_literal.size());
13285
13286 auto &size = type.array[index];
13287 if (!type.array_size_literal[index])
13288 return to_expression(size);
13289 else if (size)
13290 return convert_to_string(size);
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020013291 else if (!backend.unsized_array_supported)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020013292 {
13293 // For runtime-sized arrays, we can work around
13294 // lack of standard support for this by simply having
13295 // a single element array.
13296 //
13297 // Runtime length arrays must always be the last element
13298 // in an interface block.
13299 return "1";
13300 }
13301 else
13302 return "";
13303}
13304
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013305string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
13306{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013307 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
13308 {
13309 // We are using a wrapped pointer type, and we should not emit any array declarations here.
13310 return "";
13311 }
13312
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020013313 if (type.array.empty())
13314 return "";
13315
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013316 if (options.flatten_multidimensional_arrays)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013317 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013318 string res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013319 res += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013320 for (auto i = uint32_t(type.array.size()); i; i--)
13321 {
13322 res += enclose_expression(to_array_size(type, i - 1));
13323 if (i > 1)
13324 res += " * ";
13325 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013326 res += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013327 return res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013328 }
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013329 else
13330 {
13331 if (type.array.size() > 1)
13332 {
13333 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013334 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013335 else if (options.es && options.version < 310)
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020013336 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
13337 "Try using --flatten-multidimensional-arrays or set "
13338 "options.flatten_multidimensional_arrays to true.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013339 }
13340
13341 string res;
13342 for (auto i = uint32_t(type.array.size()); i; i--)
13343 {
13344 res += "[";
13345 res += to_array_size(type, i - 1);
13346 res += "]";
13347 }
13348 return res;
13349 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013350}
13351
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013352string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013353{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013354 auto &imagetype = get<SPIRType>(type.image.type);
13355 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013356
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013357 switch (imagetype.basetype)
13358 {
13359 case SPIRType::Int:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013360 case SPIRType::Short:
13361 case SPIRType::SByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013362 res = "i";
13363 break;
13364 case SPIRType::UInt:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013365 case SPIRType::UShort:
13366 case SPIRType::UByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013367 res = "u";
13368 break;
13369 default:
13370 break;
13371 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013372
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013373 // For half image types, we will force mediump for the sampler, and cast to f16 after any sampling operation.
13374 // We cannot express a true half texture type in GLSL. Neither for short integer formats for that matter.
13375
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020013376 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020013377 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010013378 else if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
13379 subpass_input_is_framebuffer_fetch(id))
13380 {
13381 SPIRType sampled_type = get<SPIRType>(type.image.type);
13382 sampled_type.vecsize = 4;
13383 return type_to_glsl(sampled_type);
13384 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020013385
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013386 // If we're emulating subpassInput with samplers, force sampler2D
13387 // so we don't have to specify format.
13388 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +020013389 {
13390 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
13391 if (type.image.dim == DimBuffer && type.image.sampled == 1)
13392 res += "sampler";
13393 else
13394 res += type.image.sampled == 2 ? "image" : "texture";
13395 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013396 else
13397 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013398
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013399 switch (type.image.dim)
13400 {
13401 case Dim1D:
13402 res += "1D";
13403 break;
13404 case Dim2D:
13405 res += "2D";
13406 break;
13407 case Dim3D:
13408 res += "3D";
13409 break;
13410 case DimCube:
13411 res += "Cube";
13412 break;
Sidney Justfbb4df32019-01-06 12:21:59 -080013413 case DimRect:
13414 if (options.es)
13415 SPIRV_CROSS_THROW("Rectangle textures are not supported on OpenGL ES.");
13416
13417 if (is_legacy_desktop())
13418 require_extension_internal("GL_ARB_texture_rectangle");
13419
13420 res += "2DRect";
13421 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013422
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013423 case DimBuffer:
13424 if (options.es && options.version < 320)
miomioreimu4407c0d2022-01-10 16:49:45 +080013425 require_extension_internal("GL_EXT_texture_buffer");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013426 else if (!options.es && options.version < 300)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013427 require_extension_internal("GL_EXT_texture_buffer_object");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013428 res += "Buffer";
13429 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013430
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013431 case DimSubpassData:
13432 res += "2D";
13433 break;
13434 default:
Sidney Justfbb4df32019-01-06 12:21:59 -080013435 SPIRV_CROSS_THROW("Only 1D, 2D, 2DRect, 3D, Buffer, InputTarget and Cube textures supported.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013436 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013437
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020013438 if (type.image.ms)
13439 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013440 if (type.image.arrayed)
Rob Fischer21990632016-09-17 17:01:50 +090013441 {
Lubos Lenco52158642016-09-17 15:56:23 +020013442 if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013443 require_extension_internal("GL_EXT_texture_array");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013444 res += "Array";
Rob Fischer21990632016-09-17 17:01:50 +090013445 }
Hans-Kristian Arntzena3ae8612018-02-09 12:37:17 +010013446
13447 // "Shadow" state in GLSL only exists for samplers and combined image samplers.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013448 if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) &&
Bill Hollingsfd252b22021-11-08 15:59:45 -050013449 is_depth_image(type, id))
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013450 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013451 res += "Shadow";
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013452 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013453
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013454 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013455}
13456
13457string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
13458{
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020013459 if (backend.use_array_constructor && type.array.size() > 1)
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020013460 {
13461 if (options.flatten_multidimensional_arrays)
crissdb52e272020-10-08 12:14:52 +020013462 SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, "
13463 "e.g. float[][]().");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020013464 else if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013465 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020013466 else if (options.es && options.version < 310)
13467 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
13468 }
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020013469
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013470 auto e = type_to_glsl(type);
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020013471 if (backend.use_array_constructor)
13472 {
13473 for (uint32_t i = 0; i < type.array.size(); i++)
13474 e += "[]";
13475 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013476 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013477}
13478
Bill Hollingsb41e1482017-05-29 20:45:05 -040013479// The optional id parameter indicates the object whose type we are trying
13480// to find the description for. It is optional. Most type descriptions do not
13481// depend on a specific object's use of that type.
13482string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013483{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013484 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
13485 {
13486 // Need to create a magic type name which compacts the entire type information.
13487 string name = type_to_glsl(get_pointee_type(type));
13488 for (size_t i = 0; i < type.array.size(); i++)
13489 {
13490 if (type.array_size_literal[i])
13491 name += join(type.array[i], "_");
13492 else
13493 name += join("id", type.array[i], "_");
13494 }
13495 name += "Pointer";
13496 return name;
13497 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013498
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013499 switch (type.basetype)
13500 {
13501 case SPIRType::Struct:
13502 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013503 if (backend.explicit_struct_type)
13504 return join("struct ", to_name(type.self));
13505 else
13506 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013507
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013508 case SPIRType::Image:
13509 case SPIRType::SampledImage:
Bill Hollingsb41e1482017-05-29 20:45:05 -040013510 return image_type_glsl(type, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013512 case SPIRType::Sampler:
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +020013513 // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
13514 // this distinction into the type system.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013515 return comparison_ids.count(id) ? "samplerShadow" : "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013516
Hans-Kristian Arntzen6b0e5582020-04-21 14:25:18 +020013517 case SPIRType::AccelerationStructure:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013518 return ray_tracing_is_khr ? "accelerationStructureEXT" : "accelerationStructureNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +010013519
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013520 case SPIRType::RayQuery:
13521 return "rayQueryEXT";
13522
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013523 case SPIRType::Void:
13524 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013525
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013526 default:
13527 break;
13528 }
13529
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020013530 if (type.basetype == SPIRType::UInt && is_legacy())
13531 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
13532
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013533 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
13534 {
13535 switch (type.basetype)
13536 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013537 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013538 return "bool";
Chip Davis117ccf42018-11-01 17:20:07 -050013539 case SPIRType::SByte:
13540 return backend.basic_int8_type;
13541 case SPIRType::UByte:
13542 return backend.basic_uint8_type;
13543 case SPIRType::Short:
13544 return backend.basic_int16_type;
13545 case SPIRType::UShort:
13546 return backend.basic_uint16_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013547 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050013548 return backend.basic_int_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013549 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050013550 return backend.basic_uint_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013551 case SPIRType::AtomicCounter:
13552 return "atomic_uint";
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013553 case SPIRType::Half:
13554 return "float16_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013555 case SPIRType::Float:
13556 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013557 case SPIRType::Double:
13558 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013559 case SPIRType::Int64:
13560 return "int64_t";
13561 case SPIRType::UInt64:
13562 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013563 default:
13564 return "???";
13565 }
13566 }
13567 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
13568 {
13569 switch (type.basetype)
13570 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013571 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013572 return join("bvec", type.vecsize);
Chip Davis117ccf42018-11-01 17:20:07 -050013573 case SPIRType::SByte:
13574 return join("i8vec", type.vecsize);
13575 case SPIRType::UByte:
13576 return join("u8vec", type.vecsize);
13577 case SPIRType::Short:
13578 return join("i16vec", type.vecsize);
13579 case SPIRType::UShort:
13580 return join("u16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013581 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050013582 return join("ivec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013583 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050013584 return join("uvec", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013585 case SPIRType::Half:
13586 return join("f16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013587 case SPIRType::Float:
13588 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013589 case SPIRType::Double:
13590 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013591 case SPIRType::Int64:
13592 return join("i64vec", type.vecsize);
13593 case SPIRType::UInt64:
13594 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013595 default:
13596 return "???";
13597 }
13598 }
13599 else if (type.vecsize == type.columns) // Simple Matrix builtin
13600 {
13601 switch (type.basetype)
13602 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013603 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013604 return join("bmat", type.vecsize);
13605 case SPIRType::Int:
13606 return join("imat", type.vecsize);
13607 case SPIRType::UInt:
13608 return join("umat", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013609 case SPIRType::Half:
13610 return join("f16mat", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013611 case SPIRType::Float:
13612 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013613 case SPIRType::Double:
13614 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013615 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013616 default:
13617 return "???";
13618 }
13619 }
13620 else
13621 {
13622 switch (type.basetype)
13623 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013624 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013625 return join("bmat", type.columns, "x", type.vecsize);
13626 case SPIRType::Int:
13627 return join("imat", type.columns, "x", type.vecsize);
13628 case SPIRType::UInt:
13629 return join("umat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013630 case SPIRType::Half:
13631 return join("f16mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013632 case SPIRType::Float:
13633 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013634 case SPIRType::Double:
13635 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013636 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013637 default:
13638 return "???";
13639 }
13640 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013641}
13642
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013643void CompilerGLSL::add_variable(unordered_set<string> &variables_primary,
13644 const unordered_set<string> &variables_secondary, string &name)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013645{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013646 if (name.empty())
13647 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013648
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020013649 ParsedIR::sanitize_underscores(name);
13650 if (ParsedIR::is_globally_reserved_identifier(name, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013651 {
13652 name.clear();
13653 return;
13654 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013655
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013656 update_name_cache(variables_primary, variables_secondary, name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +010013657}
13658
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013659void CompilerGLSL::add_local_variable_name(uint32_t id)
13660{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013661 add_variable(local_variable_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013662}
13663
13664void CompilerGLSL::add_resource_name(uint32_t id)
13665{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013666 add_variable(resource_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013667}
13668
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +020013669void CompilerGLSL::add_header_line(const std::string &line)
13670{
13671 header_lines.push_back(line);
13672}
13673
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010013674bool CompilerGLSL::has_extension(const std::string &ext) const
13675{
13676 auto itr = find(begin(forced_extensions), end(forced_extensions), ext);
13677 return itr != end(forced_extensions);
13678}
13679
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013680void CompilerGLSL::require_extension(const std::string &ext)
13681{
13682 if (!has_extension(ext))
13683 forced_extensions.push_back(ext);
13684}
13685
13686void CompilerGLSL::require_extension_internal(const string &ext)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013687{
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010013688 if (backend.supports_extensions && !has_extension(ext))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013689 {
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010013690 forced_extensions.push_back(ext);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013691 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013692 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013693}
13694
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013695void CompilerGLSL::flatten_buffer_block(VariableID id)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013696{
13697 auto &var = get<SPIRVariable>(id);
13698 auto &type = get<SPIRType>(var.basetype);
13699 auto name = to_name(type.self, false);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010013700 auto &flags = ir.meta[type.self].decoration.decoration_flags;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013701
13702 if (!type.array.empty())
13703 SPIRV_CROSS_THROW(name + " is an array of UBOs.");
13704 if (type.basetype != SPIRType::Struct)
13705 SPIRV_CROSS_THROW(name + " is not a struct.");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013706 if (!flags.get(DecorationBlock))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013707 SPIRV_CROSS_THROW(name + " is not a block.");
13708 if (type.member_types.empty())
13709 SPIRV_CROSS_THROW(name + " is an empty struct.");
13710
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013711 flattened_buffer_blocks.insert(id);
13712}
13713
Lukas Hermanns6673a672019-10-22 11:06:16 -040013714bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) const
13715{
13716 return false; // GLSL itself does not need to translate array builtin types to non-array builtin types
13717}
13718
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013719bool CompilerGLSL::check_atomic_image(uint32_t id)
13720{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013721 auto &type = expression_type(id);
13722 if (type.storage == StorageClassImage)
13723 {
13724 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013725 require_extension_internal("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013726
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013727 auto *var = maybe_get_backing_variable(id);
13728 if (var)
13729 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010013730 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013731 if (flags.get(DecorationNonWritable) || flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013732 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013733 flags.clear(DecorationNonWritable);
13734 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013735 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013736 }
13737 }
13738 return true;
13739 }
13740 else
13741 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013742}
13743
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013744void CompilerGLSL::add_function_overload(const SPIRFunction &func)
13745{
13746 Hasher hasher;
13747 for (auto &arg : func.arguments)
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010013748 {
13749 // Parameters can vary with pointer type or not,
13750 // but that will not change the signature in GLSL/HLSL,
13751 // so strip the pointer type before hashing.
Chip Davisfc02b3d2019-01-08 12:54:40 -060013752 uint32_t type_id = get_pointee_type_id(arg.type);
Bill Hollingse0910312018-06-24 15:06:12 -040013753 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020013754
13755 if (!combined_image_samplers.empty())
13756 {
13757 // If we have combined image samplers, we cannot really trust the image and sampler arguments
13758 // we pass down to callees, because they may be shuffled around.
13759 // Ignore these arguments, to make sure that functions need to differ in some other way
13760 // to be considered different overloads.
Bill Hollingse0910312018-06-24 15:06:12 -040013761 if (type.basetype == SPIRType::SampledImage ||
13762 (type.basetype == SPIRType::Image && type.image.sampled == 1) || type.basetype == SPIRType::Sampler)
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020013763 {
13764 continue;
13765 }
13766 }
13767
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010013768 hasher.u32(type_id);
13769 }
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013770 uint64_t types_hash = hasher.get();
13771
13772 auto function_name = to_name(func.self);
13773 auto itr = function_overloads.find(function_name);
13774 if (itr != end(function_overloads))
13775 {
13776 // There exists a function with this name already.
13777 auto &overloads = itr->second;
13778 if (overloads.count(types_hash) != 0)
13779 {
13780 // Overload conflict, assign a new name.
13781 add_resource_name(func.self);
13782 function_overloads[to_name(func.self)].insert(types_hash);
13783 }
13784 else
13785 {
13786 // Can reuse the name.
13787 overloads.insert(types_hash);
13788 }
13789 }
13790 else
13791 {
13792 // First time we see this function name.
13793 add_resource_name(func.self);
13794 function_overloads[to_name(func.self)].insert(types_hash);
13795 }
13796}
13797
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013798void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013799{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013800 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013801 add_function_overload(func);
13802
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013803 // Avoid shadow declarations.
13804 local_variable_names = resource_names;
13805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013806 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013807
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013808 auto &type = get<SPIRType>(func.return_type);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013809 decl += flags_to_qualifiers_glsl(type, return_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013810 decl += type_to_glsl(type);
Hans-Kristian Arntzen9fa91f72018-02-05 09:34:54 +010013811 decl += type_to_array_glsl(type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013812 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013813
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013814 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013815 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020013816 // If we need complex fallback in GLSL, we just wrap main() in a function
13817 // and interlock the entire shader ...
13818 if (interlocked_is_complex)
13819 decl += "spvMainInterlockedBody";
13820 else
13821 decl += "main";
13822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013823 processing_entry_point = true;
13824 }
13825 else
Bill Hollings1c180782017-11-05 21:34:42 -050013826 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013827
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013828 decl += "(";
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020013829 SmallVector<string> arglist;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013830 for (auto &arg : func.arguments)
13831 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013832 // Do not pass in separate images or samplers if we're remapping
13833 // to combined image samplers.
13834 if (skip_argument(arg.id))
13835 continue;
13836
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013837 // Might change the variable name if it already exists in this function.
13838 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
13839 // to use same name for variables.
13840 // 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 +020013841 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013842
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013843 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013845 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
13846 auto *var = maybe_get<SPIRVariable>(arg.id);
13847 if (var)
13848 var->parameter = &arg;
13849 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013850
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +020013851 for (auto &arg : func.shadow_arguments)
13852 {
13853 // Might change the variable name if it already exists in this function.
13854 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
13855 // to use same name for variables.
13856 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
13857 add_local_variable_name(arg.id);
13858
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013859 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013860
13861 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
13862 auto *var = maybe_get<SPIRVariable>(arg.id);
13863 if (var)
13864 var->parameter = &arg;
13865 }
13866
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013867 decl += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013868 decl += ")";
13869 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013870}
13871
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013872void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013873{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013874 // Avoid potential cycles.
13875 if (func.active)
13876 return;
13877 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013878
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013879 // If we depend on a function, emit that function before we emit our own function.
13880 for (auto block : func.blocks)
13881 {
13882 auto &b = get<SPIRBlock>(block);
13883 for (auto &i : b.ops)
13884 {
13885 auto ops = stream(i);
13886 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013887
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013888 if (op == OpFunctionCall)
13889 {
13890 // Recursively emit functions which are called.
13891 uint32_t id = ops[2];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013892 emit_function(get<SPIRFunction>(id), ir.meta[ops[1]].decoration.decoration_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013893 }
13894 }
13895 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013896
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020013897 if (func.entry_line.file_id != 0)
13898 emit_line_directive(func.entry_line.file_id, func.entry_line.line_literal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013899 emit_function_prototype(func, return_flags);
13900 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013901
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013902 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +020013903 emit_entry_point_declarations();
13904
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013905 current_function = &func;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013906 auto &entry_block = get<SPIRBlock>(func.entry_block);
13907
Hans-Kristian Arntzen30343f32020-02-24 13:22:52 +010013908 sort(begin(func.constant_arrays_needed_on_stack), end(func.constant_arrays_needed_on_stack));
13909 for (auto &array : func.constant_arrays_needed_on_stack)
13910 {
13911 auto &c = get<SPIRConstant>(array);
13912 auto &type = get<SPIRType>(c.constant_type);
13913 statement(variable_decl(type, join("_", array, "_array_copy")), " = ", constant_expression(c), ";");
13914 }
13915
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013916 for (auto &v : func.local_variables)
13917 {
13918 auto &var = get<SPIRVariable>(v);
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020013919 var.deferred_declaration = false;
13920
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020013921 if (variable_decl_is_remapped_storage(var, StorageClassWorkgroup))
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020013922 {
13923 // Special variable type which cannot have initializer,
13924 // need to be declared as standalone variables.
13925 // Comes from MSL which can push global variables as local variables in main function.
13926 add_local_variable_name(var.self);
13927 statement(variable_decl(var), ";");
13928 var.deferred_declaration = false;
13929 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020013930 else if (var.storage == StorageClassPrivate)
13931 {
13932 // These variables will not have had their CFG usage analyzed, so move it to the entry block.
13933 // Comes from MSL which can push global variables as local variables in main function.
13934 // We could just declare them right now, but we would miss out on an important initialization case which is
13935 // LUT declaration in MSL.
13936 // If we don't declare the variable when it is assigned we're forced to go through a helper function
13937 // which copies elements one by one.
13938 add_local_variable_name(var.self);
Hans-Kristian Arntzenf8592ec2020-04-21 11:20:49 +020013939
13940 if (var.initializer)
13941 {
13942 statement(variable_decl(var), ";");
13943 var.deferred_declaration = false;
13944 }
13945 else
13946 {
13947 auto &dominated = entry_block.dominated_variables;
13948 if (find(begin(dominated), end(dominated), var.self) == end(dominated))
13949 entry_block.dominated_variables.push_back(var.self);
13950 var.deferred_declaration = true;
13951 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020013952 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020013953 else if (var.storage == StorageClassFunction && var.remapped_variable && var.static_expression)
13954 {
13955 // No need to declare this variable, it has a static expression.
13956 var.deferred_declaration = false;
13957 }
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020013958 else if (expression_is_lvalue(v))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013959 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013960 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013961
Hans-Kristian Arntzenf1415212020-06-19 10:51:00 +020013962 // Loop variables should never be declared early, they are explicitly emitted in a loop.
13963 if (var.initializer && !var.loop_variable)
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +010013964 statement(variable_decl_function_local(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013965 else
13966 {
13967 // Don't declare variable until first use to declutter the GLSL output quite a lot.
13968 // If we don't touch the variable before first branch,
13969 // declare it then since we need variable declaration to be in top scope.
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020013970 var.deferred_declaration = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013971 }
13972 }
13973 else
13974 {
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020013975 // 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 +010013976 // For these types (non-lvalue), we enforce forwarding through a shadowed variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013977 // This means that when we OpStore to these variables, we just write in the expression ID directly.
13978 // This breaks any kind of branching, since the variable must be statically assigned.
13979 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
13980 var.statically_assigned = true;
13981 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013982
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013983 var.loop_variable_enable = false;
Hans-Kristian Arntzenb847c882016-11-18 17:06:49 +010013984
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013985 // Loop variables are never declared outside their for-loop, so block any implicit declaration.
13986 if (var.loop_variable)
13987 var.deferred_declaration = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013988 }
13989
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020013990 // Enforce declaration order for regression testing purposes.
13991 for (auto &block_id : func.blocks)
13992 {
13993 auto &block = get<SPIRBlock>(block_id);
13994 sort(begin(block.dominated_variables), end(block.dominated_variables));
13995 }
13996
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020013997 for (auto &line : current_function->fixup_hooks_in)
13998 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040013999
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014000 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014001
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014002 end_scope();
14003 processing_entry_point = false;
14004 statement("");
Hans-Kristian Arntzend81bfc52019-06-13 10:31:37 +020014005
14006 // Make sure deferred declaration state for local variables is cleared when we are done with function.
14007 // We risk declaring Private/Workgroup variables in places we are not supposed to otherwise.
14008 for (auto &v : func.local_variables)
14009 {
14010 auto &var = get<SPIRVariable>(v);
14011 var.deferred_declaration = false;
14012 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014013}
14014
14015void CompilerGLSL::emit_fixup()
14016{
Hans-Kristian Arntzen5ea576e2020-09-28 14:09:39 +020014017 if (is_vertex_like_shader())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014018 {
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020014019 if (options.vertex.fixup_clipspace)
14020 {
14021 const char *suffix = backend.float_literal_suffix ? "f" : "";
14022 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
14023 }
14024
14025 if (options.vertex.flip_vert_y)
14026 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014027 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014028}
14029
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014030void CompilerGLSL::flush_phi(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014031{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014032 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014033 if (child.ignore_phi_from_block == from)
14034 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014035
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014036 unordered_set<uint32_t> temporary_phi_variables;
14037
14038 for (auto itr = begin(child.phi_variables); itr != end(child.phi_variables); ++itr)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014039 {
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014040 auto &phi = *itr;
14041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014042 if (phi.parent == from)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014043 {
14044 auto &var = get<SPIRVariable>(phi.function_variable);
14045
14046 // A Phi variable might be a loop variable, so flush to static expression.
14047 if (var.loop_variable && !var.loop_variable_enable)
14048 var.static_expression = phi.local_variable;
14049 else
14050 {
14051 flush_variable_declaration(phi.function_variable);
14052
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014053 // Check if we are going to write to a Phi variable that another statement will read from
14054 // as part of another Phi node in our target block.
14055 // For this case, we will need to copy phi.function_variable to a temporary, and use that for future reads.
14056 // This is judged to be extremely rare, so deal with it here using a simple, but suboptimal algorithm.
14057 bool need_saved_temporary =
14058 find_if(itr + 1, end(child.phi_variables), [&](const SPIRBlock::Phi &future_phi) -> bool {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014059 return future_phi.local_variable == ID(phi.function_variable) && future_phi.parent == from;
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014060 }) != end(child.phi_variables);
14061
14062 if (need_saved_temporary)
14063 {
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014064 // Need to make sure we declare the phi variable with a copy at the right scope.
14065 // We cannot safely declare a temporary here since we might be inside a continue block.
14066 if (!var.allocate_temporary_copy)
14067 {
14068 var.allocate_temporary_copy = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014069 force_recompile();
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014070 }
14071 statement("_", phi.function_variable, "_copy", " = ", to_name(phi.function_variable), ";");
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014072 temporary_phi_variables.insert(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014073 }
14074
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014075 // This might be called in continue block, so make sure we
Hans-Kristian Arntzen91753632017-09-25 10:16:45 +020014076 // use this to emit ESSL 1.0 compliant increments/decrements.
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014077 auto lhs = to_expression(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014078
14079 string rhs;
14080 if (temporary_phi_variables.count(phi.local_variable))
14081 rhs = join("_", phi.local_variable, "_copy");
14082 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060014083 rhs = to_pointer_expression(phi.local_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014084
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020014085 if (!optimize_read_modify_write(get<SPIRType>(var.basetype), lhs, rhs))
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014086 statement(lhs, " = ", rhs, ";");
14087 }
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010014088
14089 register_write(phi.function_variable);
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014090 }
14091 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014092}
14093
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014094void CompilerGLSL::branch_to_continue(BlockID from, BlockID to)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014095{
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014096 auto &to_block = get<SPIRBlock>(to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010014097 if (from == to)
14098 return;
14099
14100 assert(is_continue(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014101 if (to_block.complex_continue)
14102 {
14103 // Just emit the whole block chain as is.
14104 auto usage_counts = expression_usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014105
14106 emit_block_chain(to_block);
14107
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020014108 // Expression usage counts are moot after returning from the continue block.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014109 expression_usage_counts = usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014110 }
14111 else
14112 {
14113 auto &from_block = get<SPIRBlock>(from);
14114 bool outside_control_flow = false;
14115 uint32_t loop_dominator = 0;
14116
14117 // FIXME: Refactor this to not use the old loop_dominator tracking.
14118 if (from_block.merge_block)
14119 {
14120 // If we are a loop header, we don't set the loop dominator,
14121 // so just use "self" here.
14122 loop_dominator = from;
14123 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014124 else if (from_block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014125 {
14126 loop_dominator = from_block.loop_dominator;
14127 }
14128
14129 if (loop_dominator != 0)
14130 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014131 auto &cfg = get_cfg_for_current_function();
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014132
14133 // For non-complex continue blocks, we implicitly branch to the continue block
14134 // by having the continue block be part of the loop header in for (; ; continue-block).
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014135 outside_control_flow = cfg.node_terminates_control_flow_in_sub_graph(loop_dominator, from);
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014136 }
14137
14138 // Some simplification for for-loops. We always end up with a useless continue;
14139 // statement since we branch to a loop block.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014140 // 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 +010014141 // we can avoid writing out an explicit continue statement.
14142 // Similar optimization to return statements if we know we're outside flow control.
14143 if (!outside_control_flow)
14144 statement("continue;");
14145 }
14146}
14147
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014148void CompilerGLSL::branch(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014149{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014150 flush_phi(from, to);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010014151 flush_control_dependent_expressions(from);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014152
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014153 bool to_is_continue = is_continue(to);
14154
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014155 // This is only a continue if we branch to our loop dominator.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014156 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 +020014157 {
14158 // This can happen if we had a complex continue block which was emitted.
14159 // Once the continue block tries to branch to the loop header, just emit continue;
14160 // and end the chain here.
14161 statement("continue;");
14162 }
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010014163 else if (from != to && is_break(to))
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014164 {
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010014165 // We cannot break to ourselves, so check explicitly for from != to.
14166 // This case can trigger if a loop header is all three of these things:
14167 // - Continue block
14168 // - Loop header
14169 // - Break merge target all at once ...
14170
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014171 // Very dirty workaround.
14172 // Switch constructs are able to break, but they cannot break out of a loop at the same time.
14173 // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block,
14174 // write to the ladder here, and defer the break.
14175 // 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 +020014176 if (current_emitting_switch && is_loop_break(to) &&
14177 current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) &&
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014178 get<SPIRBlock>(current_emitting_switch->loop_dominator).merge_block == to)
14179 {
14180 if (!current_emitting_switch->need_ladder_break)
14181 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014182 force_recompile();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014183 current_emitting_switch->need_ladder_break = true;
14184 }
14185
14186 statement("_", current_emitting_switch->self, "_ladder_break = true;");
14187 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014188 statement("break;");
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014189 }
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014190 else if (to_is_continue || from == to)
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010014191 {
14192 // For from == to case can happen for a do-while loop which branches into itself.
14193 // We don't mark these cases as continue blocks, but the only possible way to branch into
14194 // ourselves is through means of continue blocks.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014195
14196 // If we are merging to a continue block, there is no need to emit the block chain for continue here.
14197 // We can branch to the continue block after we merge execution.
14198
14199 // Here we make use of structured control flow rules from spec:
14200 // 2.11: - the merge block declared by a header block cannot be a merge block declared by any other header block
14201 // - each header block must strictly dominate its merge block, unless the merge block is unreachable in the CFG
14202 // If we are branching to a merge block, we must be inside a construct which dominates the merge block.
14203 auto &block_meta = ir.block_meta[to];
14204 bool branching_to_merge =
14205 (block_meta & (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT |
14206 ParsedIR::BLOCK_META_LOOP_MERGE_BIT)) != 0;
14207 if (!to_is_continue || !branching_to_merge)
14208 branch_to_continue(from, to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010014209 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014210 else if (!is_conditional(to))
14211 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014212
14213 // It is important that we check for break before continue.
14214 // A block might serve two purposes, a break block for the inner scope, and
14215 // a continue block in the outer scope.
14216 // Inner scope always takes precedence.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014217}
14218
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014219void CompilerGLSL::branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014220{
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020014221 auto &from_block = get<SPIRBlock>(from);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014222 BlockID merge_block = from_block.merge == SPIRBlock::MergeSelection ? from_block.next_block : BlockID(0);
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020014223
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014224 // If we branch directly to our selection merge target, we don't need a code path.
14225 bool true_block_needs_code = true_block != merge_block || flush_phi_required(from, true_block);
14226 bool false_block_needs_code = false_block != merge_block || flush_phi_required(from, false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014227
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014228 if (!true_block_needs_code && !false_block_needs_code)
14229 return;
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020014230
Hans-Kristian Arntzen449f68e2021-06-03 12:19:10 +020014231 // We might have a loop merge here. Only consider selection flattening constructs.
14232 // Loop hints are handled explicitly elsewhere.
14233 if (from_block.hint == SPIRBlock::HintFlatten || from_block.hint == SPIRBlock::HintDontFlatten)
14234 emit_block_hints(from_block);
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014235
14236 if (true_block_needs_code)
Hans-Kristian Arntzen54cc0b02020-09-17 12:02:43 +020014237 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014238 statement("if (", to_expression(cond), ")");
14239 begin_scope();
14240 branch(from, true_block);
14241 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014242
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014243 if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014244 {
14245 statement("else");
14246 begin_scope();
14247 branch(from, false_block);
14248 end_scope();
14249 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014250 }
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014251 else if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014252 {
14253 // Only need false path, use negative conditional.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014254 statement("if (!", to_enclosed_expression(cond), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014255 begin_scope();
14256 branch(from, false_block);
14257 end_scope();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014258 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014259}
14260
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014261// FIXME: This currently cannot handle complex continue blocks
14262// as in do-while.
14263// This should be seen as a "trivial" continue block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014264string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014265{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014266 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014268 // While emitting the continue block, declare_temporary will check this
14269 // if we have to emit temporaries.
14270 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014271
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020014272 SmallVector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014273
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014274 // Capture all statements into our list.
14275 auto *old = redirect_statement;
14276 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014277
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014278 // Stamp out all blocks one after each other.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014279 while ((ir.block_meta[block->self] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) == 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014280 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014281 // Write out all instructions we have in this block.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014282 emit_block_instructions(*block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014283
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014284 // For plain branchless for/while continue blocks.
14285 if (block->next_block)
14286 {
14287 flush_phi(continue_block, block->next_block);
14288 block = &get<SPIRBlock>(block->next_block);
14289 }
14290 // For do while blocks. The last block will be a select block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014291 else if (block->true_block && follow_true_block)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014292 {
14293 flush_phi(continue_block, block->true_block);
14294 block = &get<SPIRBlock>(block->true_block);
14295 }
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014296 else if (block->false_block && follow_false_block)
14297 {
14298 flush_phi(continue_block, block->false_block);
14299 block = &get<SPIRBlock>(block->false_block);
14300 }
14301 else
14302 {
14303 SPIRV_CROSS_THROW("Invalid continue block detected!");
14304 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014305 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014307 // Restore old pointer.
14308 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014309
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014310 // Somewhat ugly, strip off the last ';' since we use ',' instead.
14311 // Ideally, we should select this behavior in statement().
14312 for (auto &s : statements)
14313 {
14314 if (!s.empty() && s.back() == ';')
Corentin Wallezef9ee492016-10-05 13:01:31 -040014315 s.erase(s.size() - 1, 1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014316 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014318 current_continue_block = nullptr;
14319 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014320}
14321
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014322void CompilerGLSL::emit_while_loop_initializers(const SPIRBlock &block)
14323{
14324 // While loops do not take initializers, so declare all of them outside.
14325 for (auto &loop_var : block.loop_variables)
14326 {
14327 auto &var = get<SPIRVariable>(loop_var);
14328 statement(variable_decl(var), ";");
14329 }
14330}
14331
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014332string CompilerGLSL::emit_for_loop_initializers(const SPIRBlock &block)
14333{
14334 if (block.loop_variables.empty())
14335 return "";
14336
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014337 bool same_types = for_loop_initializers_are_same_type(block);
14338 // We can only declare for loop initializers if all variables are of same type.
14339 // If we cannot do this, declare individual variables before the loop header.
14340
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010014341 // We might have a loop variable candidate which was not assigned to for some reason.
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014342 uint32_t missing_initializers = 0;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010014343 for (auto &variable : block.loop_variables)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014344 {
14345 uint32_t expr = get<SPIRVariable>(variable).static_expression;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010014346
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014347 // Sometimes loop variables are initialized with OpUndef, but we can just declare
14348 // a plain variable without initializer in this case.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014349 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014350 missing_initializers++;
14351 }
14352
14353 if (block.loop_variables.size() == 1 && missing_initializers == 0)
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014354 {
14355 return variable_decl(get<SPIRVariable>(block.loop_variables.front()));
14356 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014357 else if (!same_types || missing_initializers == uint32_t(block.loop_variables.size()))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014358 {
14359 for (auto &loop_var : block.loop_variables)
14360 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
14361 return "";
14362 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014363 else
14364 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014365 // We have a mix of loop variables, either ones with a clear initializer, or ones without.
14366 // Separate the two streams.
14367 string expr;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014368
14369 for (auto &loop_var : block.loop_variables)
14370 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014371 uint32_t static_expr = get<SPIRVariable>(loop_var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014372 if (static_expr == 0 || ir.ids[static_expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014373 {
14374 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
14375 }
14376 else
14377 {
Chip Davis3bfb2f92018-12-03 02:06:33 -060014378 auto &var = get<SPIRVariable>(loop_var);
14379 auto &type = get_variable_data_type(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014380 if (expr.empty())
14381 {
14382 // For loop initializers are of the form <type id = value, id = value, id = value, etc ...
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014383 expr = join(to_qualifiers_glsl(var.self), type_to_glsl(type), " ");
14384 }
14385 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060014386 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014387 expr += ", ";
Chip Davis3bfb2f92018-12-03 02:06:33 -060014388 // In MSL, being based on C++, the asterisk marking a pointer
14389 // binds to the identifier, not the type.
14390 if (type.pointer)
14391 expr += "* ";
14392 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014393
Chip Davis3bfb2f92018-12-03 02:06:33 -060014394 expr += join(to_name(loop_var), " = ", to_pointer_expression(var.static_expression));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014395 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014396 }
14397 return expr;
14398 }
14399}
14400
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014401bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
14402{
14403 if (block.loop_variables.size() <= 1)
14404 return true;
14405
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014406 uint32_t expected = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014407 Bitset expected_flags;
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014408 for (auto &var : block.loop_variables)
14409 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014410 // Don't care about uninitialized variables as they will not be part of the initializers.
14411 uint32_t expr = get<SPIRVariable>(var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014412 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014413 continue;
14414
14415 if (expected == 0)
14416 {
14417 expected = get<SPIRVariable>(var).basetype;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014418 expected_flags = get_decoration_bitset(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014419 }
14420 else if (expected != get<SPIRVariable>(var).basetype)
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014421 return false;
14422
14423 // Precision flags and things like that must also match.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014424 if (expected_flags != get_decoration_bitset(var))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014425 return false;
14426 }
14427
14428 return true;
14429}
14430
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014431bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
14432{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014433 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014434
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014435 if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014436 {
14437 uint32_t current_count = statement_count;
14438 // If we're trying to create a true for loop,
14439 // we need to make sure that all opcodes before branch statement do not actually emit any code.
14440 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014441 emit_block_instructions(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014442
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014443 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014445 // This can work! We only did trivial things which could be forwarded in block body!
14446 if (current_count == statement_count && condition_is_temporary)
14447 {
14448 switch (continue_type)
14449 {
14450 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014451 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010014452 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
14453 flush_undeclared_variables(block);
14454
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014455 // Important that we do this in this order because
14456 // emitting the continue block can invalidate the condition expression.
14457 auto initializer = emit_for_loop_initializers(block);
14458 auto condition = to_expression(block.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014459
14460 // Condition might have to be inverted.
14461 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14462 condition = join("!", enclose_expression(condition));
14463
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014464 emit_block_hints(block);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014465 if (method != SPIRBlock::MergeToSelectContinueForLoop)
14466 {
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014467 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014468 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
14469 }
14470 else
14471 statement("for (", initializer, "; ", condition, "; )");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014472 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014473 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014474
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014475 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014476 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010014477 // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
14478 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014479 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014480 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014481
14482 auto condition = to_expression(block.condition);
14483 // Condition might have to be inverted.
14484 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14485 condition = join("!", enclose_expression(condition));
14486
14487 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014488 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014489 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014491 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020014492 block.disable_block_optimization = true;
14493 force_recompile();
14494 begin_scope(); // We'll see an end_scope() later.
14495 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014496 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014497
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014498 begin_scope();
14499 return true;
14500 }
14501 else
14502 {
14503 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014504 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014505 begin_scope(); // We'll see an end_scope() later.
14506 return false;
14507 }
14508 }
14509 else if (method == SPIRBlock::MergeToDirectForLoop)
14510 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014511 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014512
Hans-Kristian Arntzen5ff11cc2016-11-18 16:45:11 +010014513 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
14514 flush_undeclared_variables(child);
14515
14516 uint32_t current_count = statement_count;
14517
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014518 // If we're trying to create a true for loop,
14519 // we need to make sure that all opcodes before branch statement do not actually emit any code.
14520 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014521 emit_block_instructions(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014522
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014523 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014524
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014525 if (current_count == statement_count && condition_is_temporary)
14526 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014527 uint32_t target_block = child.true_block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014529 switch (continue_type)
14530 {
14531 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014532 {
14533 // Important that we do this in this order because
14534 // emitting the continue block can invalidate the condition expression.
14535 auto initializer = emit_for_loop_initializers(block);
14536 auto condition = to_expression(child.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014537
14538 // Condition might have to be inverted.
14539 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
14540 {
14541 condition = join("!", enclose_expression(condition));
14542 target_block = child.false_block;
14543 }
14544
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014545 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014546 emit_block_hints(block);
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014547 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014548 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014549 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014550
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014551 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014552 {
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014553 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014554 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014555
14556 auto condition = to_expression(child.condition);
14557 // Condition might have to be inverted.
14558 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
14559 {
14560 condition = join("!", enclose_expression(condition));
14561 target_block = child.false_block;
14562 }
14563
14564 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014565 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014566 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014567
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014568 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020014569 block.disable_block_optimization = true;
14570 force_recompile();
14571 begin_scope(); // We'll see an end_scope() later.
14572 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014573 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014574
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014575 begin_scope();
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014576 branch(child.self, target_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014577 return true;
14578 }
14579 else
14580 {
14581 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014582 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014583 begin_scope(); // We'll see an end_scope() later.
14584 return false;
14585 }
14586 }
14587 else
14588 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014589}
14590
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014591void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014592{
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014593 for (auto &v : block.dominated_variables)
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014594 flush_variable_declaration(v);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014595}
14596
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014597void CompilerGLSL::emit_hoisted_temporaries(SmallVector<pair<TypeID, ID>> &temporaries)
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014598{
14599 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
14600 // Need to sort these to ensure that reference output is stable.
14601 sort(begin(temporaries), end(temporaries),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014602 [](const pair<TypeID, ID> &a, const pair<TypeID, ID> &b) { return a.second < b.second; });
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014603
14604 for (auto &tmp : temporaries)
14605 {
14606 add_local_variable_name(tmp.second);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014607 auto &flags = ir.meta[tmp.second].decoration.decoration_flags;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014608 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010014609
14610 // Not all targets support pointer literals, so don't bother with that case.
14611 string initializer;
14612 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
14613 initializer = join(" = ", to_zero_initialized_expression(tmp.first));
14614
14615 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), initializer, ";");
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014616
14617 hoisted_temporaries.insert(tmp.second);
14618 forced_temporaries.insert(tmp.second);
14619
14620 // The temporary might be read from before it's assigned, set up the expression now.
14621 set<SPIRExpression>(tmp.second, to_name(tmp.second), tmp.first, true);
14622 }
14623}
14624
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014625void CompilerGLSL::emit_block_chain(SPIRBlock &block)
14626{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014627 bool select_branch_to_true_block = false;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014628 bool select_branch_to_false_block = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014629 bool skip_direct_branch = false;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014630 bool emitted_loop_header_variables = false;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014631 bool force_complex_continue_block = false;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020014632 ValueSaver<uint32_t> loop_level_saver(current_loop_level);
14633
14634 if (block.merge == SPIRBlock::MergeLoop)
14635 add_loop_level();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014636
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014637 emit_hoisted_temporaries(block.declare_temporary);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014638
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014639 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
14640 if (block.continue_block)
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010014641 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014642 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010014643 // If we know we cannot emit a loop, mark the block early as a complex loop so we don't force unnecessary recompiles.
14644 if (continue_type == SPIRBlock::ComplexLoop)
14645 block.complex_continue = true;
14646 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014647
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010014648 // If we have loop variables, stop masking out access to the variable now.
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020014649 for (auto var_id : block.loop_variables)
14650 {
14651 auto &var = get<SPIRVariable>(var_id);
14652 var.loop_variable_enable = true;
14653 // We're not going to declare the variable directly, so emit a copy here.
14654 emit_variable_temporary_copies(var);
14655 }
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010014656
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020014657 // Remember deferred declaration state. We will restore it before returning.
14658 SmallVector<bool, 64> rearm_dominated_variables(block.dominated_variables.size());
14659 for (size_t i = 0; i < block.dominated_variables.size(); i++)
14660 {
14661 uint32_t var_id = block.dominated_variables[i];
14662 auto &var = get<SPIRVariable>(var_id);
14663 rearm_dominated_variables[i] = var.deferred_declaration;
14664 }
14665
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014666 // This is the method often used by spirv-opt to implement loops.
14667 // The loop header goes straight into the continue block.
14668 // However, don't attempt this on ESSL 1.0, because if a loop variable is used in a continue block,
14669 // it *MUST* be used in the continue block. This loop method will not work.
14670 if (!is_legacy_es() && block_is_loop_candidate(block, SPIRBlock::MergeToSelectContinueForLoop))
14671 {
14672 flush_undeclared_variables(block);
14673 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
14674 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014675 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14676 select_branch_to_false_block = true;
14677 else
14678 select_branch_to_true_block = true;
14679
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014680 emitted_loop_header_variables = true;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014681 force_complex_continue_block = true;
14682 }
14683 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014684 // 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 +010014685 else if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014686 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014687 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014688 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
14689 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014690 // The body of while, is actually just the true (or false) block, so always branch there unconditionally.
14691 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14692 select_branch_to_false_block = true;
14693 else
14694 select_branch_to_true_block = true;
14695
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014696 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014697 }
14698 }
14699 // This is the newer loop behavior in glslang which branches from Loop header directly to
14700 // a new block, which in turn has a OpBranchSelection without a selection merge.
14701 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
14702 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014703 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014704 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014705 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014706 skip_direct_branch = true;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014707 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014708 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014709 }
14710 else if (continue_type == SPIRBlock::DoWhileLoop)
14711 {
Hans-Kristian Arntzenb3f6e3d2018-01-24 19:46:53 +010014712 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014713 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014714 emitted_loop_header_variables = true;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014715 // We have some temporaries where the loop header is the dominator.
14716 // We risk a case where we have code like:
14717 // for (;;) { create-temporary; break; } consume-temporary;
14718 // so force-declare temporaries here.
14719 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014720 statement("do");
14721 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014722
14723 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014724 }
14725 else if (block.merge == SPIRBlock::MergeLoop)
14726 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014727 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014728 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014729 emitted_loop_header_variables = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014730
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014731 // We have a generic loop without any distinguishable pattern like for, while or do while.
14732 get<SPIRBlock>(block.continue_block).complex_continue = true;
14733 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014734
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014735 // We have some temporaries where the loop header is the dominator.
14736 // We risk a case where we have code like:
14737 // for (;;) { create-temporary; break; } consume-temporary;
14738 // so force-declare temporaries here.
14739 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen449f68e2021-06-03 12:19:10 +020014740 emit_block_hints(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014741 statement("for (;;)");
14742 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014743
14744 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014745 }
14746 else
14747 {
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014748 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014749 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014750
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014751 // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
14752 // as writes to said loop variables might have been masked out, we need a recompile.
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014753 if (!emitted_loop_header_variables && !block.loop_variables.empty())
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014754 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014755 force_recompile();
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014756 for (auto var : block.loop_variables)
14757 get<SPIRVariable>(var).loop_variable = false;
14758 block.loop_variables.clear();
14759 }
14760
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014761 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014762 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014763
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014764 // Handle end of block.
14765 switch (block.terminator)
14766 {
14767 case SPIRBlock::Direct:
14768 // True when emitting complex continue block.
14769 if (block.loop_dominator == block.next_block)
14770 {
14771 branch(block.self, block.next_block);
14772 emit_next_block = false;
14773 }
14774 // True if MergeToDirectForLoop succeeded.
14775 else if (skip_direct_branch)
14776 emit_next_block = false;
14777 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
14778 {
14779 branch(block.self, block.next_block);
14780 emit_next_block = false;
14781 }
14782 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014783
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014784 case SPIRBlock::Select:
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014785 // True if MergeToSelectForLoop or MergeToSelectContinueForLoop succeeded.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014786 if (select_branch_to_true_block)
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014787 {
14788 if (force_complex_continue_block)
14789 {
14790 assert(block.true_block == block.continue_block);
14791
14792 // We're going to emit a continue block directly here, so make sure it's marked as complex.
14793 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
14794 bool old_complex = complex_continue;
14795 complex_continue = true;
14796 branch(block.self, block.true_block);
14797 complex_continue = old_complex;
14798 }
14799 else
14800 branch(block.self, block.true_block);
14801 }
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014802 else if (select_branch_to_false_block)
14803 {
14804 if (force_complex_continue_block)
14805 {
14806 assert(block.false_block == block.continue_block);
14807
14808 // We're going to emit a continue block directly here, so make sure it's marked as complex.
14809 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
14810 bool old_complex = complex_continue;
14811 complex_continue = true;
14812 branch(block.self, block.false_block);
14813 complex_continue = old_complex;
14814 }
14815 else
14816 branch(block.self, block.false_block);
14817 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014818 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014819 branch(block.self, block.condition, block.true_block, block.false_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014820 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014821
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014822 case SPIRBlock::MultiSelect:
14823 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014824 auto &type = expression_type(block.condition);
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014825 bool unsigned_case = type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort ||
14826 type.basetype == SPIRType::UByte || type.basetype == SPIRType::UInt64;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014827
Hans-Kristian Arntzen45baf242019-03-20 10:42:38 +010014828 if (block.merge == SPIRBlock::MergeNone)
14829 SPIRV_CROSS_THROW("Switch statement is not structured");
14830
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014831 if (!backend.support_64bit_switch && (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64))
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010014832 {
14833 // SPIR-V spec suggests this is allowed, but we cannot support it in higher level languages.
14834 SPIRV_CROSS_THROW("Cannot use 64-bit switch selectors.");
14835 }
14836
14837 const char *label_suffix = "";
14838 if (type.basetype == SPIRType::UInt && backend.uint32_t_literal_suffix)
14839 label_suffix = "u";
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014840 else if (type.basetype == SPIRType::Int64 && backend.support_64bit_switch)
14841 label_suffix = "l";
14842 else if (type.basetype == SPIRType::UInt64 && backend.support_64bit_switch)
14843 label_suffix = "ul";
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010014844 else if (type.basetype == SPIRType::UShort)
14845 label_suffix = backend.uint16_t_literal_suffix;
14846 else if (type.basetype == SPIRType::Short)
14847 label_suffix = backend.int16_t_literal_suffix;
14848
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014849 SPIRBlock *old_emitting_switch = current_emitting_switch;
14850 current_emitting_switch = &block;
14851
14852 if (block.need_ladder_break)
14853 statement("bool _", block.self, "_ladder_break = false;");
14854
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014855 // Find all unique case constructs.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014856 unordered_map<uint32_t, SmallVector<uint64_t>> case_constructs;
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014857 SmallVector<uint32_t> block_declaration_order;
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014858 SmallVector<uint64_t> literals_to_merge;
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014859
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014860 // If a switch case branches to the default block for some reason, we can just remove that literal from consideration
14861 // and let the default: block handle it.
14862 // 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.
14863 // We only need to consider possible fallthrough if order[i] branches to order[i + 1].
Sebastián Aedo75e37522021-11-12 10:17:38 -030014864 auto &cases = get_case_list(block);
14865 for (auto &c : cases)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014866 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014867 if (c.block != block.next_block && c.block != block.default_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014868 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014869 if (!case_constructs.count(c.block))
14870 block_declaration_order.push_back(c.block);
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014871 case_constructs[c.block].push_back(c.value);
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014872 }
14873 else if (c.block == block.next_block && block.default_block != block.next_block)
14874 {
14875 // We might have to flush phi inside specific case labels.
14876 // If we can piggyback on default:, do so instead.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014877 literals_to_merge.push_back(c.value);
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014878 }
14879 }
14880
14881 // Empty literal array -> default.
14882 if (block.default_block != block.next_block)
14883 {
14884 auto &default_block = get<SPIRBlock>(block.default_block);
14885
14886 // We need to slide in the default block somewhere in this chain
14887 // if there are fall-through scenarios since the default is declared separately in OpSwitch.
14888 // Only consider trivial fall-through cases here.
14889 size_t num_blocks = block_declaration_order.size();
14890 bool injected_block = false;
14891
14892 for (size_t i = 0; i < num_blocks; i++)
14893 {
14894 auto &case_block = get<SPIRBlock>(block_declaration_order[i]);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014895 if (execution_is_direct_branch(case_block, default_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014896 {
14897 // Fallthrough to default block, we must inject the default block here.
14898 block_declaration_order.insert(begin(block_declaration_order) + i + 1, block.default_block);
14899 injected_block = true;
14900 break;
14901 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014902 else if (execution_is_direct_branch(default_block, case_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014903 {
14904 // Default case is falling through to another case label, we must inject the default block here.
14905 block_declaration_order.insert(begin(block_declaration_order) + i, block.default_block);
14906 injected_block = true;
14907 break;
14908 }
14909 }
14910
14911 // Order does not matter.
14912 if (!injected_block)
14913 block_declaration_order.push_back(block.default_block);
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014914 else if (is_legacy_es())
14915 SPIRV_CROSS_THROW("Default case label fallthrough to other case label is not supported in ESSL 1.0.");
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014916
14917 case_constructs[block.default_block] = {};
14918 }
14919
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014920 size_t num_blocks = block_declaration_order.size();
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014921
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014922 const auto to_case_label = [](uint64_t literal, uint32_t width, bool is_unsigned_case) -> string
14923 {
14924 if (is_unsigned_case)
14925 return convert_to_string(literal);
14926
14927 // For smaller cases, the literals are compiled as 32 bit wide
14928 // literals so we don't need to care for all sizes specifically.
14929 if (width <= 32)
14930 {
14931 return convert_to_string(int64_t(int32_t(literal)));
14932 }
14933
14934 return convert_to_string(int64_t(literal));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014935 };
14936
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014937 const auto to_legacy_case_label = [&](uint32_t condition, const SmallVector<uint64_t> &labels,
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020014938 const char *suffix) -> string {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014939 string ret;
14940 size_t count = labels.size();
14941 for (size_t i = 0; i < count; i++)
14942 {
14943 if (i)
14944 ret += " || ";
14945 ret += join(count > 1 ? "(" : "", to_enclosed_expression(condition), " == ", labels[i], suffix,
14946 count > 1 ? ")" : "");
14947 }
14948 return ret;
14949 };
14950
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014951 // We need to deal with a complex scenario for OpPhi. If we have case-fallthrough and Phi in the picture,
14952 // we need to flush phi nodes outside the switch block in a branch,
14953 // and skip any Phi handling inside the case label to make fall-through work as expected.
14954 // This kind of code-gen is super awkward and it's a last resort. Normally we would want to handle this
14955 // inside the case label if at all possible.
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014956 for (size_t i = 1; backend.support_case_fallthrough && i < num_blocks; i++)
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014957 {
14958 if (flush_phi_required(block.self, block_declaration_order[i]) &&
14959 flush_phi_required(block_declaration_order[i - 1], block_declaration_order[i]))
14960 {
14961 uint32_t target_block = block_declaration_order[i];
14962
14963 // Make sure we flush Phi, it might have been marked to be ignored earlier.
14964 get<SPIRBlock>(target_block).ignore_phi_from_block = 0;
14965
14966 auto &literals = case_constructs[target_block];
14967
14968 if (literals.empty())
14969 {
14970 // Oh boy, gotta make a complete negative test instead! o.o
14971 // Find all possible literals that would *not* make us enter the default block.
14972 // If none of those literals match, we flush Phi ...
14973 SmallVector<string> conditions;
14974 for (size_t j = 0; j < num_blocks; j++)
14975 {
14976 auto &negative_literals = case_constructs[block_declaration_order[j]];
14977 for (auto &case_label : negative_literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020014978 conditions.push_back(join(to_enclosed_expression(block.condition),
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014979 " != ", to_case_label(case_label, type.width, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014980 }
14981
14982 statement("if (", merge(conditions, " && "), ")");
14983 begin_scope();
14984 flush_phi(block.self, target_block);
14985 end_scope();
14986 }
14987 else
14988 {
14989 SmallVector<string> conditions;
14990 conditions.reserve(literals.size());
14991 for (auto &case_label : literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020014992 conditions.push_back(join(to_enclosed_expression(block.condition),
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014993 " == ", to_case_label(case_label, type.width, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014994 statement("if (", merge(conditions, " || "), ")");
14995 begin_scope();
14996 flush_phi(block.self, target_block);
14997 end_scope();
14998 }
14999
15000 // Mark the block so that we don't flush Phi from header to case label.
15001 get<SPIRBlock>(target_block).ignore_phi_from_block = block.self;
15002 }
15003 }
15004
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015005 // If there is only one default block, and no cases, this is a case where SPIRV-opt decided to emulate
15006 // non-structured exits with the help of a switch block.
15007 // This is buggy on FXC, so just emit the logical equivalent of a do { } while(false), which is more idiomatic.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015008 bool degenerate_switch = block.default_block != block.merge_block && cases.empty();
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015009
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015010 if (degenerate_switch || is_legacy_es())
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015011 {
15012 // ESSL 1.0 is not guaranteed to support do/while.
15013 if (is_legacy_es())
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020015014 {
15015 uint32_t counter = statement_count;
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010015016 statement("for (int spvDummy", counter, " = 0; spvDummy", counter,
15017 " < 1; spvDummy", counter, "++)");
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020015018 }
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015019 else
15020 statement("do");
15021 }
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015022 else
15023 {
15024 emit_block_hints(block);
Bill Hollings974a0812021-10-21 16:11:33 -040015025 statement("switch (", to_unpacked_expression(block.condition), ")");
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015026 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015027 begin_scope();
15028
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015029 for (size_t i = 0; i < num_blocks; i++)
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015030 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015031 uint32_t target_block = block_declaration_order[i];
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015032 auto &literals = case_constructs[target_block];
15033
15034 if (literals.empty())
15035 {
15036 // Default case.
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015037 if (!degenerate_switch)
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015038 {
15039 if (is_legacy_es())
15040 statement("else");
15041 else
15042 statement("default:");
15043 }
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015044 }
15045 else
15046 {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015047 if (is_legacy_es())
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015048 {
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020015049 statement((i ? "else " : ""), "if (", to_legacy_case_label(block.condition, literals, label_suffix),
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015050 ")");
15051 }
15052 else
15053 {
15054 for (auto &case_literal : literals)
15055 {
15056 // The case label value must be sign-extended properly in SPIR-V, so we can assume 32-bit values here.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015057 statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015058 }
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015059 }
15060 }
15061
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015062 auto &case_block = get<SPIRBlock>(target_block);
Hans-Kristian Arntzen581ed0f2019-06-27 15:10:17 +020015063 if (backend.support_case_fallthrough && i + 1 < num_blocks &&
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020015064 execution_is_direct_branch(case_block, get<SPIRBlock>(block_declaration_order[i + 1])))
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015065 {
15066 // We will fall through here, so just terminate the block chain early.
15067 // We still need to deal with Phi potentially.
15068 // No need for a stack-like thing here since we only do fall-through when there is a
15069 // single trivial branch to fall-through target..
15070 current_emitting_switch_fallthrough = true;
15071 }
15072 else
15073 current_emitting_switch_fallthrough = false;
15074
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015075 if (!degenerate_switch)
15076 begin_scope();
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015077 branch(block.self, target_block);
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015078 if (!degenerate_switch)
15079 end_scope();
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015080
15081 current_emitting_switch_fallthrough = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015082 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015083
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015084 // Might still have to flush phi variables if we branch from loop header directly to merge target.
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015085 // This is supposed to emit all cases where we branch from header to merge block directly.
15086 // There are two main scenarios where cannot rely on default fallthrough.
15087 // - There is an explicit default: label already.
15088 // In this case, literals_to_merge need to form their own "default" case, so that we avoid executing that block.
15089 // - Header -> Merge requires flushing PHI. In this case, we need to collect all cases and flush PHI there.
15090 bool header_merge_requires_phi = flush_phi_required(block.self, block.next_block);
15091 bool need_fallthrough_block = block.default_block == block.next_block || !literals_to_merge.empty();
15092 if ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015093 {
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015094 for (auto &case_literal : literals_to_merge)
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015095 statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015096
15097 if (block.default_block == block.next_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015098 {
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015099 if (is_legacy_es())
15100 statement("else");
15101 else
15102 statement("default:");
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015103 }
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015104
15105 begin_scope();
15106 flush_phi(block.self, block.next_block);
15107 statement("break;");
15108 end_scope();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015109 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015110
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015111 if (degenerate_switch && !is_legacy_es())
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015112 end_scope_decl("while(false)");
15113 else
15114 end_scope();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015115
15116 if (block.need_ladder_break)
15117 {
15118 statement("if (_", block.self, "_ladder_break)");
15119 begin_scope();
15120 statement("break;");
15121 end_scope();
15122 }
15123
15124 current_emitting_switch = old_emitting_switch;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015125 break;
15126 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015128 case SPIRBlock::Return:
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015129 {
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020015130 for (auto &line : current_function->fixup_hooks_out)
15131 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040015132
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015133 if (processing_entry_point)
15134 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015135
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015136 auto &cfg = get_cfg_for_current_function();
15137
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015138 if (block.return_value)
15139 {
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015140 auto &type = expression_type(block.return_value);
15141 if (!type.array.empty() && !backend.can_return_array)
15142 {
15143 // If we cannot return arrays, we will have a special out argument we can write to instead.
15144 // The backend is responsible for setting this up, and redirection the return values as appropriate.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010015145 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020015146 {
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020015147 emit_array_copy("spvReturnValue", 0, block.return_value, StorageClassFunction,
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +020015148 get_expression_effective_storage_class(block.return_value));
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020015149 }
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015150
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015151 if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015152 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015153 {
15154 statement("return;");
15155 }
15156 }
15157 else
15158 {
15159 // OpReturnValue can return Undef, so don't emit anything for this case.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010015160 if (ir.ids[block.return_value].get_type() != TypeUndef)
Bill Hollings974a0812021-10-21 16:11:33 -040015161 statement("return ", to_unpacked_expression(block.return_value), ";");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015162 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015163 }
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015164 else if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015165 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015166 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015167 // If this block is the very final block and not called from control flow,
15168 // we do not need an explicit return which looks out of place. Just end the function here.
15169 // In the very weird case of for(;;) { return; } executing return is unconditional,
15170 // but we actually need a return here ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015171 statement("return;");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015172 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015173 break;
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015174 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015175
Bill Hollings35e92e62021-09-12 16:28:21 -040015176 // If the Kill is terminating a block with a (probably synthetic) return value, emit a return value statement.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015177 case SPIRBlock::Kill:
Bill Hollings943191a2016-10-27 10:20:01 -040015178 statement(backend.discard_literal, ";");
Bill Hollings35e92e62021-09-12 16:28:21 -040015179 if (block.return_value)
Bill Hollings974a0812021-10-21 16:11:33 -040015180 statement("return ", to_unpacked_expression(block.return_value), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015181 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015182
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010015183 case SPIRBlock::Unreachable:
15184 emit_next_block = false;
15185 break;
15186
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010015187 case SPIRBlock::IgnoreIntersection:
15188 statement("ignoreIntersectionEXT;");
15189 break;
15190
15191 case SPIRBlock::TerminateRay:
15192 statement("terminateRayEXT;");
15193 break;
15194
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015195 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015196 SPIRV_CROSS_THROW("Unimplemented block terminator.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015197 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015198
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015199 if (block.next_block && emit_next_block)
15200 {
15201 // If we hit this case, we're dealing with an unconditional branch, which means we will output
15202 // that block after this. If we had selection merge, we already flushed phi variables.
15203 if (block.merge != SPIRBlock::MergeSelection)
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020015204 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015205 flush_phi(block.self, block.next_block);
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020015206 // For a direct branch, need to remember to invalidate expressions in the next linear block instead.
15207 get<SPIRBlock>(block.next_block).invalidate_expressions = block.invalidate_expressions;
15208 }
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015209
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015210 // For switch fallthrough cases, we terminate the chain here, but we still need to handle Phi.
15211 if (!current_emitting_switch_fallthrough)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015212 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015213 // For merge selects we might have ignored the fact that a merge target
15214 // could have been a break; or continue;
15215 // We will need to deal with it here.
15216 if (is_loop_break(block.next_block))
15217 {
15218 // Cannot check for just break, because switch statements will also use break.
15219 assert(block.merge == SPIRBlock::MergeSelection);
15220 statement("break;");
15221 }
15222 else if (is_continue(block.next_block))
15223 {
15224 assert(block.merge == SPIRBlock::MergeSelection);
15225 branch_to_continue(block.self, block.next_block);
15226 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015227 else if (BlockID(block.self) != block.next_block)
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015228 emit_block_chain(get<SPIRBlock>(block.next_block));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015229 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015230 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015232 if (block.merge == SPIRBlock::MergeLoop)
15233 {
15234 if (continue_type == SPIRBlock::DoWhileLoop)
15235 {
15236 // Make sure that we run the continue block to get the expressions set, but this
15237 // should become an empty string.
15238 // We have no fallbacks if we cannot forward everything to temporaries ...
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015239 const auto &continue_block = get<SPIRBlock>(block.continue_block);
Hans-Kristian Arntzen8bfb04d2019-03-06 12:20:13 +010015240 bool positive_test = execution_is_noop(get<SPIRBlock>(continue_block.true_block),
15241 get<SPIRBlock>(continue_block.loop_dominator));
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015242
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015243 uint32_t current_count = statement_count;
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015244 auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015245 if (statement_count != current_count)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015246 {
15247 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
15248 get<SPIRBlock>(block.continue_block).complex_continue = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015249 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015250 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015251
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015252 // Might have to invert the do-while test here.
15253 auto condition = to_expression(continue_block.condition);
15254 if (!positive_test)
15255 condition = join("!", enclose_expression(condition));
15256
15257 end_scope_decl(join("while (", condition, ")"));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015258 }
15259 else
15260 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015261
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020015262 loop_level_saver.release();
15263
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015264 // We cannot break out of two loops at once, so don't check for break; here.
15265 // Using block.self as the "from" block isn't quite right, but it has the same scope
15266 // and dominance structure, so it's fine.
15267 if (is_continue(block.merge_block))
15268 branch_to_continue(block.self, block.merge_block);
15269 else
15270 emit_block_chain(get<SPIRBlock>(block.merge_block));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015271 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020015272
15273 // Forget about control dependent expressions now.
15274 block.invalidate_expressions.clear();
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020015275
15276 // After we return, we must be out of scope, so if we somehow have to re-emit this function,
15277 // re-declare variables if necessary.
15278 assert(rearm_dominated_variables.size() == block.dominated_variables.size());
15279 for (size_t i = 0; i < block.dominated_variables.size(); i++)
15280 {
15281 uint32_t var = block.dominated_variables[i];
15282 get<SPIRVariable>(var).deferred_declaration = rearm_dominated_variables[i];
15283 }
Hans-Kristian Arntzen25c74b32019-07-10 12:57:12 +020015284
15285 // Just like for deferred declaration, we need to forget about loop variable enable
15286 // if our block chain is reinstantiated later.
15287 for (auto &var_id : block.loop_variables)
15288 get<SPIRVariable>(var_id).loop_variable_enable = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015289}
15290
15291void CompilerGLSL::begin_scope()
15292{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015293 statement("{");
15294 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015295}
15296
15297void CompilerGLSL::end_scope()
15298{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015299 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015300 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015301 indent--;
15302 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015303}
15304
Chip Daviscb359342019-09-05 23:14:12 -050015305void CompilerGLSL::end_scope(const string &trailer)
15306{
15307 if (!indent)
15308 SPIRV_CROSS_THROW("Popping empty indent stack.");
15309 indent--;
15310 statement("}", trailer);
15311}
15312
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015313void CompilerGLSL::end_scope_decl()
15314{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015315 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015316 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015317 indent--;
15318 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015319}
15320
15321void CompilerGLSL::end_scope_decl(const string &decl)
15322{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015323 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015324 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015325 indent--;
15326 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015327}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020015328
15329void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
15330{
15331 // If our variable is remapped, and we rely on type-remapping information as
15332 // well, then we cannot pass the variable as a function parameter.
15333 // Fixing this is non-trivial without stamping out variants of the same function,
15334 // so for now warn about this and suggest workarounds instead.
15335 for (uint32_t i = 0; i < length; i++)
15336 {
15337 auto *var = maybe_get<SPIRVariable>(args[i]);
15338 if (!var || !var->remapped_variable)
15339 continue;
15340
15341 auto &type = get<SPIRType>(var->basetype);
15342 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
15343 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015344 SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
15345 "This will not work correctly because type-remapping information is lost. "
15346 "To workaround, please consider not passing the subpass input as a function parameter, "
15347 "or use in/out variables instead which do not need type remapping information.");
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020015348 }
15349 }
15350}
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010015351
15352const Instruction *CompilerGLSL::get_next_instruction_in_block(const Instruction &instr)
15353{
15354 // FIXME: This is kind of hacky. There should be a cleaner way.
15355 auto offset = uint32_t(&instr - current_emitting_block->ops.data());
15356 if ((offset + 1) < current_emitting_block->ops.size())
15357 return &current_emitting_block->ops[offset + 1];
15358 else
15359 return nullptr;
15360}
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010015361
15362uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
15363{
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010015364 return semantics & (MemorySemanticsAtomicCounterMemoryMask | MemorySemanticsImageMemoryMask |
15365 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask |
15366 MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010015367}
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015368
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020015369void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t, uint32_t rhs_id, StorageClass, StorageClass)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015370{
15371 statement(lhs, " = ", to_expression(rhs_id), ";");
15372}
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015373
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015374bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id)
15375{
15376 if (!backend.force_gl_in_out_block)
15377 return false;
15378 // This path is only relevant for GL backends.
15379
15380 auto *var = maybe_get<SPIRVariable>(target_id);
15381 if (!var || var->storage != StorageClassOutput)
15382 return false;
15383
15384 if (!is_builtin_variable(*var) || BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInSampleMask)
15385 return false;
15386
15387 auto &type = expression_type(source_id);
15388 string array_expr;
15389 if (type.array_size_literal.back())
15390 {
15391 array_expr = convert_to_string(type.array.back());
15392 if (type.array.back() == 0)
15393 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
15394 }
15395 else
15396 array_expr = to_expression(type.array.back());
15397
15398 SPIRType target_type;
15399 target_type.basetype = SPIRType::Int;
15400
15401 statement("for (int i = 0; i < int(", array_expr, "); i++)");
15402 begin_scope();
15403 statement(to_expression(target_id), "[i] = ",
15404 bitcast_expression(target_type, type.basetype, join(to_expression(source_id), "[i]")),
15405 ";");
15406 end_scope();
15407
15408 return true;
15409}
15410
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015411void 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 +010015412{
15413 if (!backend.force_gl_in_out_block)
15414 return;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015415 // This path is only relevant for GL backends.
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015416
15417 auto *var = maybe_get<SPIRVariable>(source_id);
15418 if (!var)
15419 return;
15420
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015421 if (var->storage != StorageClassInput && var->storage != StorageClassOutput)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015422 return;
15423
15424 auto &type = get_variable_data_type(*var);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015425 if (type.array.empty())
15426 return;
15427
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015428 auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015429 bool is_builtin = is_builtin_variable(*var) &&
15430 (builtin == BuiltInPointSize ||
15431 builtin == BuiltInPosition ||
15432 builtin == BuiltInSampleMask);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015433 bool is_tess = is_tessellation_shader();
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010015434 bool is_patch = has_decoration(var->self, DecorationPatch);
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015435 bool is_sample_mask = is_builtin && builtin == BuiltInSampleMask;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015436
15437 // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
15438 // We must unroll the array load.
15439 // For builtins, we couldn't catch this case normally,
15440 // because this is resolved in the OpAccessChain in most cases.
15441 // If we load the entire array, we have no choice but to unroll here.
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010015442 if (!is_patch && (is_builtin || is_tess))
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015443 {
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015444 auto new_expr = join("_", target_id, "_unrolled");
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015445 statement(variable_decl(type, new_expr, target_id), ";");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015446 string array_expr;
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010015447 if (type.array_size_literal.back())
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015448 {
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010015449 array_expr = convert_to_string(type.array.back());
15450 if (type.array.back() == 0)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015451 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
15452 }
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015453 else
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010015454 array_expr = to_expression(type.array.back());
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015455
15456 // The array size might be a specialization constant, so use a for-loop instead.
15457 statement("for (int i = 0; i < int(", array_expr, "); i++)");
15458 begin_scope();
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015459 if (is_builtin && !is_sample_mask)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015460 statement(new_expr, "[i] = gl_in[i].", expr, ";");
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015461 else if (is_sample_mask)
15462 {
15463 SPIRType target_type;
15464 target_type.basetype = SPIRType::Int;
15465 statement(new_expr, "[i] = ", bitcast_expression(target_type, type.basetype, join(expr, "[i]")), ";");
15466 }
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015467 else
15468 statement(new_expr, "[i] = ", expr, "[i];");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015469 end_scope();
15470
15471 expr = move(new_expr);
15472 }
15473}
15474
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020015475void CompilerGLSL::cast_from_variable_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015476{
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015477 // We will handle array cases elsewhere.
15478 if (!expr_type.array.empty())
15479 return;
15480
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020015481 auto *var = maybe_get_backing_variable(source_id);
15482 if (var)
15483 source_id = var->self;
15484
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015485 // Only interested in standalone builtin variables.
15486 if (!has_decoration(source_id, DecorationBuiltIn))
15487 return;
15488
15489 auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
15490 auto expected_type = expr_type.basetype;
15491
15492 // TODO: Fill in for more builtins.
15493 switch (builtin)
15494 {
15495 case BuiltInLayer:
15496 case BuiltInPrimitiveId:
15497 case BuiltInViewportIndex:
15498 case BuiltInInstanceId:
15499 case BuiltInInstanceIndex:
15500 case BuiltInVertexId:
15501 case BuiltInVertexIndex:
15502 case BuiltInSampleId:
Chip Davisfcad0192018-08-28 13:47:29 -050015503 case BuiltInBaseVertex:
15504 case BuiltInBaseInstance:
15505 case BuiltInDrawIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020015506 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020015507 case BuiltInInstanceCustomIndexNV:
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015508 case BuiltInSampleMask:
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +020015509 case BuiltInPrimitiveShadingRateKHR:
15510 case BuiltInShadingRateKHR:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015511 expected_type = SPIRType::Int;
15512 break;
15513
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020015514 case BuiltInGlobalInvocationId:
15515 case BuiltInLocalInvocationId:
15516 case BuiltInWorkgroupId:
15517 case BuiltInLocalInvocationIndex:
15518 case BuiltInWorkgroupSize:
15519 case BuiltInNumWorkgroups:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020015520 case BuiltInIncomingRayFlagsNV:
15521 case BuiltInLaunchIdNV:
15522 case BuiltInLaunchSizeNV:
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020015523 expected_type = SPIRType::UInt;
15524 break;
15525
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015526 default:
15527 break;
15528 }
15529
15530 if (expected_type != expr_type.basetype)
15531 expr = bitcast_expression(expr_type, expected_type, expr);
15532}
15533
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020015534void CompilerGLSL::cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015535{
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015536 auto *var = maybe_get_backing_variable(target_id);
15537 if (var)
15538 target_id = var->self;
15539
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015540 // Only interested in standalone builtin variables.
15541 if (!has_decoration(target_id, DecorationBuiltIn))
15542 return;
15543
15544 auto builtin = static_cast<BuiltIn>(get_decoration(target_id, DecorationBuiltIn));
15545 auto expected_type = expr_type.basetype;
15546
15547 // TODO: Fill in for more builtins.
15548 switch (builtin)
15549 {
15550 case BuiltInLayer:
15551 case BuiltInPrimitiveId:
15552 case BuiltInViewportIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020015553 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015554 case BuiltInSampleMask:
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +020015555 case BuiltInPrimitiveShadingRateKHR:
15556 case BuiltInShadingRateKHR:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015557 expected_type = SPIRType::Int;
15558 break;
15559
15560 default:
15561 break;
15562 }
15563
15564 if (expected_type != expr_type.basetype)
15565 {
15566 auto type = expr_type;
15567 type.basetype = expected_type;
15568 expr = bitcast_expression(type, expr_type.basetype, expr);
15569 }
15570}
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015571
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015572void CompilerGLSL::convert_non_uniform_expression(string &expr, uint32_t ptr_id)
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015573{
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020015574 if (*backend.nonuniform_qualifier == '\0')
15575 return;
15576
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015577 auto *var = maybe_get_backing_variable(ptr_id);
15578 if (!var)
15579 return;
15580
15581 if (var->storage != StorageClassUniformConstant &&
15582 var->storage != StorageClassStorageBuffer &&
15583 var->storage != StorageClassUniform)
15584 return;
15585
15586 auto &backing_type = get<SPIRType>(var->basetype);
15587 if (backing_type.array.empty())
15588 return;
15589
15590 // If we get here, we know we're accessing an arrayed resource which
15591 // might require nonuniform qualifier.
15592
15593 auto start_array_index = expr.find_first_of('[');
15594
15595 if (start_array_index == string::npos)
15596 return;
15597
15598 // We've opened a bracket, track expressions until we can close the bracket.
15599 // This must be our resource index.
15600 size_t end_array_index = string::npos;
15601 unsigned bracket_count = 1;
15602 for (size_t index = start_array_index + 1; index < expr.size(); index++)
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015603 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015604 if (expr[index] == ']')
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015605 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015606 if (--bracket_count == 0)
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015607 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015608 end_array_index = index;
15609 break;
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015610 }
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015611 }
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015612 else if (expr[index] == '[')
15613 bracket_count++;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015614 }
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015615
15616 assert(bracket_count == 0);
15617
15618 // Doesn't really make sense to declare a non-arrayed image with nonuniformEXT, but there's
15619 // nothing we can do here to express that.
15620 if (start_array_index == string::npos || end_array_index == string::npos || end_array_index < start_array_index)
15621 return;
15622
15623 start_array_index++;
15624
15625 expr = join(expr.substr(0, start_array_index), backend.nonuniform_qualifier, "(",
15626 expr.substr(start_array_index, end_array_index - start_array_index), ")",
15627 expr.substr(end_array_index, string::npos));
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015628}
15629
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +020015630void CompilerGLSL::emit_block_hints(const SPIRBlock &block)
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015631{
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +020015632 if ((options.es && options.version < 310) || (!options.es && options.version < 140))
15633 return;
15634
15635 switch (block.hint)
15636 {
15637 case SPIRBlock::HintFlatten:
15638 require_extension_internal("GL_EXT_control_flow_attributes");
15639 statement("SPIRV_CROSS_FLATTEN");
15640 break;
15641 case SPIRBlock::HintDontFlatten:
15642 require_extension_internal("GL_EXT_control_flow_attributes");
15643 statement("SPIRV_CROSS_BRANCH");
15644 break;
15645 case SPIRBlock::HintUnroll:
15646 require_extension_internal("GL_EXT_control_flow_attributes");
15647 statement("SPIRV_CROSS_UNROLL");
15648 break;
15649 case SPIRBlock::HintDontUnroll:
15650 require_extension_internal("GL_EXT_control_flow_attributes");
15651 statement("SPIRV_CROSS_LOOP");
15652 break;
15653 default:
15654 break;
15655 }
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015656}
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +010015657
15658void CompilerGLSL::preserve_alias_on_reset(uint32_t id)
15659{
15660 preserved_aliases[id] = get_name(id);
15661}
15662
15663void CompilerGLSL::reset_name_caches()
15664{
15665 for (auto &preserved : preserved_aliases)
15666 set_name(preserved.first, preserved.second);
15667
15668 preserved_aliases.clear();
15669 resource_names.clear();
15670 block_input_names.clear();
15671 block_output_names.clear();
15672 block_ubo_names.clear();
15673 block_ssbo_names.clear();
15674 block_names.clear();
15675 function_overloads.clear();
15676}
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015677
15678void CompilerGLSL::fixup_type_alias()
15679{
15680 // Due to how some backends work, the "master" type of type_alias must be a block-like type if it exists.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015681 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020015682 if (!type.type_alias)
15683 return;
15684
15685 if (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015686 {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020015687 // Top-level block types should never alias anything else.
15688 type.type_alias = 0;
15689 }
15690 else if (type_is_block_like(type) && type.self == ID(self))
15691 {
15692 // A block-like type is any type which contains Offset decoration, but not top-level blocks,
15693 // i.e. blocks which are placed inside buffers.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015694 // Become the master.
15695 ir.for_each_typed_id<SPIRType>([&](uint32_t other_id, SPIRType &other_type) {
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020015696 if (other_id == self)
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015697 return;
15698
15699 if (other_type.type_alias == type.type_alias)
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020015700 other_type.type_alias = self;
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015701 });
15702
15703 this->get<SPIRType>(type.type_alias).type_alias = self;
15704 type.type_alias = 0;
15705 }
15706 });
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015707}
15708
15709void CompilerGLSL::reorder_type_alias()
15710{
15711 // Reorder declaration of types so that the master of the type alias is always emitted first.
15712 // 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
15713 // 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 +020015714 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020015715
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015716 auto &type_ids = ir.ids_for_type[TypeType];
15717 for (auto alias_itr = begin(type_ids); alias_itr != end(type_ids); ++alias_itr)
15718 {
15719 auto &type = get<SPIRType>(*alias_itr);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015720 if (type.type_alias != TypeID(0) &&
15721 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015722 {
15723 // We will skip declaring this type, so make sure the type_alias type comes before.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015724 auto master_itr = find(begin(type_ids), end(type_ids), ID(type.type_alias));
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015725 assert(master_itr != end(type_ids));
15726
15727 if (alias_itr < master_itr)
15728 {
15729 // Must also swap the type order for the constant-type joined array.
15730 auto &joined_types = ir.ids_for_constant_or_type;
15731 auto alt_alias_itr = find(begin(joined_types), end(joined_types), *alias_itr);
15732 auto alt_master_itr = find(begin(joined_types), end(joined_types), *master_itr);
15733 assert(alt_alias_itr != end(joined_types));
15734 assert(alt_master_itr != end(joined_types));
15735
15736 swap(*alias_itr, *master_itr);
15737 swap(*alt_alias_itr, *alt_master_itr);
15738 }
15739 }
15740 }
15741}
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020015742
15743void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
15744{
15745 // If we are redirecting statements, ignore the line directive.
15746 // Common case here is continue blocks.
15747 if (redirect_statement)
15748 return;
15749
15750 if (options.emit_line_directives)
15751 {
15752 require_extension_internal("GL_GOOGLE_cpp_style_line_directive");
15753 statement_no_indent("#line ", line_literal, " \"", get<SPIRString>(file_id).str, "\"");
15754 }
15755}
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020015756
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010015757void 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 +010015758 SmallVector<uint32_t> chain)
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015759{
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015760 // Fully unroll all member/array indices one by one.
15761
15762 auto &lhs_type = get<SPIRType>(lhs_type_id);
15763 auto &rhs_type = get<SPIRType>(rhs_type_id);
15764
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015765 if (!lhs_type.array.empty())
15766 {
15767 // Could use a loop here to support specialization constants, but it gets rather complicated with nested array types,
15768 // and this is a rather obscure opcode anyways, keep it simple unless we are forced to.
15769 uint32_t array_size = to_array_size_literal(lhs_type);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015770 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015771
15772 for (uint32_t i = 0; i < array_size; i++)
15773 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015774 chain.back() = i;
15775 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 +010015776 }
15777 }
15778 else if (lhs_type.basetype == SPIRType::Struct)
15779 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015780 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015781 uint32_t member_count = uint32_t(lhs_type.member_types.size());
15782 for (uint32_t i = 0; i < member_count; i++)
15783 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015784 chain.back() = i;
15785 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 +010015786 }
15787 }
15788 else
15789 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015790 // Need to handle unpack/packing fixups since this can differ wildly between the logical types,
15791 // particularly in MSL.
15792 // To deal with this, we emit access chains and go through emit_store_statement
15793 // to deal with all the special cases we can encounter.
15794
15795 AccessChainMeta lhs_meta, rhs_meta;
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010015796 auto lhs = access_chain_internal(lhs_id, chain.data(), uint32_t(chain.size()),
15797 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &lhs_meta);
15798 auto rhs = access_chain_internal(rhs_id, chain.data(), uint32_t(chain.size()),
15799 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &rhs_meta);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015800
15801 uint32_t id = ir.increase_bound_by(2);
15802 lhs_id = id;
15803 rhs_id = id + 1;
15804
15805 {
15806 auto &lhs_expr = set<SPIRExpression>(lhs_id, move(lhs), lhs_type_id, true);
15807 lhs_expr.need_transpose = lhs_meta.need_transpose;
15808
15809 if (lhs_meta.storage_is_packed)
15810 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypePacked);
15811 if (lhs_meta.storage_physical_type != 0)
15812 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID, lhs_meta.storage_physical_type);
15813
15814 forwarded_temporaries.insert(lhs_id);
15815 suppressed_usage_tracking.insert(lhs_id);
15816 }
15817
15818 {
15819 auto &rhs_expr = set<SPIRExpression>(rhs_id, move(rhs), rhs_type_id, true);
15820 rhs_expr.need_transpose = rhs_meta.need_transpose;
15821
15822 if (rhs_meta.storage_is_packed)
15823 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypePacked);
15824 if (rhs_meta.storage_physical_type != 0)
15825 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID, rhs_meta.storage_physical_type);
15826
15827 forwarded_temporaries.insert(rhs_id);
15828 suppressed_usage_tracking.insert(rhs_id);
15829 }
15830
15831 emit_store_statement(lhs_id, rhs_id);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015832 }
15833}
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010015834
15835bool CompilerGLSL::subpass_input_is_framebuffer_fetch(uint32_t id) const
15836{
15837 if (!has_decoration(id, DecorationInputAttachmentIndex))
15838 return false;
15839
15840 uint32_t input_attachment_index = get_decoration(id, DecorationInputAttachmentIndex);
15841 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
15842 if (remap.first == input_attachment_index)
15843 return true;
15844
15845 return false;
15846}
15847
15848const SPIRVariable *CompilerGLSL::find_subpass_input_by_attachment_index(uint32_t index) const
15849{
15850 const SPIRVariable *ret = nullptr;
15851 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
15852 if (has_decoration(var.self, DecorationInputAttachmentIndex) &&
15853 get_decoration(var.self, DecorationInputAttachmentIndex) == index)
15854 {
15855 ret = &var;
15856 }
15857 });
15858 return ret;
15859}
15860
15861const SPIRVariable *CompilerGLSL::find_color_output_by_location(uint32_t location) const
15862{
15863 const SPIRVariable *ret = nullptr;
15864 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
15865 if (var.storage == StorageClassOutput && get_decoration(var.self, DecorationLocation) == location)
15866 ret = &var;
15867 });
15868 return ret;
15869}
15870
15871void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs()
15872{
15873 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
15874 {
15875 auto *subpass_var = find_subpass_input_by_attachment_index(remap.first);
15876 auto *output_var = find_color_output_by_location(remap.second);
15877 if (!subpass_var)
15878 continue;
15879 if (!output_var)
crissdb52e272020-10-08 12:14:52 +020015880 SPIRV_CROSS_THROW("Need to declare the corresponding fragment output variable to be able "
15881 "to read from it.");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010015882 if (is_array(get<SPIRType>(output_var->basetype)))
15883 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs.");
15884
15885 auto &func = get<SPIRFunction>(get_entry_point().self);
15886 func.fixup_hooks_in.push_back([=]() {
15887 if (is_legacy())
15888 {
15889 statement(to_expression(subpass_var->self), " = ", "gl_LastFragData[",
15890 get_decoration(output_var->self, DecorationLocation), "];");
15891 }
15892 else
15893 {
15894 uint32_t num_rt_components = this->get<SPIRType>(output_var->basetype).vecsize;
15895 statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ",
15896 to_expression(output_var->self), ";");
15897 }
15898 });
15899 }
15900}
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020015901
15902bool CompilerGLSL::variable_is_depth_or_compare(VariableID id) const
15903{
Bill Hollingsfd252b22021-11-08 15:59:45 -050015904 return is_depth_image(get<SPIRType>(get<SPIRVariable>(id).basetype), id);
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020015905}
crissdb52e272020-10-08 12:14:52 +020015906
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015907const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extension_name(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015908{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015909 static const char *const retval[CandidateCount] = { "GL_KHR_shader_subgroup_ballot",
15910 "GL_KHR_shader_subgroup_basic",
15911 "GL_KHR_shader_subgroup_vote",
15912 "GL_NV_gpu_shader_5",
15913 "GL_NV_shader_thread_group",
15914 "GL_NV_shader_thread_shuffle",
15915 "GL_ARB_shader_ballot",
15916 "GL_ARB_shader_group_vote",
15917 "GL_AMD_gcn_shader" };
crissdb52e272020-10-08 12:14:52 +020015918 return retval[c];
15919}
15920
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015921SmallVector<std::string> CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_names(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015922{
15923 switch (c)
15924 {
15925 case ARB_shader_ballot:
15926 return { "GL_ARB_shader_int64" };
15927 case AMD_gcn_shader:
15928 return { "GL_AMD_gpu_shader_int64", "GL_NV_gpu_shader5" };
15929 default:
15930 return {};
15931 }
15932}
15933
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015934const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_predicate(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015935{
15936 switch (c)
15937 {
15938 case ARB_shader_ballot:
15939 return "defined(GL_ARB_shader_int64)";
15940 case AMD_gcn_shader:
15941 return "(defined(GL_AMD_gpu_shader_int64) || defined(GL_NV_gpu_shader5))";
15942 default:
15943 return "";
15944 }
15945}
15946
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015947CompilerGLSL::ShaderSubgroupSupportHelper::FeatureVector CompilerGLSL::ShaderSubgroupSupportHelper::
15948 get_feature_dependencies(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015949{
15950 switch (feature)
15951 {
15952 case SubgroupAllEqualT:
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010015953 return { SubgroupBroadcast_First, SubgroupAll_Any_AllEqualBool };
crissdb52e272020-10-08 12:14:52 +020015954 case SubgroupElect:
15955 return { SubgroupBallotFindLSB_MSB, SubgroupBallot, SubgroupInvocationID };
15956 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
15957 return { SubgroupMask };
15958 case SubgroupBallotBitCount:
15959 return { SubgroupBallot };
15960 default:
15961 return {};
15962 }
15963}
15964
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015965CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::
15966 get_feature_dependency_mask(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015967{
15968 return build_mask(get_feature_dependencies(feature));
15969}
15970
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015971bool CompilerGLSL::ShaderSubgroupSupportHelper::can_feature_be_implemented_without_extensions(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015972{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015973 static const bool retval[FeatureCount] = { false, false, false, false, false, false,
15974 true, // SubgroupBalloFindLSB_MSB
15975 false, false, false, false,
15976 true, // SubgroupMemBarrier - replaced with workgroup memory barriers
15977 false, false, true, false };
crissdb52e272020-10-08 12:14:52 +020015978
15979 return retval[feature];
15980}
15981
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015982CompilerGLSL::ShaderSubgroupSupportHelper::Candidate CompilerGLSL::ShaderSubgroupSupportHelper::
15983 get_KHR_extension_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015984{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015985 static const Candidate extensions[FeatureCount] = {
crissdb52e272020-10-08 12:14:52 +020015986 KHR_shader_subgroup_ballot, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic,
15987 KHR_shader_subgroup_basic, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_vote,
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010015988 KHR_shader_subgroup_vote, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic,
15989 KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot
crissdb52e272020-10-08 12:14:52 +020015990 };
15991
15992 return extensions[feature];
15993}
15994
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015995void CompilerGLSL::ShaderSubgroupSupportHelper::request_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015996{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015997 feature_mask |= (FeatureMask(1) << feature) | get_feature_dependency_mask(feature);
crissdb52e272020-10-08 12:14:52 +020015998}
15999
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016000bool CompilerGLSL::ShaderSubgroupSupportHelper::is_feature_requested(Feature feature) const
crissdb52e272020-10-08 12:14:52 +020016001{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016002 return (feature_mask & (1u << feature)) != 0;
crissdb52e272020-10-08 12:14:52 +020016003}
16004
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016005CompilerGLSL::ShaderSubgroupSupportHelper::Result CompilerGLSL::ShaderSubgroupSupportHelper::resolve() const
crissdb52e272020-10-08 12:14:52 +020016006{
16007 Result res;
16008
16009 for (uint32_t i = 0u; i < FeatureCount; ++i)
16010 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016011 if (feature_mask & (1u << i))
crissdb52e272020-10-08 12:14:52 +020016012 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016013 auto feature = static_cast<Feature>(i);
16014 std::unordered_set<uint32_t> unique_candidates;
crissdb52e272020-10-08 12:14:52 +020016015
16016 auto candidates = get_candidates_for_feature(feature);
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016017 unique_candidates.insert(candidates.begin(), candidates.end());
crissdb52e272020-10-08 12:14:52 +020016018
16019 auto deps = get_feature_dependencies(feature);
16020 for (Feature d : deps)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016021 {
16022 candidates = get_candidates_for_feature(d);
16023 if (!candidates.empty())
16024 unique_candidates.insert(candidates.begin(), candidates.end());
16025 }
crissdb52e272020-10-08 12:14:52 +020016026
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016027 for (uint32_t c : unique_candidates)
16028 ++res.weights[static_cast<Candidate>(c)];
crissdb52e272020-10-08 12:14:52 +020016029 }
16030 }
16031
16032 return res;
16033}
16034
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016035CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
16036 get_candidates_for_feature(Feature ft, const Result &r)
crissdb52e272020-10-08 12:14:52 +020016037{
16038 auto c = get_candidates_for_feature(ft);
16039 auto cmp = [&r](Candidate a, Candidate b) {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016040 if (r.weights[a] == r.weights[b])
16041 return a < b; // Prefer candidates with lower enum value
16042 return r.weights[a] > r.weights[b];
crissdb52e272020-10-08 12:14:52 +020016043 };
16044 std::sort(c.begin(), c.end(), cmp);
crissdb52e272020-10-08 12:14:52 +020016045 return c;
16046}
16047
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016048CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
16049 get_candidates_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016050{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016051 switch (feature)
crissdb52e272020-10-08 12:14:52 +020016052 {
16053 case SubgroupMask:
16054 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
16055 case SubgroupSize:
16056 return { KHR_shader_subgroup_basic, NV_shader_thread_group, AMD_gcn_shader, ARB_shader_ballot };
16057 case SubgroupInvocationID:
16058 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot };
16059 case SubgroupID:
16060 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
16061 case NumSubgroups:
16062 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010016063 case SubgroupBroadcast_First:
crissdb52e272020-10-08 12:14:52 +020016064 return { KHR_shader_subgroup_ballot, NV_shader_thread_shuffle, ARB_shader_ballot };
16065 case SubgroupBallotFindLSB_MSB:
16066 return { KHR_shader_subgroup_ballot, NV_shader_thread_group };
16067 case SubgroupAll_Any_AllEqualBool:
16068 return { KHR_shader_subgroup_vote, NV_gpu_shader_5, ARB_shader_group_vote, AMD_gcn_shader };
16069 case SubgroupAllEqualT:
16070 return {}; // depends on other features only
16071 case SubgroupElect:
16072 return {}; // depends on other features only
16073 case SubgroupBallot:
16074 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
16075 case SubgroupBarrier:
16076 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot, AMD_gcn_shader };
16077 case SubgroupMemBarrier:
16078 return { KHR_shader_subgroup_basic };
16079 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
16080 return {};
16081 case SubgroupBallotBitExtract:
16082 return { NV_shader_thread_group };
16083 case SubgroupBallotBitCount:
16084 return {};
16085 default:
16086 return {};
16087 }
16088}
16089
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016090CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::build_mask(
16091 const SmallVector<Feature> &features)
crissdb52e272020-10-08 12:14:52 +020016092{
16093 FeatureMask mask = 0;
crissdb52e272020-10-08 12:14:52 +020016094 for (Feature f : features)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016095 mask |= FeatureMask(1) << f;
crissdb52e272020-10-08 12:14:52 +020016096 return mask;
16097}
16098
16099CompilerGLSL::ShaderSubgroupSupportHelper::Result::Result()
16100{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016101 for (auto &weight : weights)
16102 weight = 0;
crissdb52e272020-10-08 12:14:52 +020016103
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016104 // Make sure KHR_shader_subgroup extensions are always prefered.
16105 const uint32_t big_num = FeatureCount;
16106 weights[KHR_shader_subgroup_ballot] = big_num;
16107 weights[KHR_shader_subgroup_basic] = big_num;
16108 weights[KHR_shader_subgroup_vote] = big_num;
crissdb52e272020-10-08 12:14:52 +020016109}
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020016110
16111void CompilerGLSL::request_workaround_wrapper_overload(TypeID id)
16112{
16113 // Must be ordered to maintain deterministic output, so vector is appropriate.
16114 if (find(begin(workaround_ubo_load_overload_types), end(workaround_ubo_load_overload_types), id) ==
16115 end(workaround_ubo_load_overload_types))
16116 {
16117 force_recompile();
16118 workaround_ubo_load_overload_types.push_back(id);
16119 }
16120}
16121
16122void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID loaded_type, ID ptr)
16123{
16124 // Loading row-major matrices from UBOs on older AMD Windows OpenGL drivers is problematic.
16125 // To load these types correctly, we must first wrap them in a dummy function which only purpose is to
16126 // ensure row_major decoration is actually respected.
16127 auto *var = maybe_get_backing_variable(ptr);
16128 if (!var)
16129 return;
16130
16131 auto &backing_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016132 bool is_ubo = backing_type.basetype == SPIRType::Struct && backing_type.storage == StorageClassUniform &&
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020016133 has_decoration(backing_type.self, DecorationBlock);
16134 if (!is_ubo)
16135 return;
16136
16137 auto *type = &get<SPIRType>(loaded_type);
16138 bool rewrite = false;
16139
16140 if (is_matrix(*type))
16141 {
16142 // To avoid adding a lot of unnecessary meta tracking to forward the row_major state,
16143 // we will simply look at the base struct itself. It is exceptionally rare to mix and match row-major/col-major state.
16144 // If there is any row-major action going on, we apply the workaround.
16145 // It is harmless to apply the workaround to column-major matrices, so this is still a valid solution.
16146 // If an access chain occurred, the workaround is not required, so loading vectors or scalars don't need workaround.
16147 type = &backing_type;
16148 }
16149
16150 if (type->basetype == SPIRType::Struct)
16151 {
16152 // If we're loading a struct where any member is a row-major matrix, apply the workaround.
16153 for (uint32_t i = 0; i < uint32_t(type->member_types.size()); i++)
16154 {
16155 if (combined_decoration_for_member(*type, i).get(DecorationRowMajor))
16156 {
16157 rewrite = true;
16158 break;
16159 }
16160 }
16161 }
16162
16163 if (rewrite)
16164 {
16165 request_workaround_wrapper_overload(loaded_type);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010016166 expr = join("spvWorkaroundRowMajor(", expr, ")");
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020016167 }
16168}
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +010016169
16170void CompilerGLSL::mask_stage_output_by_location(uint32_t location, uint32_t component)
16171{
16172 masked_output_locations.insert({ location, component });
16173}
16174
16175void CompilerGLSL::mask_stage_output_by_builtin(BuiltIn builtin)
16176{
16177 masked_output_builtins.insert(builtin);
16178}
16179
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016180bool CompilerGLSL::is_stage_output_variable_masked(const SPIRVariable &var) const
16181{
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016182 auto &type = get<SPIRType>(var.basetype);
16183 bool is_block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016184 // Blocks by themselves are never masked. Must be masked per-member.
16185 if (is_block)
16186 return false;
16187
16188 bool is_builtin = has_decoration(var.self, DecorationBuiltIn);
16189
16190 if (is_builtin)
16191 {
16192 return is_stage_output_builtin_masked(BuiltIn(get_decoration(var.self, DecorationBuiltIn)));
16193 }
16194 else
16195 {
16196 if (!has_decoration(var.self, DecorationLocation))
16197 return false;
16198
16199 return is_stage_output_location_masked(
16200 get_decoration(var.self, DecorationLocation),
16201 get_decoration(var.self, DecorationComponent));
16202 }
16203}
16204
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016205bool CompilerGLSL::is_stage_output_block_member_masked(const SPIRVariable &var, uint32_t index, bool strip_array) const
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016206{
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016207 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016208 bool is_block = has_decoration(type.self, DecorationBlock);
16209 if (!is_block)
16210 return false;
16211
16212 BuiltIn builtin = BuiltInMax;
16213 if (is_member_builtin(type, index, &builtin))
16214 {
16215 return is_stage_output_builtin_masked(builtin);
16216 }
16217 else
16218 {
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016219 uint32_t location = get_declared_member_location(var, index, strip_array);
16220 uint32_t component = get_member_decoration(type.self, index, DecorationComponent);
16221 return is_stage_output_location_masked(location, component);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016222 }
16223}
16224
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +010016225bool CompilerGLSL::is_stage_output_location_masked(uint32_t location, uint32_t component) const
16226{
16227 return masked_output_locations.count({ location, component }) != 0;
16228}
16229
16230bool CompilerGLSL::is_stage_output_builtin_masked(spv::BuiltIn builtin) const
16231{
16232 return masked_output_builtins.count(builtin) != 0;
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016233}
16234
16235uint32_t CompilerGLSL::get_declared_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const
16236{
16237 auto &block_type = get<SPIRType>(var.basetype);
16238 if (has_member_decoration(block_type.self, mbr_idx, DecorationLocation))
16239 return get_member_decoration(block_type.self, mbr_idx, DecorationLocation);
16240 else
16241 return get_accumulated_member_location(var, mbr_idx, strip_array);
16242}
16243
16244uint32_t CompilerGLSL::get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const
16245{
16246 auto &type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
16247 uint32_t location = get_decoration(var.self, DecorationLocation);
16248
16249 for (uint32_t i = 0; i < mbr_idx; i++)
16250 {
16251 auto &mbr_type = get<SPIRType>(type.member_types[i]);
16252
16253 // Start counting from any place we have a new location decoration.
16254 if (has_member_decoration(type.self, mbr_idx, DecorationLocation))
16255 location = get_member_decoration(type.self, mbr_idx, DecorationLocation);
16256
Hans-Kristian Arntzen96ba0442021-04-20 13:03:58 +020016257 uint32_t location_count = type_to_location_count(mbr_type);
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016258 location += location_count;
16259 }
16260
16261 return location;
16262}
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020016263
16264StorageClass CompilerGLSL::get_expression_effective_storage_class(uint32_t ptr)
16265{
16266 auto *var = maybe_get_backing_variable(ptr);
16267
16268 // If the expression has been lowered to a temporary, we need to use the Generic storage class.
16269 // We're looking for the effective storage class of a given expression.
16270 // An access chain or forwarded OpLoads from such access chains
16271 // will generally have the storage class of the underlying variable, but if the load was not forwarded
16272 // we have lost any address space qualifiers.
16273 bool forced_temporary = ir.ids[ptr].get_type() == TypeExpression && !get<SPIRExpression>(ptr).access_chain &&
16274 (forced_temporaries.count(ptr) != 0 || forwarded_temporaries.count(ptr) == 0);
16275
16276 if (var && !forced_temporary)
16277 {
16278 if (variable_decl_is_remapped_storage(*var, StorageClassWorkgroup))
16279 return StorageClassWorkgroup;
16280 if (variable_decl_is_remapped_storage(*var, StorageClassStorageBuffer))
16281 return StorageClassStorageBuffer;
16282
16283 // Normalize SSBOs to StorageBuffer here.
16284 if (var->storage == StorageClassUniform &&
16285 has_decoration(get<SPIRType>(var->basetype).self, DecorationBufferBlock))
16286 return StorageClassStorageBuffer;
16287 else
16288 return var->storage;
16289 }
16290 else
16291 return expression_type(ptr).storage;
16292}
Hans-Kristian Arntzen96ba0442021-04-20 13:03:58 +020016293
16294uint32_t CompilerGLSL::type_to_location_count(const SPIRType &type) const
16295{
16296 uint32_t count;
16297 if (type.basetype == SPIRType::Struct)
16298 {
16299 uint32_t mbr_count = uint32_t(type.member_types.size());
16300 count = 0;
16301 for (uint32_t i = 0; i < mbr_count; i++)
16302 count += type_to_location_count(get<SPIRType>(type.member_types[i]));
16303 }
16304 else
16305 {
16306 count = type.columns > 1 ? type.columns : 1;
16307 }
16308
16309 uint32_t dim_count = uint32_t(type.array.size());
16310 for (uint32_t i = 0; i < dim_count; i++)
16311 count *= to_array_size_literal(type, i);
16312
16313 return count;
16314}