blob: aae238032afd02f852afa0ffc97558d3ad71e0fd [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 Arntzen1d13a3e2022-01-17 14:12:01 +0100299void CompilerGLSL::reset(uint32_t iteration_count)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100300{
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +0100301 // Sanity check the iteration count to be robust against a certain class of bugs where
302 // we keep forcing recompilations without making clear forward progress.
303 // In buggy situations we will loop forever, or loop for an unbounded number of iterations.
304 // Certain types of recompilations are considered to make forward progress,
305 // but in almost all situations, we'll never see more than 3 iterations.
306 // It is highly context-sensitive when we need to force recompilation,
307 // and it is not practical with the current architecture
308 // to resolve everything up front.
309 if (iteration_count >= 3 && !is_force_recompile_forward_progress)
310 SPIRV_CROSS_THROW("Over 3 compilation loops detected and no forward progress was made. Must be a bug!");
311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200312 // We do some speculative optimizations which should pretty much always work out,
313 // but just in case the SPIR-V is rather weird, recompile until it's happy.
314 // This typically only means one extra pass.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200315 clear_force_recompile();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100316
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200317 // Clear invalid expression tracking.
318 invalid_expressions.clear();
319 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100320
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200321 // Clear temporary usage tracking.
322 expression_usage_counts.clear();
323 forwarded_temporaries.clear();
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +0200324 suppressed_usage_tracking.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100325
Lukas Hermanns50ac6862019-09-18 14:03:54 -0400326 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -0400327 flushed_phi_variables.clear();
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400328
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +0100329 reset_name_caches();
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200330
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100331 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, SPIRFunction &func) {
332 func.active = false;
333 func.flush_undeclared = true;
334 });
335
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +0100336 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) { var.dependees.clear(); });
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100337
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400338 ir.reset_all_of_type<SPIRExpression>();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100339 ir.reset_all_of_type<SPIRAccessChain>();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 statement_count = 0;
342 indent = 0;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +0200343 current_loop_level = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100344}
345
346void CompilerGLSL::remap_pls_variables()
347{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200348 for (auto &input : pls_inputs)
349 {
350 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200352 bool input_is_target = false;
353 if (var.storage == StorageClassUniformConstant)
354 {
355 auto &type = get<SPIRType>(var.basetype);
356 input_is_target = type.image.dim == DimSubpassData;
357 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100358
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200359 if (var.storage != StorageClassInput && !input_is_target)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100360 SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200361 var.remapped_variable = true;
362 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200364 for (auto &output : pls_outputs)
365 {
366 auto &var = get<SPIRVariable>(output.id);
367 if (var.storage != StorageClassOutput)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100368 SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200369 var.remapped_variable = true;
370 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100371}
372
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200373void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100374{
375 subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200376 inout_color_attachments.push_back({ color_location, coherent });
377}
378
379bool CompilerGLSL::location_is_framebuffer_fetch(uint32_t location) const
380{
381 return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
382 [&](const std::pair<uint32_t, bool> &elem) {
383 return elem.first == location;
384 }) != end(inout_color_attachments);
385}
386
387bool CompilerGLSL::location_is_non_coherent_framebuffer_fetch(uint32_t location) const
388{
389 return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
390 [&](const std::pair<uint32_t, bool> &elem) {
391 return elem.first == location && !elem.second;
392 }) != end(inout_color_attachments);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100393}
394
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200395void CompilerGLSL::find_static_extensions()
396{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100397 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
398 if (type.basetype == SPIRType::Double)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200399 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100400 if (options.es)
401 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
402 if (!options.es && options.version < 400)
403 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200404 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100405 else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100406 {
407 if (options.es)
408 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
409 if (!options.es)
410 require_extension_internal("GL_ARB_gpu_shader_int64");
411 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100412 else if (type.basetype == SPIRType::Half)
413 {
414 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_float16");
415 if (options.vulkan_semantics)
416 require_extension_internal("GL_EXT_shader_16bit_storage");
417 }
418 else if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
419 {
420 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int8");
421 if (options.vulkan_semantics)
422 require_extension_internal("GL_EXT_shader_8bit_storage");
423 }
424 else if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
425 {
426 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int16");
427 if (options.vulkan_semantics)
428 require_extension_internal("GL_EXT_shader_16bit_storage");
429 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100430 });
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200431
432 auto &execution = get_entry_point();
433 switch (execution.model)
434 {
435 case ExecutionModelGLCompute:
436 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200437 require_extension_internal("GL_ARB_compute_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200438 if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100439 SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200440 break;
441
442 case ExecutionModelGeometry:
443 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200444 require_extension_internal("GL_EXT_geometry_shader");
robfb1820e2017-06-17 10:06:46 +0900445 if (!options.es && options.version < 150)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200446 require_extension_internal("GL_ARB_geometry_shader4");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200447
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100448 if (execution.flags.get(ExecutionModeInvocations) && execution.invocations != 1)
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200449 {
450 // Instanced GS is part of 400 core or this extension.
451 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200452 require_extension_internal("GL_ARB_gpu_shader5");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200453 }
454 break;
455
456 case ExecutionModelTessellationEvaluation:
457 case ExecutionModelTessellationControl:
458 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200459 require_extension_internal("GL_EXT_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200460 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200461 require_extension_internal("GL_ARB_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200462 break;
463
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100464 case ExecutionModelRayGenerationKHR:
465 case ExecutionModelIntersectionKHR:
466 case ExecutionModelAnyHitKHR:
467 case ExecutionModelClosestHitKHR:
468 case ExecutionModelMissKHR:
469 case ExecutionModelCallableKHR:
470 // NV enums are aliases.
Patrick Moursc74d7a42019-03-25 15:06:01 +0100471 if (options.es || options.version < 460)
472 SPIRV_CROSS_THROW("Ray tracing shaders require non-es profile with version 460 or above.");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100473 if (!options.vulkan_semantics)
474 SPIRV_CROSS_THROW("Ray tracing requires Vulkan semantics.");
475
476 // Need to figure out if we should target KHR or NV extension based on capabilities.
477 for (auto &cap : ir.declared_capabilities)
478 {
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +0200479 if (cap == CapabilityRayTracingKHR || cap == CapabilityRayQueryKHR ||
480 cap == CapabilityRayTraversalPrimitiveCullingKHR)
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100481 {
482 ray_tracing_is_khr = true;
483 break;
484 }
485 }
486
487 if (ray_tracing_is_khr)
488 {
489 // In KHR ray tracing we pass payloads by pointer instead of location,
490 // so make sure we assign locations properly.
491 ray_tracing_khr_fixup_locations();
492 require_extension_internal("GL_EXT_ray_tracing");
493 }
494 else
495 require_extension_internal("GL_NV_ray_tracing");
Patrick Moursc74d7a42019-03-25 15:06:01 +0100496 break;
497
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200498 default:
499 break;
500 }
501
502 if (!pls_inputs.empty() || !pls_outputs.empty())
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100503 {
504 if (execution.model != ExecutionModelFragment)
505 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_pixel_local_storage in fragment shaders.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200506 require_extension_internal("GL_EXT_shader_pixel_local_storage");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100507 }
508
509 if (!inout_color_attachments.empty())
510 {
511 if (execution.model != ExecutionModelFragment)
512 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
513 if (options.vulkan_semantics)
514 SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200515
516 bool has_coherent = false;
517 bool has_incoherent = false;
518
519 for (auto &att : inout_color_attachments)
520 {
521 if (att.second)
522 has_coherent = true;
523 else
524 has_incoherent = true;
525 }
526
527 if (has_coherent)
528 require_extension_internal("GL_EXT_shader_framebuffer_fetch");
529 if (has_incoherent)
530 require_extension_internal("GL_EXT_shader_framebuffer_fetch_non_coherent");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100531 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +0200532
533 if (options.separate_shader_objects && !options.es && options.version < 410)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200534 require_extension_internal("GL_ARB_separate_shader_objects");
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200535
536 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
537 {
538 if (!options.vulkan_semantics)
539 SPIRV_CROSS_THROW("GL_EXT_buffer_reference is only supported in Vulkan GLSL.");
540 if (options.es && options.version < 320)
541 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires ESSL 320.");
542 else if (!options.es && options.version < 450)
543 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires GLSL 450.");
544 require_extension_internal("GL_EXT_buffer_reference");
545 }
546 else if (ir.addressing_model != AddressingModelLogical)
547 {
548 SPIRV_CROSS_THROW("Only Logical and PhysicalStorageBuffer64EXT addressing models are supported.");
549 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200550
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100551 // Check for nonuniform qualifier and passthrough.
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200552 // Instead of looping over all decorations to find this, just look at capabilities.
553 for (auto &cap : ir.declared_capabilities)
554 {
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200555 switch (cap)
556 {
557 case CapabilityShaderNonUniformEXT:
Mateusz Kielan127224d2020-04-18 21:21:43 +0200558 if (!options.vulkan_semantics)
559 require_extension_internal("GL_NV_gpu_shader5");
560 else
561 require_extension_internal("GL_EXT_nonuniform_qualifier");
562 break;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200563 case CapabilityRuntimeDescriptorArrayEXT:
564 if (!options.vulkan_semantics)
565 SPIRV_CROSS_THROW("GL_EXT_nonuniform_qualifier is only supported in Vulkan GLSL.");
566 require_extension_internal("GL_EXT_nonuniform_qualifier");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100567 break;
568
569 case CapabilityGeometryShaderPassthroughNV:
570 if (execution.model == ExecutionModelGeometry)
571 {
572 require_extension_internal("GL_NV_geometry_shader_passthrough");
573 execution.geometry_passthrough = true;
574 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200575 break;
576
Hans-Kristian Arntzendc940842020-12-07 12:16:02 +0100577 case CapabilityVariablePointers:
578 case CapabilityVariablePointersStorageBuffer:
579 SPIRV_CROSS_THROW("VariablePointers capability is not supported in GLSL.");
580
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200581 case CapabilityMultiView:
582 if (options.vulkan_semantics)
583 require_extension_internal("GL_EXT_multiview");
584 else
585 {
586 require_extension_internal("GL_OVR_multiview2");
587 if (options.ovr_multiview_view_count == 0)
588 SPIRV_CROSS_THROW("ovr_multiview_view_count must be non-zero when using GL_OVR_multiview2.");
589 if (get_execution_model() != ExecutionModelVertex)
590 SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
591 }
592 break;
593
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +0200594 case CapabilityRayQueryKHR:
595 if (options.es || options.version < 460 || !options.vulkan_semantics)
596 SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
597 require_extension_internal("GL_EXT_ray_query");
598 ray_tracing_is_khr = true;
599 break;
600
601 case CapabilityRayTraversalPrimitiveCullingKHR:
602 if (options.es || options.version < 460 || !options.vulkan_semantics)
603 SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
604 require_extension_internal("GL_EXT_ray_flags_primitive_culling");
605 ray_tracing_is_khr = true;
606 break;
607
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200608 default:
609 break;
610 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200611 }
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200612
613 if (options.ovr_multiview_view_count)
614 {
615 if (options.vulkan_semantics)
616 SPIRV_CROSS_THROW("OVR_multiview2 cannot be used with Vulkan semantics.");
617 if (get_execution_model() != ExecutionModelVertex)
618 SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
619 require_extension_internal("GL_OVR_multiview2");
620 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200621}
622
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100623void CompilerGLSL::ray_tracing_khr_fixup_locations()
624{
625 uint32_t location = 0;
626 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen66fb0bd2021-01-22 11:22:10 +0100627 // Incoming payload storage can also be used for tracing.
628 if (var.storage != StorageClassRayPayloadKHR && var.storage != StorageClassCallableDataKHR &&
629 var.storage != StorageClassIncomingRayPayloadKHR && var.storage != StorageClassIncomingCallableDataKHR)
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100630 return;
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +0100631 if (is_hidden_variable(var))
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100632 return;
633 set_decoration(var.self, DecorationLocation, location++);
634 });
635}
636
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100637string CompilerGLSL::compile()
638{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200639 ir.fixup_reserved_names();
640
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200641 if (!options.vulkan_semantics)
Mateusz Kielan127224d2020-04-18 21:21:43 +0200642 {
643 // only NV_gpu_shader5 supports divergent indexing on OpenGL, and it does so without extra qualifiers
644 backend.nonuniform_qualifier = "";
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +0200645 backend.needs_row_major_load_workaround = true;
Mateusz Kielan127224d2020-04-18 21:21:43 +0200646 }
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200647 backend.allow_precision_qualifiers = options.vulkan_semantics || options.es;
Hans-Kristian Arntzenf708b492018-01-09 09:16:33 +0100648 backend.force_gl_in_out_block = true;
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +0100649 backend.supports_extensions = true;
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +0200650 backend.use_array_constructor = true;
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100651 backend.workgroup_size_is_hidden = true;
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100652
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200653 backend.support_precise_qualifier = (!options.es && options.version >= 400) || (options.es && options.version >= 320);
654
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +0200655 if (is_legacy_es())
656 backend.support_case_fallthrough = false;
657
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200658 // Scan the SPIR-V to find trivial uses of extensions.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200659 fixup_type_alias();
660 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200661 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200662 find_static_extensions();
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +0100663 fixup_image_load_store_access();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100664 update_active_builtins();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +0100665 analyze_image_and_sampler_usage();
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200666 analyze_interlocked_resource_usage();
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100667 if (!inout_color_attachments.empty())
668 emit_inout_fragment_outputs_copy_to_subpass_inputs();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200669
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200670 // Shaders might cast unrelated data to pointers of non-block types.
671 // Find all such instances and make sure we can cast the pointers to a synthesized block type.
672 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
673 analyze_non_block_pointer_types();
674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200675 uint32_t pass_count = 0;
676 do
677 {
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +0100678 reset(pass_count);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100679
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200680 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100681
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200682 emit_header();
683 emit_resources();
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200684 emit_extension_workarounds(get_execution_model());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100685
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200686 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100687
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200688 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200689 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100690
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200691 // Implement the interlocked wrapper function at the end.
692 // The body was implemented in lieu of main().
693 if (interlocked_is_complex)
694 {
695 statement("void main()");
696 begin_scope();
697 statement("// Interlocks were used in a way not compatible with GLSL, this is very slow.");
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330698 statement("SPIRV_Cross_beginInvocationInterlock();");
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200699 statement("spvMainInterlockedBody();");
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330700 statement("SPIRV_Cross_endInvocationInterlock();");
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200701 end_scope();
702 }
703
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100704 // Entry point in GLSL is always main().
705 get_entry_point().name = "main";
706
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200707 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100708}
709
Bill Hollingsc5c07362016-11-27 12:34:04 -0500710std::string CompilerGLSL::get_partial_source()
711{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200712 return buffer.str();
Bill Hollingsc5c07362016-11-27 12:34:04 -0500713}
714
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200715void CompilerGLSL::build_workgroup_size(SmallVector<string> &arguments, const SpecializationConstant &wg_x,
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +0100716 const SpecializationConstant &wg_y, const SpecializationConstant &wg_z)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100717{
718 auto &execution = get_entry_point();
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100719 bool builtin_workgroup = execution.workgroup_size.constant != 0;
720 bool use_local_size_id = !builtin_workgroup && execution.flags.get(ExecutionModeLocalSizeId);
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100721
722 if (wg_x.id)
723 {
724 if (options.vulkan_semantics)
725 arguments.push_back(join("local_size_x_id = ", wg_x.constant_id));
726 else
727 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(wg_x.id).specialization_constant_macro_name));
728 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100729 else if (use_local_size_id && execution.workgroup_size.id_x)
730 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(execution.workgroup_size.id_x).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100731 else
732 arguments.push_back(join("local_size_x = ", execution.workgroup_size.x));
733
734 if (wg_y.id)
735 {
736 if (options.vulkan_semantics)
737 arguments.push_back(join("local_size_y_id = ", wg_y.constant_id));
738 else
739 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(wg_y.id).specialization_constant_macro_name));
740 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100741 else if (use_local_size_id && execution.workgroup_size.id_y)
742 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(execution.workgroup_size.id_y).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100743 else
744 arguments.push_back(join("local_size_y = ", execution.workgroup_size.y));
745
746 if (wg_z.id)
747 {
748 if (options.vulkan_semantics)
749 arguments.push_back(join("local_size_z_id = ", wg_z.constant_id));
750 else
751 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(wg_z.id).specialization_constant_macro_name));
752 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100753 else if (use_local_size_id && execution.workgroup_size.id_z)
754 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(execution.workgroup_size.id_z).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100755 else
756 arguments.push_back(join("local_size_z = ", execution.workgroup_size.z));
757}
758
crissdb52e272020-10-08 12:14:52 +0200759void CompilerGLSL::request_subgroup_feature(ShaderSubgroupSupportHelper::Feature feature)
760{
761 if (options.vulkan_semantics)
762 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200763 auto khr_extension = ShaderSubgroupSupportHelper::get_KHR_extension_for_feature(feature);
764 require_extension_internal(ShaderSubgroupSupportHelper::get_extension_name(khr_extension));
crissdb52e272020-10-08 12:14:52 +0200765 }
766 else
767 {
768 if (!shader_subgroup_supporter.is_feature_requested(feature))
769 force_recompile();
770 shader_subgroup_supporter.request_feature(feature);
771 }
772}
773
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100774void CompilerGLSL::emit_header()
775{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200776 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200777 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100778
Ben Claytone9621822017-10-09 10:33:42 +0100779 if (!options.es && options.version < 420)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200780 {
Ben Claytone9621822017-10-09 10:33:42 +0100781 // Needed for binding = # on UBOs, etc.
782 if (options.enable_420pack_extension)
783 {
784 statement("#ifdef GL_ARB_shading_language_420pack");
785 statement("#extension GL_ARB_shading_language_420pack : require");
786 statement("#endif");
787 }
788 // Needed for: layout(early_fragment_tests) in;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100789 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200790 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200791 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100792
Chip Davis1df47db2019-07-10 22:42:39 -0500793 // Needed for: layout(post_depth_coverage) in;
794 if (execution.flags.get(ExecutionModePostDepthCoverage))
795 require_extension_internal("GL_ARB_post_depth_coverage");
796
Chip Davis2eff4202019-08-04 00:07:20 -0500797 // Needed for: layout({pixel,sample}_interlock_[un]ordered) in;
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330798 bool interlock_used = execution.flags.get(ExecutionModePixelInterlockOrderedEXT) ||
799 execution.flags.get(ExecutionModePixelInterlockUnorderedEXT) ||
800 execution.flags.get(ExecutionModeSampleInterlockOrderedEXT) ||
801 execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT);
802
803 if (interlock_used)
Chip Davis2eff4202019-08-04 00:07:20 -0500804 {
805 if (options.es)
806 {
807 if (options.version < 310)
808 SPIRV_CROSS_THROW("At least ESSL 3.10 required for fragment shader interlock.");
809 require_extension_internal("GL_NV_fragment_shader_interlock");
810 }
811 else
812 {
813 if (options.version < 420)
814 require_extension_internal("GL_ARB_shader_image_load_store");
815 require_extension_internal("GL_ARB_fragment_shader_interlock");
816 }
817 }
818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200819 for (auto &ext : forced_extensions)
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200820 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100821 if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16")
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200822 {
823 // Special case, this extension has a potential fallback to another vendor extension in normal GLSL.
824 // GL_AMD_gpu_shader_half_float is a superset, so try that first.
825 statement("#if defined(GL_AMD_gpu_shader_half_float)");
826 statement("#extension GL_AMD_gpu_shader_half_float : require");
Chip Davis1fb27b42018-10-31 09:43:03 -0500827 if (!options.vulkan_semantics)
828 {
829 statement("#elif defined(GL_NV_gpu_shader5)");
830 statement("#extension GL_NV_gpu_shader5 : require");
831 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100832 else
833 {
834 statement("#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)");
835 statement("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
836 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200837 statement("#else");
838 statement("#error No extension available for FP16.");
839 statement("#endif");
840 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100841 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16")
Chip Davis1fb27b42018-10-31 09:43:03 -0500842 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100843 if (options.vulkan_semantics)
844 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
845 else
846 {
847 statement("#if defined(GL_AMD_gpu_shader_int16)");
848 statement("#extension GL_AMD_gpu_shader_int16 : require");
Przemog10408c592021-05-05 21:41:53 +0200849 statement("#elif defined(GL_NV_gpu_shader5)");
850 statement("#extension GL_NV_gpu_shader5 : require");
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100851 statement("#else");
852 statement("#error No extension available for Int16.");
853 statement("#endif");
854 }
Chip Davis1fb27b42018-10-31 09:43:03 -0500855 }
Chip Davis5fe1ecc2019-08-02 21:02:05 -0500856 else if (ext == "GL_ARB_post_depth_coverage")
857 {
858 if (options.es)
859 statement("#extension GL_EXT_post_depth_coverage : require");
860 else
861 {
862 statement("#if defined(GL_ARB_post_depth_coverge)");
863 statement("#extension GL_ARB_post_depth_coverage : require");
864 statement("#else");
865 statement("#extension GL_EXT_post_depth_coverage : require");
866 statement("#endif");
867 }
868 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +0200869 else if (!options.vulkan_semantics && ext == "GL_ARB_shader_draw_parameters")
870 {
871 // Soft-enable this extension on plain GLSL.
872 statement("#ifdef ", ext);
873 statement("#extension ", ext, " : enable");
874 statement("#endif");
875 }
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +0200876 else if (ext == "GL_EXT_control_flow_attributes")
877 {
878 // These are just hints so we can conditionally enable and fallback in the shader.
879 statement("#if defined(GL_EXT_control_flow_attributes)");
880 statement("#extension GL_EXT_control_flow_attributes : require");
881 statement("#define SPIRV_CROSS_FLATTEN [[flatten]]");
882 statement("#define SPIRV_CROSS_BRANCH [[dont_flatten]]");
883 statement("#define SPIRV_CROSS_UNROLL [[unroll]]");
884 statement("#define SPIRV_CROSS_LOOP [[dont_unroll]]");
885 statement("#else");
886 statement("#define SPIRV_CROSS_FLATTEN");
887 statement("#define SPIRV_CROSS_BRANCH");
888 statement("#define SPIRV_CROSS_UNROLL");
889 statement("#define SPIRV_CROSS_LOOP");
890 statement("#endif");
891 }
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330892 else if (ext == "GL_NV_fragment_shader_interlock")
893 {
894 statement("#extension GL_NV_fragment_shader_interlock : require");
895 statement("#define SPIRV_Cross_beginInvocationInterlock() beginInvocationInterlockNV()");
896 statement("#define SPIRV_Cross_endInvocationInterlock() endInvocationInterlockNV()");
897 }
898 else if (ext == "GL_ARB_fragment_shader_interlock")
899 {
900 statement("#ifdef GL_ARB_fragment_shader_interlock");
901 statement("#extension GL_ARB_fragment_shader_interlock : enable");
902 statement("#define SPIRV_Cross_beginInvocationInterlock() beginInvocationInterlockARB()");
903 statement("#define SPIRV_Cross_endInvocationInterlock() endInvocationInterlockARB()");
904 statement("#elif defined(GL_INTEL_fragment_shader_ordering)");
905 statement("#extension GL_INTEL_fragment_shader_ordering : enable");
906 statement("#define SPIRV_Cross_beginInvocationInterlock() beginFragmentShaderOrderingINTEL()");
907 statement("#define SPIRV_Cross_endInvocationInterlock()");
908 statement("#endif");
909 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200910 else
911 statement("#extension ", ext, " : require");
912 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100913
crissdb52e272020-10-08 12:14:52 +0200914 if (!options.vulkan_semantics)
915 {
916 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200917 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +0200918
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200919 for (uint32_t feature_index = 0; feature_index < Supp::FeatureCount; feature_index++)
crissdb52e272020-10-08 12:14:52 +0200920 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200921 auto feature = static_cast<Supp::Feature>(feature_index);
crissdb52e272020-10-08 12:14:52 +0200922 if (!shader_subgroup_supporter.is_feature_requested(feature))
923 continue;
924
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200925 auto exts = Supp::get_candidates_for_feature(feature, result);
crissdb52e272020-10-08 12:14:52 +0200926 if (exts.empty())
927 continue;
928
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200929 statement("");
crissdb52e272020-10-08 12:14:52 +0200930
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200931 for (auto &ext : exts)
932 {
933 const char *name = Supp::get_extension_name(ext);
934 const char *extra_predicate = Supp::get_extra_required_extension_predicate(ext);
935 auto extra_names = Supp::get_extra_required_extension_names(ext);
936 statement(&ext != &exts.front() ? "#elif" : "#if", " defined(", name, ")",
937 (*extra_predicate != '\0' ? " && " : ""), extra_predicate);
938 for (const auto &e : extra_names)
crissdb52e272020-10-08 12:14:52 +0200939 statement("#extension ", e, " : enable");
940 statement("#extension ", name, " : require");
941 }
942
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200943 if (!Supp::can_feature_be_implemented_without_extensions(feature))
crissdb52e272020-10-08 12:14:52 +0200944 {
945 statement("#else");
946 statement("#error No extensions available to emulate requested subgroup feature.");
947 }
948
949 statement("#endif");
950 }
951 }
952
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200953 for (auto &header : header_lines)
954 statement(header);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100955
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200956 SmallVector<string> inputs;
957 SmallVector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100958
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200959 switch (execution.model)
960 {
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200961 case ExecutionModelVertex:
962 if (options.ovr_multiview_view_count)
963 inputs.push_back(join("num_views = ", options.ovr_multiview_view_count));
964 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200965 case ExecutionModelGeometry:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100966 if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200967 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100968 if (execution.flags.get(ExecutionModeInputPoints))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200969 inputs.push_back("points");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100970 if (execution.flags.get(ExecutionModeInputLines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200971 inputs.push_back("lines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100972 if (execution.flags.get(ExecutionModeInputLinesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200973 inputs.push_back("lines_adjacency");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100974 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200975 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100976 if (execution.flags.get(ExecutionModeInputTrianglesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200977 inputs.push_back("triangles_adjacency");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100978
979 if (!execution.geometry_passthrough)
980 {
981 // For passthrough, these are implies and cannot be declared in shader.
982 outputs.push_back(join("max_vertices = ", execution.output_vertices));
983 if (execution.flags.get(ExecutionModeOutputTriangleStrip))
984 outputs.push_back("triangle_strip");
985 if (execution.flags.get(ExecutionModeOutputPoints))
986 outputs.push_back("points");
987 if (execution.flags.get(ExecutionModeOutputLineStrip))
988 outputs.push_back("line_strip");
989 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200990 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100991
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200992 case ExecutionModelTessellationControl:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100993 if (execution.flags.get(ExecutionModeOutputVertices))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200994 outputs.push_back(join("vertices = ", execution.output_vertices));
995 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100996
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200997 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100998 if (execution.flags.get(ExecutionModeQuads))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200999 inputs.push_back("quads");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001000 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001001 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001002 if (execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001003 inputs.push_back("isolines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001004 if (execution.flags.get(ExecutionModePointMode))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001005 inputs.push_back("point_mode");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001006
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001007 if (!execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001008 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001009 if (execution.flags.get(ExecutionModeVertexOrderCw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001010 inputs.push_back("cw");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001011 if (execution.flags.get(ExecutionModeVertexOrderCcw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001012 inputs.push_back("ccw");
1013 }
1014
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001015 if (execution.flags.get(ExecutionModeSpacingFractionalEven))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001016 inputs.push_back("fractional_even_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001017 if (execution.flags.get(ExecutionModeSpacingFractionalOdd))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001018 inputs.push_back("fractional_odd_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001019 if (execution.flags.get(ExecutionModeSpacingEqual))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001020 inputs.push_back("equal_spacing");
1021 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001022
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001023 case ExecutionModelGLCompute:
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001024 {
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01001025 if (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId))
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001026 {
1027 SpecializationConstant wg_x, wg_y, wg_z;
1028 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
1029
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001030 // If there are any spec constants on legacy GLSL, defer declaration, we need to set up macro
1031 // declarations before we can emit the work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001032 if (options.vulkan_semantics ||
1033 ((wg_x.id == ConstantID(0)) && (wg_y.id == ConstantID(0)) && (wg_z.id == ConstantID(0))))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001034 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001035 }
1036 else
1037 {
1038 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
1039 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
1040 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
1041 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001042 break;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001043 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001044
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001045 case ExecutionModelFragment:
1046 if (options.es)
1047 {
1048 switch (options.fragment.default_float_precision)
1049 {
1050 case Options::Lowp:
1051 statement("precision lowp float;");
1052 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001053
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001054 case Options::Mediump:
1055 statement("precision mediump float;");
1056 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001057
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001058 case Options::Highp:
1059 statement("precision highp float;");
1060 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001061
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001062 default:
1063 break;
1064 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001066 switch (options.fragment.default_int_precision)
1067 {
1068 case Options::Lowp:
1069 statement("precision lowp int;");
1070 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001072 case Options::Mediump:
1073 statement("precision mediump int;");
1074 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001076 case Options::Highp:
1077 statement("precision highp int;");
1078 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001079
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001080 default:
1081 break;
1082 }
1083 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001084
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001085 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001086 inputs.push_back("early_fragment_tests");
Chip Davis1df47db2019-07-10 22:42:39 -05001087 if (execution.flags.get(ExecutionModePostDepthCoverage))
1088 inputs.push_back("post_depth_coverage");
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +01001089
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301090 if (interlock_used)
1091 statement("#if defined(GL_ARB_fragment_shader_interlock)");
1092
Chip Davis2eff4202019-08-04 00:07:20 -05001093 if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301094 statement("layout(pixel_interlock_ordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001095 else if (execution.flags.get(ExecutionModePixelInterlockUnorderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301096 statement("layout(pixel_interlock_unordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001097 else if (execution.flags.get(ExecutionModeSampleInterlockOrderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301098 statement("layout(sample_interlock_ordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001099 else if (execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301100 statement("layout(sample_interlock_unordered) in;");
1101
1102 if (interlock_used)
1103 {
1104 statement("#elif !defined(GL_INTEL_fragment_shader_ordering)");
1105 statement("#error Fragment Shader Interlock/Ordering extension missing!");
1106 statement("#endif");
1107 }
Chip Davis2eff4202019-08-04 00:07:20 -05001108
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +01001109 if (!options.es && execution.flags.get(ExecutionModeDepthGreater))
1110 statement("layout(depth_greater) out float gl_FragDepth;");
1111 else if (!options.es && execution.flags.get(ExecutionModeDepthLess))
1112 statement("layout(depth_less) out float gl_FragDepth;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001113
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001114 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001115
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001116 default:
1117 break;
1118 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001119
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +02001120 for (auto &cap : ir.declared_capabilities)
1121 if (cap == CapabilityRayTraversalPrimitiveCullingKHR)
1122 statement("layout(primitive_culling);");
1123
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001124 if (!inputs.empty())
1125 statement("layout(", merge(inputs), ") in;");
1126 if (!outputs.empty())
1127 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001128
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001129 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001130}
1131
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +01001132bool CompilerGLSL::type_is_empty(const SPIRType &type)
1133{
1134 return type.basetype == SPIRType::Struct && type.member_types.empty();
1135}
1136
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001137void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001138{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001139 // Struct types can be stamped out multiple times
1140 // with just different offsets, matrix layouts, etc ...
1141 // Type-punning with these types is legal, which complicates things
1142 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzen294259e2018-03-05 16:27:04 +01001143 // 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 +02001144 if (type.type_alias != TypeID(0) &&
1145 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001146 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001147
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001148 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001149 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001150
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001151 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001152 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001153
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001154 type.member_name_cache.clear();
1155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001156 uint32_t i = 0;
1157 bool emitted = false;
1158 for (auto &member : type.member_types)
1159 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001160 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05001161 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001162 i++;
1163 emitted = true;
1164 }
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02001165
1166 // Don't declare empty structs in GLSL, this is not allowed.
1167 if (type_is_empty(type) && !backend.supports_empty_struct)
1168 {
1169 statement("int empty_struct_member;");
1170 emitted = true;
1171 }
1172
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +02001173 if (has_extended_decoration(type.self, SPIRVCrossDecorationPaddingTarget))
1174 emit_struct_padding_target(type);
1175
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001176 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001178 if (emitted)
1179 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001180}
1181
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001182string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001183{
1184 string res;
1185 //if (flags & (1ull << DecorationSmooth))
1186 // res += "smooth ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001187 if (flags.get(DecorationFlat))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001188 res += "flat ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001189 if (flags.get(DecorationNoPerspective))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001190 res += "noperspective ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001191 if (flags.get(DecorationCentroid))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001192 res += "centroid ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001193 if (flags.get(DecorationPatch))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001194 res += "patch ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001195 if (flags.get(DecorationSample))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001196 res += "sample ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001197 if (flags.get(DecorationInvariant))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001198 res += "invariant ";
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001199
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001200 if (flags.get(DecorationExplicitInterpAMD))
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001201 {
1202 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +01001203 res += "__explicitInterpAMD ";
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001204 }
1205
1206 if (flags.get(DecorationPerVertexNV))
1207 {
1208 if (options.es && options.version < 320)
1209 SPIRV_CROSS_THROW("pervertexNV requires ESSL 320.");
1210 else if (!options.es && options.version < 450)
1211 SPIRV_CROSS_THROW("pervertexNV requires GLSL 450.");
1212 require_extension_internal("GL_NV_fragment_shader_barycentric");
1213 res += "pervertexNV ";
1214 }
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001215
1216 return res;
1217}
1218
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001219string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
1220{
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001221 if (is_legacy())
1222 return "";
1223
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001224 bool is_block = has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001225 if (!is_block)
1226 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001227
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001228 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001229 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +02001230 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001231 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001232
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001233 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001234
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001235 if (has_member_decoration(type.self, index, DecorationPassthroughNV))
1236 attr.push_back("passthrough");
1237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001238 // We can only apply layouts on members in block interfaces.
1239 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
1240 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
1241 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
1242 //
1243 // We would like to go from (SPIR-V style):
1244 //
1245 // struct Foo { layout(row_major) mat4 matrix; };
1246 // buffer UBO { Foo foo; };
1247 //
1248 // to
1249 //
1250 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
1251 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
1252 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001253
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001254 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001255 attr.push_back("row_major");
1256 // We don't emit any global layouts, so column_major is default.
1257 //if (flags & (1ull << DecorationColMajor))
1258 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001259
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001260 if (dec.decoration_flags.get(DecorationLocation) && can_use_io_location(type.storage, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001261 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001262
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001263 // Can only declare component if we can declare location.
1264 if (dec.decoration_flags.get(DecorationComponent) && can_use_io_location(type.storage, true))
1265 {
1266 if (!options.es)
1267 {
1268 if (options.version < 440 && options.version >= 140)
1269 require_extension_internal("GL_ARB_enhanced_layouts");
1270 else if (options.version < 140)
1271 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
1272 attr.push_back(join("component = ", dec.component));
1273 }
1274 else
1275 SPIRV_CROSS_THROW("Component decoration is not supported in ES targets.");
1276 }
1277
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001278 // 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 +02001279 // This is only done selectively in GLSL as needed.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02001280 if (has_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset) &&
1281 dec.decoration_flags.get(DecorationOffset))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001282 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001283 else if (type.storage == StorageClassOutput && dec.decoration_flags.get(DecorationOffset))
1284 attr.push_back(join("xfb_offset = ", dec.offset));
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001285
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001286 if (attr.empty())
1287 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001289 string res = "layout(";
1290 res += merge(attr);
1291 res += ") ";
1292 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001293}
1294
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001295const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001296{
Brad Davis76204002018-06-20 10:25:38 -07001297 if (options.es && is_desktop_only_format(format))
1298 SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001299
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001300 switch (format)
1301 {
1302 case ImageFormatRgba32f:
1303 return "rgba32f";
1304 case ImageFormatRgba16f:
1305 return "rgba16f";
1306 case ImageFormatR32f:
1307 return "r32f";
1308 case ImageFormatRgba8:
1309 return "rgba8";
1310 case ImageFormatRgba8Snorm:
1311 return "rgba8_snorm";
1312 case ImageFormatRg32f:
1313 return "rg32f";
1314 case ImageFormatRg16f:
1315 return "rg16f";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001316 case ImageFormatRgba32i:
1317 return "rgba32i";
1318 case ImageFormatRgba16i:
1319 return "rgba16i";
1320 case ImageFormatR32i:
1321 return "r32i";
1322 case ImageFormatRgba8i:
1323 return "rgba8i";
1324 case ImageFormatRg32i:
1325 return "rg32i";
1326 case ImageFormatRg16i:
1327 return "rg16i";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001328 case ImageFormatRgba32ui:
1329 return "rgba32ui";
1330 case ImageFormatRgba16ui:
1331 return "rgba16ui";
1332 case ImageFormatR32ui:
1333 return "r32ui";
1334 case ImageFormatRgba8ui:
1335 return "rgba8ui";
1336 case ImageFormatRg32ui:
1337 return "rg32ui";
1338 case ImageFormatRg16ui:
1339 return "rg16ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001340 case ImageFormatR11fG11fB10f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001341 return "r11f_g11f_b10f";
1342 case ImageFormatR16f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001343 return "r16f";
1344 case ImageFormatRgb10A2:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001345 return "rgb10_a2";
1346 case ImageFormatR8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001347 return "r8";
1348 case ImageFormatRg8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001349 return "rg8";
1350 case ImageFormatR16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001351 return "r16";
1352 case ImageFormatRg16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001353 return "rg16";
1354 case ImageFormatRgba16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001355 return "rgba16";
1356 case ImageFormatR16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001357 return "r16_snorm";
1358 case ImageFormatRg16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001359 return "rg16_snorm";
1360 case ImageFormatRgba16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001361 return "rgba16_snorm";
1362 case ImageFormatR8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001363 return "r8_snorm";
1364 case ImageFormatRg8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001365 return "rg8_snorm";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001366 case ImageFormatR8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001367 return "r8ui";
1368 case ImageFormatRg8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001369 return "rg8ui";
1370 case ImageFormatR16ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001371 return "r16ui";
1372 case ImageFormatRgb10a2ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001373 return "rgb10_a2ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001374 case ImageFormatR8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001375 return "r8i";
1376 case ImageFormatRg8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001377 return "rg8i";
1378 case ImageFormatR16i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001379 return "r16i";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001380 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001381 case ImageFormatUnknown:
1382 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001383 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001384}
1385
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001386uint32_t CompilerGLSL::type_to_packed_base_size(const SPIRType &type, BufferPackingStandard)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001387{
1388 switch (type.basetype)
1389 {
1390 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02001391 case SPIRType::Int64:
1392 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001393 return 8;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001394 case SPIRType::Float:
1395 case SPIRType::Int:
1396 case SPIRType::UInt:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001397 return 4;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001398 case SPIRType::Half:
Chip Davis117ccf42018-11-01 17:20:07 -05001399 case SPIRType::Short:
1400 case SPIRType::UShort:
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001401 return 2;
Chip Davis117ccf42018-11-01 17:20:07 -05001402 case SPIRType::SByte:
1403 case SPIRType::UByte:
1404 return 1;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001405
1406 default:
1407 SPIRV_CROSS_THROW("Unrecognized type in type_to_packed_base_size.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001408 }
1409}
1410
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001411uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bitset &flags,
1412 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001413{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001414 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1415 // and is 64-bit.
1416 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1417 {
1418 if (!type.pointer)
1419 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1420
1421 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1422 {
1423 if (packing_is_vec4_padded(packing) && type_is_array_of_pointers(type))
1424 return 16;
1425 else
1426 return 8;
1427 }
1428 else
1429 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1430 }
1431
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001432 if (!type.array.empty())
1433 {
1434 uint32_t minimum_alignment = 1;
1435 if (packing_is_vec4_padded(packing))
1436 minimum_alignment = 16;
1437
1438 auto *tmp = &get<SPIRType>(type.parent_type);
1439 while (!tmp->array.empty())
1440 tmp = &get<SPIRType>(tmp->parent_type);
1441
1442 // Get the alignment of the base type, then maybe round up.
1443 return max(minimum_alignment, type_to_packed_alignment(*tmp, flags, packing));
1444 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001445
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001446 if (type.basetype == SPIRType::Struct)
1447 {
1448 // Rule 9. Structs alignments are maximum alignment of its members.
Hans-Kristian Arntzen8c632da2019-01-28 11:02:28 +01001449 uint32_t alignment = 1;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001450 for (uint32_t i = 0; i < type.member_types.size(); i++)
1451 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001452 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +02001453 alignment =
1454 max(alignment, type_to_packed_alignment(get<SPIRType>(type.member_types[i]), member_flags, packing));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001455 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001456
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001457 // In std140, struct alignment is rounded up to 16.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001458 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001459 alignment = max(alignment, 16u);
1460
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001461 return alignment;
1462 }
1463 else
1464 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001465 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1466
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001467 // Alignment requirement for scalar block layout is always the alignment for the most basic component.
1468 if (packing_is_scalar(packing))
1469 return base_alignment;
1470
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001471 // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle
1472 // a vec4, this is handled outside since that part knows our current offset.
1473 if (type.columns == 1 && packing_is_hlsl(packing))
1474 return base_alignment;
1475
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001476 // From 7.6.2.2 in GL 4.5 core spec.
1477 // Rule 1
1478 if (type.vecsize == 1 && type.columns == 1)
1479 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001480
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001481 // Rule 2
1482 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
1483 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001484
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001485 // Rule 3
1486 if (type.vecsize == 3 && type.columns == 1)
1487 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001488
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001489 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001491 // Rule 5. Column-major matrices are stored as arrays of
1492 // vectors.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001493 if (flags.get(DecorationColMajor) && type.columns > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001494 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001495 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001496 return 4 * base_alignment;
1497 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001498 return 4 * base_alignment;
1499 else
1500 return type.vecsize * base_alignment;
1501 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001503 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001504
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001505 // Rule 7.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001506 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001507 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001508 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001509 return 4 * base_alignment;
1510 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001511 return 4 * base_alignment;
1512 else
1513 return type.columns * base_alignment;
1514 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001516 // Rule 8 implied.
1517 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001518
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001519 SPIRV_CROSS_THROW("Did not find suitable rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001520}
1521
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001522uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, const Bitset &flags,
1523 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001524{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001525 // Array stride is equal to aligned size of the underlying type.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001526 uint32_t parent = type.parent_type;
1527 assert(parent);
1528
1529 auto &tmp = get<SPIRType>(parent);
1530
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001531 uint32_t size = type_to_packed_size(tmp, flags, packing);
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001532 uint32_t alignment = type_to_packed_alignment(type, flags, packing);
1533 return (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001534}
1535
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001536uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001537{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001538 if (!type.array.empty())
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001539 {
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001540 uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing);
1541
1542 // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size,
1543 // so that it is possible to pack other vectors into the last element.
1544 if (packing_is_hlsl(packing) && type.basetype != SPIRType::Struct)
1545 packed_size -= (4 - type.vecsize) * (type.width / 8);
1546
1547 return packed_size;
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001548 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001549
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001550 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1551 // and is 64-bit.
1552 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1553 {
1554 if (!type.pointer)
1555 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1556
1557 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1558 return 8;
1559 else
1560 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1561 }
1562
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001563 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001565 if (type.basetype == SPIRType::Struct)
1566 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001567 uint32_t pad_alignment = 1;
1568
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001569 for (uint32_t i = 0; i < type.member_types.size(); i++)
1570 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001571 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001572 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001573
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001574 uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
1575 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001576
1577 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1578 // GL 4.5 spec, 7.6.2.2.
1579 if (member_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001580 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001581 else
1582 pad_alignment = 1;
1583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001584 size = (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001585 size += type_to_packed_size(member_type, member_flags, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001586 }
1587 }
1588 else
1589 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001590 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1591
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001592 if (packing_is_scalar(packing))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001593 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001594 size = type.vecsize * type.columns * base_alignment;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001595 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001596 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001597 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001598 if (type.columns == 1)
1599 size = type.vecsize * base_alignment;
1600
1601 if (flags.get(DecorationColMajor) && type.columns > 1)
1602 {
1603 if (packing_is_vec4_padded(packing))
1604 size = type.columns * 4 * base_alignment;
1605 else if (type.vecsize == 3)
1606 size = type.columns * 4 * base_alignment;
1607 else
1608 size = type.columns * type.vecsize * base_alignment;
1609 }
1610
1611 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
1612 {
1613 if (packing_is_vec4_padded(packing))
1614 size = type.vecsize * 4 * base_alignment;
1615 else if (type.columns == 3)
1616 size = type.vecsize * 4 * base_alignment;
1617 else
1618 size = type.vecsize * type.columns * base_alignment;
1619 }
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001620
1621 // For matrices in HLSL, the last element has a size which depends on its vector size,
1622 // so that it is possible to pack other vectors into the last element.
1623 if (packing_is_hlsl(packing) && type.columns > 1)
1624 size -= (4 - type.vecsize) * (type.width / 8);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001625 }
1626 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001628 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001629}
1630
msiglreithd096f5c2017-11-27 16:00:56 +01001631bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001632 uint32_t *failed_validation_index, uint32_t start_offset,
1633 uint32_t end_offset)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001634{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001635 // This is very tricky and error prone, but try to be exhaustive and correct here.
1636 // SPIR-V doesn't directly say if we're using std430 or std140.
1637 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
1638 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
1639 // 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).
1640 //
1641 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
1642 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
1643 //
1644 // The only two differences between std140 and std430 are related to padding alignment/array stride
1645 // in arrays and structs. In std140 they take minimum vec4 alignment.
1646 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001647
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001648 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001649 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001650
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001651 bool is_top_level_block =
1652 has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
1653
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001654 for (uint32_t i = 0; i < type.member_types.size(); i++)
1655 {
1656 auto &memb_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001657 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001658
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001659 // Verify alignment rules.
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001660 uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001661
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001662 // This is a rather dirty workaround to deal with some cases of OpSpecConstantOp used as array size, e.g:
1663 // layout(constant_id = 0) const int s = 10;
1664 // const int S = s + 5; // SpecConstantOp
1665 // buffer Foo { int data[S]; }; // <-- Very hard for us to deduce a fixed value here,
1666 // we would need full implementation of compile-time constant folding. :(
1667 // If we are the last member of a struct, there might be cases where the actual size of that member is irrelevant
1668 // for our analysis (e.g. unsized arrays).
1669 // This lets us simply ignore that there are spec constant op sized arrays in our buffers.
1670 // Querying size of this member will fail, so just don't call it unless we have to.
1671 //
1672 // This is likely "best effort" we can support without going into unacceptably complicated workarounds.
1673 bool member_can_be_unsized =
1674 is_top_level_block && size_t(i + 1) == type.member_types.size() && !memb_type.array.empty();
1675
1676 uint32_t packed_size = 0;
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001677 if (!member_can_be_unsized || packing_is_hlsl(packing))
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001678 packed_size = type_to_packed_size(memb_type, member_flags, packing);
1679
1680 // 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 +02001681 if (packing_is_hlsl(packing))
1682 {
1683 // If a member straddles across a vec4 boundary, alignment is actually vec4.
1684 uint32_t begin_word = offset / 16;
1685 uint32_t end_word = (offset + packed_size - 1) / 16;
1686 if (begin_word != end_word)
1687 packed_alignment = max(packed_alignment, 16u);
1688 }
1689
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001690 uint32_t actual_offset = type_struct_member_offset(type, i);
1691 // Field is not in the specified range anymore and we can ignore any further fields.
1692 if (actual_offset >= end_offset)
1693 break;
1694
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001695 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001696 offset = (offset + alignment - 1) & ~(alignment - 1);
1697
1698 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1699 // GL 4.5 spec, 7.6.2.2.
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001700 if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001701 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001702 else
1703 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001704
msiglreithd096f5c2017-11-27 16:00:56 +01001705 // Only care about packing if we are in the given range
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001706 if (actual_offset >= start_offset)
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001707 {
msiglreithd096f5c2017-11-27 16:00:56 +01001708 // We only care about offsets in std140, std430, etc ...
1709 // For EnhancedLayout variants, we have the flexibility to choose our own offsets.
1710 if (!packing_has_flexible_offset(packing))
1711 {
msiglreithd096f5c2017-11-27 16:00:56 +01001712 if (actual_offset != offset) // This cannot be the packing we're looking for.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001713 {
1714 if (failed_validation_index)
1715 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001716 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001717 }
msiglreithd096f5c2017-11-27 16:00:56 +01001718 }
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001719 else if ((actual_offset & (alignment - 1)) != 0)
1720 {
1721 // We still need to verify that alignment rules are observed, even if we have explicit offset.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001722 if (failed_validation_index)
1723 *failed_validation_index = i;
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001724 return false;
1725 }
msiglreithd096f5c2017-11-27 16:00:56 +01001726
1727 // Verify array stride rules.
1728 if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
1729 type_struct_member_array_stride(type, i))
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001730 {
1731 if (failed_validation_index)
1732 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001733 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001734 }
msiglreithd096f5c2017-11-27 16:00:56 +01001735
1736 // Verify that sub-structs also follow packing rules.
1737 // We cannot use enhanced layouts on substructs, so they better be up to spec.
1738 auto substruct_packing = packing_to_substruct_packing(packing);
1739
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001740 if (!memb_type.pointer && !memb_type.member_types.empty() &&
1741 !buffer_is_packing_standard(memb_type, substruct_packing))
1742 {
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001743 if (failed_validation_index)
1744 *failed_validation_index = i;
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001745 return false;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001746 }
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001747 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001748
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001749 // Bump size.
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001750 offset = actual_offset + packed_size;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001751 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001752
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001753 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001754}
1755
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001756bool CompilerGLSL::can_use_io_location(StorageClass storage, bool block)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001757{
1758 // Location specifiers are must have in SPIR-V, but they aren't really supported in earlier versions of GLSL.
1759 // Be very explicit here about how to solve the issue.
1760 if ((get_execution_model() != ExecutionModelVertex && storage == StorageClassInput) ||
1761 (get_execution_model() != ExecutionModelFragment && storage == StorageClassOutput))
1762 {
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001763 uint32_t minimum_desktop_version = block ? 440 : 410;
1764 // ARB_enhanced_layouts vs ARB_separate_shader_objects ...
1765
1766 if (!options.es && options.version < minimum_desktop_version && !options.separate_shader_objects)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001767 return false;
1768 else if (options.es && options.version < 310)
1769 return false;
1770 }
1771
1772 if ((get_execution_model() == ExecutionModelVertex && storage == StorageClassInput) ||
1773 (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput))
1774 {
1775 if (options.es && options.version < 300)
1776 return false;
1777 else if (!options.es && options.version < 330)
1778 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001779 }
1780
Hans-Kristian Arntzen1389aa32019-03-19 11:20:25 +01001781 if (storage == StorageClassUniform || storage == StorageClassUniformConstant || storage == StorageClassPushConstant)
Andrei Alexeyev4a430242018-04-07 22:14:35 +03001782 {
1783 if (options.es && options.version < 310)
1784 return false;
1785 else if (!options.es && options.version < 430)
1786 return false;
1787 }
1788
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001789 return true;
1790}
1791
1792string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
1793{
Hans-Kristian Arntzen62d223a2016-09-21 08:20:04 +02001794 // FIXME: Come up with a better solution for when to disable layouts.
1795 // Having layouts depend on extensions as well as which types
1796 // of layouts are used. For now, the simple solution is to just disable
1797 // layouts for legacy versions.
1798 if (is_legacy())
rob42fe8c32016-09-18 13:18:33 +09001799 return "";
1800
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01001801 if (subpass_input_is_framebuffer_fetch(var.self))
1802 return "";
1803
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001804 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001806 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001807 auto &flags = get_decoration_bitset(var.self);
1808 auto &typeflags = get_decoration_bitset(type.self);
1809
1810 if (flags.get(DecorationPassthroughNV))
1811 attr.push_back("passthrough");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001812
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001813 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
1814 attr.push_back("push_constant");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001815 else if (var.storage == StorageClassShaderRecordBufferKHR)
1816 attr.push_back(ray_tracing_is_khr ? "shaderRecordEXT" : "shaderRecordNV");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001817
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001818 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001819 attr.push_back("row_major");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001820 if (flags.get(DecorationColMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001821 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001822
1823 if (options.vulkan_semantics)
1824 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001825 if (flags.get(DecorationInputAttachmentIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001826 attr.push_back(join("input_attachment_index = ", get_decoration(var.self, DecorationInputAttachmentIndex)));
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001827 }
1828
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001829 bool is_block = has_decoration(type.self, DecorationBlock);
1830 if (flags.get(DecorationLocation) && can_use_io_location(var.storage, is_block))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001831 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001832 Bitset combined_decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001833 for (uint32_t i = 0; i < ir.meta[type.self].members.size(); i++)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001834 combined_decoration.merge_or(combined_decoration_for_member(type, i));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001835
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001836 // If our members have location decorations, we don't need to
1837 // emit location decorations at the top as well (looks weird).
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001838 if (!combined_decoration.get(DecorationLocation))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001839 attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation)));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001840 }
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001841
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02001842 if (get_execution_model() == ExecutionModelFragment && var.storage == StorageClassOutput &&
1843 location_is_non_coherent_framebuffer_fetch(get_decoration(var.self, DecorationLocation)))
1844 {
1845 attr.push_back("noncoherent");
1846 }
1847
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001848 // Transform feedback
1849 bool uses_enhanced_layouts = false;
1850 if (is_block && var.storage == StorageClassOutput)
1851 {
1852 // For blocks, there is a restriction where xfb_stride/xfb_buffer must only be declared on the block itself,
1853 // since all members must match the same xfb_buffer. The only thing we will declare for members of the block
1854 // is the xfb_offset.
1855 uint32_t member_count = uint32_t(type.member_types.size());
1856 bool have_xfb_buffer_stride = false;
1857 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001858 bool have_geom_stream = false;
1859 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001860
1861 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride))
1862 {
1863 have_xfb_buffer_stride = true;
1864 xfb_buffer = get_decoration(var.self, DecorationXfbBuffer);
1865 xfb_stride = get_decoration(var.self, DecorationXfbStride);
1866 }
1867
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001868 if (flags.get(DecorationStream))
1869 {
1870 have_geom_stream = true;
1871 geom_stream = get_decoration(var.self, DecorationStream);
1872 }
1873
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001874 // Verify that none of the members violate our assumption.
1875 for (uint32_t i = 0; i < member_count; i++)
1876 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001877 if (has_member_decoration(type.self, i, DecorationStream))
1878 {
1879 uint32_t member_geom_stream = get_member_decoration(type.self, i, DecorationStream);
1880 if (have_geom_stream && member_geom_stream != geom_stream)
1881 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
1882 have_geom_stream = true;
1883 geom_stream = member_geom_stream;
1884 }
1885
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001886 // Only members with an Offset decoration participate in XFB.
1887 if (!has_member_decoration(type.self, i, DecorationOffset))
1888 continue;
1889 have_any_xfb_offset = true;
1890
1891 if (has_member_decoration(type.self, i, DecorationXfbBuffer))
1892 {
1893 uint32_t buffer_index = get_member_decoration(type.self, i, DecorationXfbBuffer);
1894 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
1895 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
1896 have_xfb_buffer_stride = true;
1897 xfb_buffer = buffer_index;
1898 }
1899
1900 if (has_member_decoration(type.self, i, DecorationXfbStride))
1901 {
1902 uint32_t stride = get_member_decoration(type.self, i, DecorationXfbStride);
1903 if (have_xfb_buffer_stride && stride != xfb_stride)
1904 SPIRV_CROSS_THROW("IO block member XfbStride mismatch.");
1905 have_xfb_buffer_stride = true;
1906 xfb_stride = stride;
1907 }
1908 }
1909
1910 if (have_xfb_buffer_stride && have_any_xfb_offset)
1911 {
1912 attr.push_back(join("xfb_buffer = ", xfb_buffer));
1913 attr.push_back(join("xfb_stride = ", xfb_stride));
1914 uses_enhanced_layouts = true;
1915 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001916
1917 if (have_geom_stream)
1918 {
1919 if (get_execution_model() != ExecutionModelGeometry)
1920 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
1921 if (options.es)
1922 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
1923 if (options.version < 400)
1924 require_extension_internal("GL_ARB_transform_feedback3");
1925 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
1926 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001927 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001928 else if (var.storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001929 {
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01001930 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) && flags.get(DecorationOffset))
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001931 {
1932 // XFB for standalone variables, we can emit all decorations.
1933 attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer)));
1934 attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride)));
1935 attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset)));
1936 uses_enhanced_layouts = true;
1937 }
1938
1939 if (flags.get(DecorationStream))
1940 {
1941 if (get_execution_model() != ExecutionModelGeometry)
1942 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
1943 if (options.es)
1944 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
1945 if (options.version < 400)
1946 require_extension_internal("GL_ARB_transform_feedback3");
1947 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
1948 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001949 }
1950
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001951 // Can only declare Component if we can declare location.
1952 if (flags.get(DecorationComponent) && can_use_io_location(var.storage, is_block))
1953 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001954 uses_enhanced_layouts = true;
1955 attr.push_back(join("component = ", get_decoration(var.self, DecorationComponent)));
1956 }
1957
1958 if (uses_enhanced_layouts)
1959 {
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001960 if (!options.es)
1961 {
1962 if (options.version < 440 && options.version >= 140)
1963 require_extension_internal("GL_ARB_enhanced_layouts");
1964 else if (options.version < 140)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001965 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in targets below GLSL 1.40.");
1966 if (!options.es && options.version < 440)
1967 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001968 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001969 else if (options.es)
1970 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in ESSL.");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001971 }
1972
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001973 if (flags.get(DecorationIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001974 attr.push_back(join("index = ", get_decoration(var.self, DecorationIndex)));
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001975
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001976 // Do not emit set = decoration in regular GLSL output, but
1977 // we need to preserve it in Vulkan GLSL mode.
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001978 if (var.storage != StorageClassPushConstant && var.storage != StorageClassShaderRecordBufferKHR)
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001979 {
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001980 if (flags.get(DecorationDescriptorSet) && options.vulkan_semantics)
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001981 attr.push_back(join("set = ", get_decoration(var.self, DecorationDescriptorSet)));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001982 }
1983
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001984 bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001985 bool ssbo_block = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferKHR ||
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001986 (var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
1987 bool emulated_ubo = var.storage == StorageClassPushConstant && options.emit_push_constant_as_uniform_buffer;
1988 bool ubo_block = var.storage == StorageClassUniform && typeflags.get(DecorationBlock);
1989
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001990 // GL 3.0/GLSL 1.30 is not considered legacy, but it doesn't have UBOs ...
1991 bool can_use_buffer_blocks = (options.es && options.version >= 300) || (!options.es && options.version >= 140);
1992
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001993 // pretend no UBOs when options say so
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001994 if (ubo_block && options.emit_uniform_buffer_as_plain_uniforms)
1995 can_use_buffer_blocks = false;
1996
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001997 bool can_use_binding;
1998 if (options.es)
1999 can_use_binding = options.version >= 310;
2000 else
2001 can_use_binding = options.enable_420pack_extension || (options.version >= 420);
2002
Hans-Kristian Arntzen938040b2018-04-03 16:58:05 +02002003 // Make sure we don't emit binding layout for a classic uniform on GLSL 1.30.
2004 if (!can_use_buffer_blocks && var.storage == StorageClassUniform)
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02002005 can_use_binding = false;
2006
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002007 if (var.storage == StorageClassShaderRecordBufferKHR)
Patrick Mours8d64d5e2019-06-05 13:29:01 +02002008 can_use_binding = false;
2009
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002010 if (can_use_binding && flags.get(DecorationBinding))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002011 attr.push_back(join("binding = ", get_decoration(var.self, DecorationBinding)));
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02002012
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002013 if (var.storage != StorageClassOutput && flags.get(DecorationOffset))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002014 attr.push_back(join("offset = ", get_decoration(var.self, DecorationOffset)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002016 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
2017 // If SPIR-V does not comply with either layout, we cannot really work around it.
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01002018 if (can_use_buffer_blocks && (ubo_block || emulated_ubo))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002019 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002020 attr.push_back(buffer_to_packing_standard(type, false));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002021 }
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02002022 else if (can_use_buffer_blocks && (push_constant_block || ssbo_block))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002023 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002024 attr.push_back(buffer_to_packing_standard(type, true));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002025 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002026
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002027 // For images, the type itself adds a layout qualifer.
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02002028 // Only emit the format for storage images.
2029 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002030 {
2031 const char *fmt = format_to_glsl(type.image.format);
2032 if (fmt)
2033 attr.push_back(fmt);
2034 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002036 if (attr.empty())
2037 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002038
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002039 string res = "layout(";
2040 res += merge(attr);
2041 res += ") ";
2042 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002043}
2044
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002045string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type, bool support_std430_without_scalar_layout)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002046{
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002047 if (support_std430_without_scalar_layout && buffer_is_packing_standard(type, BufferPackingStd430))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002048 return "std430";
2049 else if (buffer_is_packing_standard(type, BufferPackingStd140))
2050 return "std140";
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002051 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalar))
2052 {
2053 require_extension_internal("GL_EXT_scalar_block_layout");
2054 return "scalar";
2055 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002056 else if (support_std430_without_scalar_layout &&
2057 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002058 {
2059 if (options.es && !options.vulkan_semantics)
2060 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
2061 "not support GL_ARB_enhanced_layouts.");
2062 if (!options.es && !options.vulkan_semantics && options.version < 440)
2063 require_extension_internal("GL_ARB_enhanced_layouts");
2064
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002065 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002066 return "std430";
2067 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002068 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
2069 {
2070 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
2071 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
2072 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
2073 if (options.es && !options.vulkan_semantics)
2074 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
2075 "not support GL_ARB_enhanced_layouts.");
2076 if (!options.es && !options.vulkan_semantics && options.version < 440)
2077 require_extension_internal("GL_ARB_enhanced_layouts");
2078
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002079 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002080 return "std140";
2081 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002082 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalarEnhancedLayout))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002083 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002084 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002085 require_extension_internal("GL_EXT_scalar_block_layout");
2086 return "scalar";
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002087 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002088 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
2089 buffer_is_packing_standard(type, BufferPackingStd430))
2090 {
2091 // UBOs can support std430 with GL_EXT_scalar_block_layout.
2092 require_extension_internal("GL_EXT_scalar_block_layout");
2093 return "std430";
2094 }
2095 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
2096 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
2097 {
2098 // UBOs can support std430 with GL_EXT_scalar_block_layout.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002099 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002100 require_extension_internal("GL_EXT_scalar_block_layout");
2101 return "std430";
2102 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002103 else
2104 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002105 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 +02002106 "layouts. You can try flattening this block to support a more flexible layout.");
2107 }
2108}
2109
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002110void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
2111{
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01002112 if (flattened_buffer_blocks.count(var.self))
2113 emit_buffer_block_flattened(var);
2114 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002115 emit_push_constant_block_vulkan(var);
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01002116 else if (options.emit_push_constant_as_uniform_buffer)
2117 emit_buffer_block_native(var);
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002118 else
2119 emit_push_constant_block_glsl(var);
2120}
2121
2122void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
2123{
2124 emit_buffer_block(var);
2125}
2126
2127void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
2128{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002129 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
2130 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002131
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002132 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002133 flags.clear(DecorationBinding);
2134 flags.clear(DecorationDescriptorSet);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002135
2136#if 0
2137 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002138 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002139 "Remap to location with reflection API first or disable these decorations.");
2140#endif
2141
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002142 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
2143 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002144 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002145 bool block_flag = block_flags.get(DecorationBlock);
2146 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002147
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002148 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002149
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002150 if (block_flag)
2151 block_flags.set(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002152
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002153 emit_uniform(var);
2154 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002155}
2156
2157void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
2158{
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002159 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02002160 bool ubo_block = var.storage == StorageClassUniform && has_decoration(type.self, DecorationBlock);
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002161
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002162 if (flattened_buffer_blocks.count(var.self))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002163 emit_buffer_block_flattened(var);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02002164 else if (is_legacy() || (!options.es && options.version == 130) ||
2165 (ubo_block && options.emit_uniform_buffer_as_plain_uniforms))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002166 emit_buffer_block_legacy(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002167 else
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002168 emit_buffer_block_native(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002169}
2170
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002171void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
2172{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002173 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02002174 bool ssbo = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002175 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002176 if (ssbo)
2177 SPIRV_CROSS_THROW("SSBOs not supported in legacy targets.");
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002178
2179 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
2180 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002181 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002182 bool block_flag = block_flags.get(DecorationBlock);
2183 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002184 emit_struct(type);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002185 if (block_flag)
2186 block_flags.set(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002187 emit_uniform(var);
2188 statement("");
2189}
2190
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002191void CompilerGLSL::emit_buffer_reference_block(uint32_t type_id, bool forward_declaration)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002192{
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002193 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002194 string buffer_name;
2195
2196 if (forward_declaration)
2197 {
2198 // Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
2199 // Allow aliased name since we might be declaring the block twice. Once with buffer reference (forward declared) and one proper declaration.
2200 // The names must match up.
2201 buffer_name = to_name(type.self, false);
2202
2203 // Shaders never use the block by interface name, so we don't
2204 // have to track this other than updating name caches.
2205 // If we have a collision for any reason, just fallback immediately.
2206 if (ir.meta[type.self].decoration.alias.empty() ||
2207 block_ssbo_names.find(buffer_name) != end(block_ssbo_names) ||
2208 resource_names.find(buffer_name) != end(resource_names))
2209 {
2210 buffer_name = join("_", type.self);
2211 }
2212
2213 // Make sure we get something unique for both global name scope and block name scope.
2214 // See GLSL 4.5 spec: section 4.3.9 for details.
2215 add_variable(block_ssbo_names, resource_names, buffer_name);
2216
2217 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2218 // This cannot conflict with anything else, so we're safe now.
2219 // We cannot reuse this fallback name in neither global scope (blocked by block_names) nor block name scope.
2220 if (buffer_name.empty())
2221 buffer_name = join("_", type.self);
2222
2223 block_names.insert(buffer_name);
2224 block_ssbo_names.insert(buffer_name);
Hans-Kristian Arntzene07f0a92020-11-23 16:36:49 +01002225
2226 // Ensure we emit the correct name when emitting non-forward pointer type.
2227 ir.meta[type.self].decoration.alias = buffer_name;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002228 }
2229 else if (type.basetype != SPIRType::Struct)
2230 buffer_name = type_to_glsl(type);
2231 else
2232 buffer_name = to_name(type.self, false);
2233
2234 if (!forward_declaration)
2235 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002236 auto itr = physical_storage_type_to_alignment.find(type_id);
2237 uint32_t alignment = 0;
2238 if (itr != physical_storage_type_to_alignment.end())
2239 alignment = itr->second.alignment;
2240
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002241 if (type.basetype == SPIRType::Struct)
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002242 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002243 SmallVector<std::string> attributes;
2244 attributes.push_back("buffer_reference");
2245 if (alignment)
2246 attributes.push_back(join("buffer_reference_align = ", alignment));
2247 attributes.push_back(buffer_to_packing_standard(type, true));
2248
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002249 auto flags = ir.get_buffer_block_type_flags(type);
2250 string decorations;
2251 if (flags.get(DecorationRestrict))
2252 decorations += " restrict";
2253 if (flags.get(DecorationCoherent))
2254 decorations += " coherent";
2255 if (flags.get(DecorationNonReadable))
2256 decorations += " writeonly";
2257 if (flags.get(DecorationNonWritable))
2258 decorations += " readonly";
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002259
2260 statement("layout(", merge(attributes), ")", decorations, " buffer ", buffer_name);
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002261 }
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002262 else if (alignment)
2263 statement("layout(buffer_reference, buffer_reference_align = ", alignment, ") buffer ", buffer_name);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002264 else
2265 statement("layout(buffer_reference) buffer ", buffer_name);
2266
2267 begin_scope();
2268
2269 if (type.basetype == SPIRType::Struct)
2270 {
2271 type.member_name_cache.clear();
2272
2273 uint32_t i = 0;
2274 for (auto &member : type.member_types)
2275 {
2276 add_member_name(type, i);
2277 emit_struct_member(type, member, i);
2278 i++;
2279 }
2280 }
2281 else
2282 {
2283 auto &pointee_type = get_pointee_type(type);
2284 statement(type_to_glsl(pointee_type), " value", type_to_array_glsl(pointee_type), ";");
2285 }
2286
2287 end_scope_decl();
2288 statement("");
2289 }
2290 else
2291 {
2292 statement("layout(buffer_reference) buffer ", buffer_name, ";");
2293 }
2294}
2295
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002296void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002297{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002298 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002299
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002300 Bitset flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002301 bool ssbo = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferKHR ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002302 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002303 bool is_restrict = ssbo && flags.get(DecorationRestrict);
2304 bool is_writeonly = ssbo && flags.get(DecorationNonReadable);
2305 bool is_readonly = ssbo && flags.get(DecorationNonWritable);
2306 bool is_coherent = ssbo && flags.get(DecorationCoherent);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02002307
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002308 // 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 +02002309 auto buffer_name = to_name(type.self, false);
2310
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002311 auto &block_namespace = ssbo ? block_ssbo_names : block_ubo_names;
2312
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002313 // Shaders never use the block by interface name, so we don't
2314 // have to track this other than updating name caches.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002315 // If we have a collision for any reason, just fallback immediately.
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01002316 if (ir.meta[type.self].decoration.alias.empty() || block_namespace.find(buffer_name) != end(block_namespace) ||
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002317 resource_names.find(buffer_name) != end(resource_names))
2318 {
Hans-Kristian Arntzenaab31072017-09-29 12:16:53 +02002319 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002320 }
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002321
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002322 // Make sure we get something unique for both global name scope and block name scope.
2323 // See GLSL 4.5 spec: section 4.3.9 for details.
2324 add_variable(block_namespace, resource_names, buffer_name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002325
2326 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2327 // This cannot conflict with anything else, so we're safe now.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002328 // 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 +01002329 if (buffer_name.empty())
2330 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2331
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002332 block_names.insert(buffer_name);
2333 block_namespace.insert(buffer_name);
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002334
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002335 // Save for post-reflection later.
2336 declared_block_names[var.self] = buffer_name;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002337
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02002338 statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
2339 is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
2340 buffer_name);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002341
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002342 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002343
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002344 type.member_name_cache.clear();
2345
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002346 uint32_t i = 0;
2347 for (auto &member : type.member_types)
2348 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002349 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002350 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002351 i++;
2352 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002353
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +01002354 // var.self can be used as a backup name for the block name,
2355 // so we need to make sure we don't disturb the name here on a recompile.
2356 // It will need to be reset if we have to recompile.
2357 preserve_alias_on_reset(var.self);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002358 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002359 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
2360 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002361}
2362
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002363void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002364{
2365 auto &type = get<SPIRType>(var.basetype);
2366
2367 // Block names should never alias.
2368 auto buffer_name = to_name(type.self, false);
2369 size_t buffer_size = (get_declared_struct_size(type) + 15) / 16;
2370
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002371 SPIRType::BaseType basic_type;
2372 if (get_common_basic_type(type, basic_type))
2373 {
2374 SPIRType tmp;
2375 tmp.basetype = basic_type;
Hans-Kristian Arntzenefba6102017-01-22 08:53:52 +01002376 tmp.vecsize = 4;
2377 if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt)
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002378 SPIRV_CROSS_THROW("Basic types in a flattened UBO must be float, int or uint.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002379
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002380 auto flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002381 statement("uniform ", flags_to_qualifiers_glsl(tmp, flags), type_to_glsl(tmp), " ", buffer_name, "[",
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01002382 buffer_size, "];");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002383 }
2384 else
2385 SPIRV_CROSS_THROW("All basic types in a flattened block must be the same.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002386}
2387
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002388const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002389{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002390 auto &execution = get_entry_point();
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002391
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002392 if (subpass_input_is_framebuffer_fetch(var.self))
2393 return "";
2394
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002395 if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
2396 {
2397 if (is_legacy() && execution.model == ExecutionModelVertex)
2398 return var.storage == StorageClassInput ? "attribute " : "varying ";
2399 else if (is_legacy() && execution.model == ExecutionModelFragment)
2400 return "varying "; // Fragment outputs are renamed so they never hit this case.
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002401 else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
2402 {
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02002403 uint32_t loc = get_decoration(var.self, DecorationLocation);
2404 bool is_inout = location_is_framebuffer_fetch(loc);
2405 if (is_inout)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002406 return "inout ";
2407 else
2408 return "out ";
2409 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002410 else
2411 return var.storage == StorageClassInput ? "in " : "out ";
2412 }
2413 else if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
2414 var.storage == StorageClassPushConstant)
2415 {
2416 return "uniform ";
2417 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002418 else if (var.storage == StorageClassRayPayloadKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002419 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002420 return ray_tracing_is_khr ? "rayPayloadEXT " : "rayPayloadNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002421 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002422 else if (var.storage == StorageClassIncomingRayPayloadKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002423 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002424 return ray_tracing_is_khr ? "rayPayloadInEXT " : "rayPayloadInNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002425 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002426 else if (var.storage == StorageClassHitAttributeKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002427 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002428 return ray_tracing_is_khr ? "hitAttributeEXT " : "hitAttributeNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002429 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002430 else if (var.storage == StorageClassCallableDataKHR)
Patrick Mours78917862019-06-03 15:25:21 +02002431 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002432 return ray_tracing_is_khr ? "callableDataEXT " : "callableDataNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002433 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002434 else if (var.storage == StorageClassIncomingCallableDataKHR)
Patrick Mours78917862019-06-03 15:25:21 +02002435 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002436 return ray_tracing_is_khr ? "callableDataInEXT " : "callableDataInNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002437 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002438
2439 return "";
2440}
2441
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002442void CompilerGLSL::emit_flattened_io_block_member(const std::string &basename, const SPIRType &type, const char *qual,
2443 const SmallVector<uint32_t> &indices)
2444{
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002445 uint32_t member_type_id = type.self;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002446 const SPIRType *member_type = &type;
2447 const SPIRType *parent_type = nullptr;
2448 auto flattened_name = basename;
2449 for (auto &index : indices)
2450 {
2451 flattened_name += "_";
2452 flattened_name += to_member_name(*member_type, index);
2453 parent_type = member_type;
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002454 member_type_id = member_type->member_types[index];
2455 member_type = &get<SPIRType>(member_type_id);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002456 }
2457
2458 assert(member_type->basetype != SPIRType::Struct);
2459
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002460 // We're overriding struct member names, so ensure we do so on the primary type.
2461 if (parent_type->type_alias)
2462 parent_type = &get<SPIRType>(parent_type->type_alias);
2463
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002464 // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row,
2465 // which is not allowed.
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02002466 ParsedIR::sanitize_underscores(flattened_name);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002467
2468 uint32_t last_index = indices.back();
2469
2470 // Pass in the varying qualifier here so it will appear in the correct declaration order.
2471 // Replace member name while emitting it so it encodes both struct name and member name.
2472 auto backup_name = get_member_name(parent_type->self, last_index);
2473 auto member_name = to_member_name(*parent_type, last_index);
2474 set_member_name(parent_type->self, last_index, flattened_name);
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002475 emit_struct_member(*parent_type, member_type_id, last_index, qual);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002476 // Restore member name.
2477 set_member_name(parent_type->self, last_index, member_name);
2478}
2479
2480void CompilerGLSL::emit_flattened_io_block_struct(const std::string &basename, const SPIRType &type, const char *qual,
2481 const SmallVector<uint32_t> &indices)
2482{
2483 auto sub_indices = indices;
2484 sub_indices.push_back(0);
2485
2486 const SPIRType *member_type = &type;
2487 for (auto &index : indices)
2488 member_type = &get<SPIRType>(member_type->member_types[index]);
2489
2490 assert(member_type->basetype == SPIRType::Struct);
2491
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002492 if (!member_type->array.empty())
2493 SPIRV_CROSS_THROW("Cannot flatten array of structs in I/O blocks.");
2494
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002495 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
2496 {
2497 sub_indices.back() = i;
2498 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
2499 emit_flattened_io_block_struct(basename, type, qual, sub_indices);
2500 else
2501 emit_flattened_io_block_member(basename, type, qual, sub_indices);
2502 }
2503}
2504
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002505void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual)
2506{
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002507 auto &var_type = get<SPIRType>(var.basetype);
2508 if (!var_type.array.empty())
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002509 SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings.");
2510
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002511 // Emit flattened types based on the type alias. Normally, we are never supposed to emit
2512 // struct declarations for aliased types.
2513 auto &type = var_type.type_alias ? get<SPIRType>(var_type.type_alias) : var_type;
2514
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002515 auto old_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002516 // Emit the members as if they are part of a block to get all qualifiers.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002517 ir.meta[type.self].decoration.decoration_flags.set(DecorationBlock);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002518
Hans-Kristian Arntzena8df0802017-11-22 11:19:54 +01002519 type.member_name_cache.clear();
2520
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002521 SmallVector<uint32_t> member_indices;
2522 member_indices.push_back(0);
2523 auto basename = to_name(var.self);
2524
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002525 uint32_t i = 0;
2526 for (auto &member : type.member_types)
2527 {
2528 add_member_name(type, i);
2529 auto &membertype = get<SPIRType>(member);
2530
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002531 member_indices.back() = i;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002532 if (membertype.basetype == SPIRType::Struct)
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002533 emit_flattened_io_block_struct(basename, type, qual, member_indices);
2534 else
2535 emit_flattened_io_block_member(basename, type, qual, member_indices);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002536 i++;
2537 }
2538
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002539 ir.meta[type.self].decoration.decoration_flags = old_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002540
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002541 // Treat this variable as fully flattened from now on.
2542 flattened_structs[var.self] = true;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002543}
2544
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002545void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
2546{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002547 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002548
rdbdf5e3732020-11-12 22:59:28 +01002549 if (var.storage == StorageClassInput && type.basetype == SPIRType::Double &&
2550 !options.es && options.version < 410)
2551 {
2552 require_extension_internal("GL_ARB_vertex_attrib_64bit");
2553 }
2554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002555 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002556 bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002557 const char *qual = to_storage_qualifiers_glsl(var);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002558
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002559 if (block)
2560 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002561 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2562 // I/O variables which are struct types.
2563 // To support this, flatten the struct into separate varyings instead.
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002564 if (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2565 (!options.es && options.version < 150))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002566 {
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002567 // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320.
2568 // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150).
2569 emit_flattened_io_block(var, qual);
2570 }
2571 else
2572 {
2573 if (options.es && options.version < 320)
2574 {
2575 // Geometry and tessellation extensions imply this extension.
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01002576 if (!has_extension("GL_EXT_geometry_shader") && !has_extension("GL_EXT_tessellation_shader"))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002577 require_extension_internal("GL_EXT_shader_io_blocks");
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002578 }
2579
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +01002580 // Workaround to make sure we can emit "patch in/out" correctly.
2581 fixup_io_block_patch_qualifiers(var);
2582
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002583 // Block names should never alias.
2584 auto block_name = to_name(type.self, false);
2585
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002586 // The namespace for I/O blocks is separate from other variables in GLSL.
2587 auto &block_namespace = type.storage == StorageClassInput ? block_input_names : block_output_names;
2588
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002589 // Shaders never use the block by interface name, so we don't
2590 // have to track this other than updating name caches.
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002591 if (block_name.empty() || block_namespace.find(block_name) != end(block_namespace))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002592 block_name = get_fallback_name(type.self);
2593 else
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002594 block_namespace.insert(block_name);
2595
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002596 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2597 // This cannot conflict with anything else, so we're safe now.
2598 if (block_name.empty())
2599 block_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2600
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002601 // Instance names cannot alias block names.
2602 resource_names.insert(block_name);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002603
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +01002604 bool is_patch = has_decoration(var.self, DecorationPatch);
2605 statement(layout_for_variable(var), (is_patch ? "patch " : ""), qual, block_name);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002606 begin_scope();
2607
2608 type.member_name_cache.clear();
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002609
2610 uint32_t i = 0;
2611 for (auto &member : type.member_types)
2612 {
2613 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002614 emit_struct_member(type, member, i);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002615 i++;
2616 }
2617
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002618 add_resource_name(var.self);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002619 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
2620 statement("");
2621 }
2622 }
2623 else
2624 {
2625 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2626 // I/O variables which are struct types.
2627 // To support this, flatten the struct into separate varyings instead.
2628 if (type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002629 (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2630 (!options.es && options.version < 150)))
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002631 {
2632 emit_flattened_io_block(var, qual);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002633 }
2634 else
2635 {
2636 add_resource_name(var.self);
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002637
2638 // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays.
2639 // Opt for unsized as it's the more "correct" variant to use.
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +01002640 bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() &&
2641 !has_decoration(var.self, DecorationPatch) &&
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002642 (get_entry_point().model == ExecutionModelTessellationControl ||
2643 get_entry_point().model == ExecutionModelTessellationEvaluation);
2644
2645 uint32_t old_array_size = 0;
2646 bool old_array_size_literal = true;
2647
2648 if (control_point_input_array)
2649 {
2650 swap(type.array.back(), old_array_size);
2651 swap(type.array_size_literal.back(), old_array_size_literal);
2652 }
2653
Chip Davis3bfb2f92018-12-03 02:06:33 -06002654 statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
2655 variable_decl(type, to_name(var.self), var.self), ";");
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002656
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002657 if (control_point_input_array)
2658 {
2659 swap(type.array.back(), old_array_size);
2660 swap(type.array_size_literal.back(), old_array_size_literal);
2661 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002662 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002663 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002664}
2665
2666void CompilerGLSL::emit_uniform(const SPIRVariable &var)
2667{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002668 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002669 if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002670 {
2671 if (!options.es && options.version < 420)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002672 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002673 else if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002674 SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002675 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002676
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002677 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002678 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002679}
2680
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002681string CompilerGLSL::constant_value_macro_name(uint32_t id)
2682{
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002683 return join("SPIRV_CROSS_CONSTANT_ID_", id);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002684}
2685
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002686void CompilerGLSL::emit_specialization_constant_op(const SPIRConstantOp &constant)
2687{
2688 auto &type = get<SPIRType>(constant.basetype);
2689 auto name = to_name(constant.self);
2690 statement("const ", variable_decl(type, name), " = ", constant_op_expression(constant), ";");
2691}
2692
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01002693int CompilerGLSL::get_constant_mapping_to_workgroup_component(const SPIRConstant &c) const
2694{
2695 auto &entry_point = get_entry_point();
2696 int index = -1;
2697
2698 // Need to redirect specialization constants which are used as WorkGroupSize to the builtin,
2699 // since the spec constant declarations are never explicitly declared.
2700 if (entry_point.workgroup_size.constant == 0 && entry_point.flags.get(ExecutionModeLocalSizeId))
2701 {
2702 if (c.self == entry_point.workgroup_size.id_x)
2703 index = 0;
2704 else if (c.self == entry_point.workgroup_size.id_y)
2705 index = 1;
2706 else if (c.self == entry_point.workgroup_size.id_z)
2707 index = 2;
2708 }
2709
2710 return index;
2711}
2712
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002713void CompilerGLSL::emit_constant(const SPIRConstant &constant)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002714{
2715 auto &type = get<SPIRType>(constant.constant_type);
2716 auto name = to_name(constant.self);
2717
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002718 SpecializationConstant wg_x, wg_y, wg_z;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002719 ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002720
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002721 // This specialization constant is implicitly declared by emitting layout() in;
2722 if (constant.self == workgroup_size_id)
2723 return;
2724
2725 // These specialization constants are implicitly declared by emitting layout() in;
2726 // In legacy GLSL, we will still need to emit macros for these, so a layout() in; declaration
2727 // later can use macro overrides for work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002728 bool is_workgroup_size_constant = ConstantID(constant.self) == wg_x.id || ConstantID(constant.self) == wg_y.id ||
2729 ConstantID(constant.self) == wg_z.id;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002730
2731 if (options.vulkan_semantics && is_workgroup_size_constant)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002732 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002733 // Vulkan GLSL does not need to declare workgroup spec constants explicitly, it is handled in layout().
2734 return;
2735 }
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002736 else if (!options.vulkan_semantics && is_workgroup_size_constant &&
2737 !has_decoration(constant.self, DecorationSpecId))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002738 {
2739 // 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 +02002740 return;
2741 }
2742
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002743 // Only scalars have constant IDs.
2744 if (has_decoration(constant.self, DecorationSpecId))
2745 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002746 if (options.vulkan_semantics)
2747 {
2748 statement("layout(constant_id = ", get_decoration(constant.self, DecorationSpecId), ") const ",
2749 variable_decl(type, name), " = ", constant_expression(constant), ";");
2750 }
2751 else
2752 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002753 const string &macro_name = constant.specialization_constant_macro_name;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002754 statement("#ifndef ", macro_name);
2755 statement("#define ", macro_name, " ", constant_expression(constant));
2756 statement("#endif");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002757
2758 // For workgroup size constants, only emit the macros.
2759 if (!is_workgroup_size_constant)
2760 statement("const ", variable_decl(type, name), " = ", macro_name, ";");
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002761 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002762 }
2763 else
2764 {
2765 statement("const ", variable_decl(type, name), " = ", constant_expression(constant), ";");
2766 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002767}
2768
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +02002769void CompilerGLSL::emit_entry_point_declarations()
2770{
2771}
2772
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002773void CompilerGLSL::replace_illegal_names(const unordered_set<string> &keywords)
2774{
2775 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
2776 if (is_hidden_variable(var))
2777 return;
2778
2779 auto *meta = ir.find_meta(var.self);
2780 if (!meta)
2781 return;
2782
2783 auto &m = meta->decoration;
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002784 if (keywords.find(m.alias) != end(keywords))
2785 m.alias = join("_", m.alias);
2786 });
2787
2788 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, const SPIRFunction &func) {
2789 auto *meta = ir.find_meta(func.self);
2790 if (!meta)
2791 return;
2792
2793 auto &m = meta->decoration;
2794 if (keywords.find(m.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002795 m.alias = join("_", m.alias);
2796 });
2797
2798 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
2799 auto *meta = ir.find_meta(type.self);
2800 if (!meta)
2801 return;
2802
2803 auto &m = meta->decoration;
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002804 if (keywords.find(m.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002805 m.alias = join("_", m.alias);
2806
2807 for (auto &memb : meta->members)
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002808 if (keywords.find(memb.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002809 memb.alias = join("_", memb.alias);
2810 });
2811}
2812
Robert Konrad76936562016-08-13 00:14:52 +02002813void CompilerGLSL::replace_illegal_names()
2814{
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002815 // clang-format off
2816 static const unordered_set<string> keywords = {
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002817 "abs", "acos", "acosh", "all", "any", "asin", "asinh", "atan", "atanh",
2818 "atomicAdd", "atomicCompSwap", "atomicCounter", "atomicCounterDecrement", "atomicCounterIncrement",
2819 "atomicExchange", "atomicMax", "atomicMin", "atomicOr", "atomicXor",
2820 "bitCount", "bitfieldExtract", "bitfieldInsert", "bitfieldReverse",
2821 "ceil", "cos", "cosh", "cross", "degrees",
2822 "dFdx", "dFdxCoarse", "dFdxFine",
2823 "dFdy", "dFdyCoarse", "dFdyFine",
2824 "distance", "dot", "EmitStreamVertex", "EmitVertex", "EndPrimitive", "EndStreamPrimitive", "equal", "exp", "exp2",
Chip Davis0d949e12018-11-05 14:55:56 -06002825 "faceforward", "findLSB", "findMSB", "float16BitsToInt16", "float16BitsToUint16", "floatBitsToInt", "floatBitsToUint", "floor", "fma", "fract",
2826 "frexp", "fwidth", "fwidthCoarse", "fwidthFine",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002827 "greaterThan", "greaterThanEqual", "groupMemoryBarrier",
2828 "imageAtomicAdd", "imageAtomicAnd", "imageAtomicCompSwap", "imageAtomicExchange", "imageAtomicMax", "imageAtomicMin", "imageAtomicOr", "imageAtomicXor",
Chip Davis0d949e12018-11-05 14:55:56 -06002829 "imageLoad", "imageSamples", "imageSize", "imageStore", "imulExtended", "int16BitsToFloat16", "intBitsToFloat", "interpolateAtOffset", "interpolateAtCentroid", "interpolateAtSample",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002830 "inverse", "inversesqrt", "isinf", "isnan", "ldexp", "length", "lessThan", "lessThanEqual", "log", "log2",
2831 "matrixCompMult", "max", "memoryBarrier", "memoryBarrierAtomicCounter", "memoryBarrierBuffer", "memoryBarrierImage", "memoryBarrierShared",
2832 "min", "mix", "mod", "modf", "noise", "noise1", "noise2", "noise3", "noise4", "normalize", "not", "notEqual",
Chip Davis0d949e12018-11-05 14:55:56 -06002833 "outerProduct", "packDouble2x32", "packHalf2x16", "packInt2x16", "packInt4x16", "packSnorm2x16", "packSnorm4x8",
2834 "packUint2x16", "packUint4x16", "packUnorm2x16", "packUnorm4x8", "pow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002835 "radians", "reflect", "refract", "round", "roundEven", "sign", "sin", "sinh", "smoothstep", "sqrt", "step",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002836 "tan", "tanh", "texelFetch", "texelFetchOffset", "texture", "textureGather", "textureGatherOffset", "textureGatherOffsets",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002837 "textureGrad", "textureGradOffset", "textureLod", "textureLodOffset", "textureOffset", "textureProj", "textureProjGrad",
2838 "textureProjGradOffset", "textureProjLod", "textureProjLodOffset", "textureProjOffset", "textureQueryLevels", "textureQueryLod", "textureSamples", "textureSize",
Chip Davis0d949e12018-11-05 14:55:56 -06002839 "transpose", "trunc", "uaddCarry", "uint16BitsToFloat16", "uintBitsToFloat", "umulExtended", "unpackDouble2x32", "unpackHalf2x16", "unpackInt2x16", "unpackInt4x16",
2840 "unpackSnorm2x16", "unpackSnorm4x8", "unpackUint2x16", "unpackUint4x16", "unpackUnorm2x16", "unpackUnorm4x8", "usubBorrow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002841
Pascal Muetschardaced6052018-05-04 14:53:32 -07002842 "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002843 "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard",
2844 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4",
2845 "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float",
2846 "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray",
2847 "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
2848 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect",
2849 "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant",
2850 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002851 "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp",
2852 "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump",
2853 "namespace", "noinline", "noperspective", "out", "output", "packed", "partition", "patch", "precise", "precision", "public", "readonly",
2854 "resource", "restrict", "return", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002855 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
2856 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002857 "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "shared", "short", "sizeof", "smooth", "static",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002858 "struct", "subroutine", "superp", "switch", "template", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D",
2859 "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube",
2860 "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
2861 "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002862 "usamplerCubeArray", "using", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile",
2863 "while", "writeonly",
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002864 };
2865 // clang-format on
Bas Zalmstraf537adf2016-10-27 12:51:22 +02002866
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002867 replace_illegal_names(keywords);
Robert Konrad76936562016-08-13 00:14:52 +02002868}
2869
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002870void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
2871{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002872 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002873 uint32_t location = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002874 if (m.decoration_flags.get(DecorationLocation))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002875 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002876
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002877 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
2878 // do the access chain part of this for us.
2879 auto &type = get<SPIRType>(var.basetype);
2880
2881 if (type.array.empty())
2882 {
2883 // Redirect the write to a specific render target in legacy GLSL.
2884 m.alias = join("gl_FragData[", location, "]");
Lubos Lenco52158642016-09-17 15:56:23 +02002885
2886 if (is_legacy_es() && location != 0)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002887 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002888 }
2889 else if (type.array.size() == 1)
2890 {
2891 // If location is non-zero, we probably have to add an offset.
2892 // This gets really tricky since we'd have to inject an offset in the access chain.
2893 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
2894 m.alias = "gl_FragData";
2895 if (location != 0)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002896 SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
2897 "This is unimplemented in SPIRV-Cross.");
Hans-Kristian Arntzen6cc96242016-09-17 18:46:10 +02002898
Lubos Lenco80c39412016-09-17 14:33:16 +02002899 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002900 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002901 }
2902 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002903 SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002904
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002905 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 +01002906}
2907
2908void CompilerGLSL::replace_fragment_outputs()
2909{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002910 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002911 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002912
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +01002913 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer && var.storage == StorageClassOutput)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002914 replace_fragment_output(var);
2915 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002916}
2917
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002918string CompilerGLSL::remap_swizzle(const SPIRType &out_type, uint32_t input_components, const string &expr)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002919{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002920 if (out_type.vecsize == input_components)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002921 return expr;
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01002922 else if (input_components == 1 && !backend.can_swizzle_scalar)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002923 return join(type_to_glsl(out_type), "(", expr, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002924 else
2925 {
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02002926 // FIXME: This will not work with packed expressions.
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002927 auto e = enclose_expression(expr) + ".";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002928 // Just clamp the swizzle index if we have more outputs than inputs.
2929 for (uint32_t c = 0; c < out_type.vecsize; c++)
2930 e += index_to_swizzle(min(c, input_components - 1));
2931 if (backend.swizzle_is_function && out_type.vecsize > 1)
2932 e += "()";
Hans-Kristian Arntzenffad50b2017-12-12 13:01:10 +01002933
2934 remove_duplicate_swizzle(e);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002935 return e;
2936 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002937}
2938
2939void CompilerGLSL::emit_pls()
2940{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002941 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002942 if (execution.model != ExecutionModelFragment)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002943 SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002944
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002945 if (!options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002946 SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002947
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002948 if (options.version < 300)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002949 SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002950
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002951 if (!pls_inputs.empty())
2952 {
2953 statement("__pixel_local_inEXT _PLSIn");
2954 begin_scope();
2955 for (auto &input : pls_inputs)
2956 statement(pls_decl(input), ";");
2957 end_scope_decl();
2958 statement("");
2959 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002960
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002961 if (!pls_outputs.empty())
2962 {
2963 statement("__pixel_local_outEXT _PLSOut");
2964 begin_scope();
2965 for (auto &output : pls_outputs)
2966 statement(pls_decl(output), ";");
2967 end_scope_decl();
2968 statement("");
2969 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002970}
2971
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002972void CompilerGLSL::fixup_image_load_store_access()
2973{
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002974 if (!options.enable_storage_image_qualifier_deduction)
2975 return;
2976
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002977 ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002978 auto &vartype = expression_type(var);
Hans-Kristian Arntzenb691b7d2020-04-03 12:26:13 +02002979 if (vartype.basetype == SPIRType::Image && vartype.image.sampled == 2)
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002980 {
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002981 // Very old glslangValidator and HLSL compilers do not emit required qualifiers here.
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002982 // Solve this by making the image access as restricted as possible and loosen up if we need to.
2983 // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
2984
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01002985 auto &flags = ir.meta[var].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002986 if (!flags.get(DecorationNonWritable) && !flags.get(DecorationNonReadable))
2987 {
2988 flags.set(DecorationNonWritable);
2989 flags.set(DecorationNonReadable);
2990 }
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002991 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002992 });
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002993}
2994
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002995static bool is_block_builtin(BuiltIn builtin)
2996{
2997 return builtin == BuiltInPosition || builtin == BuiltInPointSize || builtin == BuiltInClipDistance ||
2998 builtin == BuiltInCullDistance;
2999}
3000
3001bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage)
3002{
3003 // If the builtin block uses XFB, we need to force explicit redeclaration of the builtin block.
3004
3005 if (storage != StorageClassOutput)
3006 return false;
3007 bool should_force = false;
3008
3009 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
3010 if (should_force)
3011 return;
3012
3013 auto &type = this->get<SPIRType>(var.basetype);
3014 bool block = has_decoration(type.self, DecorationBlock);
3015 if (var.storage == storage && block && is_builtin_variable(var))
3016 {
3017 uint32_t member_count = uint32_t(type.member_types.size());
3018 for (uint32_t i = 0; i < member_count; i++)
3019 {
3020 if (has_member_decoration(type.self, i, DecorationBuiltIn) &&
3021 is_block_builtin(BuiltIn(get_member_decoration(type.self, i, DecorationBuiltIn))) &&
3022 has_member_decoration(type.self, i, DecorationOffset))
3023 {
3024 should_force = true;
3025 }
3026 }
3027 }
3028 else if (var.storage == storage && !block && is_builtin_variable(var))
3029 {
3030 if (is_block_builtin(BuiltIn(get_decoration(type.self, DecorationBuiltIn))) &&
3031 has_decoration(var.self, DecorationOffset))
3032 {
3033 should_force = true;
3034 }
3035 }
3036 });
3037
Hans-Kristian Arntzen3776d892021-01-07 12:14:49 +01003038 // If we're declaring clip/cull planes with control points we need to force block declaration.
3039 if (get_execution_model() == ExecutionModelTessellationControl &&
3040 (clip_distance_count || cull_distance_count))
3041 {
3042 should_force = true;
3043 }
3044
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003045 return should_force;
3046}
3047
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003048void CompilerGLSL::fixup_implicit_builtin_block_names()
3049{
3050 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
3051 auto &type = this->get<SPIRType>(var.basetype);
3052 bool block = has_decoration(type.self, DecorationBlock);
3053 if ((var.storage == StorageClassOutput || var.storage == StorageClassInput) && block &&
3054 is_builtin_variable(var))
3055 {
3056 // Make sure the array has a supported name in the code.
3057 if (var.storage == StorageClassOutput)
3058 set_name(var.self, "gl_out");
3059 else if (var.storage == StorageClassInput)
3060 set_name(var.self, "gl_in");
3061 }
3062 });
3063}
3064
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003065void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
3066{
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003067 Bitset emitted_builtins;
3068 Bitset global_builtins;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003069 const SPIRVariable *block_var = nullptr;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003070 bool emitted_block = false;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003071 bool builtin_array = false;
3072
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003073 // Need to use declared size in the type.
3074 // These variables might have been declared, but not statically used, so we haven't deduced their size yet.
3075 uint32_t cull_distance_size = 0;
3076 uint32_t clip_distance_size = 0;
3077
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003078 bool have_xfb_buffer_stride = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003079 bool have_geom_stream = false;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003080 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003081 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzendfffbb12020-01-27 15:56:47 +01003082 std::unordered_map<uint32_t, uint32_t> builtin_xfb_offsets;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003083
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003084 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003085 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003086 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003087 Bitset builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003088
3089 if (var.storage == storage && block && is_builtin_variable(var))
3090 {
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003091 uint32_t index = 0;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003092 for (auto &m : ir.meta[type.self].members)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003093 {
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003094 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003095 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003096 builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003097 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003098 cull_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003099 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003100 clip_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003101
3102 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationOffset))
3103 {
3104 have_any_xfb_offset = true;
3105 builtin_xfb_offsets[m.builtin_type] = m.offset;
3106 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003107
3108 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
3109 {
3110 uint32_t stream = m.stream;
3111 if (have_geom_stream && geom_stream != stream)
3112 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3113 have_geom_stream = true;
3114 geom_stream = stream;
3115 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003116 }
3117 index++;
3118 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003119
3120 if (storage == StorageClassOutput && has_decoration(var.self, DecorationXfbBuffer) &&
3121 has_decoration(var.self, DecorationXfbStride))
3122 {
3123 uint32_t buffer_index = get_decoration(var.self, DecorationXfbBuffer);
3124 uint32_t stride = get_decoration(var.self, DecorationXfbStride);
3125 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
3126 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3127 if (have_xfb_buffer_stride && stride != xfb_stride)
3128 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3129 have_xfb_buffer_stride = true;
3130 xfb_buffer = buffer_index;
3131 xfb_stride = stride;
3132 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003133
3134 if (storage == StorageClassOutput && has_decoration(var.self, DecorationStream))
3135 {
3136 uint32_t stream = get_decoration(var.self, DecorationStream);
3137 if (have_geom_stream && geom_stream != stream)
3138 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3139 have_geom_stream = true;
3140 geom_stream = stream;
3141 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003142 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003143 else if (var.storage == storage && !block && is_builtin_variable(var))
3144 {
3145 // While we're at it, collect all declared global builtins (HLSL mostly ...).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003146 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003147 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003148 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003149 global_builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003150 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003151 cull_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003152 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003153 clip_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003154
3155 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationXfbStride) &&
3156 m.decoration_flags.get(DecorationXfbBuffer) && m.decoration_flags.get(DecorationOffset))
3157 {
3158 have_any_xfb_offset = true;
3159 builtin_xfb_offsets[m.builtin_type] = m.offset;
3160 uint32_t buffer_index = m.xfb_buffer;
3161 uint32_t stride = m.xfb_stride;
3162 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
3163 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3164 if (have_xfb_buffer_stride && stride != xfb_stride)
3165 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3166 have_xfb_buffer_stride = true;
3167 xfb_buffer = buffer_index;
3168 xfb_stride = stride;
3169 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003170
3171 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
3172 {
3173 uint32_t stream = get_decoration(var.self, DecorationStream);
3174 if (have_geom_stream && geom_stream != stream)
3175 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3176 have_geom_stream = true;
3177 geom_stream = stream;
3178 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003179 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003180 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003181
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003182 if (builtins.empty())
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003183 return;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003184
3185 if (emitted_block)
3186 SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
3187
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003188 emitted_builtins = builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003189 emitted_block = true;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003190 builtin_array = !type.array.empty();
3191 block_var = &var;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003192 });
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003193
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01003194 global_builtins =
3195 Bitset(global_builtins.get_lower() & ((1ull << BuiltInPosition) | (1ull << BuiltInPointSize) |
3196 (1ull << BuiltInClipDistance) | (1ull << BuiltInCullDistance)));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003197
3198 // Try to collect all other declared builtins.
3199 if (!emitted_block)
3200 emitted_builtins = global_builtins;
3201
3202 // Can't declare an empty interface block.
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003203 if (emitted_builtins.empty())
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003204 return;
3205
3206 if (storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003207 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003208 SmallVector<string> attr;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003209 if (have_xfb_buffer_stride && have_any_xfb_offset)
3210 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003211 if (!options.es)
3212 {
3213 if (options.version < 440 && options.version >= 140)
3214 require_extension_internal("GL_ARB_enhanced_layouts");
3215 else if (options.version < 140)
3216 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
3217 if (!options.es && options.version < 440)
3218 require_extension_internal("GL_ARB_enhanced_layouts");
3219 }
3220 else if (options.es)
3221 SPIRV_CROSS_THROW("Need GL_ARB_enhanced_layouts for xfb_stride or xfb_buffer.");
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003222 attr.push_back(join("xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003223 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003224
3225 if (have_geom_stream)
3226 {
3227 if (get_execution_model() != ExecutionModelGeometry)
3228 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
3229 if (options.es)
3230 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
3231 if (options.version < 400)
3232 require_extension_internal("GL_ARB_transform_feedback3");
3233 attr.push_back(join("stream = ", geom_stream));
3234 }
3235
3236 if (!attr.empty())
3237 statement("layout(", merge(attr), ") out gl_PerVertex");
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003238 else
3239 statement("out gl_PerVertex");
3240 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003241 else
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01003242 {
3243 // If we have passthrough, there is no way PerVertex cannot be passthrough.
3244 if (get_entry_point().geometry_passthrough)
3245 statement("layout(passthrough) in gl_PerVertex");
3246 else
3247 statement("in gl_PerVertex");
3248 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003249
3250 begin_scope();
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003251 if (emitted_builtins.get(BuiltInPosition))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003252 {
3253 auto itr = builtin_xfb_offsets.find(BuiltInPosition);
3254 if (itr != end(builtin_xfb_offsets))
3255 statement("layout(xfb_offset = ", itr->second, ") vec4 gl_Position;");
3256 else
3257 statement("vec4 gl_Position;");
3258 }
3259
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003260 if (emitted_builtins.get(BuiltInPointSize))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003261 {
3262 auto itr = builtin_xfb_offsets.find(BuiltInPointSize);
3263 if (itr != end(builtin_xfb_offsets))
3264 statement("layout(xfb_offset = ", itr->second, ") float gl_PointSize;");
3265 else
3266 statement("float gl_PointSize;");
3267 }
3268
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003269 if (emitted_builtins.get(BuiltInClipDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003270 {
3271 auto itr = builtin_xfb_offsets.find(BuiltInClipDistance);
3272 if (itr != end(builtin_xfb_offsets))
3273 statement("layout(xfb_offset = ", itr->second, ") float gl_ClipDistance[", clip_distance_size, "];");
3274 else
3275 statement("float gl_ClipDistance[", clip_distance_size, "];");
3276 }
3277
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003278 if (emitted_builtins.get(BuiltInCullDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003279 {
3280 auto itr = builtin_xfb_offsets.find(BuiltInCullDistance);
3281 if (itr != end(builtin_xfb_offsets))
3282 statement("layout(xfb_offset = ", itr->second, ") float gl_CullDistance[", cull_distance_size, "];");
3283 else
3284 statement("float gl_CullDistance[", cull_distance_size, "];");
3285 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003286
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003287 if (builtin_array)
3288 {
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003289 if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
3290 end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]"));
3291 else
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01003292 end_scope_decl(join(to_name(block_var->self), "[]"));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003293 }
3294 else
3295 end_scope_decl();
3296 statement("");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003297}
3298
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003299void CompilerGLSL::declare_undefined_values()
3300{
3301 bool emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003302 ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003303 auto &type = this->get<SPIRType>(undef.basetype);
3304 // OpUndef can be void for some reason ...
3305 if (type.basetype == SPIRType::Void)
3306 return;
3307
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003308 string initializer;
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003309 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003310 initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
3311
crissdb52e272020-10-08 12:14:52 +02003312 statement(variable_decl(type, to_name(undef.self), undef.self), initializer, ";");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003313 emitted = true;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003314 });
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003315
3316 if (emitted)
3317 statement("");
3318}
3319
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003320bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const
3321{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003322 bool statically_assigned = var.statically_assigned && var.static_expression != ID(0) && var.remapped_variable;
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003323
3324 if (statically_assigned)
3325 {
3326 auto *constant = maybe_get<SPIRConstant>(var.static_expression);
3327 if (constant && constant->is_used_as_lut)
3328 return true;
3329 }
3330
3331 return false;
3332}
3333
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003334void CompilerGLSL::emit_resources()
3335{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02003336 auto &execution = get_entry_point();
3337
Robert Konrad76936562016-08-13 00:14:52 +02003338 replace_illegal_names();
3339
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003340 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
3341 // with builtins.
3342 if (execution.model == ExecutionModelFragment && is_legacy())
3343 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003345 // Emit PLS blocks if we have such variables.
3346 if (!pls_inputs.empty() || !pls_outputs.empty())
3347 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003348
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003349 switch (execution.model)
3350 {
3351 case ExecutionModelGeometry:
3352 case ExecutionModelTessellationControl:
3353 case ExecutionModelTessellationEvaluation:
3354 fixup_implicit_builtin_block_names();
3355 break;
3356
3357 default:
3358 break;
3359 }
3360
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003361 // Emit custom gl_PerVertex for SSO compatibility.
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003362 if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment)
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003363 {
3364 switch (execution.model)
3365 {
3366 case ExecutionModelGeometry:
3367 case ExecutionModelTessellationControl:
3368 case ExecutionModelTessellationEvaluation:
3369 emit_declared_builtin_block(StorageClassInput, execution.model);
3370 emit_declared_builtin_block(StorageClassOutput, execution.model);
3371 break;
3372
3373 case ExecutionModelVertex:
3374 emit_declared_builtin_block(StorageClassOutput, execution.model);
3375 break;
3376
3377 default:
3378 break;
3379 }
3380 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003381 else if (should_force_emit_builtin_block(StorageClassOutput))
3382 {
3383 emit_declared_builtin_block(StorageClassOutput, execution.model);
3384 }
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01003385 else if (execution.geometry_passthrough)
3386 {
3387 // Need to declare gl_in with Passthrough.
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003388 // 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 +01003389 emit_declared_builtin_block(StorageClassInput, execution.model);
3390 }
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003391 else
3392 {
3393 // Need to redeclare clip/cull distance with explicit size to use them.
3394 // SPIR-V mandates these builtins have a size declared.
3395 const char *storage = execution.model == ExecutionModelFragment ? "in" : "out";
3396 if (clip_distance_count != 0)
3397 statement(storage, " float gl_ClipDistance[", clip_distance_count, "];");
3398 if (cull_distance_count != 0)
3399 statement(storage, " float gl_CullDistance[", cull_distance_count, "];");
3400 if (clip_distance_count != 0 || cull_distance_count != 0)
3401 statement("");
3402 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003403
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003404 if (position_invariant)
3405 {
3406 statement("invariant gl_Position;");
3407 statement("");
3408 }
3409
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003410 bool emitted = false;
3411
3412 // If emitted Vulkan GLSL,
3413 // emit specialization constants as actual floats,
3414 // spec op expressions will redirect to the constant name.
3415 //
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003416 {
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +02003417 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003418 for (auto &id_ : ir.ids_for_constant_or_type)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003419 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003420 auto &id = ir.ids[id_];
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003421
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003422 if (id.get_type() == TypeConstant)
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003423 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003424 auto &c = id.get<SPIRConstant>();
3425
3426 bool needs_declaration = c.specialization || c.is_used_as_lut;
3427
3428 if (needs_declaration)
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003429 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003430 if (!options.vulkan_semantics && c.specialization)
3431 {
3432 c.specialization_constant_macro_name =
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02003433 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003434 }
3435 emit_constant(c);
3436 emitted = true;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003437 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003438 }
3439 else if (id.get_type() == TypeConstantOp)
3440 {
3441 emit_specialization_constant_op(id.get<SPIRConstantOp>());
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003442 emitted = true;
3443 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003444 else if (id.get_type() == TypeType)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003445 {
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003446 auto *type = &id.get<SPIRType>();
3447
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003448 bool is_natural_struct = type->basetype == SPIRType::Struct && type->array.empty() && !type->pointer &&
3449 (!has_decoration(type->self, DecorationBlock) &&
3450 !has_decoration(type->self, DecorationBufferBlock));
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003451
3452 // Special case, ray payload and hit attribute blocks are not really blocks, just regular structs.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003453 if (type->basetype == SPIRType::Struct && type->pointer &&
3454 has_decoration(type->self, DecorationBlock) &&
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003455 (type->storage == StorageClassRayPayloadKHR || type->storage == StorageClassIncomingRayPayloadKHR ||
3456 type->storage == StorageClassHitAttributeKHR))
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003457 {
3458 type = &get<SPIRType>(type->parent_type);
3459 is_natural_struct = true;
3460 }
3461
3462 if (is_natural_struct)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003463 {
3464 if (emitted)
3465 statement("");
3466 emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003467
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003468 emit_struct(*type);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003469 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003470 }
3471 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003472 }
3473
3474 if (emitted)
3475 statement("");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003476
3477 // If we needed to declare work group size late, check here.
3478 // If the work group size depends on a specialization constant, we need to declare the layout() block
3479 // after constants (and their macros) have been declared.
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01003480 if (execution.model == ExecutionModelGLCompute && !options.vulkan_semantics &&
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01003481 (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003482 {
3483 SpecializationConstant wg_x, wg_y, wg_z;
3484 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
3485
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003486 if ((wg_x.id != ConstantID(0)) || (wg_y.id != ConstantID(0)) || (wg_z.id != ConstantID(0)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003487 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02003488 SmallVector<string> inputs;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003489 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
3490 statement("layout(", merge(inputs), ") in;");
3491 statement("");
3492 }
3493 }
3494
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003495 emitted = false;
3496
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003497 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
3498 {
3499 for (auto type : physical_storage_non_block_pointer_types)
3500 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003501 emit_buffer_reference_block(type, false);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003502 }
3503
3504 // Output buffer reference blocks.
3505 // Do this in two stages, one with forward declaration,
3506 // and one without. Buffer reference blocks can reference themselves
3507 // to support things like linked lists.
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003508 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
3509 if (type.basetype == SPIRType::Struct && type.pointer &&
3510 type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003511 type.storage == StorageClassPhysicalStorageBufferEXT)
3512 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003513 emit_buffer_reference_block(self, true);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003514 }
3515 });
3516
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003517 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
3518 if (type.basetype == SPIRType::Struct &&
3519 type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003520 type.storage == StorageClassPhysicalStorageBufferEXT)
3521 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003522 emit_buffer_reference_block(self, false);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003523 }
3524 });
3525 }
3526
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003527 // Output UBOs and SSBOs
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003528 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003529 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003530
Patrick Mours78917862019-06-03 15:25:21 +02003531 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform ||
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003532 type.storage == StorageClassShaderRecordBufferKHR;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003533 bool has_block_flags = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
3534 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
3535
3536 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
3537 has_block_flags)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003538 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003539 emit_buffer_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003540 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003541 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003542
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003543 // Output push constant blocks
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003544 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003545 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003546 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
3547 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003548 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003549 emit_push_constant_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003550 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003551 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003552
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02003553 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003555 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003556 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003557 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003558
3559 // If we're remapping separate samplers and images, only emit the combined samplers.
3560 if (skip_separate_image_sampler)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003561 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003562 // Sampler buffers are always used without a sampler, and they will also work in regular GL.
3563 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
3564 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
3565 bool separate_sampler = type.basetype == SPIRType::Sampler;
3566 if (!sampler_buffer && (separate_image || separate_sampler))
3567 return;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003568 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003569
3570 if (var.storage != StorageClassFunction && type.pointer &&
Patrick Moursda39a7b2019-02-26 15:43:03 +01003571 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter ||
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003572 type.storage == StorageClassRayPayloadKHR || type.storage == StorageClassIncomingRayPayloadKHR ||
3573 type.storage == StorageClassCallableDataKHR || type.storage == StorageClassIncomingCallableDataKHR ||
3574 type.storage == StorageClassHitAttributeKHR) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003575 !is_hidden_variable(var))
3576 {
3577 emit_uniform(var);
3578 emitted = true;
3579 }
3580 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003581
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003582 if (emitted)
3583 statement("");
3584 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003585
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003586 bool emitted_base_instance = false;
3587
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003588 // Output in/out interfaces.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003589 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003590 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003591
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003592 bool is_hidden = is_hidden_variable(var);
3593
3594 // Unused output I/O variables might still be required to implement framebuffer fetch.
3595 if (var.storage == StorageClassOutput && !is_legacy() &&
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02003596 location_is_framebuffer_fetch(get_decoration(var.self, DecorationLocation)) != 0)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003597 {
3598 is_hidden = false;
3599 }
3600
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003601 if (var.storage != StorageClassFunction && type.pointer &&
3602 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003603 interface_variable_exists_in_entry_point(var.self) && !is_hidden)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003604 {
xinhou4b0584c2021-11-26 10:06:42 +08003605 if (options.es && get_execution_model() == ExecutionModelVertex && var.storage == StorageClassInput &&
3606 type.array.size() == 1)
3607 {
3608 SPIRV_CROSS_THROW("OpenGL ES doesn't support array input variables in vertex shader.");
3609 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003610 emit_interface_block(var);
3611 emitted = true;
3612 }
3613 else if (is_builtin_variable(var))
3614 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003615 auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003616 // For gl_InstanceIndex emulation on GLES, the API user needs to
3617 // supply this uniform.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003618
3619 // The draw parameter extension is soft-enabled on GL with some fallbacks.
3620 if (!options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003621 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003622 if (!emitted_base_instance &&
3623 ((options.vertex.support_nonzero_base_instance && builtin == BuiltInInstanceIndex) ||
3624 (builtin == BuiltInBaseInstance)))
3625 {
3626 statement("#ifdef GL_ARB_shader_draw_parameters");
3627 statement("#define SPIRV_Cross_BaseInstance gl_BaseInstanceARB");
3628 statement("#else");
3629 // A crude, but simple workaround which should be good enough for non-indirect draws.
3630 statement("uniform int SPIRV_Cross_BaseInstance;");
3631 statement("#endif");
3632 emitted = true;
3633 emitted_base_instance = true;
3634 }
3635 else if (builtin == BuiltInBaseVertex)
3636 {
3637 statement("#ifdef GL_ARB_shader_draw_parameters");
3638 statement("#define SPIRV_Cross_BaseVertex gl_BaseVertexARB");
3639 statement("#else");
3640 // A crude, but simple workaround which should be good enough for non-indirect draws.
3641 statement("uniform int SPIRV_Cross_BaseVertex;");
3642 statement("#endif");
3643 }
3644 else if (builtin == BuiltInDrawIndex)
3645 {
3646 statement("#ifndef GL_ARB_shader_draw_parameters");
3647 // Cannot really be worked around.
3648 statement("#error GL_ARB_shader_draw_parameters is not supported.");
3649 statement("#endif");
3650 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003651 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003652 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003653 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003655 // Global variables.
3656 for (auto global : global_variables)
3657 {
3658 auto &var = get<SPIRVariable>(global);
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +01003659 if (is_hidden_variable(var, true))
3660 continue;
3661
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003662 if (var.storage != StorageClassOutput)
3663 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003664 if (!variable_is_lut(var))
3665 {
3666 add_resource_name(var.self);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003667
3668 string initializer;
3669 if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate &&
3670 !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var)))
3671 {
3672 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var)));
3673 }
3674
3675 statement(variable_decl(var), initializer, ";");
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003676 emitted = true;
3677 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003678 }
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +01003679 else if (var.initializer && maybe_get<SPIRConstant>(var.initializer) != nullptr)
3680 {
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003681 emit_output_variable_initializer(var);
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +01003682 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003683 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003684
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003685 if (emitted)
3686 statement("");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003687
3688 declare_undefined_values();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003689}
3690
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003691void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var)
3692{
3693 // If a StorageClassOutput variable has an initializer, we need to initialize it in main().
3694 auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
3695 auto &type = get<SPIRType>(var.basetype);
3696 bool is_patch = has_decoration(var.self, DecorationPatch);
3697 bool is_block = has_decoration(type.self, DecorationBlock);
3698 bool is_control_point = get_execution_model() == ExecutionModelTessellationControl && !is_patch;
3699
3700 if (is_block)
3701 {
3702 uint32_t member_count = uint32_t(type.member_types.size());
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003703 bool type_is_array = type.array.size() == 1;
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003704 uint32_t array_size = 1;
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003705 if (type_is_array)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003706 array_size = to_array_size_literal(type);
3707 uint32_t iteration_count = is_control_point ? 1 : array_size;
3708
3709 // If the initializer is a block, we must initialize each block member one at a time.
3710 for (uint32_t i = 0; i < member_count; i++)
3711 {
3712 // These outputs might not have been properly declared, so don't initialize them in that case.
3713 if (has_member_decoration(type.self, i, DecorationBuiltIn))
3714 {
3715 if (get_member_decoration(type.self, i, DecorationBuiltIn) == BuiltInCullDistance &&
3716 !cull_distance_count)
3717 continue;
3718
3719 if (get_member_decoration(type.self, i, DecorationBuiltIn) == BuiltInClipDistance &&
3720 !clip_distance_count)
3721 continue;
3722 }
3723
3724 // We need to build a per-member array first, essentially transposing from AoS to SoA.
3725 // This code path hits when we have an array of blocks.
3726 string lut_name;
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003727 if (type_is_array)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003728 {
3729 lut_name = join("_", var.self, "_", i, "_init");
3730 uint32_t member_type_id = get<SPIRType>(var.basetype).member_types[i];
3731 auto &member_type = get<SPIRType>(member_type_id);
3732 auto array_type = member_type;
3733 array_type.parent_type = member_type_id;
3734 array_type.array.push_back(array_size);
3735 array_type.array_size_literal.push_back(true);
3736
3737 SmallVector<string> exprs;
3738 exprs.reserve(array_size);
3739 auto &c = get<SPIRConstant>(var.initializer);
3740 for (uint32_t j = 0; j < array_size; j++)
3741 exprs.push_back(to_expression(get<SPIRConstant>(c.subconstants[j]).subconstants[i]));
3742 statement("const ", type_to_glsl(array_type), " ", lut_name, type_to_array_glsl(array_type), " = ",
3743 type_to_glsl_constructor(array_type), "(", merge(exprs, ", "), ");");
3744 }
3745
3746 for (uint32_t j = 0; j < iteration_count; j++)
3747 {
3748 entry_func.fixup_hooks_in.push_back([=, &var]() {
3749 AccessChainMeta meta;
3750 auto &c = this->get<SPIRConstant>(var.initializer);
3751
3752 uint32_t invocation_id = 0;
3753 uint32_t member_index_id = 0;
3754 if (is_control_point)
3755 {
3756 uint32_t ids = ir.increase_bound_by(3);
3757 SPIRType uint_type;
3758 uint_type.basetype = SPIRType::UInt;
3759 uint_type.width = 32;
3760 set<SPIRType>(ids, uint_type);
3761 set<SPIRExpression>(ids + 1, builtin_to_glsl(BuiltInInvocationId, StorageClassInput), ids, true);
3762 set<SPIRConstant>(ids + 2, ids, i, false);
3763 invocation_id = ids + 1;
3764 member_index_id = ids + 2;
3765 }
3766
3767 if (is_patch)
3768 {
3769 statement("if (gl_InvocationID == 0)");
3770 begin_scope();
3771 }
3772
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003773 if (type_is_array && !is_control_point)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003774 {
3775 uint32_t indices[2] = { j, i };
3776 auto chain = access_chain_internal(var.self, indices, 2, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
3777 statement(chain, " = ", lut_name, "[", j, "];");
3778 }
3779 else if (is_control_point)
3780 {
3781 uint32_t indices[2] = { invocation_id, member_index_id };
3782 auto chain = access_chain_internal(var.self, indices, 2, 0, &meta);
3783 statement(chain, " = ", lut_name, "[", builtin_to_glsl(BuiltInInvocationId, StorageClassInput), "];");
3784 }
3785 else
3786 {
3787 auto chain =
3788 access_chain_internal(var.self, &i, 1, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
3789 statement(chain, " = ", to_expression(c.subconstants[i]), ";");
3790 }
3791
3792 if (is_patch)
3793 end_scope();
3794 });
3795 }
3796 }
3797 }
3798 else if (is_control_point)
3799 {
3800 auto lut_name = join("_", var.self, "_init");
3801 statement("const ", type_to_glsl(type), " ", lut_name, type_to_array_glsl(type),
3802 " = ", to_expression(var.initializer), ";");
3803 entry_func.fixup_hooks_in.push_back([&, lut_name]() {
3804 statement(to_expression(var.self), "[gl_InvocationID] = ", lut_name, "[gl_InvocationID];");
3805 });
3806 }
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01003807 else if (has_decoration(var.self, DecorationBuiltIn) &&
3808 BuiltIn(get_decoration(var.self, DecorationBuiltIn)) == BuiltInSampleMask)
3809 {
3810 // We cannot copy the array since gl_SampleMask is unsized in GLSL. Unroll time! <_<
3811 entry_func.fixup_hooks_in.push_back([&] {
3812 auto &c = this->get<SPIRConstant>(var.initializer);
3813 uint32_t num_constants = uint32_t(c.subconstants.size());
3814 for (uint32_t i = 0; i < num_constants; i++)
3815 {
3816 // Don't use to_expression on constant since it might be uint, just fish out the raw int.
3817 statement(to_expression(var.self), "[", i, "] = ",
3818 convert_to_string(this->get<SPIRConstant>(c.subconstants[i]).scalar_i32()), ";");
3819 }
3820 });
3821 }
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003822 else
3823 {
3824 auto lut_name = join("_", var.self, "_init");
3825 statement("const ", type_to_glsl(type), " ", lut_name,
3826 type_to_array_glsl(type), " = ", to_expression(var.initializer), ";");
3827 entry_func.fixup_hooks_in.push_back([&, lut_name, is_patch]() {
3828 if (is_patch)
3829 {
3830 statement("if (gl_InvocationID == 0)");
3831 begin_scope();
3832 }
3833 statement(to_expression(var.self), " = ", lut_name, ";");
3834 if (is_patch)
3835 end_scope();
3836 });
3837 }
3838}
3839
crissdb52e272020-10-08 12:14:52 +02003840void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
3841{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01003842 static const char *workaround_types[] = { "int", "ivec2", "ivec3", "ivec4", "uint", "uvec2", "uvec3", "uvec4",
3843 "float", "vec2", "vec3", "vec4", "double", "dvec2", "dvec3", "dvec4" };
crissdb52e272020-10-08 12:14:52 +02003844
3845 if (!options.vulkan_semantics)
3846 {
3847 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003848 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +02003849
3850 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMask))
3851 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003852 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupMask, result);
crissdb52e272020-10-08 12:14:52 +02003853
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003854 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003855 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003856 const char *name = Supp::get_extension_name(e);
3857 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003858
crissdb52e272020-10-08 12:14:52 +02003859 switch (e)
3860 {
3861 case Supp::NV_shader_thread_group:
3862 statement("#define gl_SubgroupEqMask uvec4(gl_ThreadEqMaskNV, 0u, 0u, 0u)");
3863 statement("#define gl_SubgroupGeMask uvec4(gl_ThreadGeMaskNV, 0u, 0u, 0u)");
3864 statement("#define gl_SubgroupGtMask uvec4(gl_ThreadGtMaskNV, 0u, 0u, 0u)");
3865 statement("#define gl_SubgroupLeMask uvec4(gl_ThreadLeMaskNV, 0u, 0u, 0u)");
3866 statement("#define gl_SubgroupLtMask uvec4(gl_ThreadLtMaskNV, 0u, 0u, 0u)");
3867 break;
3868 case Supp::ARB_shader_ballot:
3869 statement("#define gl_SubgroupEqMask uvec4(unpackUint2x32(gl_SubGroupEqMaskARB), 0u, 0u)");
3870 statement("#define gl_SubgroupGeMask uvec4(unpackUint2x32(gl_SubGroupGeMaskARB), 0u, 0u)");
3871 statement("#define gl_SubgroupGtMask uvec4(unpackUint2x32(gl_SubGroupGtMaskARB), 0u, 0u)");
3872 statement("#define gl_SubgroupLeMask uvec4(unpackUint2x32(gl_SubGroupLeMaskARB), 0u, 0u)");
3873 statement("#define gl_SubgroupLtMask uvec4(unpackUint2x32(gl_SubGroupLtMaskARB), 0u, 0u)");
3874 break;
3875 default:
3876 break;
3877 }
3878 }
3879 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003880 statement("");
crissdb52e272020-10-08 12:14:52 +02003881 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003882
crissdb52e272020-10-08 12:14:52 +02003883 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupSize))
3884 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003885 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupSize, result);
crissdb52e272020-10-08 12:14:52 +02003886
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003887 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003888 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003889 const char *name = Supp::get_extension_name(e);
3890 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003891
crissdb52e272020-10-08 12:14:52 +02003892 switch (e)
3893 {
3894 case Supp::NV_shader_thread_group:
3895 statement("#define gl_SubgroupSize gl_WarpSizeNV");
3896 break;
3897 case Supp::ARB_shader_ballot:
3898 statement("#define gl_SubgroupSize gl_SubGroupSizeARB");
3899 break;
3900 case Supp::AMD_gcn_shader:
3901 statement("#define gl_SubgroupSize uint(gl_SIMDGroupSizeAMD)");
3902 break;
3903 default:
3904 break;
3905 }
3906 }
3907 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003908 statement("");
crissdb52e272020-10-08 12:14:52 +02003909 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003910
crissdb52e272020-10-08 12:14:52 +02003911 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInvocationID))
3912 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003913 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupInvocationID, result);
crissdb52e272020-10-08 12:14:52 +02003914
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003915 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003916 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003917 const char *name = Supp::get_extension_name(e);
3918 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003919
crissdb52e272020-10-08 12:14:52 +02003920 switch (e)
3921 {
3922 case Supp::NV_shader_thread_group:
3923 statement("#define gl_SubgroupInvocationID gl_ThreadInWarpNV");
3924 break;
3925 case Supp::ARB_shader_ballot:
3926 statement("#define gl_SubgroupInvocationID gl_SubGroupInvocationARB");
3927 break;
3928 default:
3929 break;
3930 }
3931 }
3932 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003933 statement("");
crissdb52e272020-10-08 12:14:52 +02003934 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003935
crissdb52e272020-10-08 12:14:52 +02003936 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupID))
3937 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003938 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupID, result);
crissdb52e272020-10-08 12:14:52 +02003939
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003940 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003941 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003942 const char *name = Supp::get_extension_name(e);
3943 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003944
crissdb52e272020-10-08 12:14:52 +02003945 switch (e)
3946 {
3947 case Supp::NV_shader_thread_group:
3948 statement("#define gl_SubgroupID gl_WarpIDNV");
3949 break;
3950 default:
3951 break;
3952 }
3953 }
3954 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003955 statement("");
crissdb52e272020-10-08 12:14:52 +02003956 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003957
crissdb52e272020-10-08 12:14:52 +02003958 if (shader_subgroup_supporter.is_feature_requested(Supp::NumSubgroups))
3959 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003960 auto exts = Supp::get_candidates_for_feature(Supp::NumSubgroups, result);
crissdb52e272020-10-08 12:14:52 +02003961
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003962 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003963 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003964 const char *name = Supp::get_extension_name(e);
3965 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003966
crissdb52e272020-10-08 12:14:52 +02003967 switch (e)
3968 {
3969 case Supp::NV_shader_thread_group:
3970 statement("#define gl_NumSubgroups gl_WarpsPerSMNV");
3971 break;
3972 default:
3973 break;
3974 }
3975 }
3976 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003977 statement("");
crissdb52e272020-10-08 12:14:52 +02003978 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003979
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01003980 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBroadcast_First))
crissdb52e272020-10-08 12:14:52 +02003981 {
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01003982 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBroadcast_First, result);
crissdb52e272020-10-08 12:14:52 +02003983
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003984 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003985 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003986 const char *name = Supp::get_extension_name(e);
3987 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003988
crissdb52e272020-10-08 12:14:52 +02003989 switch (e)
3990 {
3991 case Supp::NV_shader_thread_shuffle:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003992 for (const char *t : workaround_types)
3993 {
3994 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02003995 " value) { return shuffleNV(value, findLSB(ballotThreadNV(true)), gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003996 }
3997 for (const char *t : workaround_types)
3998 {
3999 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02004000 " value, uint id) { return shuffleNV(value, id, gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004001 }
crissdb52e272020-10-08 12:14:52 +02004002 break;
4003 case Supp::ARB_shader_ballot:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004004 for (const char *t : workaround_types)
4005 {
4006 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02004007 " value) { return readFirstInvocationARB(value); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004008 }
4009 for (const char *t : workaround_types)
4010 {
4011 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02004012 " value, uint id) { return readInvocationARB(value, id); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004013 }
crissdb52e272020-10-08 12:14:52 +02004014 break;
4015 default:
4016 break;
4017 }
4018 }
4019 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004020 statement("");
crissdb52e272020-10-08 12:14:52 +02004021 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004022
crissdb52e272020-10-08 12:14:52 +02004023 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotFindLSB_MSB))
4024 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004025 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallotFindLSB_MSB, result);
crissdb52e272020-10-08 12:14:52 +02004026
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004027 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004028 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004029 const char *name = Supp::get_extension_name(e);
4030 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004031
crissdb52e272020-10-08 12:14:52 +02004032 switch (e)
4033 {
4034 case Supp::NV_shader_thread_group:
4035 statement("uint subgroupBallotFindLSB(uvec4 value) { return findLSB(value.x); }");
4036 statement("uint subgroupBallotFindMSB(uvec4 value) { return findMSB(value.x); }");
4037 break;
4038 default:
4039 break;
4040 }
4041 }
4042 statement("#else");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004043 statement("uint subgroupBallotFindLSB(uvec4 value)");
4044 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004045 statement("int firstLive = findLSB(value.x);");
4046 statement("return uint(firstLive != -1 ? firstLive : (findLSB(value.y) + 32));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004047 end_scope();
4048 statement("uint subgroupBallotFindMSB(uvec4 value)");
4049 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004050 statement("int firstLive = findMSB(value.y);");
4051 statement("return uint(firstLive != -1 ? (firstLive + 32) : findMSB(value.x));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004052 end_scope();
crissdb52e272020-10-08 12:14:52 +02004053 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004054 statement("");
crissdb52e272020-10-08 12:14:52 +02004055 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004056
crissdb52e272020-10-08 12:14:52 +02004057 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAll_Any_AllEqualBool))
4058 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004059 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupAll_Any_AllEqualBool, result);
crissdb52e272020-10-08 12:14:52 +02004060
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004061 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004062 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004063 const char *name = Supp::get_extension_name(e);
4064 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004065
crissdb52e272020-10-08 12:14:52 +02004066 switch (e)
4067 {
4068 case Supp::NV_gpu_shader_5:
4069 statement("bool subgroupAll(bool value) { return allThreadsNV(value); }");
4070 statement("bool subgroupAny(bool value) { return anyThreadNV(value); }");
4071 statement("bool subgroupAllEqual(bool value) { return allThreadsEqualNV(value); }");
4072 break;
4073 case Supp::ARB_shader_group_vote:
4074 statement("bool subgroupAll(bool v) { return allInvocationsARB(v); }");
4075 statement("bool subgroupAny(bool v) { return anyInvocationARB(v); }");
4076 statement("bool subgroupAllEqual(bool v) { return allInvocationsEqualARB(v); }");
4077 break;
4078 case Supp::AMD_gcn_shader:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004079 statement("bool subgroupAll(bool value) { return ballotAMD(value) == ballotAMD(true); }");
4080 statement("bool subgroupAny(bool value) { return ballotAMD(value) != 0ull; }");
4081 statement("bool subgroupAllEqual(bool value) { uint64_t b = ballotAMD(value); return b == 0ull || "
4082 "b == ballotAMD(true); }");
crissdb52e272020-10-08 12:14:52 +02004083 break;
4084 default:
4085 break;
4086 }
4087 }
4088 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004089 statement("");
crissdb52e272020-10-08 12:14:52 +02004090 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004091
crissdb52e272020-10-08 12:14:52 +02004092 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAllEqualT))
4093 {
4094 statement("#ifndef GL_KHR_shader_subgroup_vote");
4095 statement(
4096 "#define _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(type) bool subgroupAllEqual(type value) { return "
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004097 "subgroupAllEqual(subgroupBroadcastFirst(value) == value); }");
4098 for (const char *t : workaround_types)
4099 statement("_SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(", t, ")");
crissdb52e272020-10-08 12:14:52 +02004100 statement("#undef _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND");
4101 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004102 statement("");
crissdb52e272020-10-08 12:14:52 +02004103 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004104
crissdb52e272020-10-08 12:14:52 +02004105 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallot))
4106 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004107 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallot, result);
crissdb52e272020-10-08 12:14:52 +02004108
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004109 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004110 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004111 const char *name = Supp::get_extension_name(e);
4112 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004113
crissdb52e272020-10-08 12:14:52 +02004114 switch (e)
4115 {
4116 case Supp::NV_shader_thread_group:
4117 statement("uvec4 subgroupBallot(bool v) { return uvec4(ballotThreadNV(v), 0u, 0u, 0u); }");
4118 break;
4119 case Supp::ARB_shader_ballot:
4120 statement("uvec4 subgroupBallot(bool v) { return uvec4(unpackUint2x32(ballotARB(v)), 0u, 0u); }");
4121 break;
4122 default:
4123 break;
4124 }
4125 }
4126 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004127 statement("");
crissdb52e272020-10-08 12:14:52 +02004128 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004129
crissdb52e272020-10-08 12:14:52 +02004130 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupElect))
4131 {
4132 statement("#ifndef GL_KHR_shader_subgroup_basic");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004133 statement("bool subgroupElect()");
4134 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004135 statement("uvec4 activeMask = subgroupBallot(true);");
4136 statement("uint firstLive = subgroupBallotFindLSB(activeMask);");
4137 statement("return gl_SubgroupInvocationID == firstLive;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004138 end_scope();
crissdb52e272020-10-08 12:14:52 +02004139 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004140 statement("");
crissdb52e272020-10-08 12:14:52 +02004141 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004142
crissdb52e272020-10-08 12:14:52 +02004143 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBarrier))
4144 {
4145 // Extensions we're using in place of GL_KHR_shader_subgroup_basic state
4146 // that subgroup execute in lockstep so this barrier is implicit.
devsh6c5f3942020-10-31 21:46:59 +01004147 // However the GL 4.6 spec also states that `barrier` implies a shared memory barrier,
4148 // and a specific test of optimizing scans by leveraging lock-step invocation execution,
4149 // has shown that a `memoryBarrierShared` is needed in place of a `subgroupBarrier`.
4150 // https://github.com/buildaworldnet/IrrlichtBAW/commit/d8536857991b89a30a6b65d29441e51b64c2c7ad#diff-9f898d27be1ea6fc79b03d9b361e299334c1a347b6e4dc344ee66110c6aa596aR19
crissdb52e272020-10-08 12:14:52 +02004151 statement("#ifndef GL_KHR_shader_subgroup_basic");
devsh6c5f3942020-10-31 21:46:59 +01004152 statement("void subgroupBarrier() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02004153 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004154 statement("");
crissdb52e272020-10-08 12:14:52 +02004155 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004156
crissdb52e272020-10-08 12:14:52 +02004157 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMemBarrier))
4158 {
4159 if (model == spv::ExecutionModelGLCompute)
4160 {
4161 statement("#ifndef GL_KHR_shader_subgroup_basic");
4162 statement("void subgroupMemoryBarrier() { groupMemoryBarrier(); }");
4163 statement("void subgroupMemoryBarrierBuffer() { groupMemoryBarrier(); }");
devsh6c5f3942020-10-31 21:46:59 +01004164 statement("void subgroupMemoryBarrierShared() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02004165 statement("void subgroupMemoryBarrierImage() { groupMemoryBarrier(); }");
4166 statement("#endif");
4167 }
4168 else
4169 {
4170 statement("#ifndef GL_KHR_shader_subgroup_basic");
4171 statement("void subgroupMemoryBarrier() { memoryBarrier(); }");
4172 statement("void subgroupMemoryBarrierBuffer() { memoryBarrierBuffer(); }");
4173 statement("void subgroupMemoryBarrierImage() { memoryBarrierImage(); }");
4174 statement("#endif");
4175 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004176 statement("");
crissdb52e272020-10-08 12:14:52 +02004177 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004178
crissdb52e272020-10-08 12:14:52 +02004179 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInverseBallot_InclBitCount_ExclBitCout))
4180 {
4181 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4182 statement("bool subgroupInverseBallot(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004183 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004184 statement("return any(notEqual(value.xy & gl_SubgroupEqMask.xy, uvec2(0u)));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004185 end_scope();
crissdb52e272020-10-08 12:14:52 +02004186
4187 statement("uint subgroupBallotInclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004188 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004189 statement("uvec2 v = value.xy & gl_SubgroupLeMask.xy;");
4190 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004191 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004192 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004193 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004194 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004195 statement_no_indent("#endif");
4196 end_scope();
crissdb52e272020-10-08 12:14:52 +02004197
4198 statement("uint subgroupBallotExclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004199 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004200 statement("uvec2 v = value.xy & gl_SubgroupLtMask.xy;");
4201 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004202 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004203 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004204 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004205 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004206 statement_no_indent("#endif");
4207 end_scope();
crissdb52e272020-10-08 12:14:52 +02004208 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004209 statement("");
crissdb52e272020-10-08 12:14:52 +02004210 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004211
crissdb52e272020-10-08 12:14:52 +02004212 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitCount))
4213 {
4214 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4215 statement("uint subgroupBallotBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004216 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004217 statement("ivec2 c = bitCount(value.xy);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004218 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004219 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004220 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004221 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004222 statement_no_indent("#endif");
4223 end_scope();
crissdb52e272020-10-08 12:14:52 +02004224 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004225 statement("");
crissdb52e272020-10-08 12:14:52 +02004226 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004227
crissdb52e272020-10-08 12:14:52 +02004228 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitExtract))
4229 {
4230 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4231 statement("bool subgroupBallotBitExtract(uvec4 value, uint index)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004232 begin_scope();
4233 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004234 statement("uint shifted = value.x >> index;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004235 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004236 statement("uint shifted = value[index >> 5u] >> (index & 0x1fu);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004237 statement_no_indent("#endif");
crissdb52e272020-10-08 12:14:52 +02004238 statement("return (shifted & 1u) != 0u;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004239 end_scope();
crissdb52e272020-10-08 12:14:52 +02004240 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004241 statement("");
crissdb52e272020-10-08 12:14:52 +02004242 }
4243 }
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02004244
4245 if (!workaround_ubo_load_overload_types.empty())
4246 {
4247 for (auto &type_id : workaround_ubo_load_overload_types)
4248 {
4249 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004250 statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type),
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02004251 " wrap) { return wrap; }");
4252 }
4253 statement("");
4254 }
rdbbf719942020-11-05 17:09:33 +01004255
4256 if (requires_transpose_2x2)
4257 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004258 statement("mat2 spvTranspose(mat2 m)");
rdbbf719942020-11-05 17:09:33 +01004259 begin_scope();
4260 statement("return mat2(m[0][0], m[1][0], m[0][1], m[1][1]);");
4261 end_scope();
4262 statement("");
4263 }
4264
4265 if (requires_transpose_3x3)
4266 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004267 statement("mat3 spvTranspose(mat3 m)");
rdbbf719942020-11-05 17:09:33 +01004268 begin_scope();
4269 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]);");
4270 end_scope();
4271 statement("");
4272 }
4273
4274 if (requires_transpose_4x4)
4275 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004276 statement("mat4 spvTranspose(mat4 m)");
rdbbf719942020-11-05 17:09:33 +01004277 begin_scope();
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01004278 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], "
4279 "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 +01004280 end_scope();
4281 statement("");
4282 }
crissdb52e272020-10-08 12:14:52 +02004283}
4284
Bill Hollingsb321b832016-07-06 20:30:47 -04004285// Returns a string representation of the ID, usable as a function arg.
4286// Default is to simply return the expression representation fo the arg ID.
4287// Subclasses may override to modify the return value.
Chip Davis39dce882019-08-02 15:11:19 -05004288string CompilerGLSL::to_func_call_arg(const SPIRFunction::Parameter &, uint32_t id)
Bill Hollingsb321b832016-07-06 20:30:47 -04004289{
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +02004290 // Make sure that we use the name of the original variable, and not the parameter alias.
4291 uint32_t name_id = id;
4292 auto *var = maybe_get<SPIRVariable>(id);
4293 if (var && var->basevariable)
4294 name_id = var->basevariable;
4295 return to_expression(name_id);
Bill Hollingsb321b832016-07-06 20:30:47 -04004296}
4297
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004298void CompilerGLSL::handle_invalid_expression(uint32_t id)
4299{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004300 // We tried to read an invalidated expression.
4301 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +01004302 auto res = forced_temporaries.insert(id);
4303
4304 // Forcing new temporaries guarantees forward progress.
4305 if (res.second)
4306 force_recompile_guarantee_forward_progress();
4307 else
4308 force_recompile();
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004309}
4310
Bill Hollingsb332bae2017-03-01 13:07:40 -05004311// Converts the format of the current expression from packed to unpacked,
4312// by wrapping the expression in a constructor of the appropriate type.
4313// GLSL does not support packed formats, so simply return the expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004314// Subclasses that do will override.
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004315string CompilerGLSL::unpack_expression_type(string expr_str, const SPIRType &, uint32_t, bool, bool)
Bill Hollingsb332bae2017-03-01 13:07:40 -05004316{
4317 return expr_str;
4318}
4319
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01004320// Sometimes we proactively enclosed an expression where it turns out we might have not needed it after all.
4321void CompilerGLSL::strip_enclosed_expression(string &expr)
4322{
4323 if (expr.size() < 2 || expr.front() != '(' || expr.back() != ')')
4324 return;
4325
4326 // Have to make sure that our first and last parens actually enclose everything inside it.
4327 uint32_t paren_count = 0;
4328 for (auto &c : expr)
4329 {
4330 if (c == '(')
4331 paren_count++;
4332 else if (c == ')')
4333 {
4334 paren_count--;
4335
4336 // If we hit 0 and this is not the final char, our first and final parens actually don't
4337 // enclose the expression, and we cannot strip, e.g.: (a + b) * (c + d).
4338 if (paren_count == 0 && &c != &expr.back())
4339 return;
4340 }
4341 }
Corentin Walleze88c88c2017-01-18 17:22:19 -05004342 expr.erase(expr.size() - 1, 1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01004343 expr.erase(begin(expr));
4344}
4345
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004346string CompilerGLSL::enclose_expression(const string &expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004347{
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004348 bool need_parens = false;
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004349
4350 // If the expression starts with a unary we need to enclose to deal with cases where we have back-to-back
4351 // unary expressions.
4352 if (!expr.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004353 {
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004354 auto c = expr.front();
Chip Davis3bfb2f92018-12-03 02:06:33 -06004355 if (c == '-' || c == '+' || c == '!' || c == '~' || c == '&' || c == '*')
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004356 need_parens = true;
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004357 }
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004358
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004359 if (!need_parens)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004360 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004361 uint32_t paren_count = 0;
4362 for (auto c : expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004363 {
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02004364 if (c == '(' || c == '[')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004365 paren_count++;
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02004366 else if (c == ')' || c == ']')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004367 {
4368 assert(paren_count);
4369 paren_count--;
4370 }
4371 else if (c == ' ' && paren_count == 0)
4372 {
4373 need_parens = true;
4374 break;
4375 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004376 }
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004377 assert(paren_count == 0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004378 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004379
4380 // If this expression contains any spaces which are not enclosed by parentheses,
4381 // we need to enclose it so we can treat the whole string as an expression.
4382 // This happens when two expressions have been part of a binary op earlier.
4383 if (need_parens)
4384 return join('(', expr, ')');
4385 else
4386 return expr;
4387}
4388
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02004389string CompilerGLSL::dereference_expression(const SPIRType &expr_type, const std::string &expr)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004390{
4391 // If this expression starts with an address-of operator ('&'), then
4392 // just return the part after the operator.
4393 // TODO: Strip parens if unnecessary?
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01004394 if (expr.front() == '&')
Chip Davis3bfb2f92018-12-03 02:06:33 -06004395 return expr.substr(1);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004396 else if (backend.native_pointers)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004397 return join('*', expr);
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02004398 else if (expr_type.storage == StorageClassPhysicalStorageBufferEXT && expr_type.basetype != SPIRType::Struct &&
4399 expr_type.pointer_depth == 1)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004400 {
4401 return join(enclose_expression(expr), ".value");
4402 }
4403 else
4404 return expr;
Chip Davis3bfb2f92018-12-03 02:06:33 -06004405}
4406
4407string CompilerGLSL::address_of_expression(const std::string &expr)
4408{
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004409 if (expr.size() > 3 && expr[0] == '(' && expr[1] == '*' && expr.back() == ')')
4410 {
4411 // If we have an expression which looks like (*foo), taking the address of it is the same as stripping
4412 // the first two and last characters. We might have to enclose the expression.
4413 // This doesn't work for cases like (*foo + 10),
4414 // but this is an r-value expression which we cannot take the address of anyways.
4415 return enclose_expression(expr.substr(2, expr.size() - 3));
4416 }
4417 else if (expr.front() == '*')
4418 {
4419 // If this expression starts with a dereference operator ('*'), then
4420 // just return the part after the operator.
Chip Davis3bfb2f92018-12-03 02:06:33 -06004421 return expr.substr(1);
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004422 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06004423 else
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004424 return join('&', enclose_expression(expr));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004425}
4426
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004427// Just like to_expression except that we enclose the expression inside parentheses if needed.
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004428string CompilerGLSL::to_enclosed_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004429{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004430 return enclose_expression(to_expression(id, register_expression_read));
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004431}
4432
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004433// Used explicitly when we want to read a row-major expression, but without any transpose shenanigans.
4434// need_transpose must be forced to false.
4435string CompilerGLSL::to_unpacked_row_major_matrix_expression(uint32_t id)
4436{
4437 return unpack_expression_type(to_expression(id), expression_type(id),
4438 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
4439 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), true);
4440}
4441
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004442string CompilerGLSL::to_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004443{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02004444 // If we need to transpose, it will also take care of unpacking rules.
4445 auto *e = maybe_get<SPIRExpression>(id);
4446 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004447 bool is_remapped = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4448 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004449
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004450 if (!need_transpose && (is_remapped || is_packed))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004451 {
Hans-Kristian Arntzen1ece67a2019-07-23 17:06:37 +02004452 return unpack_expression_type(to_expression(id, register_expression_read),
4453 get_pointee_type(expression_type_id(id)),
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004454 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004455 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), false);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004456 }
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004457 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004458 return to_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004459}
4460
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004461string CompilerGLSL::to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004462{
Bill Hollings974a0812021-10-21 16:11:33 -04004463 return enclose_expression(to_unpacked_expression(id, register_expression_read));
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004464}
4465
Chip Davis3bfb2f92018-12-03 02:06:33 -06004466string CompilerGLSL::to_dereferenced_expression(uint32_t id, bool register_expression_read)
4467{
4468 auto &type = expression_type(id);
4469 if (type.pointer && should_dereference(id))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004470 return dereference_expression(type, to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004471 else
4472 return to_expression(id, register_expression_read);
4473}
4474
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004475string CompilerGLSL::to_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004476{
4477 auto &type = expression_type(id);
4478 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004479 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004480 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004481 return to_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004482}
4483
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004484string CompilerGLSL::to_enclosed_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004485{
4486 auto &type = expression_type(id);
4487 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004488 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004489 else
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01004490 return to_enclosed_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004491}
4492
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004493string CompilerGLSL::to_extract_component_expression(uint32_t id, uint32_t index)
4494{
4495 auto expr = to_enclosed_expression(id);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004496 if (has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004497 return join(expr, "[", index, "]");
4498 else
4499 return join(expr, ".", index_to_swizzle(index));
4500}
4501
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +01004502string CompilerGLSL::to_extract_constant_composite_expression(uint32_t result_type, const SPIRConstant &c,
4503 const uint32_t *chain, uint32_t length)
4504{
4505 // It is kinda silly if application actually enter this path since they know the constant up front.
4506 // It is useful here to extract the plain constant directly.
4507 SPIRConstant tmp;
4508 tmp.constant_type = result_type;
4509 auto &composite_type = get<SPIRType>(c.constant_type);
4510 assert(composite_type.basetype != SPIRType::Struct && composite_type.array.empty());
4511 assert(!c.specialization);
4512
4513 if (is_matrix(composite_type))
4514 {
4515 if (length == 2)
4516 {
4517 tmp.m.c[0].vecsize = 1;
4518 tmp.m.columns = 1;
4519 tmp.m.c[0].r[0] = c.m.c[chain[0]].r[chain[1]];
4520 }
4521 else
4522 {
4523 assert(length == 1);
4524 tmp.m.c[0].vecsize = composite_type.vecsize;
4525 tmp.m.columns = 1;
4526 tmp.m.c[0] = c.m.c[chain[0]];
4527 }
4528 }
4529 else
4530 {
4531 assert(length == 1);
4532 tmp.m.c[0].vecsize = 1;
4533 tmp.m.columns = 1;
4534 tmp.m.c[0].r[0] = c.m.c[0].r[chain[0]];
4535 }
4536
4537 return constant_expression(tmp);
4538}
4539
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004540string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
4541{
4542 uint32_t size = to_array_size_literal(type);
4543 auto &parent = get<SPIRType>(type.parent_type);
4544 string expr = "{ ";
4545
4546 for (uint32_t i = 0; i < size; i++)
4547 {
4548 auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
4549 if (parent.array.empty())
4550 expr += subexpr;
4551 else
4552 expr += to_rerolled_array_expression(subexpr, parent);
4553
4554 if (i + 1 < size)
4555 expr += ", ";
4556 }
4557
4558 expr += " }";
4559 return expr;
4560}
4561
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004562string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool uses_buffer_offset)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004563{
4564 auto &type = expression_type(id);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004565
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004566 bool reroll_array = !type.array.empty() && (!backend.array_is_value_type ||
4567 (uses_buffer_offset && !backend.buffer_offset_array_is_value_type));
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004568
4569 if (reroll_array)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004570 {
4571 // For this case, we need to "re-roll" an array initializer from a temporary.
4572 // We cannot simply pass the array directly, since it decays to a pointer and it cannot
4573 // participate in a struct initializer. E.g.
4574 // float arr[2] = { 1.0, 2.0 };
4575 // Foo foo = { arr }; must be transformed to
4576 // Foo foo = { { arr[0], arr[1] } };
4577 // The array sizes cannot be deduced from specialization constants since we cannot use any loops.
4578
4579 // We're only triggering one read of the array expression, but this is fine since arrays have to be declared
4580 // as temporaries anyways.
4581 return to_rerolled_array_expression(to_enclosed_expression(id), type);
4582 }
4583 else
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02004584 return to_unpacked_expression(id);
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004585}
4586
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004587string CompilerGLSL::to_non_uniform_aware_expression(uint32_t id)
4588{
4589 string expr = to_expression(id);
4590
4591 if (has_decoration(id, DecorationNonUniform))
4592 convert_non_uniform_expression(expr, id);
4593
4594 return expr;
4595}
4596
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004597string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004598{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004599 auto itr = invalid_expressions.find(id);
4600 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004601 handle_invalid_expression(id);
4602
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004603 if (ir.ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004604 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004605 // We might have a more complex chain of dependencies.
4606 // A possible scenario is that we
4607 //
4608 // %1 = OpLoad
4609 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
4610 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
4611 // 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.
4612 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
4613 //
4614 // 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,
4615 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004616 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004617 for (uint32_t dep : expr.expression_dependencies)
4618 if (invalid_expressions.find(dep) != end(invalid_expressions))
4619 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004620 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004621
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004622 if (register_expression_read)
4623 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004624
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004625 switch (ir.ids[id].get_type())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004626 {
4627 case TypeExpression:
4628 {
4629 auto &e = get<SPIRExpression>(id);
4630 if (e.base_expression)
Hans-Kristian Arntzenea781e62016-12-06 17:19:34 +01004631 return to_enclosed_expression(e.base_expression) + e.expression;
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02004632 else if (e.need_transpose)
Bill Hollings607b0d62018-02-11 16:52:57 -05004633 {
Hans-Kristian Arntzen2172b192019-07-22 16:27:47 +02004634 // This should not be reached for access chains, since we always deal explicitly with transpose state
4635 // when consuming an access chain expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004636 uint32_t physical_type_id = get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4637 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02004638 return convert_row_major_matrix(e.expression, get<SPIRType>(e.expression_type), physical_type_id,
4639 is_packed);
Bill Hollings607b0d62018-02-11 16:52:57 -05004640 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004641 else if (flattened_structs.count(id))
4642 {
4643 return load_flattened_struct(e.expression, get<SPIRType>(e.expression_type));
4644 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004645 else
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004646 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02004647 if (is_forcing_recompilation())
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004648 {
4649 // During first compilation phase, certain expression patterns can trigger exponential growth of memory.
4650 // Avoid this by returning dummy expressions during this phase.
4651 // Do not use empty expressions here, because those are sentinels for other cases.
4652 return "_";
4653 }
4654 else
4655 return e.expression;
4656 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004657 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004658
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004659 case TypeConstant:
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004660 {
4661 auto &c = get<SPIRConstant>(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004662 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02004663
4664 // WorkGroupSize may be a constant.
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004665 if (has_decoration(c.self, DecorationBuiltIn))
4666 return builtin_to_glsl(BuiltIn(get_decoration(c.self, DecorationBuiltIn)), StorageClassGeneric);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004667 else if (c.specialization)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004668 {
4669 if (backend.workgroup_size_is_hidden)
4670 {
4671 int wg_index = get_constant_mapping_to_workgroup_component(c);
4672 if (wg_index >= 0)
4673 {
4674 auto wg_size = join(builtin_to_glsl(BuiltInWorkgroupSize, StorageClassInput), vector_swizzle(1, wg_index));
4675 if (type.basetype != SPIRType::UInt)
4676 wg_size = bitcast_expression(type, SPIRType::UInt, wg_size);
4677 return wg_size;
4678 }
4679 }
4680
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004681 return to_name(id);
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004682 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02004683 else if (c.is_used_as_lut)
4684 return to_name(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004685 else if (type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
4686 return to_name(id);
4687 else if (!type.array.empty() && !backend.can_declare_arrays_inline)
4688 return to_name(id);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004689 else
4690 return constant_expression(c);
4691 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004692
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004693 case TypeConstantOp:
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01004694 return to_name(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004695
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004696 case TypeVariable:
4697 {
4698 auto &var = get<SPIRVariable>(id);
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01004699 // If we try to use a loop variable before the loop header, we have to redirect it to the static expression,
4700 // the variable has not been declared yet.
4701 if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004702 return to_expression(var.static_expression);
4703 else if (var.deferred_declaration)
4704 {
4705 var.deferred_declaration = false;
4706 return variable_decl(var);
4707 }
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004708 else if (flattened_structs.count(id))
4709 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004710 return load_flattened_struct(to_name(id), get<SPIRType>(var.basetype));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004711 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004712 else
4713 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004714 auto &dec = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004715 if (dec.builtin)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004716 return builtin_to_glsl(dec.builtin_type, var.storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004717 else
4718 return to_name(id);
4719 }
4720 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004721
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02004722 case TypeCombinedImageSampler:
4723 // This type should never be taken the expression of directly.
4724 // The intention is that texture sampling functions will extract the image and samplers
4725 // separately and take their expressions as needed.
4726 // GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
4727 // expression ala sampler2D(texture, sampler).
4728 SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
4729
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004730 case TypeAccessChain:
4731 // We cannot express this type. They only have meaning in other OpAccessChains, OpStore or OpLoad.
4732 SPIRV_CROSS_THROW("Access chains have no default expression representation.");
4733
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004734 default:
4735 return to_name(id);
4736 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004737}
4738
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004739string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
4740{
4741 auto &type = get<SPIRType>(cop.basetype);
4742 bool binary = false;
4743 bool unary = false;
4744 string op;
4745
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004746 if (is_legacy() && is_unsigned_opcode(cop.opcode))
4747 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
4748
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004749 // TODO: Find a clean way to reuse emit_instruction.
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004750 switch (cop.opcode)
4751 {
4752 case OpSConvert:
4753 case OpUConvert:
4754 case OpFConvert:
4755 op = type_to_glsl_constructor(type);
4756 break;
4757
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004758#define GLSL_BOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004759 case Op##opname: \
4760 binary = true; \
4761 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004762 break
4763
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004764#define GLSL_UOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004765 case Op##opname: \
4766 unary = true; \
4767 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004768 break
4769
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004770 GLSL_UOP(SNegate, "-");
4771 GLSL_UOP(Not, "~");
4772 GLSL_BOP(IAdd, "+");
4773 GLSL_BOP(ISub, "-");
4774 GLSL_BOP(IMul, "*");
4775 GLSL_BOP(SDiv, "/");
4776 GLSL_BOP(UDiv, "/");
4777 GLSL_BOP(UMod, "%");
4778 GLSL_BOP(SMod, "%");
4779 GLSL_BOP(ShiftRightLogical, ">>");
4780 GLSL_BOP(ShiftRightArithmetic, ">>");
4781 GLSL_BOP(ShiftLeftLogical, "<<");
4782 GLSL_BOP(BitwiseOr, "|");
4783 GLSL_BOP(BitwiseXor, "^");
4784 GLSL_BOP(BitwiseAnd, "&");
4785 GLSL_BOP(LogicalOr, "||");
4786 GLSL_BOP(LogicalAnd, "&&");
4787 GLSL_UOP(LogicalNot, "!");
4788 GLSL_BOP(LogicalEqual, "==");
4789 GLSL_BOP(LogicalNotEqual, "!=");
4790 GLSL_BOP(IEqual, "==");
4791 GLSL_BOP(INotEqual, "!=");
4792 GLSL_BOP(ULessThan, "<");
4793 GLSL_BOP(SLessThan, "<");
4794 GLSL_BOP(ULessThanEqual, "<=");
4795 GLSL_BOP(SLessThanEqual, "<=");
4796 GLSL_BOP(UGreaterThan, ">");
4797 GLSL_BOP(SGreaterThan, ">");
4798 GLSL_BOP(UGreaterThanEqual, ">=");
4799 GLSL_BOP(SGreaterThanEqual, ">=");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004800
Bill Hollings5fb1ca42021-09-03 18:20:49 -04004801 case OpSRem:
4802 {
4803 uint32_t op0 = cop.arguments[0];
4804 uint32_t op1 = cop.arguments[1];
4805 return join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
4806 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
4807 }
4808
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004809 case OpSelect:
4810 {
4811 if (cop.arguments.size() < 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004812 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004813
4814 // This one is pretty annoying. It's triggered from
4815 // uint(bool), int(bool) from spec constants.
4816 // In order to preserve its compile-time constness in Vulkan GLSL,
4817 // we need to reduce the OpSelect expression back to this simplified model.
4818 // If we cannot, fail.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004819 if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004820 {
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004821 // Implement as a simple cast down below.
4822 }
4823 else
4824 {
4825 // Implement a ternary and pray the compiler understands it :)
4826 return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004827 }
4828 break;
4829 }
4830
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02004831 case OpVectorShuffle:
4832 {
4833 string expr = type_to_glsl_constructor(type);
4834 expr += "(";
4835
4836 uint32_t left_components = expression_type(cop.arguments[0]).vecsize;
4837 string left_arg = to_enclosed_expression(cop.arguments[0]);
4838 string right_arg = to_enclosed_expression(cop.arguments[1]);
4839
4840 for (uint32_t i = 2; i < uint32_t(cop.arguments.size()); i++)
4841 {
4842 uint32_t index = cop.arguments[i];
4843 if (index >= left_components)
4844 expr += right_arg + "." + "xyzw"[index - left_components];
4845 else
4846 expr += left_arg + "." + "xyzw"[index];
4847
4848 if (i + 1 < uint32_t(cop.arguments.size()))
4849 expr += ", ";
4850 }
4851
4852 expr += ")";
4853 return expr;
4854 }
4855
4856 case OpCompositeExtract:
4857 {
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01004858 auto expr = access_chain_internal(cop.arguments[0], &cop.arguments[1], uint32_t(cop.arguments.size() - 1),
4859 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02004860 return expr;
4861 }
4862
4863 case OpCompositeInsert:
4864 SPIRV_CROSS_THROW("OpCompositeInsert spec constant op is not supported.");
4865
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004866 default:
4867 // Some opcodes are unimplemented here, these are currently not possible to test from glslang.
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004868 SPIRV_CROSS_THROW("Unimplemented spec constant op.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004869 }
4870
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004871 uint32_t bit_width = 0;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004872 if (unary || binary || cop.opcode == OpSConvert || cop.opcode == OpUConvert)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004873 bit_width = expression_type(cop.arguments[0]).width;
4874
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004875 SPIRType::BaseType input_type;
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004876 bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004877
4878 switch (cop.opcode)
4879 {
4880 case OpIEqual:
4881 case OpINotEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004882 input_type = to_signed_basetype(bit_width);
4883 break;
4884
4885 case OpSLessThan:
4886 case OpSLessThanEqual:
4887 case OpSGreaterThan:
4888 case OpSGreaterThanEqual:
4889 case OpSMod:
4890 case OpSDiv:
4891 case OpShiftRightArithmetic:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004892 case OpSConvert:
4893 case OpSNegate:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004894 input_type = to_signed_basetype(bit_width);
4895 break;
4896
4897 case OpULessThan:
4898 case OpULessThanEqual:
4899 case OpUGreaterThan:
4900 case OpUGreaterThanEqual:
4901 case OpUMod:
4902 case OpUDiv:
4903 case OpShiftRightLogical:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004904 case OpUConvert:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004905 input_type = to_unsigned_basetype(bit_width);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004906 break;
4907
4908 default:
4909 input_type = type.basetype;
4910 break;
4911 }
4912
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004913#undef GLSL_BOP
4914#undef GLSL_UOP
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004915 if (binary)
4916 {
4917 if (cop.arguments.size() < 2)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004918 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004919
4920 string cast_op0;
4921 string cast_op1;
4922 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, cop.arguments[0],
4923 cop.arguments[1], skip_cast_if_equal_type);
4924
4925 if (type.basetype != input_type && type.basetype != SPIRType::Boolean)
4926 {
4927 expected_type.basetype = input_type;
4928 auto expr = bitcast_glsl_op(type, expected_type);
4929 expr += '(';
4930 expr += join(cast_op0, " ", op, " ", cast_op1);
4931 expr += ')';
4932 return expr;
4933 }
4934 else
4935 return join("(", cast_op0, " ", op, " ", cast_op1, ")");
4936 }
4937 else if (unary)
4938 {
4939 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004940 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004941
4942 // Auto-bitcast to result type as needed.
4943 // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
4944 return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")");
4945 }
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004946 else if (cop.opcode == OpSConvert || cop.opcode == OpUConvert)
4947 {
4948 if (cop.arguments.size() < 1)
4949 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
4950
4951 auto &arg_type = expression_type(cop.arguments[0]);
4952 if (arg_type.width < type.width && input_type != arg_type.basetype)
4953 {
4954 auto expected = arg_type;
4955 expected.basetype = input_type;
4956 return join(op, "(", bitcast_glsl(expected, cop.arguments[0]), ")");
4957 }
4958 else
4959 return join(op, "(", to_expression(cop.arguments[0]), ")");
4960 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004961 else
4962 {
4963 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004964 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004965 return join(op, "(", to_expression(cop.arguments[0]), ")");
4966 }
4967}
4968
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004969string CompilerGLSL::constant_expression(const SPIRConstant &c)
4970{
Chip Davis3bfb2f92018-12-03 02:06:33 -06004971 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004972
Chip Davis3bfb2f92018-12-03 02:06:33 -06004973 if (type.pointer)
4974 {
4975 return backend.null_pointer_literal;
4976 }
4977 else if (!c.subconstants.empty())
4978 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004979 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004980 string res;
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004981
Lukas Hermanns50ac6862019-09-18 14:03:54 -04004982 // Allow Metal to use the array<T> template to make arrays a value type
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004983 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen57a15df2018-09-10 10:08:02 +02004984 if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004985 type.array.empty())
4986 {
4987 res = type_to_glsl_constructor(type) + "{ ";
4988 }
Hans-Kristian Arntzenc2655ab2020-03-19 14:21:42 +01004989 else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
4990 !type.array.empty())
Mark Satterthwaited50659a2019-08-13 18:18:48 -04004991 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02004992 res = type_to_glsl_constructor(type) + "({ ";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004993 needs_trailing_tracket = true;
Mark Satterthwaited50659a2019-08-13 18:18:48 -04004994 }
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004995 else if (backend.use_initializer_list)
4996 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004997 res = "{ ";
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004998 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004999 else
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02005000 {
5001 res = type_to_glsl_constructor(type) + "(";
5002 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005003
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005004 for (auto &elem : c.subconstants)
5005 {
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02005006 auto &subc = get<SPIRConstant>(elem);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005007 if (subc.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02005008 res += to_name(elem);
5009 else
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02005010 res += constant_expression(subc);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02005011
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005012 if (&elem != &c.subconstants.back())
5013 res += ", ";
5014 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005015
5016 res += backend.use_initializer_list ? " }" : ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005017 if (needs_trailing_tracket)
Mark Satterthwaited50659a2019-08-13 18:18:48 -04005018 res += ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005019
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005020 return res;
5021 }
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04005022 else if (type.basetype == SPIRType::Struct && type.member_types.size() == 0)
5023 {
5024 // Metal tessellation likes empty structs which are then constant expressions.
Hans-Kristian Arntzen3b5c4c72019-10-24 17:05:55 +02005025 if (backend.supports_empty_struct)
5026 return "{ }";
5027 else if (backend.use_typed_initializer_list)
5028 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "{ 0 }");
5029 else if (backend.use_initializer_list)
5030 return "{ 0 }";
5031 else
5032 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "(0)");
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04005033 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005034 else if (c.columns() == 1)
5035 {
5036 return constant_expression_vector(c, 0);
5037 }
5038 else
5039 {
5040 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
5041 for (uint32_t col = 0; col < c.columns(); col++)
5042 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005043 if (c.specialization_constant_id(col) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005044 res += to_name(c.specialization_constant_id(col));
5045 else
5046 res += constant_expression_vector(c, col);
5047
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005048 if (col + 1 < c.columns())
5049 res += ", ";
5050 }
5051 res += ")";
5052 return res;
5053 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005054}
5055
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005056#ifdef _MSC_VER
5057// sprintf warning.
5058// We cannot rely on snprintf existing because, ..., MSVC.
5059#pragma warning(push)
5060#pragma warning(disable : 4996)
5061#endif
5062
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005063string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5064{
5065 string res;
5066 float float_value = c.scalar_f16(col, row);
5067
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005068 // There is no literal "hf" in GL_NV_gpu_shader5, so to avoid lots
5069 // of complicated workarounds, just value-cast to the half type always.
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005070 if (std::isnan(float_value) || std::isinf(float_value))
5071 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005072 SPIRType type;
5073 type.basetype = SPIRType::Half;
5074 type.vecsize = 1;
5075 type.columns = 1;
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005076
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005077 if (float_value == numeric_limits<float>::infinity())
5078 res = join(type_to_glsl(type), "(1.0 / 0.0)");
5079 else if (float_value == -numeric_limits<float>::infinity())
5080 res = join(type_to_glsl(type), "(-1.0 / 0.0)");
5081 else if (std::isnan(float_value))
5082 res = join(type_to_glsl(type), "(0.0 / 0.0)");
5083 else
5084 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005085 }
5086 else
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005087 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005088 SPIRType type;
5089 type.basetype = SPIRType::Half;
5090 type.vecsize = 1;
5091 type.columns = 1;
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005092 res = join(type_to_glsl(type), "(", convert_to_string(float_value, current_locale_radix_character), ")");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005093 }
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005094
5095 return res;
5096}
5097
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005098string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5099{
5100 string res;
5101 float float_value = c.scalar_f32(col, row);
5102
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005103 if (std::isnan(float_value) || std::isinf(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005104 {
5105 // Use special representation.
5106 if (!is_legacy())
5107 {
5108 SPIRType out_type;
5109 SPIRType in_type;
5110 out_type.basetype = SPIRType::Float;
5111 in_type.basetype = SPIRType::UInt;
5112 out_type.vecsize = 1;
5113 in_type.vecsize = 1;
5114 out_type.width = 32;
5115 in_type.width = 32;
5116
5117 char print_buffer[32];
5118 sprintf(print_buffer, "0x%xu", c.scalar(col, row));
xndcn02fb8f22021-05-26 22:43:26 +08005119
5120 const char *comment = "inf";
5121 if (float_value == -numeric_limits<float>::infinity())
5122 comment = "-inf";
5123 else if (std::isnan(float_value))
5124 comment = "nan";
5125 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005126 }
5127 else
5128 {
5129 if (float_value == numeric_limits<float>::infinity())
5130 {
5131 if (backend.float_literal_suffix)
5132 res = "(1.0f / 0.0f)";
5133 else
5134 res = "(1.0 / 0.0)";
5135 }
5136 else if (float_value == -numeric_limits<float>::infinity())
5137 {
5138 if (backend.float_literal_suffix)
5139 res = "(-1.0f / 0.0f)";
5140 else
5141 res = "(-1.0 / 0.0)";
5142 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005143 else if (std::isnan(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005144 {
5145 if (backend.float_literal_suffix)
5146 res = "(0.0f / 0.0f)";
5147 else
5148 res = "(0.0 / 0.0)";
5149 }
5150 else
5151 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
5152 }
5153 }
5154 else
5155 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005156 res = convert_to_string(float_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005157 if (backend.float_literal_suffix)
5158 res += "f";
5159 }
5160
5161 return res;
5162}
5163
5164std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5165{
5166 string res;
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005167 double double_value = c.scalar_f64(col, row);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005168
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005169 if (std::isnan(double_value) || std::isinf(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005170 {
5171 // Use special representation.
5172 if (!is_legacy())
5173 {
5174 SPIRType out_type;
5175 SPIRType in_type;
5176 out_type.basetype = SPIRType::Double;
5177 in_type.basetype = SPIRType::UInt64;
5178 out_type.vecsize = 1;
5179 in_type.vecsize = 1;
5180 out_type.width = 64;
5181 in_type.width = 64;
5182
5183 uint64_t u64_value = c.scalar_u64(col, row);
5184
5185 if (options.es)
5186 SPIRV_CROSS_THROW("64-bit integers/float not supported in ES profile.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005187 require_extension_internal("GL_ARB_gpu_shader_int64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005188
5189 char print_buffer[64];
5190 sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
5191 backend.long_long_literal_suffix ? "ull" : "ul");
xndcn02fb8f22021-05-26 22:43:26 +08005192
5193 const char *comment = "inf";
5194 if (double_value == -numeric_limits<double>::infinity())
5195 comment = "-inf";
5196 else if (std::isnan(double_value))
5197 comment = "nan";
5198 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005199 }
5200 else
5201 {
5202 if (options.es)
5203 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
5204 if (options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005205 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005206
5207 if (double_value == numeric_limits<double>::infinity())
5208 {
5209 if (backend.double_literal_suffix)
5210 res = "(1.0lf / 0.0lf)";
5211 else
5212 res = "(1.0 / 0.0)";
5213 }
5214 else if (double_value == -numeric_limits<double>::infinity())
5215 {
5216 if (backend.double_literal_suffix)
5217 res = "(-1.0lf / 0.0lf)";
5218 else
5219 res = "(-1.0 / 0.0)";
5220 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005221 else if (std::isnan(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005222 {
5223 if (backend.double_literal_suffix)
5224 res = "(0.0lf / 0.0lf)";
5225 else
5226 res = "(0.0 / 0.0)";
5227 }
5228 else
5229 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
5230 }
5231 }
5232 else
5233 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005234 res = convert_to_string(double_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005235 if (backend.double_literal_suffix)
5236 res += "lf";
5237 }
5238
5239 return res;
5240}
5241
5242#ifdef _MSC_VER
5243#pragma warning(pop)
5244#endif
5245
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005246string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
5247{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005248 auto type = get<SPIRType>(c.constant_type);
5249 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005250
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005251 auto scalar_type = type;
5252 scalar_type.vecsize = 1;
5253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005254 string res;
Robert Konradea24ee82016-09-23 18:57:18 +02005255 bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005256 bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005257
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005258 if (!type_is_floating_point(type))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005259 {
5260 // Cannot swizzle literal integers as a special case.
5261 swizzle_splat = false;
5262 }
5263
5264 if (splat || swizzle_splat)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005265 {
5266 // Cannot use constant splatting if we have specialization constants somewhere in the vector.
5267 for (uint32_t i = 0; i < c.vector_size(); i++)
5268 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005269 if (c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005270 {
5271 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005272 swizzle_splat = false;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005273 break;
5274 }
5275 }
5276 }
5277
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005278 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005279 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02005280 if (type.width == 64)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005281 {
5282 uint64_t ident = c.scalar_u64(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_u64(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 break;
5290 }
5291 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005292 }
5293 else
5294 {
5295 uint32_t ident = c.scalar(vector, 0);
5296 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005297 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005298 if (ident != c.scalar(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005299 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005300 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005301 swizzle_splat = false;
5302 }
5303 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005304 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005305 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005306
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005307 if (c.vector_size() > 1 && !swizzle_splat)
5308 res += type_to_glsl(type) + "(";
5309
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005310 switch (type.basetype)
5311 {
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005312 case SPIRType::Half:
5313 if (splat || swizzle_splat)
5314 {
5315 res += convert_half_to_string(c, vector, 0);
5316 if (swizzle_splat)
5317 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
5318 }
5319 else
5320 {
5321 for (uint32_t i = 0; i < c.vector_size(); i++)
5322 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005323 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005324 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005325 else
5326 res += convert_half_to_string(c, vector, i);
5327
5328 if (i + 1 < c.vector_size())
5329 res += ", ";
5330 }
5331 }
5332 break;
5333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005334 case SPIRType::Float:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005335 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005336 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005337 res += convert_float_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005338 if (swizzle_splat)
5339 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005340 }
5341 else
5342 {
5343 for (uint32_t i = 0; i < c.vector_size(); i++)
5344 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005345 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005346 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005347 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005348 res += convert_float_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005349
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005350 if (i + 1 < c.vector_size())
5351 res += ", ";
5352 }
5353 }
5354 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005355
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005356 case SPIRType::Double:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005357 if (splat || swizzle_splat)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005358 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005359 res += convert_double_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005360 if (swizzle_splat)
5361 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005362 }
5363 else
5364 {
5365 for (uint32_t i = 0; i < c.vector_size(); i++)
5366 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005367 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005368 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005369 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005370 res += convert_double_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005371
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005372 if (i + 1 < c.vector_size())
5373 res += ", ";
5374 }
5375 }
5376 break;
5377
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005378 case SPIRType::Int64:
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005379 {
5380 auto tmp = type;
5381 tmp.vecsize = 1;
5382 tmp.columns = 1;
5383 auto int64_type = type_to_glsl(tmp);
5384
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005385 if (splat)
5386 {
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005387 res += convert_to_string(c.scalar_i64(vector, 0), int64_type, backend.long_long_literal_suffix);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005388 }
5389 else
5390 {
5391 for (uint32_t i = 0; i < c.vector_size(); i++)
5392 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005393 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005394 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005395 else
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005396 res += convert_to_string(c.scalar_i64(vector, i), int64_type, backend.long_long_literal_suffix);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005397
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005398 if (i + 1 < c.vector_size())
5399 res += ", ";
5400 }
5401 }
5402 break;
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005403 }
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005404
5405 case SPIRType::UInt64:
5406 if (splat)
5407 {
5408 res += convert_to_string(c.scalar_u64(vector, 0));
5409 if (backend.long_long_literal_suffix)
5410 res += "ull";
5411 else
5412 res += "ul";
5413 }
5414 else
5415 {
5416 for (uint32_t i = 0; i < c.vector_size(); i++)
5417 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005418 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005419 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005420 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005421 {
5422 res += convert_to_string(c.scalar_u64(vector, i));
5423 if (backend.long_long_literal_suffix)
5424 res += "ull";
5425 else
5426 res += "ul";
5427 }
5428
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005429 if (i + 1 < c.vector_size())
5430 res += ", ";
5431 }
5432 }
5433 break;
5434
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005435 case SPIRType::UInt:
5436 if (splat)
5437 {
5438 res += convert_to_string(c.scalar(vector, 0));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005439 if (is_legacy())
5440 {
5441 // Fake unsigned constant literals with signed ones if possible.
5442 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
5443 if (c.scalar_i32(vector, 0) < 0)
5444 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative.");
5445 }
5446 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005447 res += "u";
5448 }
5449 else
5450 {
5451 for (uint32_t i = 0; i < c.vector_size(); i++)
5452 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005453 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005454 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005455 else
5456 {
5457 res += convert_to_string(c.scalar(vector, i));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005458 if (is_legacy())
5459 {
5460 // Fake unsigned constant literals with signed ones if possible.
5461 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
5462 if (c.scalar_i32(vector, i) < 0)
crissdb52e272020-10-08 12:14:52 +02005463 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made "
5464 "the literal negative.");
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005465 }
5466 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005467 res += "u";
5468 }
5469
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005470 if (i + 1 < c.vector_size())
5471 res += ", ";
5472 }
5473 }
5474 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005475
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005476 case SPIRType::Int:
5477 if (splat)
5478 res += convert_to_string(c.scalar_i32(vector, 0));
5479 else
5480 {
5481 for (uint32_t i = 0; i < c.vector_size(); i++)
5482 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005483 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005484 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005485 else
5486 res += convert_to_string(c.scalar_i32(vector, i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005487 if (i + 1 < c.vector_size())
5488 res += ", ";
5489 }
5490 }
5491 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005492
Chip Davisca4744a2018-11-02 14:39:55 -05005493 case SPIRType::UShort:
5494 if (splat)
5495 {
5496 res += convert_to_string(c.scalar(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005497 }
5498 else
5499 {
5500 for (uint32_t i = 0; i < c.vector_size(); i++)
5501 {
5502 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005503 res += to_expression(c.specialization_constant_id(vector, i));
Chip Davisca4744a2018-11-02 14:39:55 -05005504 else
5505 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005506 if (*backend.uint16_t_literal_suffix)
Chip Davisca4744a2018-11-02 14:39:55 -05005507 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005508 res += convert_to_string(c.scalar_u16(vector, i));
5509 res += backend.uint16_t_literal_suffix;
Chip Davisca4744a2018-11-02 14:39:55 -05005510 }
Bill Hollingsc48702d2019-03-28 14:23:32 -04005511 else
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005512 {
5513 // If backend doesn't have a literal suffix, we need to value cast.
5514 res += type_to_glsl(scalar_type);
5515 res += "(";
5516 res += convert_to_string(c.scalar_u16(vector, i));
5517 res += ")";
5518 }
Chip Davisca4744a2018-11-02 14:39:55 -05005519 }
5520
5521 if (i + 1 < c.vector_size())
5522 res += ", ";
5523 }
5524 }
5525 break;
5526
5527 case SPIRType::Short:
5528 if (splat)
5529 {
5530 res += convert_to_string(c.scalar_i16(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005531 }
5532 else
5533 {
5534 for (uint32_t i = 0; i < c.vector_size(); i++)
5535 {
5536 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005537 res += to_expression(c.specialization_constant_id(vector, i));
Chip Davisca4744a2018-11-02 14:39:55 -05005538 else
5539 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005540 if (*backend.int16_t_literal_suffix)
5541 {
5542 res += convert_to_string(c.scalar_i16(vector, i));
5543 res += backend.int16_t_literal_suffix;
5544 }
5545 else
5546 {
5547 // If backend doesn't have a literal suffix, we need to value cast.
5548 res += type_to_glsl(scalar_type);
5549 res += "(";
5550 res += convert_to_string(c.scalar_i16(vector, i));
5551 res += ")";
5552 }
Chip Davisca4744a2018-11-02 14:39:55 -05005553 }
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005554
Chip Davisca4744a2018-11-02 14:39:55 -05005555 if (i + 1 < c.vector_size())
5556 res += ", ";
5557 }
5558 }
5559 break;
5560
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005561 case SPIRType::UByte:
5562 if (splat)
5563 {
5564 res += convert_to_string(c.scalar_u8(vector, 0));
5565 }
5566 else
5567 {
5568 for (uint32_t i = 0; i < c.vector_size(); i++)
5569 {
5570 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005571 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005572 else
5573 {
5574 res += type_to_glsl(scalar_type);
5575 res += "(";
5576 res += convert_to_string(c.scalar_u8(vector, i));
5577 res += ")";
5578 }
5579
5580 if (i + 1 < c.vector_size())
5581 res += ", ";
5582 }
5583 }
5584 break;
5585
5586 case SPIRType::SByte:
5587 if (splat)
5588 {
5589 res += convert_to_string(c.scalar_i8(vector, 0));
5590 }
5591 else
5592 {
5593 for (uint32_t i = 0; i < c.vector_size(); i++)
5594 {
5595 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005596 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005597 else
5598 {
5599 res += type_to_glsl(scalar_type);
5600 res += "(";
5601 res += convert_to_string(c.scalar_i8(vector, i));
5602 res += ")";
5603 }
5604
5605 if (i + 1 < c.vector_size())
5606 res += ", ";
5607 }
5608 }
5609 break;
5610
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005611 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005612 if (splat)
5613 res += c.scalar(vector, 0) ? "true" : "false";
5614 else
5615 {
5616 for (uint32_t i = 0; i < c.vector_size(); i++)
5617 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005618 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005619 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005620 else
5621 res += c.scalar(vector, i) ? "true" : "false";
5622
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005623 if (i + 1 < c.vector_size())
5624 res += ", ";
5625 }
5626 }
5627 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005628
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005629 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005630 SPIRV_CROSS_THROW("Invalid constant expression basetype.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005631 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005632
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005633 if (c.vector_size() > 1 && !swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005634 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005636 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005637}
5638
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005639SPIRExpression &CompilerGLSL::emit_uninitialized_temporary_expression(uint32_t type, uint32_t id)
5640{
5641 forced_temporaries.insert(id);
5642 emit_uninitialized_temporary(type, id);
5643 return set<SPIRExpression>(id, to_name(id), type, true);
5644}
5645
5646void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t result_id)
5647{
5648 // If we're declaring temporaries inside continue blocks,
5649 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
5650 if (current_continue_block && !hoisted_temporaries.count(result_id))
5651 {
5652 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5653 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
5654 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
5655 return tmp.first == result_type && tmp.second == result_id;
5656 }) == end(header.declare_temporary))
5657 {
5658 header.declare_temporary.emplace_back(result_type, result_id);
5659 hoisted_temporaries.insert(result_id);
5660 force_recompile();
5661 }
5662 }
5663 else if (hoisted_temporaries.count(result_id) == 0)
5664 {
5665 auto &type = get<SPIRType>(result_type);
5666 auto &flags = ir.meta[result_id].decoration.decoration_flags;
5667
5668 // The result_id has not been made into an expression yet, so use flags interface.
5669 add_local_variable_name(result_id);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01005670
5671 string initializer;
5672 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
5673 initializer = join(" = ", to_zero_initialized_expression(result_type));
5674
5675 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), initializer, ";");
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005676 }
5677}
5678
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005679string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
5680{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005681 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01005682 auto &flags = ir.meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005683
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005684 // If we're declaring temporaries inside continue blocks,
5685 // 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 +01005686 if (current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005687 {
5688 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5689 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005690 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005691 return tmp.first == result_type && tmp.second == result_id;
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01005692 }) == end(header.declare_temporary))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005693 {
5694 header.declare_temporary.emplace_back(result_type, result_id);
Hans-Kristian Arntzen7d223b82018-01-18 12:07:10 +01005695 hoisted_temporaries.insert(result_id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02005696 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005697 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005698
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005699 return join(to_name(result_id), " = ");
5700 }
Hans-Kristian Arntzenb629ca12017-11-21 09:27:49 +01005701 else if (hoisted_temporaries.count(result_id))
5702 {
5703 // The temporary has already been declared earlier, so just "declare" the temporary by writing to it.
5704 return join(to_name(result_id), " = ");
5705 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005706 else
5707 {
5708 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen35f64d02018-03-24 01:53:08 +01005709 add_local_variable_name(result_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02005710 return join(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005711 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005712}
5713
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005714bool CompilerGLSL::expression_is_forwarded(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005715{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005716 return forwarded_temporaries.count(id) != 0;
5717}
5718
5719bool CompilerGLSL::expression_suppresses_usage_tracking(uint32_t id) const
5720{
5721 return suppressed_usage_tracking.count(id) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005722}
5723
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02005724bool CompilerGLSL::expression_read_implies_multiple_reads(uint32_t id) const
5725{
5726 auto *expr = maybe_get<SPIRExpression>(id);
5727 if (!expr)
5728 return false;
5729
5730 // If we're emitting code at a deeper loop level than when we emitted the expression,
5731 // we're probably reading the same expression over and over.
5732 return current_loop_level > expr->emitted_loop_level;
5733}
5734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005735SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005736 bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005737{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005738 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
5739 {
5740 // Just forward it without temporary.
5741 // If the forward is trivial, we do not force flushing to temporary for this expression.
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005742 forwarded_temporaries.insert(result_id);
5743 if (suppress_usage_tracking)
5744 suppressed_usage_tracking.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005745
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005746 return set<SPIRExpression>(result_id, rhs, result_type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005747 }
5748 else
5749 {
5750 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
5751 statement(declare_temporary(result_type, result_id), rhs, ";");
5752 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
5753 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005754}
5755
5756void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
5757{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005758 bool forward = should_forward(op0);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005759 emit_op(result_type, result_id, join(op, to_enclosed_unpacked_expression(op0)), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005760 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005761}
5762
5763void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
5764{
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +02005765 // Various FP arithmetic opcodes such as add, sub, mul will hit this.
5766 bool force_temporary_precise = backend.support_precise_qualifier &&
5767 has_decoration(result_id, DecorationNoContraction) &&
5768 type_is_floating_point(get<SPIRType>(result_type));
5769 bool forward = should_forward(op0) && should_forward(op1) && !force_temporary_precise;
5770
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005771 emit_op(result_type, result_id,
5772 join(to_enclosed_unpacked_expression(op0), " ", op, " ", to_enclosed_unpacked_expression(op1)), forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005773
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005774 inherit_expression_dependencies(result_id, op0);
5775 inherit_expression_dependencies(result_id, op1);
5776}
5777
Robert Konradf3a82772017-03-24 15:00:48 +01005778void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
5779{
5780 auto &type = get<SPIRType>(result_type);
5781 auto expr = type_to_glsl_constructor(type);
5782 expr += '(';
5783 for (uint32_t i = 0; i < type.vecsize; i++)
5784 {
5785 // Make sure to call to_expression multiple times to ensure
5786 // that these expressions are properly flushed to temporaries if needed.
5787 expr += op;
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02005788 expr += to_extract_component_expression(operand, i);
Robert Konradf3a82772017-03-24 15:00:48 +01005789
5790 if (i + 1 < type.vecsize)
5791 expr += ", ";
5792 }
5793 expr += ')';
5794 emit_op(result_type, result_id, expr, should_forward(operand));
5795
5796 inherit_expression_dependencies(result_id, operand);
5797}
5798
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005799void 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 +02005800 const char *op, bool negate, SPIRType::BaseType expected_type)
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005801{
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005802 auto &type0 = expression_type(op0);
5803 auto &type1 = expression_type(op1);
5804
5805 SPIRType target_type0 = type0;
5806 SPIRType target_type1 = type1;
5807 target_type0.basetype = expected_type;
5808 target_type1.basetype = expected_type;
5809 target_type0.vecsize = 1;
5810 target_type1.vecsize = 1;
5811
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005812 auto &type = get<SPIRType>(result_type);
5813 auto expr = type_to_glsl_constructor(type);
5814 expr += '(';
5815 for (uint32_t i = 0; i < type.vecsize; i++)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005816 {
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005817 // Make sure to call to_expression multiple times to ensure
5818 // that these expressions are properly flushed to temporaries if needed.
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005819 if (negate)
5820 expr += "!(";
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005821
5822 if (expected_type != SPIRType::Unknown && type0.basetype != expected_type)
5823 expr += bitcast_expression(target_type0, type0.basetype, to_extract_component_expression(op0, i));
5824 else
5825 expr += to_extract_component_expression(op0, i);
5826
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005827 expr += ' ';
5828 expr += op;
5829 expr += ' ';
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005830
5831 if (expected_type != SPIRType::Unknown && type1.basetype != expected_type)
5832 expr += bitcast_expression(target_type1, type1.basetype, to_extract_component_expression(op1, i));
5833 else
5834 expr += to_extract_component_expression(op1, i);
5835
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005836 if (negate)
5837 expr += ")";
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005838
5839 if (i + 1 < type.vecsize)
5840 expr += ", ";
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005841 }
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005842 expr += ')';
5843 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
5844
5845 inherit_expression_dependencies(result_id, op0);
5846 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005847}
5848
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005849SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
5850 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
5851{
5852 auto &type0 = expression_type(op0);
5853 auto &type1 = expression_type(op1);
5854
5855 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
5856 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
5857 // since equality test is exactly the same.
5858 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
5859
5860 // Create a fake type so we can bitcast to it.
5861 // We only deal with regular arithmetic types here like int, uints and so on.
5862 SPIRType expected_type;
5863 expected_type.basetype = input_type;
5864 expected_type.vecsize = type0.vecsize;
5865 expected_type.columns = type0.columns;
5866 expected_type.width = type0.width;
5867
5868 if (cast)
5869 {
5870 cast_op0 = bitcast_glsl(expected_type, op0);
5871 cast_op1 = bitcast_glsl(expected_type, op1);
5872 }
5873 else
5874 {
5875 // 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 +02005876 cast_op0 = to_enclosed_unpacked_expression(op0);
5877 cast_op1 = to_enclosed_unpacked_expression(op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005878 input_type = type0.basetype;
5879 }
5880
5881 return expected_type;
5882}
5883
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02005884bool CompilerGLSL::emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0)
5885{
5886 // Some bitcasts may require complex casting sequences, and are implemented here.
5887 // Otherwise a simply unary function will do with bitcast_glsl_op.
5888
5889 auto &output_type = get<SPIRType>(result_type);
5890 auto &input_type = expression_type(op0);
5891 string expr;
5892
5893 if (output_type.basetype == SPIRType::Half && input_type.basetype == SPIRType::Float && input_type.vecsize == 1)
5894 expr = join("unpackFloat2x16(floatBitsToUint(", to_unpacked_expression(op0), "))");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02005895 else if (output_type.basetype == SPIRType::Float && input_type.basetype == SPIRType::Half &&
5896 input_type.vecsize == 2)
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02005897 expr = join("uintBitsToFloat(packFloat2x16(", to_unpacked_expression(op0), "))");
5898 else
5899 return false;
5900
5901 emit_op(result_type, id, expr, should_forward(op0));
5902 return true;
5903}
5904
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005905void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5906 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
5907{
5908 string cast_op0, cast_op1;
5909 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
5910 auto &out_type = get<SPIRType>(result_type);
5911
5912 // We might have casted away from the result type, so bitcast again.
5913 // For example, arithmetic right shift with uint inputs.
5914 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005915 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005916 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005917 {
5918 expected_type.basetype = input_type;
5919 expr = bitcast_glsl_op(out_type, expected_type);
5920 expr += '(';
5921 expr += join(cast_op0, " ", op, " ", cast_op1);
5922 expr += ')';
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005923 }
5924 else
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005925 expr += join(cast_op0, " ", op, " ", cast_op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005926
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005927 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005928 inherit_expression_dependencies(result_id, op0);
5929 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005930}
5931
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005932void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
5933{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005934 bool forward = should_forward(op0);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005935 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005936 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005937}
5938
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005939void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5940 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005941{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005942 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005943 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ")"),
5944 forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005945 inherit_expression_dependencies(result_id, op0);
5946 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005947}
5948
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005949void CompilerGLSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5950 const char *op)
5951{
5952 forced_temporaries.insert(result_id);
5953 emit_op(result_type, result_id,
5954 join(op, "(", to_non_uniform_aware_expression(op0), ", ",
5955 to_unpacked_expression(op1), ")"), false);
5956 flush_all_atomic_capable_variables();
5957}
5958
5959void CompilerGLSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id,
5960 uint32_t op0, uint32_t op1, uint32_t op2,
5961 const char *op)
5962{
5963 forced_temporaries.insert(result_id);
5964 emit_op(result_type, result_id,
5965 join(op, "(", to_non_uniform_aware_expression(op0), ", ",
5966 to_unpacked_expression(op1), ", ", to_unpacked_expression(op2), ")"), false);
5967 flush_all_atomic_capable_variables();
5968}
5969
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005970void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op,
5971 SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type)
5972{
5973 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005974 auto &expr_type = expression_type(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005975 auto expected_type = out_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005976
5977 // 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 +01005978 expected_type.basetype = input_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005979 expected_type.width = expr_type.width;
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01005980
5981 string cast_op;
5982 if (expr_type.basetype != input_type)
5983 {
5984 if (expr_type.basetype == SPIRType::Boolean)
5985 cast_op = join(type_to_glsl(expected_type), "(", to_unpacked_expression(op0), ")");
5986 else
5987 cast_op = bitcast_glsl(expected_type, op0);
5988 }
5989 else
5990 cast_op = to_unpacked_expression(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005991
5992 string expr;
5993 if (out_type.basetype != expected_result_type)
5994 {
5995 expected_type.basetype = expected_result_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005996 expected_type.width = out_type.width;
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01005997 if (out_type.basetype == SPIRType::Boolean)
5998 expr = type_to_glsl(out_type);
5999 else
6000 expr = bitcast_glsl_op(out_type, expected_type);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006001 expr += '(';
6002 expr += join(op, "(", cast_op, ")");
6003 expr += ')';
6004 }
6005 else
6006 {
6007 expr += join(op, "(", cast_op, ")");
6008 }
6009
6010 emit_op(result_type, result_id, expr, should_forward(op0));
6011 inherit_expression_dependencies(result_id, op0);
6012}
6013
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006014// Very special case. Handling bitfieldExtract requires us to deal with different bitcasts of different signs
6015// and different vector sizes all at once. Need a special purpose method here.
6016void CompilerGLSL::emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6017 uint32_t op2, const char *op,
6018 SPIRType::BaseType expected_result_type,
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006019 SPIRType::BaseType input_type0, SPIRType::BaseType input_type1,
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006020 SPIRType::BaseType input_type2)
6021{
6022 auto &out_type = get<SPIRType>(result_type);
6023 auto expected_type = out_type;
6024 expected_type.basetype = input_type0;
6025
6026 string cast_op0 =
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006027 expression_type(op0).basetype != input_type0 ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006028
6029 auto op1_expr = to_unpacked_expression(op1);
6030 auto op2_expr = to_unpacked_expression(op2);
6031
6032 // Use value casts here instead. Input must be exactly int or uint, but SPIR-V might be 16-bit.
6033 expected_type.basetype = input_type1;
6034 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006035 string cast_op1 = expression_type(op1).basetype != input_type1 ?
6036 join(type_to_glsl_constructor(expected_type), "(", op1_expr, ")") :
6037 op1_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006038
6039 expected_type.basetype = input_type2;
6040 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006041 string cast_op2 = expression_type(op2).basetype != input_type2 ?
6042 join(type_to_glsl_constructor(expected_type), "(", op2_expr, ")") :
6043 op2_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006044
6045 string expr;
6046 if (out_type.basetype != expected_result_type)
6047 {
6048 expected_type.vecsize = out_type.vecsize;
6049 expected_type.basetype = expected_result_type;
6050 expr = bitcast_glsl_op(out_type, expected_type);
6051 expr += '(';
6052 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6053 expr += ')';
6054 }
6055 else
6056 {
6057 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6058 }
6059
6060 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
6061 inherit_expression_dependencies(result_id, op0);
6062 inherit_expression_dependencies(result_id, op1);
6063 inherit_expression_dependencies(result_id, op2);
6064}
6065
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006066void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6067 uint32_t op2, const char *op, SPIRType::BaseType input_type)
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006068{
6069 auto &out_type = get<SPIRType>(result_type);
6070 auto expected_type = out_type;
6071 expected_type.basetype = input_type;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006072 string cast_op0 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006073 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006074 string cast_op1 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006075 expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_unpacked_expression(op1);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006076 string cast_op2 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006077 expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_unpacked_expression(op2);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006078
6079 string expr;
6080 if (out_type.basetype != input_type)
6081 {
6082 expr = bitcast_glsl_op(out_type, expected_type);
6083 expr += '(';
6084 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6085 expr += ')';
6086 }
6087 else
6088 {
6089 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6090 }
6091
6092 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
6093 inherit_expression_dependencies(result_id, op0);
6094 inherit_expression_dependencies(result_id, op1);
6095 inherit_expression_dependencies(result_id, op2);
6096}
6097
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01006098void CompilerGLSL::emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0,
6099 uint32_t op1, const char *op, SPIRType::BaseType input_type)
6100{
6101 // Special purpose method for implementing clustered subgroup opcodes.
6102 // Main difference is that op1 does not participate in any casting, it needs to be a literal.
6103 auto &out_type = get<SPIRType>(result_type);
6104 auto expected_type = out_type;
6105 expected_type.basetype = input_type;
6106 string cast_op0 =
6107 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
6108
6109 string expr;
6110 if (out_type.basetype != input_type)
6111 {
6112 expr = bitcast_glsl_op(out_type, expected_type);
6113 expr += '(';
6114 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
6115 expr += ')';
6116 }
6117 else
6118 {
6119 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
6120 }
6121
6122 emit_op(result_type, result_id, expr, should_forward(op0));
6123 inherit_expression_dependencies(result_id, op0);
6124}
6125
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006126void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6127 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
6128{
6129 string cast_op0, cast_op1;
6130 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
6131 auto &out_type = get<SPIRType>(result_type);
6132
6133 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
6134 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02006135 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006136 {
6137 expected_type.basetype = input_type;
6138 expr = bitcast_glsl_op(out_type, expected_type);
6139 expr += '(';
6140 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
6141 expr += ')';
6142 }
6143 else
6144 {
6145 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
6146 }
6147
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006148 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006149 inherit_expression_dependencies(result_id, op0);
6150 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006151}
6152
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006153void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6154 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006155{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006156 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006157 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006158 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
6159 to_unpacked_expression(op2), ")"),
6160 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006161
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006162 inherit_expression_dependencies(result_id, op0);
6163 inherit_expression_dependencies(result_id, op1);
6164 inherit_expression_dependencies(result_id, op2);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006165}
6166
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006167void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6168 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006169{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006170 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01006171 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006172 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
6173 to_unpacked_expression(op2), ", ", to_unpacked_expression(op3), ")"),
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006174 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006175
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006176 inherit_expression_dependencies(result_id, op0);
6177 inherit_expression_dependencies(result_id, op1);
6178 inherit_expression_dependencies(result_id, op2);
6179 inherit_expression_dependencies(result_id, op3);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006180}
6181
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006182void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6183 uint32_t op2, uint32_t op3, const char *op,
6184 SPIRType::BaseType offset_count_type)
6185{
6186 // Only need to cast offset/count arguments. Types of base/insert must be same as result type,
6187 // and bitfieldInsert is sign invariant.
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006188 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006189
6190 auto op0_expr = to_unpacked_expression(op0);
6191 auto op1_expr = to_unpacked_expression(op1);
6192 auto op2_expr = to_unpacked_expression(op2);
6193 auto op3_expr = to_unpacked_expression(op3);
6194
6195 SPIRType target_type;
6196 target_type.vecsize = 1;
6197 target_type.basetype = offset_count_type;
6198
6199 if (expression_type(op2).basetype != offset_count_type)
6200 {
6201 // Value-cast here. Input might be 16-bit. GLSL requires int.
6202 op2_expr = join(type_to_glsl_constructor(target_type), "(", op2_expr, ")");
6203 }
6204
6205 if (expression_type(op3).basetype != offset_count_type)
6206 {
6207 // Value-cast here. Input might be 16-bit. GLSL requires int.
6208 op3_expr = join(type_to_glsl_constructor(target_type), "(", op3_expr, ")");
6209 }
6210
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006211 emit_op(result_type, result_id, join(op, "(", op0_expr, ", ", op1_expr, ", ", op2_expr, ", ", op3_expr, ")"),
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006212 forward);
6213
6214 inherit_expression_dependencies(result_id, op0);
6215 inherit_expression_dependencies(result_id, op1);
6216 inherit_expression_dependencies(result_id, op2);
6217 inherit_expression_dependencies(result_id, op3);
6218}
6219
rdbb3bd6742020-11-07 12:43:53 +01006220string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t tex)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006221{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006222 const char *type;
6223 switch (imgtype.image.dim)
6224 {
6225 case spv::Dim1D:
Rob Fischer21990632016-09-17 17:01:50 +09006226 type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006227 break;
6228 case spv::Dim2D:
Rob Fischer21990632016-09-17 17:01:50 +09006229 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006230 break;
6231 case spv::Dim3D:
6232 type = "3D";
6233 break;
6234 case spv::DimCube:
6235 type = "Cube";
6236 break;
Sidney Justfbb4df32019-01-06 12:21:59 -08006237 case spv::DimRect:
6238 type = "2DRect";
6239 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006240 case spv::DimBuffer:
6241 type = "Buffer";
6242 break;
6243 case spv::DimSubpassData:
6244 type = "2D";
6245 break;
6246 default:
6247 type = "";
6248 break;
6249 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006250
rdbe8c500c2020-11-05 22:55:44 +01006251 // In legacy GLSL, an extension is required for textureLod in the fragment
6252 // shader or textureGrad anywhere.
6253 bool legacy_lod_ext = false;
6254 auto &execution = get_entry_point();
6255 if (op == "textureGrad" || op == "textureProjGrad" ||
6256 ((op == "textureLod" || op == "textureProjLod") && execution.model != ExecutionModelVertex))
Lubos Lenco0028b4f2016-11-21 22:37:20 +01006257 {
Robert Konradedfc2972017-03-23 13:25:24 +01006258 if (is_legacy_es())
6259 {
rdbe8c500c2020-11-05 22:55:44 +01006260 legacy_lod_ext = true;
6261 require_extension_internal("GL_EXT_shader_texture_lod");
Robert Konradedfc2972017-03-23 13:25:24 +01006262 }
rdbe8c500c2020-11-05 22:55:44 +01006263 else if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02006264 require_extension_internal("GL_ARB_shader_texture_lod");
Lubos Lenco0028b4f2016-11-21 22:37:20 +01006265 }
Lubos Lenco52158642016-09-17 15:56:23 +02006266
Sidney Just5ac55ee2018-06-25 02:11:46 -07006267 if (op == "textureLodOffset" || op == "textureProjLodOffset")
6268 {
6269 if (is_legacy_es())
6270 SPIRV_CROSS_THROW(join(op, " not allowed in legacy ES"));
6271
6272 require_extension_internal("GL_EXT_gpu_shader4");
6273 }
6274
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02006275 // GLES has very limited support for shadow samplers.
Sidney Just5ac55ee2018-06-25 02:11:46 -07006276 // Basically shadow2D and shadow2DProj work through EXT_shadow_samplers,
6277 // everything else can just throw
Bill Hollingsfd252b22021-11-08 15:59:45 -05006278 bool is_comparison = is_depth_image(imgtype, tex);
rdb10fa5f62020-11-09 15:26:46 +01006279 if (is_comparison && is_legacy_es())
Sidney Just5ac55ee2018-06-25 02:11:46 -07006280 {
6281 if (op == "texture" || op == "textureProj")
6282 require_extension_internal("GL_EXT_shadow_samplers");
6283 else
6284 SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
6285 }
6286
rdb10fa5f62020-11-09 15:26:46 +01006287 if (op == "textureSize")
6288 {
6289 if (is_legacy_es())
6290 SPIRV_CROSS_THROW("textureSize not supported in legacy ES");
6291 if (is_comparison)
6292 SPIRV_CROSS_THROW("textureSize not supported on shadow sampler in legacy GLSL");
6293 require_extension_internal("GL_EXT_gpu_shader4");
6294 }
6295
6296 if (op == "texelFetch" && is_legacy_es())
6297 SPIRV_CROSS_THROW("texelFetch not supported in legacy ES");
6298
6299 bool is_es_and_depth = is_legacy_es() && is_comparison;
6300 std::string type_prefix = is_comparison ? "shadow" : "texture";
Sidney Just0f62b5d2018-06-22 01:40:01 -07006301
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006302 if (op == "texture")
Sidney Just5ac55ee2018-06-25 02:11:46 -07006303 return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
Robert Konradedfc2972017-03-23 13:25:24 +01006304 else if (op == "textureLod")
rdbe8c500c2020-11-05 22:55:44 +01006305 return join(type_prefix, type, legacy_lod_ext ? "LodEXT" : "Lod");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006306 else if (op == "textureProj")
Sidney Just5ac55ee2018-06-25 02:11:46 -07006307 return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
Sidney Juste66fd6c2018-03-12 00:59:06 +10006308 else if (op == "textureGrad")
Sidney Just0f62b5d2018-06-22 01:40:01 -07006309 return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006310 else if (op == "textureProjLod")
rdbe8c500c2020-11-05 22:55:44 +01006311 return join(type_prefix, type, legacy_lod_ext ? "ProjLodEXT" : "ProjLod");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006312 else if (op == "textureLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01006313 return join(type_prefix, type, "LodOffset");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006314 else if (op == "textureProjGrad")
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02006315 return join(type_prefix, type,
6316 is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006317 else if (op == "textureProjLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01006318 return join(type_prefix, type, "ProjLodOffset");
rdb10fa5f62020-11-09 15:26:46 +01006319 else if (op == "textureSize")
6320 return join("textureSize", type);
6321 else if (op == "texelFetch")
6322 return join("texelFetch", type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006323 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006324 {
6325 SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
6326 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006327}
6328
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006329bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
6330{
6331 auto *cleft = maybe_get<SPIRConstant>(left);
6332 auto *cright = maybe_get<SPIRConstant>(right);
6333 auto &lerptype = expression_type(lerp);
6334
6335 // If our targets aren't constants, we cannot use construction.
6336 if (!cleft || !cright)
6337 return false;
6338
6339 // If our targets are spec constants, we cannot use construction.
6340 if (cleft->specialization || cright->specialization)
6341 return false;
6342
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006343 auto &value_type = get<SPIRType>(cleft->constant_type);
6344
6345 if (lerptype.basetype != SPIRType::Boolean)
6346 return false;
6347 if (value_type.basetype == SPIRType::Struct || is_array(value_type))
6348 return false;
6349 if (!backend.use_constructor_splatting && value_type.vecsize != lerptype.vecsize)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006350 return false;
6351
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006352 // Only valid way in SPIR-V 1.4 to use matrices in select is a scalar select.
6353 // matrix(scalar) constructor fills in diagnonals, so gets messy very quickly.
6354 // Just avoid this case.
6355 if (value_type.columns > 1)
6356 return false;
6357
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006358 // 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 +02006359 bool ret = true;
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006360 for (uint32_t row = 0; ret && row < value_type.vecsize; row++)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006361 {
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006362 switch (type.basetype)
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006363 {
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006364 case SPIRType::Short:
6365 case SPIRType::UShort:
6366 ret = cleft->scalar_u16(0, row) == 0 && cright->scalar_u16(0, row) == 1;
6367 break;
Chip Davis117ccf42018-11-01 17:20:07 -05006368
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006369 case SPIRType::Int:
6370 case SPIRType::UInt:
6371 ret = cleft->scalar(0, row) == 0 && cright->scalar(0, row) == 1;
6372 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006373
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006374 case SPIRType::Half:
6375 ret = cleft->scalar_f16(0, row) == 0.0f && cright->scalar_f16(0, row) == 1.0f;
6376 break;
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01006377
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006378 case SPIRType::Float:
6379 ret = cleft->scalar_f32(0, row) == 0.0f && cright->scalar_f32(0, row) == 1.0f;
6380 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006381
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006382 case SPIRType::Double:
6383 ret = cleft->scalar_f64(0, row) == 0.0 && cright->scalar_f64(0, row) == 1.0;
6384 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006385
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006386 case SPIRType::Int64:
6387 case SPIRType::UInt64:
6388 ret = cleft->scalar_u64(0, row) == 0 && cright->scalar_u64(0, row) == 1;
6389 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006390
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006391 default:
6392 ret = false;
6393 break;
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006394 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006395 }
6396
6397 if (ret)
6398 op = type_to_glsl_constructor(type);
6399 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006400}
6401
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006402string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
6403 uint32_t false_value)
6404{
6405 string expr;
6406 auto &lerptype = expression_type(select);
6407
6408 if (lerptype.vecsize == 1)
Chip Davis3bfb2f92018-12-03 02:06:33 -06006409 expr = join(to_enclosed_expression(select), " ? ", to_enclosed_pointer_expression(true_value), " : ",
6410 to_enclosed_pointer_expression(false_value));
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006411 else
6412 {
6413 auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
6414
6415 expr = type_to_glsl_constructor(restype);
6416 expr += "(";
6417 for (uint32_t i = 0; i < restype.vecsize; i++)
6418 {
6419 expr += swiz(select, i);
6420 expr += " ? ";
6421 expr += swiz(true_value, i);
6422 expr += " : ";
6423 expr += swiz(false_value, i);
6424 if (i + 1 < restype.vecsize)
6425 expr += ", ";
6426 }
6427 expr += ")";
6428 }
6429
6430 return expr;
6431}
6432
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006433void 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 +01006434{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006435 auto &lerptype = expression_type(lerp);
6436 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006437
Chip Davis3bfb2f92018-12-03 02:06:33 -06006438 // If this results in a variable pointer, assume it may be written through.
6439 if (restype.pointer)
6440 {
6441 register_write(left);
6442 register_write(right);
6443 }
6444
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006445 string mix_op;
Chip Davis6628ea62019-07-10 23:46:40 -05006446 bool has_boolean_mix = *backend.boolean_mix_function &&
Hans-Kristian Arntzen851acf32017-05-04 10:28:30 +02006447 ((options.es && options.version >= 310) || (!options.es && options.version >= 450));
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006448 bool trivial_mix = to_trivial_mix_op(restype, mix_op, left, right, lerp);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006449
Hans-Kristian Arntzen0e7c33f2017-02-11 10:52:34 +01006450 // Cannot use boolean mix when the lerp argument is just one boolean,
6451 // fall back to regular trinary statements.
6452 if (lerptype.vecsize == 1)
6453 has_boolean_mix = false;
6454
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006455 // If we can reduce the mix to a simple cast, do so.
6456 // This helps for cases like int(bool), uint(bool) which is implemented with
6457 // OpSelect bool 1 0.
6458 if (trivial_mix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006459 {
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006460 emit_unary_func_op(result_type, id, lerp, mix_op.c_str());
6461 }
6462 else if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
6463 {
6464 // Boolean mix not supported on desktop without extension.
6465 // Was added in OpenGL 4.5 with ES 3.1 compat.
6466 //
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006467 // Could use GL_EXT_shader_integer_mix on desktop at least,
6468 // but Apple doesn't support it. :(
6469 // Just implement it as ternary expressions.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006470 auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006471 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006472 inherit_expression_dependencies(id, left);
6473 inherit_expression_dependencies(id, right);
6474 inherit_expression_dependencies(id, lerp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006475 }
Chip Davis6628ea62019-07-10 23:46:40 -05006476 else if (lerptype.basetype == SPIRType::Boolean)
6477 emit_trinary_func_op(result_type, id, left, right, lerp, backend.boolean_mix_function);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006478 else
6479 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006480}
6481
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006482string CompilerGLSL::to_combined_image_sampler(VariableID image_id, VariableID samp_id)
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006483{
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006484 // Keep track of the array indices we have used to load the image.
6485 // We'll need to use the same array index into the combined image sampler array.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006486 auto image_expr = to_non_uniform_aware_expression(image_id);
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006487 string array_expr;
6488 auto array_index = image_expr.find_first_of('[');
6489 if (array_index != string::npos)
6490 array_expr = image_expr.substr(array_index, string::npos);
6491
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006492 auto &args = current_function->arguments;
6493
6494 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
6495 // all possible combinations into new sampler2D uniforms.
6496 auto *image = maybe_get_backing_variable(image_id);
6497 auto *samp = maybe_get_backing_variable(samp_id);
6498 if (image)
6499 image_id = image->self;
6500 if (samp)
6501 samp_id = samp->self;
6502
6503 auto image_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006504 [image_id](const SPIRFunction::Parameter &param) { return image_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006505
6506 auto sampler_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006507 [samp_id](const SPIRFunction::Parameter &param) { return samp_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006508
6509 if (image_itr != end(args) || sampler_itr != end(args))
6510 {
6511 // If any parameter originates from a parameter, we will find it in our argument list.
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02006512 bool global_image = image_itr == end(args);
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006513 bool global_sampler = sampler_itr == end(args);
Hans-Kristian Arntzenc3ff67c2019-09-17 10:16:47 +02006514 VariableID iid = global_image ? image_id : VariableID(uint32_t(image_itr - begin(args)));
6515 VariableID sid = global_sampler ? samp_id : VariableID(uint32_t(sampler_itr - begin(args)));
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006516
6517 auto &combined = current_function->combined_parameters;
6518 auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02006519 return p.global_image == global_image && p.global_sampler == global_sampler && p.image_id == iid &&
6520 p.sampler_id == sid;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006521 });
6522
6523 if (itr != end(combined))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006524 return to_expression(itr->id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006525 else
6526 {
crissdb52e272020-10-08 12:14:52 +02006527 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler parameter, was "
6528 "build_combined_image_samplers() used "
6529 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006530 }
6531 }
6532 else
6533 {
6534 // For global sampler2D, look directly at the global remapping table.
6535 auto &mapping = combined_image_samplers;
6536 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
6537 return combined.image_id == image_id && combined.sampler_id == samp_id;
6538 });
6539
6540 if (itr != end(combined_image_samplers))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006541 return to_expression(itr->combined_id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006542 else
6543 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006544 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
6545 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006546 }
6547 }
6548}
6549
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02006550bool CompilerGLSL::is_supported_subgroup_op_in_opengl(spv::Op op)
crissdb52e272020-10-08 12:14:52 +02006551{
6552 switch (op)
6553 {
6554 case OpGroupNonUniformElect:
6555 case OpGroupNonUniformBallot:
6556 case OpGroupNonUniformBallotFindLSB:
6557 case OpGroupNonUniformBallotFindMSB:
6558 case OpGroupNonUniformBroadcast:
6559 case OpGroupNonUniformBroadcastFirst:
6560 case OpGroupNonUniformAll:
6561 case OpGroupNonUniformAny:
6562 case OpGroupNonUniformAllEqual:
6563 case OpControlBarrier:
6564 case OpMemoryBarrier:
6565 case OpGroupNonUniformBallotBitCount:
6566 case OpGroupNonUniformBallotBitExtract:
6567 case OpGroupNonUniformInverseBallot:
6568 return true;
6569 default:
6570 return false;
6571 }
6572}
6573
Bill Hollings5aafb282016-04-23 21:47:41 -04006574void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
6575{
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006576 if (options.vulkan_semantics && combined_image_samplers.empty())
6577 {
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006578 emit_binary_func_op(result_type, result_id, image_id, samp_id,
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02006579 type_to_glsl(get<SPIRType>(result_type), result_id).c_str());
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006580 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006581 else
Hans-Kristian Arntzen02808002018-04-27 09:34:13 +02006582 {
6583 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
6584 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true);
6585 }
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02006586
6587 // Make sure to suppress usage tracking and any expression invalidation.
6588 // It is illegal to create temporaries of opaque types.
6589 forwarded_temporaries.erase(result_id);
Bill Hollings5aafb282016-04-23 21:47:41 -04006590}
6591
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006592static inline bool image_opcode_is_sample_no_dref(Op op)
6593{
6594 switch (op)
6595 {
6596 case OpImageSampleExplicitLod:
6597 case OpImageSampleImplicitLod:
6598 case OpImageSampleProjExplicitLod:
6599 case OpImageSampleProjImplicitLod:
6600 case OpImageFetch:
6601 case OpImageRead:
6602 case OpImageSparseSampleExplicitLod:
6603 case OpImageSparseSampleImplicitLod:
6604 case OpImageSparseSampleProjExplicitLod:
6605 case OpImageSparseSampleProjImplicitLod:
6606 case OpImageSparseFetch:
6607 case OpImageSparseRead:
6608 return true;
6609
6610 default:
6611 return false;
6612 }
6613}
6614
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006615void CompilerGLSL::emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id, uint32_t &feedback_id,
6616 uint32_t &texel_id)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006617{
6618 // Need to allocate two temporaries.
6619 if (options.es)
6620 SPIRV_CROSS_THROW("Sparse texture feedback is not supported on ESSL.");
6621 require_extension_internal("GL_ARB_sparse_texture2");
6622
6623 auto &temps = extra_sub_expressions[id];
6624 if (temps == 0)
6625 temps = ir.increase_bound_by(2);
6626
6627 feedback_id = temps + 0;
6628 texel_id = temps + 1;
6629
6630 auto &return_type = get<SPIRType>(result_type_id);
6631 if (return_type.basetype != SPIRType::Struct || return_type.member_types.size() != 2)
6632 SPIRV_CROSS_THROW("Invalid return type for sparse feedback.");
6633 emit_uninitialized_temporary(return_type.member_types[0], feedback_id);
6634 emit_uninitialized_temporary(return_type.member_types[1], texel_id);
6635}
6636
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006637uint32_t CompilerGLSL::get_sparse_feedback_texel_id(uint32_t id) const
6638{
6639 auto itr = extra_sub_expressions.find(id);
6640 if (itr == extra_sub_expressions.end())
6641 return 0;
6642 else
6643 return itr->second + 1;
6644}
6645
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006646void CompilerGLSL::emit_texture_op(const Instruction &i, bool sparse)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006647{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02006648 auto *ops = stream(i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006649 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006650
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006651 SmallVector<uint32_t> inherited_expressions;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006652
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006653 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006654 uint32_t id = ops[1];
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006655 auto &return_type = get<SPIRType>(result_type_id);
6656
6657 uint32_t sparse_code_id = 0;
6658 uint32_t sparse_texel_id = 0;
6659 if (sparse)
6660 emit_sparse_feedback_temporaries(result_type_id, id, sparse_code_id, sparse_texel_id);
Chip Davis39dce882019-08-02 15:11:19 -05006661
6662 bool forward = false;
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006663 string expr = to_texture_op(i, sparse, &forward, inherited_expressions);
6664
6665 if (sparse)
6666 {
6667 statement(to_expression(sparse_code_id), " = ", expr, ";");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006668 expr = join(type_to_glsl(return_type), "(", to_expression(sparse_code_id), ", ", to_expression(sparse_texel_id),
6669 ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006670 forward = true;
6671 inherited_expressions.clear();
6672 }
6673
Chip Davis39dce882019-08-02 15:11:19 -05006674 emit_op(result_type_id, id, expr, forward);
6675 for (auto &inherit : inherited_expressions)
6676 inherit_expression_dependencies(id, inherit);
6677
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006678 // Do not register sparse ops as control dependent as they are always lowered to a temporary.
Chip Davis39dce882019-08-02 15:11:19 -05006679 switch (op)
6680 {
6681 case OpImageSampleDrefImplicitLod:
6682 case OpImageSampleImplicitLod:
6683 case OpImageSampleProjImplicitLod:
6684 case OpImageSampleProjDrefImplicitLod:
6685 register_control_dependent_expression(id);
6686 break;
6687
6688 default:
6689 break;
6690 }
6691}
6692
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006693std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool *forward,
Chip Davis39dce882019-08-02 15:11:19 -05006694 SmallVector<uint32_t> &inherited_expressions)
6695{
6696 auto *ops = stream(i);
6697 auto op = static_cast<Op>(i.op);
6698 uint32_t length = i.length;
6699
6700 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006701 VariableID img = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006702 uint32_t coord = ops[3];
6703 uint32_t dref = 0;
6704 uint32_t comp = 0;
6705 bool gather = false;
6706 bool proj = false;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006707 bool fetch = false;
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01006708 bool nonuniform_expression = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006709 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006710
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006711 auto &result_type = get<SPIRType>(result_type_id);
6712
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006713 inherited_expressions.push_back(coord);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006714 if (has_decoration(img, DecorationNonUniform) && !maybe_get_backing_variable(img))
6715 nonuniform_expression = true;
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02006716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006717 switch (op)
6718 {
6719 case OpImageSampleDrefImplicitLod:
6720 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006721 case OpImageSparseSampleDrefImplicitLod:
6722 case OpImageSparseSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006723 dref = ops[4];
6724 opt = &ops[5];
6725 length -= 5;
6726 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006727
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006728 case OpImageSampleProjDrefImplicitLod:
6729 case OpImageSampleProjDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006730 case OpImageSparseSampleProjDrefImplicitLod:
6731 case OpImageSparseSampleProjDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006732 dref = ops[4];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006733 opt = &ops[5];
6734 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006735 proj = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006736 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006738 case OpImageDrefGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006739 case OpImageSparseDrefGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006740 dref = ops[4];
6741 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006742 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006743 gather = true;
rdb509908d2020-11-07 00:01:57 +01006744 if (options.es && options.version < 310)
6745 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6746 else if (!options.es && options.version < 400)
6747 SPIRV_CROSS_THROW("textureGather with depth compare requires GLSL 400.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006748 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006749
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006750 case OpImageGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006751 case OpImageSparseGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006752 comp = ops[4];
6753 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006754 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006755 gather = true;
rdb509908d2020-11-07 00:01:57 +01006756 if (options.es && options.version < 310)
6757 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6758 else if (!options.es && options.version < 400)
6759 {
6760 if (!expression_is_constant_null(comp))
6761 SPIRV_CROSS_THROW("textureGather with component requires GLSL 400.");
6762 require_extension_internal("GL_ARB_texture_gather");
6763 }
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006764 break;
6765
6766 case OpImageFetch:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006767 case OpImageSparseFetch:
Bill Hollings8f6df772017-05-19 18:14:08 -04006768 case OpImageRead: // Reads == fetches in Metal (other langs will not get here)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006769 opt = &ops[4];
6770 length -= 4;
6771 fetch = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006772 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006773
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006774 case OpImageSampleProjImplicitLod:
6775 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006776 case OpImageSparseSampleProjImplicitLod:
6777 case OpImageSparseSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006778 opt = &ops[4];
6779 length -= 4;
6780 proj = true;
6781 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006782
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006783 default:
6784 opt = &ops[4];
6785 length -= 4;
6786 break;
6787 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006788
Bill Hollings8f6df772017-05-19 18:14:08 -04006789 // Bypass pointers because we need the real image struct
6790 auto &type = expression_type(img);
6791 auto &imgtype = get<SPIRType>(type.self);
6792
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006793 uint32_t coord_components = 0;
6794 switch (imgtype.image.dim)
6795 {
6796 case spv::Dim1D:
6797 coord_components = 1;
6798 break;
6799 case spv::Dim2D:
6800 coord_components = 2;
6801 break;
6802 case spv::Dim3D:
6803 coord_components = 3;
6804 break;
6805 case spv::DimCube:
6806 coord_components = 3;
6807 break;
6808 case spv::DimBuffer:
6809 coord_components = 1;
6810 break;
6811 default:
6812 coord_components = 2;
6813 break;
6814 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006815
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006816 if (dref)
6817 inherited_expressions.push_back(dref);
6818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006819 if (proj)
6820 coord_components++;
6821 if (imgtype.image.arrayed)
6822 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006823
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006824 uint32_t bias = 0;
6825 uint32_t lod = 0;
6826 uint32_t grad_x = 0;
6827 uint32_t grad_y = 0;
6828 uint32_t coffset = 0;
6829 uint32_t offset = 0;
6830 uint32_t coffsets = 0;
6831 uint32_t sample = 0;
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006832 uint32_t minlod = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006833 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006835 if (length)
6836 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006837 flags = *opt++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006838 length--;
6839 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006840
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02006841 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006842 if (length && (flags & flag))
6843 {
6844 v = *opt++;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006845 inherited_expressions.push_back(v);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006846 length--;
6847 }
6848 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006849
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006850 test(bias, ImageOperandsBiasMask);
6851 test(lod, ImageOperandsLodMask);
6852 test(grad_x, ImageOperandsGradMask);
6853 test(grad_y, ImageOperandsGradMask);
6854 test(coffset, ImageOperandsConstOffsetMask);
6855 test(offset, ImageOperandsOffsetMask);
6856 test(coffsets, ImageOperandsConstOffsetsMask);
6857 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006858 test(minlod, ImageOperandsMinLodMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006859
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006860 TextureFunctionBaseArguments base_args = {};
6861 base_args.img = img;
6862 base_args.imgtype = &imgtype;
6863 base_args.is_fetch = fetch != 0;
6864 base_args.is_gather = gather != 0;
6865 base_args.is_proj = proj != 0;
6866
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006867 string expr;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006868 TextureFunctionNameArguments name_args = {};
6869
6870 name_args.base = base_args;
6871 name_args.has_array_offsets = coffsets != 0;
6872 name_args.has_offset = coffset != 0 || offset != 0;
6873 name_args.has_grad = grad_x != 0 || grad_y != 0;
6874 name_args.has_dref = dref != 0;
6875 name_args.is_sparse_feedback = sparse;
6876 name_args.has_min_lod = minlod != 0;
6877 name_args.lod = lod;
6878 expr += to_function_name(name_args);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006879 expr += "(";
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006880
6881 uint32_t sparse_texel_id = 0;
6882 if (sparse)
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006883 sparse_texel_id = get_sparse_feedback_texel_id(ops[1]);
6884
6885 TextureFunctionArguments args = {};
6886 args.base = base_args;
6887 args.coord = coord;
6888 args.coord_components = coord_components;
6889 args.dref = dref;
6890 args.grad_x = grad_x;
6891 args.grad_y = grad_y;
6892 args.lod = lod;
6893 args.coffset = coffset;
6894 args.offset = offset;
6895 args.bias = bias;
6896 args.component = comp;
6897 args.sample = sample;
6898 args.sparse_texel = sparse_texel_id;
6899 args.min_lod = minlod;
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01006900 args.nonuniform_expression = nonuniform_expression;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006901 expr += to_function_args(args, forward);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006902 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006903
Sidney Justf6dad782018-06-22 00:28:40 -07006904 // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here.
Bill Hollingsfd252b22021-11-08 15:59:45 -05006905 if (is_legacy() && is_depth_image(imgtype, img))
Sidney Justf6dad782018-06-22 00:28:40 -07006906 expr += ".r";
6907
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006908 // Sampling from a texture which was deduced to be a depth image, might actually return 1 component here.
6909 // Remap back to 4 components as sampling opcodes expect.
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006910 if (backend.comparison_image_samples_scalar && image_opcode_is_sample_no_dref(op))
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006911 {
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006912 bool image_is_depth = false;
6913 const auto *combined = maybe_get<SPIRCombinedImageSampler>(img);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006914 VariableID image_id = combined ? combined->image : img;
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006915
Bill Hollingsfd252b22021-11-08 15:59:45 -05006916 if (combined && is_depth_image(imgtype, combined->image))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006917 image_is_depth = true;
Bill Hollingsfd252b22021-11-08 15:59:45 -05006918 else if (is_depth_image(imgtype, img))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006919 image_is_depth = true;
6920
6921 // We must also check the backing variable for the image.
6922 // We might have loaded an OpImage, and used that handle for two different purposes.
6923 // Once with comparison, once without.
6924 auto *image_variable = maybe_get_backing_variable(image_id);
Bill Hollingsfd252b22021-11-08 15:59:45 -05006925 if (image_variable && is_depth_image(get<SPIRType>(image_variable->basetype), image_variable->self))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006926 image_is_depth = true;
6927
6928 if (image_is_depth)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006929 expr = remap_swizzle(result_type, 1, expr);
6930 }
6931
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006932 if (!sparse && !backend.support_small_type_sampling_result && result_type.width < 32)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006933 {
6934 // Just value cast (narrowing) to expected type since we cannot rely on narrowing to work automatically.
6935 // Hopefully compiler picks this up and converts the texturing instruction to the appropriate precision.
6936 expr = join(type_to_glsl_constructor(result_type), "(", expr, ")");
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006937 }
6938
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01006939 // Deals with reads from MSL. We might need to downconvert to fewer components.
6940 if (op == OpImageRead)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006941 expr = remap_swizzle(result_type, 4, expr);
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01006942
Chip Davis39dce882019-08-02 15:11:19 -05006943 return expr;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006944}
6945
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006946bool CompilerGLSL::expression_is_constant_null(uint32_t id) const
6947{
6948 auto *c = maybe_get<SPIRConstant>(id);
6949 if (!c)
6950 return false;
6951 return c->constant_is_null();
6952}
6953
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02006954bool CompilerGLSL::expression_is_non_value_type_array(uint32_t ptr)
6955{
6956 auto &type = expression_type(ptr);
6957 if (type.array.empty())
6958 return false;
6959
6960 if (!backend.array_is_value_type)
6961 return true;
6962
6963 auto *var = maybe_get_backing_variable(ptr);
6964 if (!var)
6965 return false;
6966
6967 auto &backed_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006968 return !backend.buffer_offset_array_is_value_type && backed_type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02006969 has_member_decoration(backed_type.self, 0, DecorationOffset);
6970}
6971
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006972// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
6973// For some subclasses, the function is a method on the specified image.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006974string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006975{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006976 if (args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006977 {
6978 if (options.es)
6979 SPIRV_CROSS_THROW("Sparse residency is not supported in ESSL.");
6980 require_extension_internal("GL_ARB_sparse_texture_clamp");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006981 }
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006982
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006983 string fname;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006984 auto &imgtype = *args.base.imgtype;
6985 VariableID tex = args.base.img;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006986
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006987 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006988 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
6989 // 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 +02006990 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006991 bool workaround_lod_array_shadow_as_grad = false;
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006992 if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Bill Hollingsfd252b22021-11-08 15:59:45 -05006993 is_depth_image(imgtype, tex) && args.lod)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006994 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006995 if (!expression_is_constant_null(args.lod))
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006996 {
crissdb52e272020-10-08 12:14:52 +02006997 SPIRV_CROSS_THROW("textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be "
6998 "expressed in GLSL.");
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006999 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007000 workaround_lod_array_shadow_as_grad = true;
7001 }
7002
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007003 if (args.is_sparse_feedback)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007004 fname += "sparse";
7005
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007006 if (args.base.is_fetch)
7007 fname += args.is_sparse_feedback ? "TexelFetch" : "texelFetch";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007008 else
7009 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007010 fname += args.is_sparse_feedback ? "Texture" : "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007011
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007012 if (args.base.is_gather)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007013 fname += "Gather";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007014 if (args.has_array_offsets)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007015 fname += "Offsets";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007016 if (args.base.is_proj)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007017 fname += "Proj";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007018 if (args.has_grad || workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007019 fname += "Grad";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007020 if (args.lod != 0 && !workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007021 fname += "Lod";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007022 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007023
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007024 if (args.has_offset)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007025 fname += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007026
Hans-Kristian Arntzenf383cc92020-06-08 13:39:02 +02007027 if (args.has_min_lod)
7028 fname += "Clamp";
7029
7030 if (args.is_sparse_feedback || args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007031 fname += "ARB";
7032
rdb509908d2020-11-07 00:01:57 +01007033 return (is_legacy() && !args.base.is_gather) ? legacy_tex_op(fname, imgtype, tex) : fname;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007034}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007035
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007036std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id)
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007037{
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007038 auto *var = maybe_get_backing_variable(id);
7039
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007040 // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler in GLSL.
7041 // In Vulkan GLSL, we can make use of the newer GL_EXT_samplerless_texture_functions.
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007042 if (var)
7043 {
7044 auto &type = get<SPIRType>(var->basetype);
7045 if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer)
7046 {
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007047 if (options.vulkan_semantics)
7048 {
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007049 if (dummy_sampler_id)
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02007050 {
7051 // Don't need to consider Shadow state since the dummy sampler is always non-shadow.
7052 auto sampled_type = type;
7053 sampled_type.basetype = SPIRType::SampledImage;
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007054 return join(type_to_glsl(sampled_type), "(", to_non_uniform_aware_expression(id), ", ",
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02007055 to_expression(dummy_sampler_id), ")");
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02007056 }
7057 else
7058 {
7059 // Newer glslang supports this extension to deal with texture2D as argument to texture functions.
7060 require_extension_internal("GL_EXT_samplerless_texture_functions");
7061 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007062 }
7063 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007064 {
7065 if (!dummy_sampler_id)
crissdb52e272020-10-08 12:14:52 +02007066 SPIRV_CROSS_THROW("Cannot find dummy sampler ID. Was "
7067 "build_dummy_sampler_for_combined_images() called?");
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007068
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007069 return to_combined_image_sampler(id, dummy_sampler_id);
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007070 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007071 }
7072 }
7073
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007074 return to_non_uniform_aware_expression(id);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007075}
7076
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007077// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007078string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool *p_forward)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007079{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007080 VariableID img = args.base.img;
7081 auto &imgtype = *args.base.imgtype;
7082
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007083 string farg_str;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007084 if (args.base.is_fetch)
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007085 farg_str = convert_separate_image_to_expression(img);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007086 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007087 farg_str = to_non_uniform_aware_expression(img);
Hans-Kristian Arntzen1a2e4de2018-02-21 13:43:16 +01007088
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01007089 if (args.nonuniform_expression && farg_str.find_first_of('[') != string::npos)
7090 {
7091 // Only emit nonuniformEXT() wrapper if the underlying expression is arrayed in some way.
7092 farg_str = join(backend.nonuniform_qualifier, "(", farg_str, ")");
7093 }
7094
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007095 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02007096 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007097 if (comps == in_comps)
7098 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007099
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007100 switch (comps)
7101 {
7102 case 1:
7103 return ".x";
7104 case 2:
7105 return swizz_func ? ".xy()" : ".xy";
7106 case 3:
7107 return swizz_func ? ".xyz()" : ".xyz";
7108 default:
7109 return "";
7110 }
7111 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007112
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007113 bool forward = should_forward(args.coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007114
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007115 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007116 auto swizzle_expr = swizzle(args.coord_components, expression_type(args.coord).vecsize);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01007117 // Only enclose the UV expression if needed.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02007118 auto coord_expr =
7119 (*swizzle_expr == '\0') ? to_expression(args.coord) : (to_enclosed_expression(args.coord) + swizzle_expr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007120
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007121 // texelFetch only takes int, not uint.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007122 auto &coord_type = expression_type(args.coord);
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007123 if (coord_type.basetype == SPIRType::UInt)
7124 {
7125 auto expected_type = coord_type;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007126 expected_type.vecsize = args.coord_components;
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007127 expected_type.basetype = SPIRType::Int;
7128 coord_expr = bitcast_expression(expected_type, coord_type.basetype, coord_expr);
7129 }
7130
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007131 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007132 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
7133 // 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 +02007134 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02007135 bool workaround_lod_array_shadow_as_grad =
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007136 ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Bill Hollingsfd252b22021-11-08 15:59:45 -05007137 is_depth_image(imgtype, img) && args.lod != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007138
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007139 if (args.dref)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007140 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007141 forward = forward && should_forward(args.dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007142
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007143 // SPIR-V splits dref and coordinate.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02007144 if (args.base.is_gather ||
7145 args.coord_components == 4) // GLSL also splits the arguments in two. Same for textureGather.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007146 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007147 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007148 farg_str += to_expression(args.coord);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007149 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007150 farg_str += to_expression(args.dref);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007151 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007152 else if (args.base.is_proj)
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007153 {
7154 // Have to reshuffle so we get vec4(coord, dref, proj), special case.
7155 // Other shading languages splits up the arguments for coord and compare value like SPIR-V.
7156 // The coordinate type for textureProj shadow is always vec4 even for sampler1DShadow.
7157 farg_str += ", vec4(";
7158
7159 if (imgtype.image.dim == Dim1D)
7160 {
7161 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007162 farg_str += to_enclosed_expression(args.coord) + ".x";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007163 farg_str += ", ";
7164 farg_str += "0.0, ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007165 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007166 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007167 farg_str += to_enclosed_expression(args.coord) + ".y)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007168 }
7169 else if (imgtype.image.dim == Dim2D)
7170 {
7171 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007172 farg_str += to_enclosed_expression(args.coord) + (swizz_func ? ".xy()" : ".xy");
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007173 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007174 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007175 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007176 farg_str += to_enclosed_expression(args.coord) + ".z)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007177 }
7178 else
7179 SPIRV_CROSS_THROW("Invalid type for textureProj with shadow.");
7180 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007181 else
7182 {
7183 // Create a composite which merges coord/dref into a single vector.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007184 auto type = expression_type(args.coord);
7185 type.vecsize = args.coord_components + 1;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007186 farg_str += ", ";
7187 farg_str += type_to_glsl_constructor(type);
7188 farg_str += "(";
7189 farg_str += coord_expr;
7190 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007191 farg_str += to_expression(args.dref);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007192 farg_str += ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007193 }
7194 }
7195 else
7196 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007197 farg_str += ", ";
7198 farg_str += coord_expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007199 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007200
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007201 if (args.grad_x || args.grad_y)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007202 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007203 forward = forward && should_forward(args.grad_x);
7204 forward = forward && should_forward(args.grad_y);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007205 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007206 farg_str += to_expression(args.grad_x);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007207 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007208 farg_str += to_expression(args.grad_y);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007209 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007210
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007211 if (args.lod)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007212 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007213 if (workaround_lod_array_shadow_as_grad)
Robert Konrad3f745032017-03-23 09:55:32 +01007214 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007215 // Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
7216 // Implementing this as plain texture() is not safe on some implementations.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007217 if (imgtype.image.dim == Dim2D)
7218 farg_str += ", vec2(0.0), vec2(0.0)";
7219 else if (imgtype.image.dim == DimCube)
7220 farg_str += ", vec3(0.0), vec3(0.0)";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007221 }
7222 else
7223 {
rdbe8c500c2020-11-05 22:55:44 +01007224 forward = forward && should_forward(args.lod);
7225 farg_str += ", ";
7226
7227 auto &lod_expr_type = expression_type(args.lod);
7228
7229 // Lod expression for TexelFetch in GLSL must be int, and only int.
7230 if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms &&
7231 lod_expr_type.basetype != SPIRType::Int)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007232 {
rdbe8c500c2020-11-05 22:55:44 +01007233 farg_str += join("int(", to_expression(args.lod), ")");
7234 }
7235 else
7236 {
7237 farg_str += to_expression(args.lod);
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007238 }
Robert Konrad3f745032017-03-23 09:55:32 +01007239 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007240 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007241 else if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms)
Hans-Kristian Arntzend93807a2018-04-30 10:53:21 +02007242 {
7243 // Lod argument is optional in OpImageFetch, but we require a LOD value, pick 0 as the default.
7244 farg_str += ", 0";
7245 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007246
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007247 if (args.coffset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007248 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007249 forward = forward && should_forward(args.coffset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007250 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007251 farg_str += to_expression(args.coffset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007252 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007253 else if (args.offset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007254 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007255 forward = forward && should_forward(args.offset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007256 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007257 farg_str += to_expression(args.offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007258 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007259
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007260 if (args.sample)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007261 {
7262 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007263 farg_str += to_expression(args.sample);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007264 }
7265
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007266 if (args.min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007267 {
7268 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007269 farg_str += to_expression(args.min_lod);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007270 }
7271
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007272 if (args.sparse_texel)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007273 {
7274 // Sparse texel output parameter comes after everything else, except it's before the optional, component/bias arguments.
7275 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007276 farg_str += to_expression(args.sparse_texel);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007277 }
7278
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007279 if (args.bias)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007280 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007281 forward = forward && should_forward(args.bias);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007282 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007283 farg_str += to_expression(args.bias);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007284 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007285
rdb509908d2020-11-07 00:01:57 +01007286 if (args.component && !expression_is_constant_null(args.component))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007287 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007288 forward = forward && should_forward(args.component);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007289 farg_str += ", ";
Hans-Kristian Arntzen165dbff2021-06-03 11:37:45 +02007290 auto &component_type = expression_type(args.component);
7291 if (component_type.basetype == SPIRType::Int)
7292 farg_str += to_expression(args.component);
7293 else
7294 farg_str += join("int(", to_expression(args.component), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007295 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007296
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007297 *p_forward = forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007298
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007299 return farg_str;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007300}
7301
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007302void 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 +01007303{
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02007304 auto op = static_cast<GLSLstd450>(eop);
7305
7306 if (is_legacy() && is_unsigned_glsl_opcode(op))
7307 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy GLSL targets.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007308
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007309 // If we need to do implicit bitcasts, make sure we do it with the correct type.
7310 uint32_t integer_width = get_integer_width_for_glsl_instruction(op, args, length);
7311 auto int_type = to_signed_basetype(integer_width);
7312 auto uint_type = to_unsigned_basetype(integer_width);
7313
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007314 switch (op)
7315 {
7316 // FP fiddling
7317 case GLSLstd450Round:
rdb9e6e5d22020-11-06 17:34:38 +01007318 if (!is_legacy())
7319 emit_unary_func_op(result_type, id, args[0], "round");
7320 else
7321 {
7322 auto op0 = to_enclosed_expression(args[0]);
7323 auto &op0_type = expression_type(args[0]);
7324 auto expr = join("floor(", op0, " + ", type_to_glsl_constructor(op0_type), "(0.5))");
7325 bool forward = should_forward(args[0]);
7326 emit_op(result_type, id, expr, forward);
7327 inherit_expression_dependencies(id, args[0]);
7328 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007329 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007330
7331 case GLSLstd450RoundEven:
rdb9e6e5d22020-11-06 17:34:38 +01007332 if (!is_legacy())
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007333 emit_unary_func_op(result_type, id, args[0], "roundEven");
rdb9e6e5d22020-11-06 17:34:38 +01007334 else if (!options.es)
7335 {
7336 // This extension provides round() with round-to-even semantics.
7337 require_extension_internal("GL_EXT_gpu_shader4");
7338 emit_unary_func_op(result_type, id, args[0], "round");
7339 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007340 else
rdb9e6e5d22020-11-06 17:34:38 +01007341 SPIRV_CROSS_THROW("roundEven supported only in ESSL 300.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007342 break;
7343
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007344 case GLSLstd450Trunc:
7345 emit_unary_func_op(result_type, id, args[0], "trunc");
7346 break;
7347 case GLSLstd450SAbs:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007348 emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type);
7349 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007350 case GLSLstd450FAbs:
7351 emit_unary_func_op(result_type, id, args[0], "abs");
7352 break;
7353 case GLSLstd450SSign:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007354 emit_unary_func_op_cast(result_type, id, args[0], "sign", int_type, int_type);
7355 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007356 case GLSLstd450FSign:
7357 emit_unary_func_op(result_type, id, args[0], "sign");
7358 break;
7359 case GLSLstd450Floor:
7360 emit_unary_func_op(result_type, id, args[0], "floor");
7361 break;
7362 case GLSLstd450Ceil:
7363 emit_unary_func_op(result_type, id, args[0], "ceil");
7364 break;
7365 case GLSLstd450Fract:
7366 emit_unary_func_op(result_type, id, args[0], "fract");
7367 break;
7368 case GLSLstd450Radians:
7369 emit_unary_func_op(result_type, id, args[0], "radians");
7370 break;
7371 case GLSLstd450Degrees:
7372 emit_unary_func_op(result_type, id, args[0], "degrees");
7373 break;
7374 case GLSLstd450Fma:
Hans-Kristian Arntzen3ca8bc52019-04-08 10:33:34 +02007375 if ((!options.es && options.version < 400) || (options.es && options.version < 320))
7376 {
7377 auto expr = join(to_enclosed_expression(args[0]), " * ", to_enclosed_expression(args[1]), " + ",
7378 to_enclosed_expression(args[2]));
7379
7380 emit_op(result_type, id, expr,
7381 should_forward(args[0]) && should_forward(args[1]) && should_forward(args[2]));
7382 for (uint32_t i = 0; i < 3; i++)
7383 inherit_expression_dependencies(id, args[i]);
7384 }
7385 else
7386 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007387 break;
7388 case GLSLstd450Modf:
7389 register_call_out_argument(args[1]);
7390 forced_temporaries.insert(id);
7391 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
7392 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007393
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007394 case GLSLstd450ModfStruct:
7395 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007396 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02007397 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007398 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
7399 to_expression(id), ".", to_member_name(type, 1), ");");
7400 break;
7401 }
7402
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007403 // Minmax
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007404 case GLSLstd450UMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007405 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", uint_type, false);
7406 break;
7407
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007408 case GLSLstd450SMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007409 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", int_type, false);
7410 break;
7411
7412 case GLSLstd450FMin:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007413 emit_binary_func_op(result_type, id, args[0], args[1], "min");
7414 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007415
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007416 case GLSLstd450FMax:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007417 emit_binary_func_op(result_type, id, args[0], args[1], "max");
7418 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007419
7420 case GLSLstd450UMax:
7421 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", uint_type, false);
7422 break;
7423
7424 case GLSLstd450SMax:
7425 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", int_type, false);
7426 break;
7427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007428 case GLSLstd450FClamp:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007429 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
7430 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007431
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007432 case GLSLstd450UClamp:
7433 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", uint_type);
7434 break;
7435
7436 case GLSLstd450SClamp:
7437 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", int_type);
7438 break;
7439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007440 // Trig
7441 case GLSLstd450Sin:
7442 emit_unary_func_op(result_type, id, args[0], "sin");
7443 break;
7444 case GLSLstd450Cos:
7445 emit_unary_func_op(result_type, id, args[0], "cos");
7446 break;
7447 case GLSLstd450Tan:
7448 emit_unary_func_op(result_type, id, args[0], "tan");
7449 break;
7450 case GLSLstd450Asin:
7451 emit_unary_func_op(result_type, id, args[0], "asin");
7452 break;
7453 case GLSLstd450Acos:
7454 emit_unary_func_op(result_type, id, args[0], "acos");
7455 break;
7456 case GLSLstd450Atan:
7457 emit_unary_func_op(result_type, id, args[0], "atan");
7458 break;
7459 case GLSLstd450Sinh:
7460 emit_unary_func_op(result_type, id, args[0], "sinh");
7461 break;
7462 case GLSLstd450Cosh:
7463 emit_unary_func_op(result_type, id, args[0], "cosh");
7464 break;
7465 case GLSLstd450Tanh:
7466 emit_unary_func_op(result_type, id, args[0], "tanh");
7467 break;
7468 case GLSLstd450Asinh:
7469 emit_unary_func_op(result_type, id, args[0], "asinh");
7470 break;
7471 case GLSLstd450Acosh:
7472 emit_unary_func_op(result_type, id, args[0], "acosh");
7473 break;
7474 case GLSLstd450Atanh:
7475 emit_unary_func_op(result_type, id, args[0], "atanh");
7476 break;
7477 case GLSLstd450Atan2:
7478 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
7479 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007480
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007481 // Exponentials
7482 case GLSLstd450Pow:
7483 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
7484 break;
7485 case GLSLstd450Exp:
7486 emit_unary_func_op(result_type, id, args[0], "exp");
7487 break;
7488 case GLSLstd450Log:
7489 emit_unary_func_op(result_type, id, args[0], "log");
7490 break;
7491 case GLSLstd450Exp2:
7492 emit_unary_func_op(result_type, id, args[0], "exp2");
7493 break;
7494 case GLSLstd450Log2:
7495 emit_unary_func_op(result_type, id, args[0], "log2");
7496 break;
7497 case GLSLstd450Sqrt:
7498 emit_unary_func_op(result_type, id, args[0], "sqrt");
7499 break;
7500 case GLSLstd450InverseSqrt:
7501 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
7502 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007503
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007504 // Matrix math
7505 case GLSLstd450Determinant:
7506 emit_unary_func_op(result_type, id, args[0], "determinant");
7507 break;
7508 case GLSLstd450MatrixInverse:
7509 emit_unary_func_op(result_type, id, args[0], "inverse");
7510 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007512 // Lerping
7513 case GLSLstd450FMix:
7514 case GLSLstd450IMix:
7515 {
7516 emit_mix_op(result_type, id, args[0], args[1], args[2]);
7517 break;
7518 }
7519 case GLSLstd450Step:
7520 emit_binary_func_op(result_type, id, args[0], args[1], "step");
7521 break;
7522 case GLSLstd450SmoothStep:
7523 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
7524 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007525
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007526 // Packing
7527 case GLSLstd450Frexp:
7528 register_call_out_argument(args[1]);
7529 forced_temporaries.insert(id);
7530 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
7531 break;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007532
7533 case GLSLstd450FrexpStruct:
7534 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007535 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02007536 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007537 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
7538 to_expression(id), ".", to_member_name(type, 1), ");");
7539 break;
7540 }
7541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007542 case GLSLstd450Ldexp:
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007543 {
7544 bool forward = should_forward(args[0]) && should_forward(args[1]);
7545
7546 auto op0 = to_unpacked_expression(args[0]);
7547 auto op1 = to_unpacked_expression(args[1]);
7548 auto &op1_type = expression_type(args[1]);
7549 if (op1_type.basetype != SPIRType::Int)
7550 {
7551 // Need a value cast here.
7552 auto target_type = op1_type;
7553 target_type.basetype = SPIRType::Int;
7554 op1 = join(type_to_glsl_constructor(target_type), "(", op1, ")");
7555 }
7556
7557 auto expr = join("ldexp(", op0, ", ", op1, ")");
7558
7559 emit_op(result_type, id, expr, forward);
7560 inherit_expression_dependencies(id, args[0]);
7561 inherit_expression_dependencies(id, args[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007562 break;
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007563 }
7564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007565 case GLSLstd450PackSnorm4x8:
7566 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
7567 break;
7568 case GLSLstd450PackUnorm4x8:
7569 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
7570 break;
7571 case GLSLstd450PackSnorm2x16:
7572 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
7573 break;
7574 case GLSLstd450PackUnorm2x16:
7575 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
7576 break;
7577 case GLSLstd450PackHalf2x16:
7578 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
7579 break;
7580 case GLSLstd450UnpackSnorm4x8:
7581 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
7582 break;
7583 case GLSLstd450UnpackUnorm4x8:
7584 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
7585 break;
7586 case GLSLstd450UnpackSnorm2x16:
7587 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
7588 break;
7589 case GLSLstd450UnpackUnorm2x16:
7590 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
7591 break;
7592 case GLSLstd450UnpackHalf2x16:
7593 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
7594 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007595
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007596 case GLSLstd450PackDouble2x32:
7597 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
7598 break;
7599 case GLSLstd450UnpackDouble2x32:
7600 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
7601 break;
7602
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007603 // Vector math
7604 case GLSLstd450Length:
7605 emit_unary_func_op(result_type, id, args[0], "length");
7606 break;
7607 case GLSLstd450Distance:
7608 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
7609 break;
7610 case GLSLstd450Cross:
7611 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
7612 break;
7613 case GLSLstd450Normalize:
7614 emit_unary_func_op(result_type, id, args[0], "normalize");
7615 break;
7616 case GLSLstd450FaceForward:
7617 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
7618 break;
7619 case GLSLstd450Reflect:
7620 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
7621 break;
7622 case GLSLstd450Refract:
7623 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
7624 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007626 // Bit-fiddling
7627 case GLSLstd450FindILsb:
Hans-Kristian Arntzen932ee0e2019-07-12 10:57:56 +02007628 // findLSB always returns int.
7629 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 +02007630 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007631
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007632 case GLSLstd450FindSMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007633 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", int_type, int_type);
7634 break;
7635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007636 case GLSLstd450FindUMsb:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02007637 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type,
7638 int_type); // findMSB always returns int.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007639 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007640
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007641 // Multisampled varying
7642 case GLSLstd450InterpolateAtCentroid:
7643 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
7644 break;
7645 case GLSLstd450InterpolateAtSample:
7646 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
7647 break;
7648 case GLSLstd450InterpolateAtOffset:
7649 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
7650 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007651
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007652 case GLSLstd450NMin:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007653 case GLSLstd450NMax:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007654 {
7655 emit_nminmax_op(result_type, id, args[0], args[1], op);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007656 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007657 }
7658
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007659 case GLSLstd450NClamp:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007660 {
7661 // Make sure we have a unique ID here to avoid aliasing the extra sub-expressions between clamp and NMin sub-op.
7662 // 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 +01007663 uint32_t &max_id = extra_sub_expressions[id | EXTRA_SUB_EXPRESSION_TYPE_AUX];
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007664 if (!max_id)
7665 max_id = ir.increase_bound_by(1);
7666
7667 // Inherit precision qualifiers.
7668 ir.meta[max_id] = ir.meta[id];
7669
7670 emit_nminmax_op(result_type, max_id, args[0], args[1], GLSLstd450NMax);
7671 emit_nminmax_op(result_type, id, max_id, args[2], GLSLstd450NMin);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007672 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007673 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007675 default:
7676 statement("// unimplemented GLSL op ", eop);
7677 break;
7678 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007679}
7680
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007681void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op)
7682{
7683 // Need to emulate this call.
7684 uint32_t &ids = extra_sub_expressions[id];
7685 if (!ids)
7686 {
7687 ids = ir.increase_bound_by(5);
7688 auto btype = get<SPIRType>(result_type);
7689 btype.basetype = SPIRType::Boolean;
7690 set<SPIRType>(ids, btype);
7691 }
7692
7693 uint32_t btype_id = ids + 0;
7694 uint32_t left_nan_id = ids + 1;
7695 uint32_t right_nan_id = ids + 2;
7696 uint32_t tmp_id = ids + 3;
7697 uint32_t mixed_first_id = ids + 4;
7698
7699 // Inherit precision qualifiers.
7700 ir.meta[tmp_id] = ir.meta[id];
7701 ir.meta[mixed_first_id] = ir.meta[id];
7702
7703 emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
7704 emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
7705 emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max");
7706 emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id);
7707 emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id);
7708}
7709
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007710void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
7711 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007712{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007713 require_extension_internal("GL_AMD_shader_ballot");
Lou Kramer6671f522017-11-21 14:04:57 +01007714
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007715 enum AMDShaderBallot
7716 {
Lou Kramer6671f522017-11-21 14:04:57 +01007717 SwizzleInvocationsAMD = 1,
7718 SwizzleInvocationsMaskedAMD = 2,
7719 WriteInvocationAMD = 3,
7720 MbcntAMD = 4
7721 };
7722
7723 auto op = static_cast<AMDShaderBallot>(eop);
7724
7725 switch (op)
7726 {
7727 case SwizzleInvocationsAMD:
7728 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007729 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007730 break;
7731
7732 case SwizzleInvocationsMaskedAMD:
7733 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsMaskedAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007734 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007735 break;
7736
7737 case WriteInvocationAMD:
7738 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "writeInvocationAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007739 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007740 break;
7741
7742 case MbcntAMD:
7743 emit_unary_func_op(result_type, id, args[0], "mbcntAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007744 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007745 break;
7746
7747 default:
7748 statement("// unimplemented SPV AMD shader ballot op ", eop);
7749 break;
7750 }
7751}
7752
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007753void CompilerGLSL::emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t id, uint32_t eop,
7754 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007755{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007756 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Lou Kramer6671f522017-11-21 14:04:57 +01007757
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007758 enum AMDShaderExplicitVertexParameter
7759 {
Lou Kramer6671f522017-11-21 14:04:57 +01007760 InterpolateAtVertexAMD = 1
7761 };
7762
7763 auto op = static_cast<AMDShaderExplicitVertexParameter>(eop);
7764
7765 switch (op)
7766 {
7767 case InterpolateAtVertexAMD:
7768 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtVertexAMD");
7769 break;
7770
7771 default:
7772 statement("// unimplemented SPV AMD shader explicit vertex parameter op ", eop);
7773 break;
7774 }
7775}
7776
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007777void CompilerGLSL::emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t id, uint32_t eop,
7778 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007779{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007780 require_extension_internal("GL_AMD_shader_trinary_minmax");
Lou Kramer6671f522017-11-21 14:04:57 +01007781
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007782 enum AMDShaderTrinaryMinMax
7783 {
Lou Kramer6671f522017-11-21 14:04:57 +01007784 FMin3AMD = 1,
7785 UMin3AMD = 2,
7786 SMin3AMD = 3,
7787 FMax3AMD = 4,
7788 UMax3AMD = 5,
7789 SMax3AMD = 6,
7790 FMid3AMD = 7,
7791 UMid3AMD = 8,
7792 SMid3AMD = 9
7793 };
7794
7795 auto op = static_cast<AMDShaderTrinaryMinMax>(eop);
7796
7797 switch (op)
7798 {
7799 case FMin3AMD:
7800 case UMin3AMD:
7801 case SMin3AMD:
7802 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "min3");
7803 break;
7804
7805 case FMax3AMD:
7806 case UMax3AMD:
7807 case SMax3AMD:
7808 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "max3");
7809 break;
7810
7811 case FMid3AMD:
7812 case UMid3AMD:
7813 case SMid3AMD:
7814 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mid3");
7815 break;
7816
7817 default:
7818 statement("// unimplemented SPV AMD shader trinary minmax op ", eop);
7819 break;
7820 }
7821}
7822
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007823void CompilerGLSL::emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
7824 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007825{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007826 require_extension_internal("GL_AMD_gcn_shader");
Lou Kramer6671f522017-11-21 14:04:57 +01007827
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007828 enum AMDGCNShader
7829 {
Lou Kramer6671f522017-11-21 14:04:57 +01007830 CubeFaceIndexAMD = 1,
7831 CubeFaceCoordAMD = 2,
7832 TimeAMD = 3
7833 };
7834
7835 auto op = static_cast<AMDGCNShader>(eop);
7836
7837 switch (op)
7838 {
7839 case CubeFaceIndexAMD:
7840 emit_unary_func_op(result_type, id, args[0], "cubeFaceIndexAMD");
7841 break;
7842 case CubeFaceCoordAMD:
7843 emit_unary_func_op(result_type, id, args[0], "cubeFaceCoordAMD");
7844 break;
7845 case TimeAMD:
7846 {
7847 string expr = "timeAMD()";
7848 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007849 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007850 break;
7851 }
7852
7853 default:
7854 statement("// unimplemented SPV AMD gcn shader op ", eop);
7855 break;
7856 }
7857}
7858
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007859void CompilerGLSL::emit_subgroup_op(const Instruction &i)
7860{
7861 const uint32_t *ops = stream(i);
7862 auto op = static_cast<Op>(i.op);
7863
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02007864 if (!options.vulkan_semantics && !is_supported_subgroup_op_in_opengl(op))
crissdb52e272020-10-08 12:14:52 +02007865 SPIRV_CROSS_THROW("This subgroup operation is only supported in Vulkan semantics.");
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007866
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01007867 // If we need to do implicit bitcasts, make sure we do it with the correct type.
7868 uint32_t integer_width = get_integer_width_for_instruction(i);
7869 auto int_type = to_signed_basetype(integer_width);
7870 auto uint_type = to_unsigned_basetype(integer_width);
7871
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007872 switch (op)
7873 {
7874 case OpGroupNonUniformElect:
crissdb52e272020-10-08 12:14:52 +02007875 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupElect);
7876 break;
7877
7878 case OpGroupNonUniformBallotBitCount:
7879 {
7880 const GroupOperation operation = static_cast<GroupOperation>(ops[3]);
7881 if (operation == GroupOperationReduce)
7882 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitCount);
7883 else if (operation == GroupOperationInclusiveScan || operation == GroupOperationExclusiveScan)
7884 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
7885 }
7886 break;
7887
7888 case OpGroupNonUniformBallotBitExtract:
7889 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitExtract);
7890 break;
7891
7892 case OpGroupNonUniformInverseBallot:
7893 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
7894 break;
7895
7896 case OpGroupNonUniformBallot:
7897 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallot);
7898 break;
7899
7900 case OpGroupNonUniformBallotFindLSB:
7901 case OpGroupNonUniformBallotFindMSB:
7902 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotFindLSB_MSB);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007903 break;
7904
7905 case OpGroupNonUniformBroadcast:
7906 case OpGroupNonUniformBroadcastFirst:
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01007907 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBroadcast_First);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007908 break;
7909
7910 case OpGroupNonUniformShuffle:
7911 case OpGroupNonUniformShuffleXor:
7912 require_extension_internal("GL_KHR_shader_subgroup_shuffle");
7913 break;
7914
7915 case OpGroupNonUniformShuffleUp:
7916 case OpGroupNonUniformShuffleDown:
7917 require_extension_internal("GL_KHR_shader_subgroup_shuffle_relative");
7918 break;
7919
7920 case OpGroupNonUniformAll:
7921 case OpGroupNonUniformAny:
7922 case OpGroupNonUniformAllEqual:
crissdb52e272020-10-08 12:14:52 +02007923 {
7924 const SPIRType &type = expression_type(ops[3]);
7925 if (type.basetype == SPIRType::BaseType::Boolean && type.vecsize == 1u)
7926 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAll_Any_AllEqualBool);
7927 else
7928 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAllEqualT);
7929 }
7930 break;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007931
7932 case OpGroupNonUniformFAdd:
7933 case OpGroupNonUniformFMul:
7934 case OpGroupNonUniformFMin:
7935 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007936 case OpGroupNonUniformIAdd:
7937 case OpGroupNonUniformIMul:
7938 case OpGroupNonUniformSMin:
7939 case OpGroupNonUniformSMax:
7940 case OpGroupNonUniformUMin:
7941 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007942 case OpGroupNonUniformBitwiseAnd:
7943 case OpGroupNonUniformBitwiseOr:
7944 case OpGroupNonUniformBitwiseXor:
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +01007945 case OpGroupNonUniformLogicalAnd:
7946 case OpGroupNonUniformLogicalOr:
7947 case OpGroupNonUniformLogicalXor:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007948 {
7949 auto operation = static_cast<GroupOperation>(ops[3]);
7950 if (operation == GroupOperationClusteredReduce)
7951 {
7952 require_extension_internal("GL_KHR_shader_subgroup_clustered");
7953 }
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02007954 else if (operation == GroupOperationExclusiveScan || operation == GroupOperationInclusiveScan ||
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007955 operation == GroupOperationReduce)
7956 {
7957 require_extension_internal("GL_KHR_shader_subgroup_arithmetic");
7958 }
7959 else
7960 SPIRV_CROSS_THROW("Invalid group operation.");
7961 break;
7962 }
7963
7964 case OpGroupNonUniformQuadSwap:
7965 case OpGroupNonUniformQuadBroadcast:
7966 require_extension_internal("GL_KHR_shader_subgroup_quad");
7967 break;
7968
7969 default:
7970 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
7971 }
7972
7973 uint32_t result_type = ops[0];
7974 uint32_t id = ops[1];
7975
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02007976 auto scope = static_cast<Scope>(evaluate_constant_u32(ops[2]));
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007977 if (scope != ScopeSubgroup)
7978 SPIRV_CROSS_THROW("Only subgroup scope is supported.");
7979
7980 switch (op)
7981 {
7982 case OpGroupNonUniformElect:
7983 emit_op(result_type, id, "subgroupElect()", true);
7984 break;
7985
7986 case OpGroupNonUniformBroadcast:
7987 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBroadcast");
7988 break;
7989
7990 case OpGroupNonUniformBroadcastFirst:
7991 emit_unary_func_op(result_type, id, ops[3], "subgroupBroadcastFirst");
7992 break;
7993
7994 case OpGroupNonUniformBallot:
7995 emit_unary_func_op(result_type, id, ops[3], "subgroupBallot");
7996 break;
7997
7998 case OpGroupNonUniformInverseBallot:
7999 emit_unary_func_op(result_type, id, ops[3], "subgroupInverseBallot");
8000 break;
8001
8002 case OpGroupNonUniformBallotBitExtract:
8003 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBallotBitExtract");
8004 break;
8005
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008006 case OpGroupNonUniformBallotFindLSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008007 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindLSB");
8008 break;
8009
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008010 case OpGroupNonUniformBallotFindMSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008011 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindMSB");
8012 break;
8013
8014 case OpGroupNonUniformBallotBitCount:
8015 {
8016 auto operation = static_cast<GroupOperation>(ops[3]);
8017 if (operation == GroupOperationReduce)
8018 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotBitCount");
8019 else if (operation == GroupOperationInclusiveScan)
8020 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotInclusiveBitCount");
8021 else if (operation == GroupOperationExclusiveScan)
8022 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotExclusiveBitCount");
8023 else
8024 SPIRV_CROSS_THROW("Invalid BitCount operation.");
8025 break;
8026 }
8027
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008028 case OpGroupNonUniformShuffle:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008029 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffle");
8030 break;
8031
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008032 case OpGroupNonUniformShuffleXor:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008033 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleXor");
8034 break;
8035
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008036 case OpGroupNonUniformShuffleUp:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008037 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleUp");
8038 break;
8039
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008040 case OpGroupNonUniformShuffleDown:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008041 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleDown");
8042 break;
8043
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008044 case OpGroupNonUniformAll:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008045 emit_unary_func_op(result_type, id, ops[3], "subgroupAll");
8046 break;
8047
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008048 case OpGroupNonUniformAny:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008049 emit_unary_func_op(result_type, id, ops[3], "subgroupAny");
8050 break;
8051
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008052 case OpGroupNonUniformAllEqual:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008053 emit_unary_func_op(result_type, id, ops[3], "subgroupAllEqual");
8054 break;
8055
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008056 // clang-format off
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008057#define GLSL_GROUP_OP(op, glsl_op) \
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008058case OpGroupNonUniform##op: \
8059 { \
8060 auto operation = static_cast<GroupOperation>(ops[3]); \
8061 if (operation == GroupOperationReduce) \
8062 emit_unary_func_op(result_type, id, ops[4], "subgroup" #glsl_op); \
8063 else if (operation == GroupOperationInclusiveScan) \
8064 emit_unary_func_op(result_type, id, ops[4], "subgroupInclusive" #glsl_op); \
8065 else if (operation == GroupOperationExclusiveScan) \
8066 emit_unary_func_op(result_type, id, ops[4], "subgroupExclusive" #glsl_op); \
8067 else if (operation == GroupOperationClusteredReduce) \
8068 emit_binary_func_op(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op); \
8069 else \
8070 SPIRV_CROSS_THROW("Invalid group operation."); \
8071 break; \
8072 }
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008073
8074#define GLSL_GROUP_OP_CAST(op, glsl_op, type) \
8075case OpGroupNonUniform##op: \
8076 { \
8077 auto operation = static_cast<GroupOperation>(ops[3]); \
8078 if (operation == GroupOperationReduce) \
8079 emit_unary_func_op_cast(result_type, id, ops[4], "subgroup" #glsl_op, type, type); \
8080 else if (operation == GroupOperationInclusiveScan) \
8081 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupInclusive" #glsl_op, type, type); \
8082 else if (operation == GroupOperationExclusiveScan) \
8083 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupExclusive" #glsl_op, type, type); \
8084 else if (operation == GroupOperationClusteredReduce) \
8085 emit_binary_func_op_cast_clustered(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op, type); \
8086 else \
8087 SPIRV_CROSS_THROW("Invalid group operation."); \
8088 break; \
8089 }
8090
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008091 GLSL_GROUP_OP(FAdd, Add)
8092 GLSL_GROUP_OP(FMul, Mul)
8093 GLSL_GROUP_OP(FMin, Min)
8094 GLSL_GROUP_OP(FMax, Max)
8095 GLSL_GROUP_OP(IAdd, Add)
8096 GLSL_GROUP_OP(IMul, Mul)
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008097 GLSL_GROUP_OP_CAST(SMin, Min, int_type)
8098 GLSL_GROUP_OP_CAST(SMax, Max, int_type)
8099 GLSL_GROUP_OP_CAST(UMin, Min, uint_type)
8100 GLSL_GROUP_OP_CAST(UMax, Max, uint_type)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008101 GLSL_GROUP_OP(BitwiseAnd, And)
8102 GLSL_GROUP_OP(BitwiseOr, Or)
8103 GLSL_GROUP_OP(BitwiseXor, Xor)
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +01008104 GLSL_GROUP_OP(LogicalAnd, And)
8105 GLSL_GROUP_OP(LogicalOr, Or)
8106 GLSL_GROUP_OP(LogicalXor, Xor)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008107#undef GLSL_GROUP_OP
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008108#undef GLSL_GROUP_OP_CAST
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008109 // clang-format on
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008110
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008111 case OpGroupNonUniformQuadSwap:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008112 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008113 uint32_t direction = evaluate_constant_u32(ops[4]);
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008114 if (direction == 0)
8115 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapHorizontal");
8116 else if (direction == 1)
8117 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapVertical");
8118 else if (direction == 2)
8119 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapDiagonal");
8120 else
8121 SPIRV_CROSS_THROW("Invalid quad swap direction.");
8122 break;
8123 }
8124
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008125 case OpGroupNonUniformQuadBroadcast:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008126 {
8127 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupQuadBroadcast");
8128 break;
8129 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008130
8131 default:
8132 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
8133 }
8134
8135 register_control_dependent_expression(id);
8136}
8137
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008138string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008139{
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008140 // OpBitcast can deal with pointers.
8141 if (out_type.pointer || in_type.pointer)
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +02008142 {
8143 if (out_type.vecsize == 2 || in_type.vecsize == 2)
8144 require_extension_internal("GL_EXT_buffer_reference_uvec2");
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008145 return type_to_glsl(out_type);
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +02008146 }
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008147
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008148 if (out_type.basetype == in_type.basetype)
8149 return "";
8150
Chip Davisef0b1fc2019-01-30 20:19:05 -06008151 assert(out_type.basetype != SPIRType::Boolean);
8152 assert(in_type.basetype != SPIRType::Boolean);
8153
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008154 bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
8155 bool same_size_cast = out_type.width == in_type.width;
8156
8157 // Trivial bitcast case, casts between integers.
8158 if (integral_cast && same_size_cast)
Chip Davis0d949e12018-11-05 14:55:56 -06008159 return type_to_glsl(out_type);
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008160
8161 // Catch-all 8-bit arithmetic casts (GL_EXT_shader_explicit_arithmetic_types).
8162 if (out_type.width == 8 && in_type.width >= 16 && integral_cast && in_type.vecsize == 1)
8163 return "unpack8";
8164 else if (in_type.width == 8 && out_type.width == 16 && integral_cast && out_type.vecsize == 1)
8165 return "pack16";
8166 else if (in_type.width == 8 && out_type.width == 32 && integral_cast && out_type.vecsize == 1)
8167 return "pack32";
8168
8169 // Floating <-> Integer special casts. Just have to enumerate all cases. :(
8170 // 16-bit, 32-bit and 64-bit floats.
8171 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008172 {
8173 if (is_legacy_es())
8174 SPIRV_CROSS_THROW("Float -> Uint bitcast not supported on legacy ESSL.");
8175 else if (!options.es && options.version < 330)
8176 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008177 return "floatBitsToUint";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008178 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008179 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008180 {
8181 if (is_legacy_es())
8182 SPIRV_CROSS_THROW("Float -> Int bitcast not supported on legacy ESSL.");
8183 else if (!options.es && options.version < 330)
8184 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008185 return "floatBitsToInt";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008186 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008187 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008188 {
8189 if (is_legacy_es())
8190 SPIRV_CROSS_THROW("Uint -> Float bitcast not supported on legacy ESSL.");
8191 else if (!options.es && options.version < 330)
8192 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008193 return "uintBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008194 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008195 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008196 {
8197 if (is_legacy_es())
8198 SPIRV_CROSS_THROW("Int -> Float bitcast not supported on legacy ESSL.");
8199 else if (!options.es && options.version < 330)
8200 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008201 return "intBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008202 }
8203
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02008204 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
8205 return "doubleBitsToInt64";
8206 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
8207 return "doubleBitsToUint64";
8208 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
8209 return "int64BitsToDouble";
8210 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
8211 return "uint64BitsToDouble";
Chip Davis0d949e12018-11-05 14:55:56 -06008212 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Half)
8213 return "float16BitsToInt16";
8214 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half)
8215 return "float16BitsToUint16";
8216 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Short)
8217 return "int16BitsToFloat16";
8218 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
8219 return "uint16BitsToFloat16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008220
8221 // And finally, some even more special purpose casts.
8222 if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
Lou Kramer6671f522017-11-21 14:04:57 +01008223 return "packUint2x32";
Asuka55dfbea2020-04-17 22:46:06 +08008224 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UInt64 && out_type.vecsize == 2)
8225 return "unpackUint2x32";
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008226 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
8227 return "unpackFloat2x16";
8228 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)
8229 return "packFloat2x16";
Chip Davis0d949e12018-11-05 14:55:56 -06008230 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Short && in_type.vecsize == 2)
8231 return "packInt2x16";
8232 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int && in_type.vecsize == 1)
8233 return "unpackInt2x16";
8234 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UShort && in_type.vecsize == 2)
8235 return "packUint2x16";
8236 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
8237 return "unpackUint2x16";
8238 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Short && in_type.vecsize == 4)
8239 return "packInt4x16";
8240 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int64 && in_type.vecsize == 1)
8241 return "unpackInt4x16";
8242 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UShort && in_type.vecsize == 4)
8243 return "packUint4x16";
8244 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt64 && in_type.vecsize == 1)
8245 return "unpackUint4x16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008246
8247 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008248}
8249
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008250string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008251{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008252 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008253 if (op.empty())
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02008254 return to_enclosed_unpacked_expression(argument);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008255 else
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02008256 return join(op, "(", to_unpacked_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008257}
8258
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008259std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg)
8260{
8261 auto expr = to_expression(arg);
8262 auto &src_type = expression_type(arg);
8263 if (src_type.basetype != target_type)
8264 {
8265 auto target = src_type;
8266 target.basetype = target_type;
8267 expr = join(bitcast_glsl_op(target, src_type), "(", expr, ")");
8268 }
8269
8270 return expr;
8271}
8272
8273std::string CompilerGLSL::bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type,
8274 const std::string &expr)
8275{
8276 if (target_type.basetype == expr_type)
8277 return expr;
8278
8279 auto src_type = target_type;
8280 src_type.basetype = expr_type;
8281 return join(bitcast_glsl_op(target_type, src_type), "(", expr, ")");
8282}
8283
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008284string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008285{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008286 switch (builtin)
8287 {
8288 case BuiltInPosition:
8289 return "gl_Position";
8290 case BuiltInPointSize:
8291 return "gl_PointSize";
Bill Hollingse73e8e42016-12-17 17:07:53 -05008292 case BuiltInClipDistance:
8293 return "gl_ClipDistance";
Hans-Kristian Arntzen7f2e1792017-03-05 12:44:29 +01008294 case BuiltInCullDistance:
8295 return "gl_CullDistance";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008296 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008297 if (options.vulkan_semantics)
crissdb52e272020-10-08 12:14:52 +02008298 SPIRV_CROSS_THROW("Cannot implement gl_VertexID in Vulkan GLSL. This shader was created "
8299 "with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008300 return "gl_VertexID";
8301 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008302 if (options.vulkan_semantics)
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02008303 {
8304 auto model = get_entry_point().model;
8305 switch (model)
8306 {
8307 case spv::ExecutionModelIntersectionKHR:
8308 case spv::ExecutionModelAnyHitKHR:
8309 case spv::ExecutionModelClosestHitKHR:
8310 // gl_InstanceID is allowed in these shaders.
8311 break;
8312
8313 default:
crissdb52e272020-10-08 12:14:52 +02008314 SPIRV_CROSS_THROW("Cannot implement gl_InstanceID in Vulkan GLSL. This shader was "
8315 "created with GL semantics.");
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02008316 }
8317 }
rdb031cbaa2020-06-12 22:42:26 +02008318 if (!options.es && options.version < 140)
8319 {
8320 require_extension_internal("GL_ARB_draw_instanced");
8321 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008322 return "gl_InstanceID";
8323 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008324 if (options.vulkan_semantics)
8325 return "gl_VertexIndex";
8326 else
8327 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008328 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008329 if (options.vulkan_semantics)
8330 return "gl_InstanceIndex";
rdb031cbaa2020-06-12 22:42:26 +02008331
8332 if (!options.es && options.version < 140)
8333 {
8334 require_extension_internal("GL_ARB_draw_instanced");
8335 }
8336
8337 if (options.vertex.support_nonzero_base_instance)
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008338 {
8339 if (!options.vulkan_semantics)
8340 {
8341 // This is a soft-enable. We will opt-in to using gl_BaseInstanceARB if supported.
8342 require_extension_internal("GL_ARB_shader_draw_parameters");
8343 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008344 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008345 }
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02008346 else
8347 return "gl_InstanceID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008348 case BuiltInPrimitiveId:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02008349 if (storage == StorageClassInput && get_entry_point().model == ExecutionModelGeometry)
8350 return "gl_PrimitiveIDIn";
8351 else
8352 return "gl_PrimitiveID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008353 case BuiltInInvocationId:
8354 return "gl_InvocationID";
8355 case BuiltInLayer:
8356 return "gl_Layer";
Hans-Kristian Arntzenf825bd92018-01-04 12:41:25 +01008357 case BuiltInViewportIndex:
8358 return "gl_ViewportIndex";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008359 case BuiltInTessLevelOuter:
8360 return "gl_TessLevelOuter";
8361 case BuiltInTessLevelInner:
8362 return "gl_TessLevelInner";
8363 case BuiltInTessCoord:
8364 return "gl_TessCoord";
8365 case BuiltInFragCoord:
8366 return "gl_FragCoord";
8367 case BuiltInPointCoord:
8368 return "gl_PointCoord";
8369 case BuiltInFrontFacing:
8370 return "gl_FrontFacing";
8371 case BuiltInFragDepth:
8372 return "gl_FragDepth";
8373 case BuiltInNumWorkgroups:
8374 return "gl_NumWorkGroups";
8375 case BuiltInWorkgroupSize:
8376 return "gl_WorkGroupSize";
8377 case BuiltInWorkgroupId:
8378 return "gl_WorkGroupID";
8379 case BuiltInLocalInvocationId:
8380 return "gl_LocalInvocationID";
8381 case BuiltInGlobalInvocationId:
8382 return "gl_GlobalInvocationID";
8383 case BuiltInLocalInvocationIndex:
8384 return "gl_LocalInvocationIndex";
Hans-Kristian Arntzen61f1d8b2018-11-28 15:18:43 +01008385 case BuiltInHelperInvocation:
8386 return "gl_HelperInvocation";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008387
Chip Davisfcad0192018-08-28 13:47:29 -05008388 case BuiltInBaseVertex:
8389 if (options.es)
8390 SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008391
8392 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008393 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008394 if (options.version < 460)
8395 {
8396 require_extension_internal("GL_ARB_shader_draw_parameters");
8397 return "gl_BaseVertexARB";
8398 }
8399 return "gl_BaseVertex";
Chip Davisfcad0192018-08-28 13:47:29 -05008400 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008401 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8402 require_extension_internal("GL_ARB_shader_draw_parameters");
8403 return "SPIRV_Cross_BaseVertex";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008404
Chip Davisfcad0192018-08-28 13:47:29 -05008405 case BuiltInBaseInstance:
8406 if (options.es)
8407 SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008408
8409 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008410 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008411 if (options.version < 460)
8412 {
8413 require_extension_internal("GL_ARB_shader_draw_parameters");
8414 return "gl_BaseInstanceARB";
8415 }
8416 return "gl_BaseInstance";
Chip Davisfcad0192018-08-28 13:47:29 -05008417 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008418 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8419 require_extension_internal("GL_ARB_shader_draw_parameters");
8420 return "SPIRV_Cross_BaseInstance";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008421
Chip Davisfcad0192018-08-28 13:47:29 -05008422 case BuiltInDrawIndex:
8423 if (options.es)
8424 SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008425
8426 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008427 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008428 if (options.version < 460)
8429 {
8430 require_extension_internal("GL_ARB_shader_draw_parameters");
8431 return "gl_DrawIDARB";
8432 }
8433 return "gl_DrawID";
8434 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008435 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8436 require_extension_internal("GL_ARB_shader_draw_parameters");
8437 return "gl_DrawIDARB";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008438
8439 case BuiltInSampleId:
8440 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008441 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008442 if (!options.es && options.version < 400)
8443 SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
8444 return "gl_SampleID";
8445
8446 case BuiltInSampleMask:
8447 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008448 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008449 if (!options.es && options.version < 400)
8450 SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
8451
8452 if (storage == StorageClassInput)
8453 return "gl_SampleMaskIn";
8454 else
8455 return "gl_SampleMask";
8456
8457 case BuiltInSamplePosition:
8458 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008459 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008460 if (!options.es && options.version < 400)
8461 SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
8462 return "gl_SamplePosition";
8463
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008464 case BuiltInViewIndex:
8465 if (options.vulkan_semantics)
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008466 return "gl_ViewIndex";
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008467 else
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008468 return "gl_ViewID_OVR";
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008469
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008470 case BuiltInNumSubgroups:
crissdb52e272020-10-08 12:14:52 +02008471 request_subgroup_feature(ShaderSubgroupSupportHelper::NumSubgroups);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008472 return "gl_NumSubgroups";
8473
8474 case BuiltInSubgroupId:
crissdb52e272020-10-08 12:14:52 +02008475 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008476 return "gl_SubgroupID";
8477
8478 case BuiltInSubgroupSize:
crissdb52e272020-10-08 12:14:52 +02008479 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupSize);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008480 return "gl_SubgroupSize";
8481
8482 case BuiltInSubgroupLocalInvocationId:
crissdb52e272020-10-08 12:14:52 +02008483 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInvocationID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008484 return "gl_SubgroupInvocationID";
8485
8486 case BuiltInSubgroupEqMask:
crissdb52e272020-10-08 12:14:52 +02008487 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008488 return "gl_SubgroupEqMask";
8489
8490 case BuiltInSubgroupGeMask:
crissdb52e272020-10-08 12:14:52 +02008491 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008492 return "gl_SubgroupGeMask";
8493
8494 case BuiltInSubgroupGtMask:
crissdb52e272020-10-08 12:14:52 +02008495 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008496 return "gl_SubgroupGtMask";
8497
8498 case BuiltInSubgroupLeMask:
crissdb52e272020-10-08 12:14:52 +02008499 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008500 return "gl_SubgroupLeMask";
8501
8502 case BuiltInSubgroupLtMask:
crissdb52e272020-10-08 12:14:52 +02008503 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008504 return "gl_SubgroupLtMask";
8505
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008506 case BuiltInLaunchIdKHR:
8507 return ray_tracing_is_khr ? "gl_LaunchIDEXT" : "gl_LaunchIDNV";
8508 case BuiltInLaunchSizeKHR:
8509 return ray_tracing_is_khr ? "gl_LaunchSizeEXT" : "gl_LaunchSizeNV";
8510 case BuiltInWorldRayOriginKHR:
8511 return ray_tracing_is_khr ? "gl_WorldRayOriginEXT" : "gl_WorldRayOriginNV";
8512 case BuiltInWorldRayDirectionKHR:
8513 return ray_tracing_is_khr ? "gl_WorldRayDirectionEXT" : "gl_WorldRayDirectionNV";
8514 case BuiltInObjectRayOriginKHR:
8515 return ray_tracing_is_khr ? "gl_ObjectRayOriginEXT" : "gl_ObjectRayOriginNV";
8516 case BuiltInObjectRayDirectionKHR:
8517 return ray_tracing_is_khr ? "gl_ObjectRayDirectionEXT" : "gl_ObjectRayDirectionNV";
8518 case BuiltInRayTminKHR:
8519 return ray_tracing_is_khr ? "gl_RayTminEXT" : "gl_RayTminNV";
8520 case BuiltInRayTmaxKHR:
8521 return ray_tracing_is_khr ? "gl_RayTmaxEXT" : "gl_RayTmaxNV";
8522 case BuiltInInstanceCustomIndexKHR:
8523 return ray_tracing_is_khr ? "gl_InstanceCustomIndexEXT" : "gl_InstanceCustomIndexNV";
8524 case BuiltInObjectToWorldKHR:
8525 return ray_tracing_is_khr ? "gl_ObjectToWorldEXT" : "gl_ObjectToWorldNV";
8526 case BuiltInWorldToObjectKHR:
8527 return ray_tracing_is_khr ? "gl_WorldToObjectEXT" : "gl_WorldToObjectNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +01008528 case BuiltInHitTNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008529 // gl_HitTEXT is an alias of RayTMax in KHR.
Patrick Moursda39a7b2019-02-26 15:43:03 +01008530 return "gl_HitTNV";
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008531 case BuiltInHitKindKHR:
8532 return ray_tracing_is_khr ? "gl_HitKindEXT" : "gl_HitKindNV";
8533 case BuiltInIncomingRayFlagsKHR:
8534 return ray_tracing_is_khr ? "gl_IncomingRayFlagsEXT" : "gl_IncomingRayFlagsNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +01008535
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008536 case BuiltInBaryCoordNV:
8537 {
8538 if (options.es && options.version < 320)
8539 SPIRV_CROSS_THROW("gl_BaryCoordNV requires ESSL 320.");
8540 else if (!options.es && options.version < 450)
8541 SPIRV_CROSS_THROW("gl_BaryCoordNV requires GLSL 450.");
8542 require_extension_internal("GL_NV_fragment_shader_barycentric");
8543 return "gl_BaryCoordNV";
8544 }
8545
8546 case BuiltInBaryCoordNoPerspNV:
8547 {
8548 if (options.es && options.version < 320)
8549 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires ESSL 320.");
8550 else if (!options.es && options.version < 450)
8551 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires GLSL 450.");
8552 require_extension_internal("GL_NV_fragment_shader_barycentric");
8553 return "gl_BaryCoordNoPerspNV";
8554 }
8555
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +02008556 case BuiltInFragStencilRefEXT:
8557 {
8558 if (!options.es)
8559 {
8560 require_extension_internal("GL_ARB_shader_stencil_export");
8561 return "gl_FragStencilRefARB";
8562 }
8563 else
8564 SPIRV_CROSS_THROW("Stencil export not supported in GLES.");
8565 }
8566
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +02008567 case BuiltInPrimitiveShadingRateKHR:
8568 {
8569 if (!options.vulkan_semantics)
8570 SPIRV_CROSS_THROW("Can only use PrimitiveShadingRateKHR in Vulkan GLSL.");
8571 require_extension_internal("GL_EXT_fragment_shading_rate");
8572 return "gl_PrimitiveShadingRateEXT";
8573 }
8574
8575 case BuiltInShadingRateKHR:
8576 {
8577 if (!options.vulkan_semantics)
8578 SPIRV_CROSS_THROW("Can only use ShadingRateKHR in Vulkan GLSL.");
8579 require_extension_internal("GL_EXT_fragment_shading_rate");
8580 return "gl_ShadingRateEXT";
8581 }
8582
Chip Davis6a585542019-07-12 21:50:50 -05008583 case BuiltInDeviceIndex:
8584 if (!options.vulkan_semantics)
8585 SPIRV_CROSS_THROW("Need Vulkan semantics for device group support.");
8586 require_extension_internal("GL_EXT_device_group");
8587 return "gl_DeviceIndex";
8588
Hans-Kristian Arntzen3fd14842021-04-20 13:44:52 +02008589 case BuiltInFullyCoveredEXT:
8590 if (!options.es)
8591 require_extension_internal("GL_NV_conservative_raster_underestimation");
8592 else
8593 SPIRV_CROSS_THROW("Need desktop GL to use GL_NV_conservative_raster_underestimation.");
8594 return "gl_FragFullyCoveredNV";
8595
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008596 default:
Bill Hollingse73e8e42016-12-17 17:07:53 -05008597 return join("gl_BuiltIn_", convert_to_string(builtin));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008598 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008599}
8600
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008601const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008602{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008603 switch (index)
8604 {
8605 case 0:
8606 return "x";
8607 case 1:
8608 return "y";
8609 case 2:
8610 return "z";
8611 case 3:
8612 return "w";
8613 default:
Bill Hollings595eb0c2021-10-20 14:46:30 -04008614 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 +02008615 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008616}
8617
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02008618void CompilerGLSL::access_chain_internal_append_index(std::string &expr, uint32_t /*base*/, const SPIRType * /*type*/,
Lukas Hermanns6673a672019-10-22 11:06:16 -04008619 AccessChainFlags flags, bool & /*access_chain_is_arrayed*/,
8620 uint32_t index)
8621{
8622 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
8623 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
8624
8625 expr += "[";
8626
Lukas Hermanns6673a672019-10-22 11:06:16 -04008627 if (index_is_literal)
8628 expr += convert_to_string(index);
8629 else
Bill Hollings974a0812021-10-21 16:11:33 -04008630 expr += to_unpacked_expression(index, register_expression_read);
Lukas Hermanns6673a672019-10-22 11:06:16 -04008631
Lukas Hermanns6673a672019-10-22 11:06:16 -04008632 expr += "]";
8633}
8634
Hans-Kristian Arntzen75ed7382021-04-14 15:10:02 +02008635bool CompilerGLSL::access_chain_needs_stage_io_builtin_translation(uint32_t)
8636{
8637 return true;
8638}
8639
Hans-Kristian Arntzeneb5e09f2017-02-23 19:33:14 +01008640string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008641 AccessChainFlags flags, AccessChainMeta *meta)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008642{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008643 string expr;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008644
8645 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008646 bool msb_is_id = (flags & ACCESS_CHAIN_LITERAL_MSB_FORCE_ID) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008647 bool chain_only = (flags & ACCESS_CHAIN_CHAIN_ONLY_BIT) != 0;
8648 bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0;
8649 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008650 bool flatten_member_reference = (flags & ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008651
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008652 if (!chain_only)
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008653 {
8654 // We handle transpose explicitly, so don't resolve that here.
8655 auto *e = maybe_get<SPIRExpression>(base);
8656 bool old_transpose = e && e->need_transpose;
8657 if (e)
8658 e->need_transpose = false;
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008659 expr = to_enclosed_expression(base, register_expression_read);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008660 if (e)
8661 e->need_transpose = old_transpose;
8662 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008663
Bill Hollings1e84a372017-08-12 00:21:13 -04008664 // Start traversing type hierarchy at the proper non-pointer types,
8665 // but keep type_id referencing the original pointer for use below.
Bill Hollingse0910312018-06-24 15:06:12 -04008666 uint32_t type_id = expression_type_id(base);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02008667
8668 if (!backend.native_pointers)
8669 {
8670 if (ptr_chain)
8671 SPIRV_CROSS_THROW("Backend does not support native pointers and does not support OpPtrAccessChain.");
8672
8673 // Wrapped buffer reference pointer types will need to poke into the internal "value" member before
8674 // continuing the access chain.
8675 if (should_dereference(base))
8676 {
8677 auto &type = get<SPIRType>(type_id);
8678 expr = dereference_expression(type, expr);
8679 }
8680 }
8681
Chip Davisfc02b3d2019-01-08 12:54:40 -06008682 const auto *type = &get_pointee_type(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008683
Hans-Kristian Arntzenb71f5df2018-05-08 15:33:51 +02008684 bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos;
Bill Hollings13583622016-12-14 02:12:52 -05008685 bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008686 bool is_packed = has_extended_decoration(base, SPIRVCrossDecorationPhysicalTypePacked);
8687 uint32_t physical_type = get_extended_decoration(base, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008688 bool is_invariant = has_decoration(base, DecorationInvariant);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008689 bool pending_array_enclose = false;
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008690 bool dimension_flatten = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008691
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008692 const auto append_index = [&](uint32_t index, bool is_literal) {
8693 AccessChainFlags mod_flags = flags;
8694 if (!is_literal)
8695 mod_flags &= ~ACCESS_CHAIN_INDEX_IS_LITERAL_BIT;
8696 access_chain_internal_append_index(expr, base, type, mod_flags, access_chain_is_arrayed, index);
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02008697 };
8698
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008699 for (uint32_t i = 0; i < count; i++)
8700 {
8701 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008702
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008703 bool is_literal = index_is_literal;
8704 if (is_literal && msb_is_id && (index >> 31u) != 0u)
8705 {
8706 is_literal = false;
8707 index &= 0x7fffffffu;
8708 }
8709
Chip Davis3bfb2f92018-12-03 02:06:33 -06008710 // Pointer chains
8711 if (ptr_chain && i == 0)
8712 {
8713 // If we are flattening multidimensional arrays, only create opening bracket on first
8714 // array index.
8715 if (options.flatten_multidimensional_arrays)
8716 {
8717 dimension_flatten = type->array.size() >= 1;
8718 pending_array_enclose = dimension_flatten;
8719 if (pending_array_enclose)
8720 expr += "[";
8721 }
8722
8723 if (options.flatten_multidimensional_arrays && dimension_flatten)
8724 {
8725 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008726 if (is_literal)
Chip Davis3bfb2f92018-12-03 02:06:33 -06008727 expr += convert_to_string(index);
8728 else
8729 expr += to_enclosed_expression(index, register_expression_read);
8730
8731 for (auto j = uint32_t(type->array.size()); j; j--)
8732 {
8733 expr += " * ";
8734 expr += enclose_expression(to_array_size(*type, j - 1));
8735 }
8736
8737 if (type->array.empty())
8738 pending_array_enclose = false;
8739 else
8740 expr += " + ";
8741
8742 if (!pending_array_enclose)
8743 expr += "]";
8744 }
8745 else
8746 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008747 append_index(index, is_literal);
Chip Davis3bfb2f92018-12-03 02:06:33 -06008748 }
8749
Chip Davise75add42019-02-05 18:13:26 -06008750 if (type->basetype == SPIRType::ControlPointArray)
8751 {
8752 type_id = type->parent_type;
8753 type = &get<SPIRType>(type_id);
8754 }
8755
Chip Davis3bfb2f92018-12-03 02:06:33 -06008756 access_chain_is_arrayed = true;
8757 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008758 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06008759 else if (!type->array.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008760 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008761 // If we are flattening multidimensional arrays, only create opening bracket on first
8762 // array index.
8763 if (options.flatten_multidimensional_arrays && !pending_array_enclose)
8764 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008765 dimension_flatten = type->array.size() > 1;
8766 pending_array_enclose = dimension_flatten;
8767 if (pending_array_enclose)
8768 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008769 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008770
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01008771 assert(type->parent_type);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008772
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008773 auto *var = maybe_get<SPIRVariable>(base);
Bill Hollings27d4af72018-01-08 16:18:34 -05008774 if (backend.force_gl_in_out_block && i == 0 && var && is_builtin_variable(*var) &&
8775 !has_decoration(type->self, DecorationBlock))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008776 {
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008777 // This deals with scenarios for tesc/geom where arrays of gl_Position[] are declared.
8778 // Normally, these variables live in blocks when compiled from GLSL,
8779 // but HLSL seems to just emit straight arrays here.
8780 // We must pretend this access goes through gl_in/gl_out arrays
8781 // to be able to access certain builtins as arrays.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02008782 auto builtin = ir.meta[base].decoration.builtin_type;
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008783 switch (builtin)
8784 {
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01008785 // case BuiltInCullDistance: // These are already arrays, need to figure out rules for these in tess/geom.
8786 // case BuiltInClipDistance:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008787 case BuiltInPosition:
8788 case BuiltInPointSize:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008789 if (var->storage == StorageClassInput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008790 expr = join("gl_in[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008791 else if (var->storage == StorageClassOutput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008792 expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008793 else
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008794 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008795 break;
8796
8797 default:
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008798 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008799 break;
8800 }
8801 }
8802 else if (options.flatten_multidimensional_arrays && dimension_flatten)
8803 {
8804 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008805 auto &parent_type = get<SPIRType>(type->parent_type);
8806
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008807 if (is_literal)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008808 expr += convert_to_string(index);
8809 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008810 expr += to_enclosed_expression(index, register_expression_read);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008811
8812 for (auto j = uint32_t(parent_type.array.size()); j; j--)
8813 {
8814 expr += " * ";
8815 expr += enclose_expression(to_array_size(parent_type, j - 1));
8816 }
8817
8818 if (parent_type.array.empty())
8819 pending_array_enclose = false;
8820 else
8821 expr += " + ";
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008822
8823 if (!pending_array_enclose)
8824 expr += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008825 }
Hans-Kristian Arntzen9d18c822019-10-24 17:10:22 +02008826 // 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.
8827 // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask.
8828 else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn))))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008829 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008830 append_index(index, is_literal);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008831 }
8832
Bill Hollings1e84a372017-08-12 00:21:13 -04008833 type_id = type->parent_type;
8834 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008836 access_chain_is_arrayed = true;
8837 }
Bill Hollings76cb8072021-10-28 10:16:34 -04008838 // 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 +02008839 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
8840 else if (type->basetype == SPIRType::Struct)
8841 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008842 if (!is_literal)
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008843 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008844
Bill Hollings76cb8072021-10-28 10:16:34 -04008845 if (index < uint32_t(type->member_type_index_redirection.size()))
8846 index = type->member_type_index_redirection[index];
8847
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008848 if (index >= type->member_types.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008849 SPIRV_CROSS_THROW("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008850
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008851 BuiltIn builtin;
Hans-Kristian Arntzen75ed7382021-04-14 15:10:02 +02008852 if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008853 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008854 if (access_chain_is_arrayed)
8855 {
8856 expr += ".";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008857 expr += builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008858 }
8859 else
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008860 expr = builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008861 }
8862 else
8863 {
Bill Hollingsc1b81542017-05-22 21:41:19 -04008864 // If the member has a qualified name, use it as the entire chain
Bill Hollings1e84a372017-08-12 00:21:13 -04008865 string qual_mbr_name = get_member_qualified_name(type_id, index);
Bill Hollingsc1b81542017-05-22 21:41:19 -04008866 if (!qual_mbr_name.empty())
8867 expr = qual_mbr_name;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008868 else if (flatten_member_reference)
8869 expr += join("_", to_member_name(*type, index));
Bill Hollingsc1b81542017-05-22 21:41:19 -04008870 else
Chip Davis3bfb2f92018-12-03 02:06:33 -06008871 expr += to_member_reference(base, *type, index, ptr_chain);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008872 }
Bill Hollingsb332bae2017-03-01 13:07:40 -05008873
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008874 if (has_member_decoration(type->self, index, DecorationInvariant))
8875 is_invariant = true;
8876
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008877 is_packed = member_is_packed_physical_type(*type, index);
Hans-Kristian Arntzenf6251e42019-07-19 11:21:02 +02008878 if (member_is_remapped_physical_type(*type, index))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008879 physical_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008880 else
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008881 physical_type = 0;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008882
Bill Hollings13583622016-12-14 02:12:52 -05008883 row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008884 type = &get<SPIRType>(type->member_types[index]);
8885 }
8886 // Matrix -> Vector
8887 else if (type->columns > 1)
8888 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008889 // If we have a row-major matrix here, we need to defer any transpose in case this access chain
8890 // is used to store a column. We can resolve it right here and now if we access a scalar directly,
8891 // by flipping indexing order of the matrix.
Bill Hollings343677e2016-12-11 11:01:08 -05008892
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008893 expr += "[";
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008894 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008895 expr += convert_to_string(index);
8896 else
Bill Hollings974a0812021-10-21 16:11:33 -04008897 expr += to_unpacked_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008898 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008899
Bill Hollings1e84a372017-08-12 00:21:13 -04008900 type_id = type->parent_type;
8901 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008902 }
8903 // Vector -> Scalar
8904 else if (type->vecsize > 1)
8905 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008906 string deferred_index;
8907 if (row_major_matrix_needs_conversion)
8908 {
8909 // Flip indexing order.
8910 auto column_index = expr.find_last_of('[');
8911 if (column_index != string::npos)
8912 {
8913 deferred_index = expr.substr(column_index);
8914 expr.resize(column_index);
8915 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008916 }
8917
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008918 // Internally, access chain implementation can also be used on composites,
8919 // ignore scalar access workarounds in this case.
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02008920 StorageClass effective_storage = StorageClassGeneric;
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008921 bool ignore_potential_sliced_writes = false;
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02008922 if ((flags & ACCESS_CHAIN_FORCE_COMPOSITE_BIT) == 0)
8923 {
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +02008924 if (expression_type(base).pointer)
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02008925 effective_storage = get_expression_effective_storage_class(base);
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008926
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008927 // Special consideration for control points.
8928 // Control points can only be written by InvocationID, so there is no need
8929 // to consider scalar access chains here.
8930 // Cleans up some cases where it's very painful to determine the accurate storage class
8931 // since blocks can be partially masked ...
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +02008932 auto *var = maybe_get_backing_variable(base);
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008933 if (var && var->storage == StorageClassOutput &&
8934 get_execution_model() == ExecutionModelTessellationControl &&
8935 !has_decoration(var->self, DecorationPatch))
8936 {
8937 ignore_potential_sliced_writes = true;
8938 }
8939 }
8940 else
8941 ignore_potential_sliced_writes = true;
8942
8943 if (!row_major_matrix_needs_conversion && !ignore_potential_sliced_writes)
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008944 {
8945 // On some backends, we might not be able to safely access individual scalars in a vector.
8946 // To work around this, we might have to cast the access chain reference to something which can,
8947 // like a pointer to scalar, which we can then index into.
8948 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
8949 is_packed);
8950 }
8951
Sebastián Aedo905b8242021-11-11 12:57:57 -03008952 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008953 {
Sebastián Aedo905b8242021-11-11 12:57:57 -03008954 bool out_of_bounds = (index >= type->vecsize);
8955
8956 if (!is_packed && !row_major_matrix_needs_conversion)
8957 {
8958 expr += ".";
8959 expr += index_to_swizzle(out_of_bounds ? 0 : index);
8960 }
8961 else
8962 {
8963 // For packed vectors, we can only access them as an array, not by swizzle.
8964 expr += join("[", out_of_bounds ? 0 : index, "]");
8965 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008966 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008967 else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008968 {
8969 auto &c = get<SPIRConstant>(index);
Sebastián Aedo905b8242021-11-11 12:57:57 -03008970 bool out_of_bounds = (c.scalar() >= type->vecsize);
8971
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02008972 if (c.specialization)
8973 {
8974 // If the index is a spec constant, we cannot turn extract into a swizzle.
Sebastián Aedo905b8242021-11-11 12:57:57 -03008975 expr += join("[", out_of_bounds ? "0" : to_expression(index), "]");
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02008976 }
8977 else
8978 {
8979 expr += ".";
Sebastián Aedo905b8242021-11-11 12:57:57 -03008980 expr += index_to_swizzle(out_of_bounds ? 0 : c.scalar());
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02008981 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008982 }
8983 else
8984 {
8985 expr += "[";
Bill Hollings974a0812021-10-21 16:11:33 -04008986 expr += to_unpacked_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008987 expr += "]";
8988 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008989
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02008990 if (row_major_matrix_needs_conversion && !ignore_potential_sliced_writes)
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008991 {
8992 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
8993 is_packed);
8994 }
8995
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008996 expr += deferred_index;
8997 row_major_matrix_needs_conversion = false;
8998
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01008999 is_packed = false;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009000 physical_type = 0;
Bill Hollings1e84a372017-08-12 00:21:13 -04009001 type_id = type->parent_type;
9002 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009003 }
Bill Hollings2964e322018-02-13 14:44:40 -05009004 else if (!backend.allow_truncated_access_chain)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01009005 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009006 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009007
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009008 if (pending_array_enclose)
9009 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02009010 SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
9011 "but the access chain was terminated in the middle of a multidimensional array. "
9012 "This is not supported.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009013 }
9014
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009015 if (meta)
9016 {
9017 meta->need_transpose = row_major_matrix_needs_conversion;
9018 meta->storage_is_packed = is_packed;
9019 meta->storage_is_invariant = is_invariant;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009020 meta->storage_physical_type = physical_type;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009021 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009022
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009023 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009024}
9025
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02009026void CompilerGLSL::prepare_access_chain_for_scalar_access(std::string &, const SPIRType &, spv::StorageClass, bool &)
9027{
9028}
9029
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009030string CompilerGLSL::to_flattened_struct_member(const string &basename, const SPIRType &type, uint32_t index)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009031{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009032 auto ret = join(basename, "_", to_member_name(type, index));
9033 ParsedIR::sanitize_underscores(ret);
9034 return ret;
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009035}
9036
Bill Hollings2d0d3282017-01-20 11:33:59 -05009037string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
Chip Davis3bfb2f92018-12-03 02:06:33 -06009038 AccessChainMeta *meta, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009039{
Arseny Kapoulkine24c66252017-01-16 14:19:49 -08009040 if (flattened_buffer_blocks.count(base))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009041 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009042 uint32_t matrix_stride = 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009043 uint32_t array_stride = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009044 bool need_transpose = false;
Chip Davis3bfb2f92018-12-03 02:06:33 -06009045 flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009046 &array_stride, ptr_chain);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009047
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009048 if (meta)
9049 {
9050 meta->need_transpose = target_type.columns > 1 && need_transpose;
9051 meta->storage_is_packed = false;
9052 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009053
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01009054 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, array_stride,
9055 need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009056 }
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009057 else if (flattened_structs.count(base) && count > 0)
9058 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009059 AccessChainFlags flags = ACCESS_CHAIN_CHAIN_ONLY_BIT | ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
9060 if (ptr_chain)
9061 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
9062
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009063 if (flattened_structs[base])
9064 {
9065 flags |= ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT;
9066 if (meta)
9067 meta->flattened_struct = target_type.basetype == SPIRType::Struct;
9068 }
9069
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009070 auto chain = access_chain_internal(base, indices, count, flags, nullptr).substr(1);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009071 if (meta)
9072 {
9073 meta->need_transpose = false;
9074 meta->storage_is_packed = false;
9075 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009076
9077 auto basename = to_flattened_access_chain_expression(base);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009078 auto ret = join(basename, "_", chain);
9079 ParsedIR::sanitize_underscores(ret);
9080 return ret;
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009081 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009082 else
9083 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009084 AccessChainFlags flags = ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
9085 if (ptr_chain)
9086 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
9087 return access_chain_internal(base, indices, count, flags, meta);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009088 }
9089}
9090
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009091string CompilerGLSL::load_flattened_struct(const string &basename, const SPIRType &type)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009092{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009093 auto expr = type_to_glsl_constructor(type);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009094 expr += '(';
9095
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009096 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
9097 {
9098 if (i)
9099 expr += ", ";
9100
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009101 auto &member_type = get<SPIRType>(type.member_types[i]);
9102 if (member_type.basetype == SPIRType::Struct)
9103 expr += load_flattened_struct(to_flattened_struct_member(basename, type, i), member_type);
9104 else
9105 expr += to_flattened_struct_member(basename, type, i);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009106 }
9107 expr += ')';
9108 return expr;
9109}
9110
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009111std::string CompilerGLSL::to_flattened_access_chain_expression(uint32_t id)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009112{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009113 // Do not use to_expression as that will unflatten access chains.
9114 string basename;
9115 if (const auto *var = maybe_get<SPIRVariable>(id))
9116 basename = to_name(var->self);
9117 else if (const auto *expr = maybe_get<SPIRExpression>(id))
9118 basename = expr->expression;
9119 else
9120 basename = to_expression(id);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009121
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009122 return basename;
9123}
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009124
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009125void CompilerGLSL::store_flattened_struct(const string &basename, uint32_t rhs_id, const SPIRType &type,
9126 const SmallVector<uint32_t> &indices)
9127{
9128 SmallVector<uint32_t> sub_indices = indices;
9129 sub_indices.push_back(0);
9130
9131 auto *member_type = &type;
9132 for (auto &index : indices)
9133 member_type = &get<SPIRType>(member_type->member_types[index]);
9134
9135 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009136 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009137 sub_indices.back() = i;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009138 auto lhs = join(basename, "_", to_member_name(*member_type, i));
9139 ParsedIR::sanitize_underscores(lhs);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009140
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009141 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
9142 {
9143 store_flattened_struct(lhs, rhs_id, type, sub_indices);
9144 }
9145 else
9146 {
9147 auto rhs = to_expression(rhs_id) + to_multi_member_reference(type, sub_indices);
9148 statement(lhs, " = ", rhs, ";");
9149 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009150 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009151}
9152
9153void CompilerGLSL::store_flattened_struct(uint32_t lhs_id, uint32_t value)
9154{
9155 auto &type = expression_type(lhs_id);
9156 auto basename = to_flattened_access_chain_expression(lhs_id);
9157 store_flattened_struct(basename, value, type, {});
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009158}
9159
Bill Hollings2d0d3282017-01-20 11:33:59 -05009160std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009161 const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009162 uint32_t /* array_stride */, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009163{
9164 if (!target_type.array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009165 SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009166 else if (target_type.basetype == SPIRType::Struct)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009167 return flattened_access_chain_struct(base, indices, count, target_type, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009168 else if (target_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009169 return flattened_access_chain_matrix(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009170 else
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009171 return flattened_access_chain_vector(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009172}
9173
Bill Hollings2d0d3282017-01-20 11:33:59 -05009174std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
9175 const SPIRType &target_type, uint32_t offset)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009176{
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009177 std::string expr;
9178
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01009179 expr += type_to_glsl_constructor(target_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009180 expr += "(";
9181
Henrik Rydgårdbfae0412017-03-07 09:59:26 +01009182 for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009183 {
9184 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08009185 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009186
9187 const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009188 uint32_t member_offset = type_struct_member_offset(target_type, i);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009189
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009190 // The access chain terminates at the struct, so we need to find matrix strides and row-major information
9191 // ahead of time.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009192 bool need_transpose = false;
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009193 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009194 if (member_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009195 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009196 need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009197 matrix_stride = type_struct_member_matrix_stride(target_type, i);
9198 }
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009199
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009200 auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009201 0 /* array_stride */, need_transpose);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009202
9203 // Cannot forward transpositions, so resolve them here.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009204 if (need_transpose)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009205 expr += convert_row_major_matrix(tmp, member_type, 0, false);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009206 else
9207 expr += tmp;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009208 }
9209
9210 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009211
9212 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009213}
9214
Bill Hollings2d0d3282017-01-20 11:33:59 -05009215std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009216 const SPIRType &target_type, uint32_t offset,
9217 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009218{
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009219 assert(matrix_stride);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009220 SPIRType tmp_type = target_type;
9221 if (need_transpose)
9222 swap(tmp_type.vecsize, tmp_type.columns);
9223
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009224 std::string expr;
9225
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009226 expr += type_to_glsl_constructor(tmp_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009227 expr += "(";
9228
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009229 for (uint32_t i = 0; i < tmp_type.columns; i++)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009230 {
9231 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08009232 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009233
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009234 expr += flattened_access_chain_vector(base, indices, count, tmp_type, offset + i * matrix_stride, matrix_stride,
9235 /* need_transpose= */ false);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009236 }
9237
9238 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009239
9240 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009241}
9242
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009243std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
9244 const SPIRType &target_type, uint32_t offset,
9245 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009246{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02009247 auto result = flattened_access_chain_offset(expression_type(base), indices, count, offset, 16);
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009248
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009249 auto buffer_name = to_name(expression_type(base).self);
9250
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009251 if (need_transpose)
9252 {
9253 std::string expr;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009254
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08009255 if (target_type.vecsize > 1)
9256 {
9257 expr += type_to_glsl_constructor(target_type);
9258 expr += "(";
9259 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009260
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009261 for (uint32_t i = 0; i < target_type.vecsize; ++i)
9262 {
9263 if (i != 0)
9264 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009265
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009266 uint32_t component_offset = result.second + i * matrix_stride;
9267
9268 assert(component_offset % (target_type.width / 8) == 0);
9269 uint32_t index = component_offset / (target_type.width / 8);
9270
9271 expr += buffer_name;
9272 expr += "[";
9273 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
9274 expr += convert_to_string(index / 4);
9275 expr += "]";
9276
9277 expr += vector_swizzle(1, index % 4);
9278 }
9279
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08009280 if (target_type.vecsize > 1)
9281 {
9282 expr += ")";
9283 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009284
9285 return expr;
9286 }
9287 else
9288 {
9289 assert(result.second % (target_type.width / 8) == 0);
9290 uint32_t index = result.second / (target_type.width / 8);
9291
9292 std::string expr;
9293
9294 expr += buffer_name;
9295 expr += "[";
9296 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
9297 expr += convert_to_string(index / 4);
9298 expr += "]";
9299
9300 expr += vector_swizzle(target_type.vecsize, index % 4);
9301
9302 return expr;
9303 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009304}
9305
Chip Davis3bfb2f92018-12-03 02:06:33 -06009306std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(
9307 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 +01009308 bool *need_transpose, uint32_t *out_matrix_stride, uint32_t *out_array_stride, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009309{
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01009310 // Start traversing type hierarchy at the proper non-pointer types.
Chip Davisfc02b3d2019-01-08 12:54:40 -06009311 const auto *type = &get_pointee_type(basetype);
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01009312
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009313 std::string expr;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009314
9315 // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout.
9316 bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false;
9317 uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009318 uint32_t array_stride = out_array_stride ? *out_array_stride : 0;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009319
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009320 for (uint32_t i = 0; i < count; i++)
9321 {
9322 uint32_t index = indices[i];
9323
Chip Davis3bfb2f92018-12-03 02:06:33 -06009324 // Pointers
9325 if (ptr_chain && i == 0)
9326 {
9327 // Here, the pointer type will be decorated with an array stride.
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009328 array_stride = get_decoration(basetype.self, DecorationArrayStride);
Chip Davis3bfb2f92018-12-03 02:06:33 -06009329 if (!array_stride)
9330 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
9331
9332 auto *constant = maybe_get<SPIRConstant>(index);
9333 if (constant)
9334 {
9335 // Constant array access.
9336 offset += constant->scalar() * array_stride;
9337 }
9338 else
9339 {
9340 // Dynamic array access.
9341 if (array_stride % word_stride)
9342 {
crissdb52e272020-10-08 12:14:52 +02009343 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
9344 "of a 4-component vector. "
9345 "Likely culprit here is a float or vec2 array inside a push "
9346 "constant block which is std430. "
9347 "This cannot be flattened. Try using std140 layout instead.");
Chip Davis3bfb2f92018-12-03 02:06:33 -06009348 }
9349
9350 expr += to_enclosed_expression(index);
9351 expr += " * ";
9352 expr += convert_to_string(array_stride / word_stride);
9353 expr += " + ";
9354 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06009355 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009356 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06009357 else if (!type->array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009358 {
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009359 auto *constant = maybe_get<SPIRConstant>(index);
9360 if (constant)
9361 {
9362 // Constant array access.
9363 offset += constant->scalar() * array_stride;
9364 }
9365 else
9366 {
9367 // Dynamic array access.
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009368 if (array_stride % word_stride)
9369 {
crissdb52e272020-10-08 12:14:52 +02009370 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
9371 "of a 4-component vector. "
9372 "Likely culprit here is a float or vec2 array inside a push "
9373 "constant block which is std430. "
9374 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009375 }
9376
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009377 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009378 expr += " * ";
9379 expr += convert_to_string(array_stride / word_stride);
9380 expr += " + ";
9381 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009382
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009383 uint32_t parent_type = type->parent_type;
9384 type = &get<SPIRType>(parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01009385
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009386 if (!type->array.empty())
9387 array_stride = get_decoration(parent_type, DecorationArrayStride);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009388 }
9389 // For structs, the index refers to a constant, which indexes into the members.
9390 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
9391 else if (type->basetype == SPIRType::Struct)
9392 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009393 index = evaluate_constant_u32(index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009394
9395 if (index >= type->member_types.size())
9396 SPIRV_CROSS_THROW("Member index is out of bounds!");
9397
9398 offset += type_struct_member_offset(*type, index);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009399
9400 auto &struct_type = *type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009401 type = &get<SPIRType>(type->member_types[index]);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009402
9403 if (type->columns > 1)
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009404 {
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009405 matrix_stride = type_struct_member_matrix_stride(struct_type, index);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009406 row_major_matrix_needs_conversion =
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009407 combined_decoration_for_member(struct_type, index).get(DecorationRowMajor);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009408 }
9409 else
9410 row_major_matrix_needs_conversion = false;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009411
9412 if (!type->array.empty())
9413 array_stride = type_struct_member_array_stride(struct_type, index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009414 }
9415 // Matrix -> Vector
9416 else if (type->columns > 1)
9417 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009418 auto *constant = maybe_get<SPIRConstant>(index);
9419 if (constant)
9420 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009421 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009422 offset += index * (row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride);
9423 }
9424 else
9425 {
9426 uint32_t indexing_stride = row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride;
9427 // Dynamic array access.
9428 if (indexing_stride % word_stride)
9429 {
crissdb52e272020-10-08 12:14:52 +02009430 SPIRV_CROSS_THROW("Matrix stride for dynamic indexing must be divisible by the size of a "
9431 "4-component vector. "
9432 "Likely culprit here is a row-major matrix being accessed dynamically. "
9433 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009434 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009435
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009436 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009437 expr += " * ";
9438 expr += convert_to_string(indexing_stride / word_stride);
9439 expr += " + ";
9440 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009441
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009442 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009443 }
9444 // Vector -> Scalar
9445 else if (type->vecsize > 1)
9446 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009447 auto *constant = maybe_get<SPIRConstant>(index);
9448 if (constant)
9449 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009450 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009451 offset += index * (row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8));
9452 }
9453 else
9454 {
9455 uint32_t indexing_stride = row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009456
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009457 // Dynamic array access.
9458 if (indexing_stride % word_stride)
9459 {
crissdb52e272020-10-08 12:14:52 +02009460 SPIRV_CROSS_THROW("Stride for dynamic vector indexing must be divisible by the "
9461 "size of a 4-component vector. "
9462 "This cannot be flattened in legacy targets.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009463 }
9464
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009465 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009466 expr += " * ";
9467 expr += convert_to_string(indexing_stride / word_stride);
9468 expr += " + ";
9469 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009470
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009471 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009472 }
9473 else
9474 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
9475 }
9476
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08009477 if (need_transpose)
9478 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009479 if (out_matrix_stride)
9480 *out_matrix_stride = matrix_stride;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009481 if (out_array_stride)
9482 *out_array_stride = array_stride;
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08009483
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009484 return std::make_pair(expr, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009485}
9486
Chip Davis3bfb2f92018-12-03 02:06:33 -06009487bool CompilerGLSL::should_dereference(uint32_t id)
9488{
9489 const auto &type = expression_type(id);
9490 // Non-pointer expressions don't need to be dereferenced.
9491 if (!type.pointer)
9492 return false;
9493
9494 // Handles shouldn't be dereferenced either.
9495 if (!expression_is_lvalue(id))
9496 return false;
9497
9498 // If id is a variable but not a phi variable, we should not dereference it.
9499 if (auto *var = maybe_get<SPIRVariable>(id))
9500 return var->phi_variable;
9501
9502 // If id is an access chain, we should not dereference it.
9503 if (auto *expr = maybe_get<SPIRExpression>(id))
9504 return !expr->access_chain;
9505
9506 // Otherwise, we should dereference this pointer expression.
9507 return true;
9508}
9509
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009510bool CompilerGLSL::should_forward(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009511{
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07009512 // If id is a variable we will try to forward it regardless of force_temporary check below
9513 // 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 +02009514 auto *var = maybe_get<SPIRVariable>(id);
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07009515 if (var && var->forwardable)
9516 return true;
9517
9518 // For debugging emit temporary variables for all expressions
9519 if (options.force_temporary)
9520 return false;
9521
9522 // Immutable expression can always be forwarded.
9523 if (is_immutable(id))
9524 return true;
9525
9526 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009527}
9528
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009529bool CompilerGLSL::should_suppress_usage_tracking(uint32_t id) const
9530{
9531 // Used only by opcodes which don't do any real "work", they just swizzle data in some fashion.
9532 return !expression_is_forwarded(id) || expression_suppresses_usage_tracking(id);
9533}
9534
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009535void CompilerGLSL::track_expression_read(uint32_t id)
9536{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009537 switch (ir.ids[id].get_type())
9538 {
9539 case TypeExpression:
9540 {
9541 auto &e = get<SPIRExpression>(id);
9542 for (auto implied_read : e.implied_read_expressions)
9543 track_expression_read(implied_read);
9544 break;
9545 }
9546
9547 case TypeAccessChain:
9548 {
9549 auto &e = get<SPIRAccessChain>(id);
9550 for (auto implied_read : e.implied_read_expressions)
9551 track_expression_read(implied_read);
9552 break;
9553 }
9554
9555 default:
9556 break;
9557 }
9558
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009559 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
9560 // 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 +02009561 if (expression_is_forwarded(id) && !expression_suppresses_usage_tracking(id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009562 {
9563 auto &v = expression_usage_counts[id];
9564 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009565
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02009566 // If we create an expression outside a loop,
9567 // but access it inside a loop, we're implicitly reading it multiple times.
9568 // If the expression in question is expensive, we should hoist it out to avoid relying on loop-invariant code motion
9569 // working inside the backend compiler.
9570 if (expression_read_implies_multiple_reads(id))
9571 v++;
9572
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009573 if (v >= 2)
9574 {
9575 //if (v == 2)
9576 // 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 +01009577
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009578 forced_temporaries.insert(id);
9579 // Force a recompile after this pass to avoid forwarding this variable.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009580 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009581 }
9582 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009583}
9584
9585bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
9586{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009587 if (forced_temporaries.find(id) != end(forced_temporaries))
9588 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009589
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009590 for (uint32_t i = 0; i < num_args; i++)
9591 if (!should_forward(args[i]))
9592 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009593
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009594 // We need to forward globals as well.
9595 if (!pure)
9596 {
9597 for (auto global : global_variables)
9598 if (!should_forward(global))
9599 return false;
9600 for (auto aliased : aliased_variables)
9601 if (!should_forward(aliased))
9602 return false;
9603 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009604
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009605 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009606}
9607
9608void CompilerGLSL::register_impure_function_call()
9609{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009610 // Impure functions can modify globals and aliased variables, so invalidate them as well.
9611 for (auto global : global_variables)
9612 flush_dependees(get<SPIRVariable>(global));
9613 for (auto aliased : aliased_variables)
9614 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009615}
9616
9617void CompilerGLSL::register_call_out_argument(uint32_t id)
9618{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009619 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009620
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009621 auto *var = maybe_get<SPIRVariable>(id);
9622 if (var)
9623 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009624}
9625
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01009626string CompilerGLSL::variable_decl_function_local(SPIRVariable &var)
9627{
9628 // These variables are always function local,
9629 // so make sure we emit the variable without storage qualifiers.
9630 // Some backends will inject custom variables locally in a function
9631 // with a storage qualifier which is not function-local.
9632 auto old_storage = var.storage;
9633 var.storage = StorageClassFunction;
9634 auto expr = variable_decl(var);
9635 var.storage = old_storage;
9636 return expr;
9637}
9638
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009639void CompilerGLSL::emit_variable_temporary_copies(const SPIRVariable &var)
9640{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04009641 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen3f569ed2019-10-24 17:12:23 +02009642 if (var.allocate_temporary_copy && !flushed_phi_variables.count(var.self))
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009643 {
9644 auto &type = get<SPIRType>(var.basetype);
9645 auto &flags = get_decoration_bitset(var.self);
9646 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, join("_", var.self, "_copy")), ";");
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04009647 flushed_phi_variables.insert(var.self);
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009648 }
9649}
9650
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009651void CompilerGLSL::flush_variable_declaration(uint32_t id)
9652{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04009653 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009654 auto *var = maybe_get<SPIRVariable>(id);
9655 if (var && var->deferred_declaration)
9656 {
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01009657 string initializer;
9658 if (options.force_zero_initialized_variables &&
9659 (var->storage == StorageClassFunction || var->storage == StorageClassGeneric ||
9660 var->storage == StorageClassPrivate) &&
9661 !var->initializer && type_can_zero_initialize(get_variable_data_type(*var)))
9662 {
9663 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(*var)));
9664 }
9665
9666 statement(variable_decl_function_local(*var), initializer, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009667 var->deferred_declaration = false;
9668 }
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04009669 if (var)
9670 {
9671 emit_variable_temporary_copies(*var);
9672 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009673}
9674
9675bool CompilerGLSL::remove_duplicate_swizzle(string &op)
9676{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009677 auto pos = op.find_last_of('.');
9678 if (pos == string::npos || pos == 0)
9679 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009680
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009681 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009683 if (backend.swizzle_is_function)
9684 {
9685 if (final_swiz.size() < 2)
9686 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009687
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009688 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
9689 final_swiz.erase(final_swiz.size() - 2, string::npos);
9690 else
9691 return false;
9692 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009693
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009694 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
9695 // If so, and previous swizzle is of same length,
9696 // we can drop the final swizzle altogether.
9697 for (uint32_t i = 0; i < final_swiz.size(); i++)
9698 {
9699 static const char expected[] = { 'x', 'y', 'z', 'w' };
9700 if (i >= 4 || final_swiz[i] != expected[i])
9701 return false;
9702 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009703
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009704 auto prevpos = op.find_last_of('.', pos - 1);
9705 if (prevpos == string::npos)
9706 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009707
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009708 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009709
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009710 // Make sure there are only swizzles here ...
9711 for (auto i = prevpos; i < pos; i++)
9712 {
9713 if (op[i] < 'w' || op[i] > 'z')
9714 {
9715 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
9716 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
9717 break;
9718 return false;
9719 }
9720 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009721
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009722 // If original swizzle is large enough, just carve out the components we need.
9723 // E.g. foobar.wyx.xy will turn into foobar.wy.
9724 if (pos - prevpos >= final_swiz.size())
9725 {
9726 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009727
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009728 // Add back the function call ...
9729 if (backend.swizzle_is_function)
9730 op += "()";
9731 }
9732 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009733}
9734
9735// Optimizes away vector swizzles where we have something like
9736// vec3 foo;
9737// foo.xyz <-- swizzle expression does nothing.
9738// This is a very common pattern after OpCompositeCombine.
9739bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
9740{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009741 auto pos = op.find_last_of('.');
9742 if (pos == string::npos || pos == 0)
9743 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009745 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009746
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009747 if (backend.swizzle_is_function)
9748 {
9749 if (final_swiz.size() < 2)
9750 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009751
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009752 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
9753 final_swiz.erase(final_swiz.size() - 2, string::npos);
9754 else
9755 return false;
9756 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009757
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009758 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
9759 // If so, and previous swizzle is of same length,
9760 // we can drop the final swizzle altogether.
9761 for (uint32_t i = 0; i < final_swiz.size(); i++)
9762 {
9763 static const char expected[] = { 'x', 'y', 'z', 'w' };
9764 if (i >= 4 || final_swiz[i] != expected[i])
9765 return false;
9766 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009767
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009768 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009769
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009770 // Sanity checking ...
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04009771 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009772
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009773 if (type.vecsize == final_swiz.size())
9774 op.erase(pos, string::npos);
9775 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009776}
9777
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009778string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009779{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009780 ID base = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009781 string op;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009782 string subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009783
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009784 // Can only merge swizzles for vectors.
9785 auto &type = get<SPIRType>(return_type);
9786 bool can_apply_swizzle_opt = type.basetype != SPIRType::Struct && type.array.empty() && type.columns == 1;
9787 bool swizzle_optimization = false;
9788
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009789 for (uint32_t i = 0; i < length; i++)
9790 {
9791 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009792
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009793 // If we're merging another scalar which belongs to the same base
9794 // 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 +01009795 if (can_apply_swizzle_opt && e && e->base_expression && e->base_expression == base)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009796 {
9797 // Only supposed to be used for vector swizzle -> scalar.
9798 assert(!e->expression.empty() && e->expression.front() == '.');
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009799 subop += e->expression.substr(1, string::npos);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009800 swizzle_optimization = true;
9801 }
9802 else
9803 {
9804 // We'll likely end up with duplicated swizzles, e.g.
9805 // foobar.xyz.xyz from patterns like
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009806 // OpVectorShuffle
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009807 // OpCompositeExtract x 3
9808 // OpCompositeConstruct 3x + other scalar.
9809 // Just modify op in-place.
9810 if (swizzle_optimization)
9811 {
9812 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009813 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009814
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009815 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
9816 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
9817 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
9818 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
9819 // Case 1:
9820 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
9821 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
9822 // Case 2:
9823 // foo.xyz: Duplicate swizzle won't kick in.
9824 // If foo is vec3, we can remove xyz, giving just foo.
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009825 if (!remove_duplicate_swizzle(subop))
9826 remove_unity_swizzle(base, subop);
9827
9828 // Strips away redundant parens if we created them during component extraction.
9829 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009830 swizzle_optimization = false;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009831 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009832 }
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009833 else
9834 op += subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009836 if (i)
9837 op += ", ";
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02009838
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02009839 bool uses_buffer_offset =
9840 type.basetype == SPIRType::Struct && has_member_decoration(type.self, i, DecorationOffset);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02009841 subop = to_composite_constructor_expression(elems[i], uses_buffer_offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009842 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009843
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009844 base = e ? e->base_expression : ID(0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009845 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009846
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009847 if (swizzle_optimization)
9848 {
9849 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009850 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009851
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009852 if (!remove_duplicate_swizzle(subop))
9853 remove_unity_swizzle(base, subop);
9854 // Strips away redundant parens if we created them during component extraction.
9855 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009856 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009857
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009858 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009859 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009860}
9861
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02009862bool CompilerGLSL::skip_argument(uint32_t id) const
9863{
9864 if (!combined_image_samplers.empty() || !options.vulkan_semantics)
9865 {
9866 auto &type = expression_type(id);
9867 if (type.basetype == SPIRType::Sampler || (type.basetype == SPIRType::Image && type.image.sampled == 1))
9868 return true;
9869 }
9870 return false;
9871}
9872
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02009873bool CompilerGLSL::optimize_read_modify_write(const SPIRType &type, const string &lhs, const string &rhs)
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009874{
9875 // Do this with strings because we have a very clear pattern we can check for and it avoids
9876 // adding lots of special cases to the code emission.
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01009877 if (rhs.size() < lhs.size() + 3)
9878 return false;
9879
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02009880 // Do not optimize matrices. They are a bit awkward to reason about in general
9881 // (in which order does operation happen?), and it does not work on MSL anyways.
9882 if (type.vecsize > 1 && type.columns > 1)
9883 return false;
9884
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009885 auto index = rhs.find(lhs);
9886 if (index != 0)
9887 return false;
9888
9889 // TODO: Shift operators, but it's not important for now.
9890 auto op = rhs.find_first_of("+-/*%|&^", lhs.size() + 1);
9891 if (op != lhs.size() + 1)
9892 return false;
9893
David Srbeckye596d402017-09-05 16:05:53 +01009894 // Check that the op is followed by space. This excludes && and ||.
Hans-Kristian Arntzen03db5c42017-09-06 09:15:27 +02009895 if (rhs[op + 1] != ' ')
David Srbeckye596d402017-09-05 16:05:53 +01009896 return false;
9897
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01009898 char bop = rhs[op];
9899 auto expr = rhs.substr(lhs.size() + 3);
9900 // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code.
9901 // Find some common patterns which are equivalent.
9902 if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)"))
9903 statement(lhs, bop, bop, ";");
9904 else
9905 statement(lhs, " ", bop, "= ", expr, ";");
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009906 return true;
9907}
9908
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009909void CompilerGLSL::register_control_dependent_expression(uint32_t expr)
9910{
9911 if (forwarded_temporaries.find(expr) == end(forwarded_temporaries))
9912 return;
9913
9914 assert(current_emitting_block);
9915 current_emitting_block->invalidate_expressions.push_back(expr);
9916}
9917
9918void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02009919{
9920 current_emitting_block = &block;
9921 for (auto &op : block.ops)
9922 emit_instruction(op);
9923 current_emitting_block = nullptr;
9924}
9925
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009926void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression &expr)
9927{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009928 // Allow trivially forwarded expressions like OpLoad or trivial shuffles,
9929 // these will be marked as having suppressed usage tracking.
9930 // Our only concern is to make sure arithmetic operations are done in similar ways.
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009931 if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) &&
9932 forced_invariant_temporaries.count(expr.self) == 0)
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009933 {
9934 forced_temporaries.insert(expr.self);
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009935 forced_invariant_temporaries.insert(expr.self);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009936 force_recompile();
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009937
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009938 for (auto &dependent : expr.expression_dependencies)
9939 disallow_forwarding_in_expression_chain(get<SPIRExpression>(dependent));
9940 }
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009941}
9942
9943void CompilerGLSL::handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id)
9944{
9945 // Variables or access chains marked invariant are complicated. We will need to make sure the code-gen leading up to
9946 // this variable is consistent. The failure case for SPIRV-Cross is when an expression is forced to a temporary
9947 // in one translation unit, but not another, e.g. due to multiple use of an expression.
9948 // This causes variance despite the output variable being marked invariant, so the solution here is to force all dependent
9949 // expressions to be temporaries.
9950 // It is uncertain if this is enough to support invariant in all possible cases, but it should be good enough
9951 // for all reasonable uses of invariant.
9952 if (!has_decoration(store_id, DecorationInvariant))
9953 return;
9954
9955 auto *expr = maybe_get<SPIRExpression>(value_id);
9956 if (!expr)
9957 return;
9958
9959 disallow_forwarding_in_expression_chain(*expr);
9960}
9961
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01009962void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009963{
9964 auto rhs = to_pointer_expression(rhs_expression);
9965
9966 // Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
9967 if (!rhs.empty())
9968 {
9969 handle_store_to_invariant_variable(lhs_expression, rhs_expression);
9970
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01009971 if (!unroll_array_to_complex_store(lhs_expression, rhs_expression))
9972 {
9973 auto lhs = to_dereferenced_expression(lhs_expression);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02009974 if (has_decoration(lhs_expression, DecorationNonUniform))
9975 convert_non_uniform_expression(lhs, lhs_expression);
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009976
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01009977 // We might need to cast in order to store to a builtin.
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +02009978 cast_to_variable_store(lhs_expression, rhs, expression_type(rhs_expression));
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009979
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01009980 // Tries to optimize assignments like "<lhs> = <lhs> op expr".
9981 // While this is purely cosmetic, this is important for legacy ESSL where loop
9982 // variable increments must be in either i++ or i += const-expr.
9983 // Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
9984 if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
9985 statement(lhs, " = ", rhs, ";");
9986 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009987 register_write(lhs_expression);
9988 }
9989}
9990
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009991uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &instr) const
9992{
9993 if (instr.length < 3)
9994 return 32;
9995
9996 auto *ops = stream(instr);
9997
9998 switch (instr.op)
9999 {
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020010000 case OpSConvert:
10001 case OpConvertSToF:
10002 case OpUConvert:
10003 case OpConvertUToF:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010004 case OpIEqual:
10005 case OpINotEqual:
10006 case OpSLessThan:
10007 case OpSLessThanEqual:
10008 case OpSGreaterThan:
10009 case OpSGreaterThanEqual:
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020010010 case OpULessThan:
10011 case OpULessThanEqual:
10012 case OpUGreaterThan:
10013 case OpUGreaterThanEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010014 return expression_type(ops[2]).width;
10015
10016 default:
10017 {
10018 // We can look at result type which is more robust.
10019 auto *type = maybe_get<SPIRType>(ops[0]);
10020 if (type && type_is_integral(*type))
10021 return type->width;
10022 else
10023 return 32;
10024 }
10025 }
10026}
10027
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +010010028uint32_t CompilerGLSL::get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *ops, uint32_t length) const
10029{
10030 if (length < 1)
10031 return 32;
10032
10033 switch (op)
10034 {
10035 case GLSLstd450SAbs:
10036 case GLSLstd450SSign:
10037 case GLSLstd450UMin:
10038 case GLSLstd450SMin:
10039 case GLSLstd450UMax:
10040 case GLSLstd450SMax:
10041 case GLSLstd450UClamp:
10042 case GLSLstd450SClamp:
10043 case GLSLstd450FindSMsb:
10044 case GLSLstd450FindUMsb:
10045 return expression_type(ops[0]).width;
10046
10047 default:
10048 {
10049 // We don't need to care about other opcodes, just return 32.
10050 return 32;
10051 }
10052 }
10053}
10054
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +020010055void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010056{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010057 auto ops = stream(instruction);
10058 auto opcode = static_cast<Op>(instruction.op);
10059 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010060
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010061#define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
10062#define GLSL_BOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010063 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 +020010064#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
10065#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
10066#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
10067#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
10068#define GLSL_BFOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010069 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 +020010070#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
10071#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010072
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010073 // If we need to do implicit bitcasts, make sure we do it with the correct type.
10074 uint32_t integer_width = get_integer_width_for_instruction(instruction);
10075 auto int_type = to_signed_basetype(integer_width);
10076 auto uint_type = to_unsigned_basetype(integer_width);
10077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010078 switch (opcode)
10079 {
10080 // Dealing with memory
10081 case OpLoad:
10082 {
10083 uint32_t result_type = ops[0];
10084 uint32_t id = ops[1];
10085 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010087 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010088
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010089 // If we're loading from memory that cannot be changed by the shader,
10090 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010091 // If an expression is mutable and forwardable, we speculate that it is immutable.
10092 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
10093
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010094 // If loading a non-native row-major matrix, mark the expression as need_transpose.
10095 bool need_transpose = false;
10096 bool old_need_transpose = false;
10097
10098 auto *ptr_expression = maybe_get<SPIRExpression>(ptr);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010099
10100 if (forward)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010101 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010102 // If we're forwarding the load, we're also going to forward transpose state, so don't transpose while
10103 // taking the expression.
10104 if (ptr_expression && ptr_expression->need_transpose)
10105 {
10106 old_need_transpose = true;
10107 ptr_expression->need_transpose = false;
10108 need_transpose = true;
10109 }
10110 else if (is_non_native_row_major_matrix(ptr))
10111 need_transpose = true;
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010112 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010113
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010114 // If we are forwarding this load,
10115 // don't register the read to access chain here, defer that to when we actually use the expression,
10116 // using the add_implied_read_expression mechanism.
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010117 string expr;
10118
10119 bool is_packed = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked);
10120 bool is_remapped = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID);
10121 if (forward || (!is_packed && !is_remapped))
10122 {
10123 // For the simple case, we do not need to deal with repacking.
10124 expr = to_dereferenced_expression(ptr, false);
10125 }
10126 else
10127 {
10128 // If we are not forwarding the expression, we need to unpack and resolve any physical type remapping here before
10129 // storing the expression to a temporary.
10130 expr = to_unpacked_expression(ptr);
10131 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010132
Chip Davis5281d992020-06-13 23:03:30 -050010133 auto &type = get<SPIRType>(result_type);
10134 auto &expr_type = expression_type(ptr);
10135
10136 // If the expression has more vector components than the result type, insert
10137 // a swizzle. This shouldn't happen normally on valid SPIR-V, but it might
10138 // happen with e.g. the MSL backend replacing the type of an input variable.
10139 if (expr_type.vecsize > type.vecsize)
10140 expr = enclose_expression(expr + vector_swizzle(type.vecsize, 0));
10141
Chip Davis3e6010d2020-10-14 15:04:03 -050010142 // We might need to cast in order to load from a builtin.
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020010143 cast_from_variable_load(ptr, expr, type);
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020010144
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010010145 // We might be trying to load a gl_Position[N], where we should be
10146 // doing float4[](gl_in[i].gl_Position, ...) instead.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010010147 // Similar workarounds are required for input arrays in tessellation.
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010010148 // Also, loading from gl_SampleMask array needs special unroll.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010010149 unroll_array_from_complex_load(id, ptr, expr);
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010010150
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010151 if (!type_is_opaque_value(type) && has_decoration(ptr, DecorationNonUniform))
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010152 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010153 // If we're loading something non-opaque, we need to handle non-uniform descriptor access.
10154 convert_non_uniform_expression(expr, ptr);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010155 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020010156
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010157 if (forward && ptr_expression)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010158 ptr_expression->need_transpose = old_need_transpose;
Bill Hollings13583622016-12-14 02:12:52 -050010159
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020010160 bool flattened = ptr_expression && flattened_buffer_blocks.count(ptr_expression->loaded_from) != 0;
10161
10162 if (backend.needs_row_major_load_workaround && !is_non_native_row_major_matrix(ptr) && !flattened)
10163 rewrite_load_for_wrapped_row_major(expr, result_type, ptr);
10164
Hans-Kristian Arntzen18b82ca2018-07-09 14:02:50 +020010165 // 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 +020010166 // However, if we try to load a complex, composite object from a flattened buffer,
10167 // 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 +020010168 bool usage_tracking = flattened && (type.basetype == SPIRType::Struct || (type.columns > 1));
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +020010169
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010170 SPIRExpression *e = nullptr;
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +020010171 if (!forward && expression_is_non_value_type_array(ptr))
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010172 {
10173 // Complicated load case where we need to make a copy of ptr, but we cannot, because
10174 // it is an array, and our backend does not support arrays as value types.
10175 // Emit the temporary, and copy it explicitly.
10176 e = &emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020010177 emit_array_copy(to_expression(id), id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010178 }
10179 else
10180 e = &emit_op(result_type, id, expr, forward, !usage_tracking);
10181
10182 e->need_transpose = need_transpose;
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010183 register_read(id, ptr, forward);
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010184
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010185 if (forward)
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +010010186 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010187 // Pass through whether the result is of a packed type and the physical type ID.
10188 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked))
10189 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10190 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID))
10191 {
10192 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID,
10193 get_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID));
10194 }
10195 }
10196 else
10197 {
10198 // This might have been set on an earlier compilation iteration, force it to be unset.
10199 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10200 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +010010201 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010202
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010203 inherit_expression_dependencies(id, ptr);
10204 if (forward)
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010205 add_implied_read_expression(*e, ptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010206 break;
10207 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010208
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010209 case OpInBoundsAccessChain:
10210 case OpAccessChain:
Chip Davis3bfb2f92018-12-03 02:06:33 -060010211 case OpPtrAccessChain:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010212 {
10213 auto *var = maybe_get<SPIRVariable>(ops[2]);
10214 if (var)
10215 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010216
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010217 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010218 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010219 AccessChainMeta meta;
Chip Davis3bfb2f92018-12-03 02:06:33 -060010220 bool ptr_chain = opcode == OpPtrAccessChain;
10221 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 +020010222
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010223 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +020010224
10225 auto *backing_variable = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010226 expr.loaded_from = backing_variable ? backing_variable->self : ID(ops[2]);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010227 expr.need_transpose = meta.need_transpose;
Chip Davis3bfb2f92018-12-03 02:06:33 -060010228 expr.access_chain = true;
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010229
10230 // Mark the result as being packed. Some platforms handled packed vectors differently than non-packed.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010231 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010232 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypePacked);
10233 if (meta.storage_physical_type != 0)
10234 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010235 if (meta.storage_is_invariant)
10236 set_decoration(ops[1], DecorationInvariant);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010237 if (meta.flattened_struct)
10238 flattened_structs[ops[1]] = true;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010239
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010240 // If we have some expression dependencies in our access chain, this access chain is technically a forwarded
10241 // temporary which could be subject to invalidation.
10242 // Need to assume we're forwarded while calling inherit_expression_depdendencies.
10243 forwarded_temporaries.insert(ops[1]);
10244 // The access chain itself is never forced to a temporary, but its dependencies might.
10245 suppressed_usage_tracking.insert(ops[1]);
10246
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010247 for (uint32_t i = 2; i < length; i++)
10248 {
10249 inherit_expression_dependencies(ops[1], ops[i]);
10250 add_implied_read_expression(expr, ops[i]);
10251 }
10252
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010253 // If we have no dependencies after all, i.e., all indices in the access chain are immutable temporaries,
10254 // we're not forwarded after all.
10255 if (expr.expression_dependencies.empty())
10256 forwarded_temporaries.erase(ops[1]);
10257
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010258 break;
10259 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010261 case OpStore:
10262 {
10263 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010264
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010265 if (var && var->statically_assigned)
10266 var->static_expression = ops[1];
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010267 else if (var && var->loop_variable && !var->loop_variable_enable)
10268 var->static_expression = ops[1];
Hans-Kristian Arntzend31bc022020-05-28 11:49:28 +020010269 else if (var && var->remapped_variable && var->static_expression)
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020010270 {
10271 // Skip the write.
10272 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010273 else if (flattened_structs.count(ops[0]))
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +010010274 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010275 store_flattened_struct(ops[0], ops[1]);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +010010276 register_write(ops[0]);
10277 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010278 else
10279 {
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +010010280 emit_store_statement(ops[0], ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010281 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +010010282
Chip Davis3bfb2f92018-12-03 02:06:33 -060010283 // Storing a pointer results in a variable pointer, so we must conservatively assume
10284 // we can write through it.
10285 if (expression_type(ops[1]).pointer)
10286 register_write(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010287 break;
10288 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010289
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010290 case OpArrayLength:
10291 {
10292 uint32_t result_type = ops[0];
10293 uint32_t id = ops[1];
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +010010294 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 +020010295 if (has_decoration(ops[2], DecorationNonUniform))
10296 convert_non_uniform_expression(e, ops[2]);
Hans-Kristian Arntzenb6f8a202019-05-07 19:02:32 +020010297 set<SPIRExpression>(id, join(type_to_glsl(get<SPIRType>(result_type)), "(", e, ".length())"), result_type,
10298 true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010299 break;
10300 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010301
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010302 // Function calls
10303 case OpFunctionCall:
10304 {
10305 uint32_t result_type = ops[0];
10306 uint32_t id = ops[1];
10307 uint32_t func = ops[2];
10308 const auto *arg = &ops[3];
10309 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010311 auto &callee = get<SPIRFunction>(func);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010312 auto &return_type = get<SPIRType>(callee.return_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010313 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010315 bool callee_has_out_variables = false;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010316 bool emit_return_value_as_argument = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010318 // Invalidate out variables passed to functions since they can be OpStore'd to.
10319 for (uint32_t i = 0; i < length; i++)
10320 {
10321 if (callee.arguments[i].write_count)
10322 {
10323 register_call_out_argument(arg[i]);
10324 callee_has_out_variables = true;
10325 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010326
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010327 flush_variable_declaration(arg[i]);
10328 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010329
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010330 if (!return_type.array.empty() && !backend.can_return_array)
10331 {
10332 callee_has_out_variables = true;
10333 emit_return_value_as_argument = true;
10334 }
10335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010336 if (!pure)
10337 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010338
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010339 string funexpr;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020010340 SmallVector<string> arglist;
Bill Hollings1c180782017-11-05 21:34:42 -050010341 funexpr += to_name(func) + "(";
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010342
10343 if (emit_return_value_as_argument)
10344 {
10345 statement(type_to_glsl(return_type), " ", to_name(id), type_to_array_glsl(return_type), ";");
10346 arglist.push_back(to_name(id));
10347 }
10348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010349 for (uint32_t i = 0; i < length; i++)
10350 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010351 // Do not pass in separate images or samplers if we're remapping
10352 // to combined image samplers.
10353 if (skip_argument(arg[i]))
10354 continue;
10355
Chip Davis39dce882019-08-02 15:11:19 -050010356 arglist.push_back(to_func_call_arg(callee.arguments[i], arg[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010357 }
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +020010358
10359 for (auto &combined : callee.combined_parameters)
10360 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010361 auto image_id = combined.global_image ? combined.image_id : VariableID(arg[combined.image_id]);
10362 auto sampler_id = combined.global_sampler ? combined.sampler_id : VariableID(arg[combined.sampler_id]);
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +020010363 arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +020010364 }
Bill Hollingsa759e2c2016-10-19 14:09:51 -070010365
Bill Hollingsac00c602016-10-24 09:24:24 -040010366 append_global_func_args(callee, length, arglist);
Bill Hollingsa759e2c2016-10-19 14:09:51 -070010367
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010368 funexpr += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010369 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010370
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020010371 // Check for function call constraints.
10372 check_function_call_constraints(arg, length);
10373
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010374 if (return_type.basetype != SPIRType::Void)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010375 {
10376 // If the function actually writes to an out variable,
10377 // take the conservative route and do not forward.
10378 // The problem is that we might not read the function
10379 // result (and emit the function) before an out variable
10380 // is read (common case when return value is ignored!
10381 // In order to avoid start tracking invalid variables,
10382 // just avoid the forwarding problem altogether.
10383 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
10384 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010385
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010010386 if (emit_return_value_as_argument)
10387 {
10388 statement(funexpr, ";");
10389 set<SPIRExpression>(id, to_name(id), result_type, true);
10390 }
10391 else
10392 emit_op(result_type, id, funexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010393
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010394 // Function calls are implicit loads from all variables in question.
10395 // Set dependencies for them.
10396 for (uint32_t i = 0; i < length; i++)
10397 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010398
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010399 // If we're going to forward the temporary result,
10400 // put dependencies on every variable that must not change.
10401 if (forward)
10402 register_global_read_dependencies(callee, id);
10403 }
10404 else
10405 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010406
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010407 break;
10408 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010409
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010410 // Composite munging
10411 case OpCompositeConstruct:
10412 {
10413 uint32_t result_type = ops[0];
10414 uint32_t id = ops[1];
Hans-Kristian Arntzen9a527132018-03-09 15:26:36 +010010415 const auto *const elems = &ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010416 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010417
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010418 bool forward = true;
10419 for (uint32_t i = 0; i < length; i++)
10420 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010421
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010422 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010423 auto *in_type = length > 0 ? &expression_type(elems[0]) : nullptr;
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020010424
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010425 // Only splat if we have vector constructors.
10426 // Arrays and structs must be initialized properly in full.
10427 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010428
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010429 bool splat = false;
10430 bool swizzle_splat = false;
10431
10432 if (in_type)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +010010433 {
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010434 splat = in_type->vecsize == 1 && in_type->columns == 1 && !composite && backend.use_constructor_splatting;
10435 swizzle_splat = in_type->vecsize == 1 && in_type->columns == 1 && backend.can_swizzle_scalar;
10436
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010437 if (ir.ids[elems[0]].get_type() == TypeConstant && !type_is_floating_point(*in_type))
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010438 {
10439 // Cannot swizzle literal integers as a special case.
10440 swizzle_splat = false;
10441 }
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +010010442 }
10443
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010444 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010445 {
10446 uint32_t input = elems[0];
10447 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010448 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010449 if (input != elems[i])
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010450 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010451 splat = false;
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010452 swizzle_splat = false;
10453 }
10454 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010455 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010456
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010010457 if (out_type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
10458 forward = false;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +010010459 if (!out_type.array.empty() && !backend.can_declare_arrays_inline)
10460 forward = false;
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010461 if (type_is_empty(out_type) && !backend.supports_empty_struct)
10462 forward = false;
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010010463
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010464 string constructor_op;
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +020010465 if (backend.use_initializer_list && composite)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010466 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010467 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010468 // Only use this path if we are building composites.
10469 // This path cannot be used for arithmetic.
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +020010470 if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010010471 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
Hans-Kristian Arntzenc9d4f9c2020-02-24 12:47:14 +010010472 else if (backend.use_typed_initializer_list && backend.array_is_value_type && !out_type.array.empty())
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010473 {
10474 // MSL path. Array constructor is baked into type here, do not use _constructor variant.
10475 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
10476 needs_trailing_tracket = true;
10477 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010478 constructor_op += "{ ";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010479
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010480 if (type_is_empty(out_type) && !backend.supports_empty_struct)
10481 constructor_op += "0";
10482 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020010483 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010484 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010010485 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010486 constructor_op += " }";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020010487 if (needs_trailing_tracket)
10488 constructor_op += ")";
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010489 }
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010010490 else if (swizzle_splat && !composite)
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +010010491 {
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020010492 constructor_op = remap_swizzle(get<SPIRType>(result_type), 1, to_unpacked_expression(elems[0]));
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +010010493 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010494 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010495 {
10496 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010497 if (type_is_empty(out_type) && !backend.supports_empty_struct)
10498 constructor_op += "0";
10499 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020010500 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010501 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010010502 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020010503 constructor_op += ")";
10504 }
10505
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +020010506 if (!constructor_op.empty())
10507 {
10508 emit_op(result_type, id, constructor_op, forward);
10509 for (uint32_t i = 0; i < length; i++)
10510 inherit_expression_dependencies(id, elems[i]);
10511 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010512 break;
10513 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010514
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010515 case OpVectorInsertDynamic:
10516 {
10517 uint32_t result_type = ops[0];
10518 uint32_t id = ops[1];
10519 uint32_t vec = ops[2];
10520 uint32_t comp = ops[3];
10521 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010522
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010523 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010524
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010525 // Make a copy, then use access chain to store the variable.
10526 statement(declare_temporary(result_type, id), to_expression(vec), ";");
10527 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010528 auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +020010529 statement(chain, " = ", to_unpacked_expression(comp), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010530 break;
10531 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010532
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010533 case OpVectorExtractDynamic:
10534 {
10535 uint32_t result_type = ops[0];
10536 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010537
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010538 auto expr = access_chain_internal(ops[2], &ops[3], 1, 0, nullptr);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010010539 emit_op(result_type, id, expr, should_forward(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010540 inherit_expression_dependencies(id, ops[2]);
10541 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010542 break;
10543 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010545 case OpCompositeExtract:
10546 {
10547 uint32_t result_type = ops[0];
10548 uint32_t id = ops[1];
10549 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010550
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010551 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010552
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +020010553 // We can only split the expression here if our expression is forwarded as a temporary.
10554 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
10555
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +010010556 // Do not allow base expression for struct members. We risk doing "swizzle" optimizations in this case.
10557 auto &composite_type = expression_type(ops[2]);
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010558 bool composite_type_is_complex = composite_type.basetype == SPIRType::Struct || !composite_type.array.empty();
10559 if (composite_type_is_complex)
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +010010560 allow_base_expression = false;
10561
Hans-Kristian Arntzenc7b75a82020-04-07 18:22:14 +020010562 // Packed expressions or physical ID mapped expressions cannot be split up.
10563 if (has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypePacked) ||
10564 has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypeID))
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +010010565 allow_base_expression = false;
10566
Hans-Kristian Arntzen7ff2db42019-08-27 11:41:54 +020010567 // Cannot use base expression for row-major matrix row-extraction since we need to interleave access pattern
10568 // into the base expression.
10569 if (is_non_native_row_major_matrix(ops[2]))
10570 allow_base_expression = false;
10571
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010572 AccessChainMeta meta;
10573 SPIRExpression *e = nullptr;
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010574 auto *c = maybe_get<SPIRConstant>(ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010575
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010576 if (c && !c->specialization && !composite_type_is_complex)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010577 {
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010010578 auto expr = to_extract_constant_composite_expression(result_type, *c, ops + 3, length);
10579 e = &emit_op(result_type, id, expr, true, true);
10580 }
10581 else if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
10582 {
10583 // Only apply this optimization if result is scalar.
10584
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010585 // We want to split the access chain from the base.
10586 // This is so we can later combine different CompositeExtract results
10587 // with CompositeConstruct without emitting code like
10588 //
10589 // vec3 temp = texture(...).xyz
10590 // vec4(temp.x, temp.y, temp.z, 1.0).
10591 //
10592 // when we actually wanted to emit this
10593 // vec4(texture(...).xyz, 1.0).
10594 //
10595 // Including the base will prevent this and would trigger multiple reads
10596 // from expression causing it to be forced to an actual temporary in GLSL.
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010597 auto expr = access_chain_internal(ops[2], &ops[3], length,
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +020010598 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_CHAIN_ONLY_BIT |
10599 ACCESS_CHAIN_FORCE_COMPOSITE_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010600 e = &emit_op(result_type, id, expr, true, should_suppress_usage_tracking(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010601 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010602 e->base_expression = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010603 }
10604 else
10605 {
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +020010606 auto expr = access_chain_internal(ops[2], &ops[3], length,
10607 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_FORCE_COMPOSITE_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010608 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 +010010609 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010610 }
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010611
10612 // Pass through some meta information to the loaded expression.
10613 // We can still end up loading a buffer type to a variable, then CompositeExtract from it
10614 // instead of loading everything through an access chain.
10615 e->need_transpose = meta.need_transpose;
10616 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010617 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10618 if (meta.storage_physical_type != 0)
10619 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010620 if (meta.storage_is_invariant)
10621 set_decoration(id, DecorationInvariant);
10622
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010623 break;
10624 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010626 case OpCompositeInsert:
10627 {
10628 uint32_t result_type = ops[0];
10629 uint32_t id = ops[1];
10630 uint32_t obj = ops[2];
10631 uint32_t composite = ops[3];
10632 const auto *elems = &ops[4];
10633 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010634
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010635 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010636
David Srbecky77b5b442017-06-26 18:32:53 +010010637 // Make a copy, then use access chain to store the variable.
10638 statement(declare_temporary(result_type, id), to_expression(composite), ";");
10639 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010640 auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +020010641 statement(chain, " = ", to_unpacked_expression(obj), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010642
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010643 break;
10644 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010645
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010646 case OpCopyMemory:
10647 {
10648 uint32_t lhs = ops[0];
10649 uint32_t rhs = ops[1];
10650 if (lhs != rhs)
10651 {
Hans-Kristian Arntzen4ca06c72021-03-08 14:09:32 +010010652 uint32_t &tmp_id = extra_sub_expressions[instruction.offset | EXTRA_SUB_EXPRESSION_TYPE_STREAM_OFFSET];
10653 if (!tmp_id)
10654 tmp_id = ir.increase_bound_by(1);
10655 uint32_t tmp_type_id = expression_type(rhs).parent_type;
10656
10657 EmbeddedInstruction fake_load, fake_store;
10658 fake_load.op = OpLoad;
10659 fake_load.length = 3;
10660 fake_load.ops.push_back(tmp_type_id);
10661 fake_load.ops.push_back(tmp_id);
10662 fake_load.ops.push_back(rhs);
10663
10664 fake_store.op = OpStore;
10665 fake_store.length = 2;
10666 fake_store.ops.push_back(lhs);
10667 fake_store.ops.push_back(tmp_id);
10668
10669 // Load and Store do a *lot* of workarounds, and we'd like to reuse them as much as possible.
10670 // Synthesize a fake Load and Store pair for CopyMemory.
10671 emit_instruction(fake_load);
10672 emit_instruction(fake_store);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010673 }
10674 break;
10675 }
10676
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010010677 case OpCopyLogical:
10678 {
10679 // This is used for copying object of different types, arrays and structs.
10680 // We need to unroll the copy, element-by-element.
10681 uint32_t result_type = ops[0];
10682 uint32_t id = ops[1];
10683 uint32_t rhs = ops[2];
10684
10685 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010010686 emit_copy_logical_type(id, result_type, rhs, expression_type_id(rhs), {});
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010010687 break;
10688 }
10689
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010690 case OpCopyObject:
10691 {
10692 uint32_t result_type = ops[0];
10693 uint32_t id = ops[1];
10694 uint32_t rhs = ops[2];
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010695 bool pointer = get<SPIRType>(result_type).pointer;
10696
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010697 auto *chain = maybe_get<SPIRAccessChain>(rhs);
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010698 auto *imgsamp = maybe_get<SPIRCombinedImageSampler>(rhs);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010699 if (chain)
10700 {
10701 // Cannot lower to a SPIRExpression, just copy the object.
10702 auto &e = set<SPIRAccessChain>(id, *chain);
10703 e.self = id;
10704 }
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010705 else if (imgsamp)
10706 {
10707 // Cannot lower to a SPIRExpression, just copy the object.
10708 // GLSL does not currently use this type and will never get here, but MSL does.
Bill Hollings7f67abe2020-10-30 16:05:44 -040010709 // Handled here instead of CompilerMSL for better integration and general handling,
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010710 // and in case GLSL or other subclasses require it in the future.
10711 auto &e = set<SPIRCombinedImageSampler>(id, *imgsamp);
10712 e.self = id;
10713 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010714 else if (expression_is_lvalue(rhs) && !pointer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010715 {
10716 // Need a copy.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010717 // For pointer types, we copy the pointer itself.
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010718 statement(declare_temporary(result_type, id), to_unpacked_expression(rhs), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010719 set<SPIRExpression>(id, to_name(id), result_type, true);
10720 }
10721 else
10722 {
10723 // RHS expression is immutable, so just forward it.
10724 // Copying these things really make no sense, but
10725 // seems to be allowed anyways.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010726 auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
10727 if (pointer)
10728 {
10729 auto *var = maybe_get_backing_variable(rhs);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010730 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010731 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010732
10733 // If we're copying an access chain, need to inherit the read expressions.
10734 auto *rhs_expr = maybe_get<SPIRExpression>(rhs);
10735 if (rhs_expr)
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010736 {
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010737 e.implied_read_expressions = rhs_expr->implied_read_expressions;
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010738 e.expression_dependencies = rhs_expr->expression_dependencies;
10739 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010740 }
10741 break;
10742 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010743
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010744 case OpVectorShuffle:
10745 {
10746 uint32_t result_type = ops[0];
10747 uint32_t id = ops[1];
10748 uint32_t vec0 = ops[2];
10749 uint32_t vec1 = ops[3];
10750 const auto *elems = &ops[4];
10751 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010752
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010753 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010754
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010755 // If we have the undefined swizzle index -1, we need to swizzle in undefined data,
10756 // or in our case, T(0).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010757 bool shuffle = false;
10758 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010759 if (elems[i] >= type0.vecsize || elems[i] == 0xffffffffu)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010760 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010761
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010762 // Cannot use swizzles with packed expressions, force shuffle path.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010763 if (!shuffle && has_extended_decoration(vec0, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010764 shuffle = true;
10765
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010766 string expr;
Bill Hollings1845f312017-12-31 18:55:04 -050010767 bool should_fwd, trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010769 if (shuffle)
10770 {
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +010010771 should_fwd = should_forward(vec0) && should_forward(vec1);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010772 trivial_forward = should_suppress_usage_tracking(vec0) && should_suppress_usage_tracking(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010773
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010774 // Constructor style and shuffling from two different vectors.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020010775 SmallVector<string> args;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010776 for (uint32_t i = 0; i < length; i++)
10777 {
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010778 if (elems[i] == 0xffffffffu)
10779 {
10780 // Use a constant 0 here.
10781 // We could use the first component or similar, but then we risk propagating
10782 // a value we might not need, and bog down codegen.
10783 SPIRConstant c;
10784 c.constant_type = type0.parent_type;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010785 assert(type0.parent_type != ID(0));
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010786 args.push_back(constant_expression(c));
10787 }
10788 else if (elems[i] >= type0.vecsize)
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010789 args.push_back(to_extract_component_expression(vec1, elems[i] - type0.vecsize));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010790 else
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010791 args.push_back(to_extract_component_expression(vec0, elems[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010792 }
10793 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
10794 }
10795 else
10796 {
Bill Hollings1845f312017-12-31 18:55:04 -050010797 should_fwd = should_forward(vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010798 trivial_forward = should_suppress_usage_tracking(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010799
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010800 // We only source from first vector, so can use swizzle.
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010801 // If the vector is packed, unpack it before applying a swizzle (needed for MSL)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +020010802 expr += to_enclosed_unpacked_expression(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010803 expr += ".";
10804 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010805 {
10806 assert(elems[i] != 0xffffffffu);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010807 expr += index_to_swizzle(elems[i]);
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010808 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010809
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010810 if (backend.swizzle_is_function && length > 1)
10811 expr += "()";
10812 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010814 // A shuffle is trivial in that it doesn't actually *do* anything.
10815 // 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 +010010816
Bill Hollings1845f312017-12-31 18:55:04 -050010817 emit_op(result_type, id, expr, should_fwd, trivial_forward);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010818
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010819 inherit_expression_dependencies(id, vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010820 if (vec0 != vec1)
10821 inherit_expression_dependencies(id, vec1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010822 break;
10823 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010824
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010825 // ALU
10826 case OpIsNan:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010827 GLSL_UFOP(isnan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010828 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010829
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010830 case OpIsInf:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010831 GLSL_UFOP(isinf);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010832 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010833
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010834 case OpSNegate:
10835 case OpFNegate:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010836 GLSL_UOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010837 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010838
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010839 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010840 {
10841 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
10842 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010843 GLSL_BOP_CAST(+, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010844 break;
10845 }
10846
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010847 case OpFAdd:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010848 GLSL_BOP(+);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010849 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010850
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010851 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010852 {
10853 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010854 GLSL_BOP_CAST(-, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010855 break;
10856 }
10857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010858 case OpFSub:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010859 GLSL_BOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010860 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010861
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010862 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010863 {
10864 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010865 GLSL_BOP_CAST(*, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010866 break;
10867 }
10868
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010869 case OpVectorTimesMatrix:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010870 case OpMatrixTimesVector:
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010871 {
10872 // If the matrix needs transpose, just flip the multiply order.
10873 auto *e = maybe_get<SPIRExpression>(ops[opcode == OpMatrixTimesVector ? 2 : 3]);
10874 if (e && e->need_transpose)
10875 {
10876 e->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010877 string expr;
10878
10879 if (opcode == OpMatrixTimesVector)
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020010880 expr = join(to_enclosed_unpacked_expression(ops[3]), " * ",
10881 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010882 else
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020010883 expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
10884 to_enclosed_unpacked_expression(ops[2]));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010885
10886 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
10887 emit_op(ops[0], ops[1], expr, forward);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010888 e->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010889 inherit_expression_dependencies(ops[1], ops[2]);
10890 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010891 }
10892 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010893 GLSL_BOP(*);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010894 break;
10895 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010896
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010897 case OpMatrixTimesMatrix:
10898 {
10899 auto *a = maybe_get<SPIRExpression>(ops[2]);
10900 auto *b = maybe_get<SPIRExpression>(ops[3]);
10901
10902 // If both matrices need transpose, we can multiply in flipped order and tag the expression as transposed.
10903 // a^T * b^T = (b * a)^T.
10904 if (a && b && a->need_transpose && b->need_transpose)
10905 {
10906 a->need_transpose = false;
10907 b->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010908 auto expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
10909 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
10910 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
10911 auto &e = emit_op(ops[0], ops[1], expr, forward);
10912 e.need_transpose = true;
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010913 a->need_transpose = true;
10914 b->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010915 inherit_expression_dependencies(ops[1], ops[2]);
10916 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010917 }
10918 else
10919 GLSL_BOP(*);
10920
10921 break;
10922 }
10923
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010924 case OpFMul:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010925 case OpMatrixTimesScalar:
10926 case OpVectorTimesScalar:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010927 GLSL_BOP(*);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010928 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010929
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010930 case OpOuterProduct:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010931 GLSL_BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010932 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010933
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010934 case OpDot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010935 GLSL_BFOP(dot);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010936 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010937
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010938 case OpTranspose:
rdbbf719942020-11-05 17:09:33 +010010939 if (options.version < 120) // Matches GLSL 1.10 / ESSL 1.00
10940 {
10941 // transpose() is not available, so instead, flip need_transpose,
10942 // which can later be turned into an emulated transpose op by
10943 // convert_row_major_matrix(), if necessary.
10944 uint32_t result_type = ops[0];
10945 uint32_t result_id = ops[1];
10946 uint32_t input = ops[2];
10947
10948 // Force need_transpose to false temporarily to prevent
10949 // to_expression() from doing the transpose.
10950 bool need_transpose = false;
10951 auto *input_e = maybe_get<SPIRExpression>(input);
10952 if (input_e)
10953 swap(need_transpose, input_e->need_transpose);
10954
10955 bool forward = should_forward(input);
10956 auto &e = emit_op(result_type, result_id, to_expression(input), forward);
10957 e.need_transpose = !need_transpose;
10958
10959 // Restore the old need_transpose flag.
10960 if (input_e)
10961 input_e->need_transpose = need_transpose;
10962 }
10963 else
10964 GLSL_UFOP(transpose);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010965 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010966
Jin Zhoue792cd62018-05-22 00:44:34 -040010967 case OpSRem:
Jin Zhou6b144cc2018-05-24 01:17:47 -040010968 {
10969 uint32_t result_type = ops[0];
10970 uint32_t result_id = ops[1];
10971 uint32_t op0 = ops[2];
10972 uint32_t op1 = ops[3];
10973
10974 // Needs special handling.
10975 bool forward = should_forward(op0) && should_forward(op1);
10976 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
10977 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
10978
10979 emit_op(result_type, result_id, expr, forward);
10980 inherit_expression_dependencies(result_id, op0);
10981 inherit_expression_dependencies(result_id, op1);
Jin Zhoue792cd62018-05-22 00:44:34 -040010982 break;
Jin Zhou6b144cc2018-05-24 01:17:47 -040010983 }
Jin Zhoue792cd62018-05-22 00:44:34 -040010984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010985 case OpSDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010986 GLSL_BOP_CAST(/, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010987 break;
10988
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010989 case OpUDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010990 GLSL_BOP_CAST(/, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010991 break;
10992
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010993 case OpIAddCarry:
10994 case OpISubBorrow:
10995 {
10996 if (options.es && options.version < 310)
10997 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
10998 else if (!options.es && options.version < 400)
10999 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 400.");
11000
11001 uint32_t result_type = ops[0];
11002 uint32_t result_id = ops[1];
11003 uint32_t op0 = ops[2];
11004 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011005 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020011006 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011007 const char *op = opcode == OpIAddCarry ? "uaddCarry" : "usubBorrow";
11008
11009 statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", op, "(", to_expression(op0), ", ",
11010 to_expression(op1), ", ", to_expression(result_id), ".", to_member_name(type, 1), ");");
11011 break;
11012 }
11013
11014 case OpUMulExtended:
11015 case OpSMulExtended:
11016 {
11017 if (options.es && options.version < 310)
11018 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
11019 else if (!options.es && options.version < 400)
11020 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 4000.");
11021
11022 uint32_t result_type = ops[0];
11023 uint32_t result_id = ops[1];
11024 uint32_t op0 = ops[2];
11025 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011026 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020011027 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011028 const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended";
11029
11030 statement(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(result_id), ".",
11031 to_member_name(type, 1), ", ", to_expression(result_id), ".", to_member_name(type, 0), ");");
11032 break;
11033 }
11034
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011035 case OpFDiv:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011036 GLSL_BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011037 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011038
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011039 case OpShiftRightLogical:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011040 GLSL_BOP_CAST(>>, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011041 break;
11042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011043 case OpShiftRightArithmetic:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011044 GLSL_BOP_CAST(>>, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011045 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011046
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011047 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020011048 {
11049 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011050 GLSL_BOP_CAST(<<, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011051 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020011052 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011053
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011054 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011055 {
11056 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011057 GLSL_BOP_CAST(|, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011058 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011059 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011061 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011062 {
11063 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +010011064 GLSL_BOP_CAST(^, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011065 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011066 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011067
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011068 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011069 {
11070 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011071 GLSL_BOP_CAST(&, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011072 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011073 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011074
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011075 case OpNot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011076 GLSL_UOP(~);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011077 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011078
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011079 case OpUMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011080 GLSL_BOP_CAST(%, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011081 break;
11082
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011083 case OpSMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011084 GLSL_BOP_CAST(%, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011085 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011087 case OpFMod:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011088 GLSL_BFOP(mod);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011089 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +020011090
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011091 case OpFRem:
11092 {
11093 if (is_legacy())
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010011094 SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is "
11095 "needed for legacy.");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011096
11097 uint32_t result_type = ops[0];
11098 uint32_t result_id = ops[1];
11099 uint32_t op0 = ops[2];
11100 uint32_t op1 = ops[3];
11101
11102 // Needs special handling.
11103 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010011104 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
11105 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011106
11107 emit_op(result_type, result_id, expr, forward);
11108 inherit_expression_dependencies(result_id, op0);
11109 inherit_expression_dependencies(result_id, op1);
11110 break;
11111 }
11112
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011113 // Relational
11114 case OpAny:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011115 GLSL_UFOP(any);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011116 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011118 case OpAll:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011119 GLSL_UFOP(all);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011120 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011121
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011122 case OpSelect:
11123 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
11124 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011125
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011126 case OpLogicalOr:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011127 {
11128 // No vector variant in GLSL for logical OR.
11129 auto result_type = ops[0];
11130 auto id = ops[1];
11131 auto &type = get<SPIRType>(result_type);
11132
11133 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020011134 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011135 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011136 GLSL_BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011137 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011138 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011139
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011140 case OpLogicalAnd:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011141 {
11142 // No vector variant in GLSL for logical AND.
11143 auto result_type = ops[0];
11144 auto id = ops[1];
11145 auto &type = get<SPIRType>(result_type);
11146
11147 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020011148 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011149 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011150 GLSL_BOP(&&);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011151 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011152 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011153
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011154 case OpLogicalNot:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011155 {
11156 auto &type = get<SPIRType>(ops[0]);
11157 if (type.vecsize > 1)
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010011158 GLSL_UFOP(not );
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011159 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011160 GLSL_UOP(!);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011161 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011162 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011163
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011164 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011165 {
11166 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011167 GLSL_BFOP_CAST(equal, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011168 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011169 GLSL_BOP_CAST(==, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011170 break;
11171 }
11172
11173 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011174 case OpFOrdEqual:
11175 {
11176 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011177 GLSL_BFOP(equal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011178 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011179 GLSL_BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011180 break;
11181 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011182
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011183 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011184 {
11185 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011186 GLSL_BFOP_CAST(notEqual, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011187 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011188 GLSL_BOP_CAST(!=, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011189 break;
11190 }
11191
11192 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011193 case OpFOrdNotEqual:
11194 {
11195 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011196 GLSL_BFOP(notEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011197 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011198 GLSL_BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011199 break;
11200 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011201
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011202 case OpUGreaterThan:
11203 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011204 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011205 auto type = opcode == OpUGreaterThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011206 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011207 GLSL_BFOP_CAST(greaterThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011208 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011209 GLSL_BOP_CAST(>, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011210 break;
11211 }
11212
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011213 case OpFOrdGreaterThan:
11214 {
11215 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011216 GLSL_BFOP(greaterThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011217 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011218 GLSL_BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011219 break;
11220 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011222 case OpUGreaterThanEqual:
11223 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011224 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011225 auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011226 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011227 GLSL_BFOP_CAST(greaterThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011228 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011229 GLSL_BOP_CAST(>=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011230 break;
11231 }
11232
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011233 case OpFOrdGreaterThanEqual:
11234 {
11235 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011236 GLSL_BFOP(greaterThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011237 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011238 GLSL_BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011239 break;
11240 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011241
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011242 case OpULessThan:
11243 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011244 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011245 auto type = opcode == OpULessThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011246 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011247 GLSL_BFOP_CAST(lessThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011248 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011249 GLSL_BOP_CAST(<, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011250 break;
11251 }
11252
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011253 case OpFOrdLessThan:
11254 {
11255 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011256 GLSL_BFOP(lessThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011257 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011258 GLSL_BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011259 break;
11260 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011261
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011262 case OpULessThanEqual:
11263 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011264 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011265 auto type = opcode == OpULessThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011266 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011267 GLSL_BFOP_CAST(lessThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011268 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011269 GLSL_BOP_CAST(<=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011270 break;
11271 }
11272
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011273 case OpFOrdLessThanEqual:
11274 {
11275 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011276 GLSL_BFOP(lessThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011277 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011278 GLSL_BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011279 break;
11280 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011281
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011282 // Conversion
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020011283 case OpSConvert:
11284 case OpConvertSToF:
11285 case OpUConvert:
11286 case OpConvertUToF:
11287 {
11288 auto input_type = opcode == OpSConvert || opcode == OpConvertSToF ? int_type : uint_type;
11289 uint32_t result_type = ops[0];
11290 uint32_t id = ops[1];
11291
11292 auto &type = get<SPIRType>(result_type);
11293 auto &arg_type = expression_type(ops[2]);
11294 auto func = type_to_glsl_constructor(type);
11295
Hans-Kristian Arntzen4edb99d2019-11-28 13:49:53 +010011296 if (arg_type.width < type.width || type_is_floating_point(type))
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020011297 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), input_type, type.basetype);
11298 else
11299 emit_unary_func_op(result_type, id, ops[2], func.c_str());
11300 break;
11301 }
11302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011303 case OpConvertFToU:
11304 case OpConvertFToS:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020011305 {
11306 // Cast to expected arithmetic type, then potentially bitcast away to desired signedness.
11307 uint32_t result_type = ops[0];
11308 uint32_t id = ops[1];
11309 auto &type = get<SPIRType>(result_type);
11310 auto expected_type = type;
11311 auto &float_type = expression_type(ops[2]);
11312 expected_type.basetype =
11313 opcode == OpConvertFToS ? to_signed_basetype(type.width) : to_unsigned_basetype(type.width);
11314
11315 auto func = type_to_glsl_constructor(expected_type);
11316 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), float_type.basetype, expected_type.basetype);
11317 break;
11318 }
11319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011320 case OpFConvert:
11321 {
11322 uint32_t result_type = ops[0];
11323 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011324
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011325 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
11326 emit_unary_func_op(result_type, id, ops[2], func.c_str());
11327 break;
11328 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011329
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011330 case OpBitcast:
11331 {
11332 uint32_t result_type = ops[0];
11333 uint32_t id = ops[1];
11334 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011335
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +020011336 if (!emit_complex_bitcast(result_type, id, arg))
11337 {
11338 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
11339 emit_unary_func_op(result_type, id, arg, op.c_str());
11340 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011341 break;
11342 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011343
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020011344 case OpQuantizeToF16:
11345 {
11346 uint32_t result_type = ops[0];
11347 uint32_t id = ops[1];
11348 uint32_t arg = ops[2];
11349
11350 string op;
11351 auto &type = get<SPIRType>(result_type);
11352
11353 switch (type.vecsize)
11354 {
11355 case 1:
11356 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
11357 break;
11358 case 2:
11359 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
11360 break;
11361 case 3:
11362 {
11363 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
11364 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
11365 op = join("vec3(", op0, ", ", op1, ")");
11366 break;
11367 }
11368 case 4:
11369 {
11370 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
11371 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
11372 op = join("vec4(", op0, ", ", op1, ")");
11373 break;
11374 }
11375 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011376 SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020011377 }
11378
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011379 emit_op(result_type, id, op, should_forward(arg));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010011380 inherit_expression_dependencies(id, arg);
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020011381 break;
11382 }
11383
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011384 // Derivatives
11385 case OpDPdx:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011386 GLSL_UFOP(dFdx);
Lubos Lenco80c39412016-09-17 14:33:16 +020011387 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011388 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011389 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011390 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011391
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011392 case OpDPdy:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011393 GLSL_UFOP(dFdy);
Lubos Lenco80c39412016-09-17 14:33:16 +020011394 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011395 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011396 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011397 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011398
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011399 case OpDPdxFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011400 GLSL_UFOP(dFdxFine);
Robert Konradcb637db2017-03-24 15:58:54 +010011401 if (options.es)
11402 {
11403 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11404 }
11405 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011406 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011407 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011408 break;
11409
11410 case OpDPdyFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011411 GLSL_UFOP(dFdyFine);
Robert Konradcb637db2017-03-24 15:58:54 +010011412 if (options.es)
11413 {
11414 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11415 }
11416 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011417 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011418 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011419 break;
11420
11421 case OpDPdxCoarse:
Robert Konradcb637db2017-03-24 15:58:54 +010011422 if (options.es)
11423 {
11424 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11425 }
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011426 GLSL_UFOP(dFdxCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010011427 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011428 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011429 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011430 break;
11431
11432 case OpDPdyCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011433 GLSL_UFOP(dFdyCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010011434 if (options.es)
11435 {
11436 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11437 }
11438 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011439 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011440 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010011441 break;
11442
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011443 case OpFwidth:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011444 GLSL_UFOP(fwidth);
Lubos Lenco80c39412016-09-17 14:33:16 +020011445 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011446 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011447 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011448 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011449
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011450 case OpFwidthCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011451 GLSL_UFOP(fwidthCoarse);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011452 if (options.es)
11453 {
11454 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11455 }
11456 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011457 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011458 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011459 break;
11460
11461 case OpFwidthFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011462 GLSL_UFOP(fwidthFine);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011463 if (options.es)
11464 {
11465 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
11466 }
11467 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011468 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011469 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010011470 break;
11471
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011472 // Bitfield
11473 case OpBitFieldInsert:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011474 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020011475 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 +020011476 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011477 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011479 case OpBitFieldSExtract:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011480 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020011481 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 +020011482 SPIRType::Int, SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011483 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011484 }
11485
11486 case OpBitFieldUExtract:
11487 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020011488 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 +020011489 SPIRType::Int, SPIRType::Int);
11490 break;
11491 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011492
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011493 case OpBitReverse:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011494 // BitReverse does not have issues with sign since result type must match input type.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011495 GLSL_UFOP(bitfieldReverse);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011496 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011497
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011498 case OpBitCount:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011499 {
11500 auto basetype = expression_type(ops[2]).basetype;
11501 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "bitCount", basetype, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011502 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020011503 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011504
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011505 // Atomics
11506 case OpAtomicExchange:
11507 {
11508 uint32_t result_type = ops[0];
11509 uint32_t id = ops[1];
11510 uint32_t ptr = ops[2];
11511 // Ignore semantics for now, probably only relevant to CL.
11512 uint32_t val = ops[5];
11513 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011514
11515 emit_atomic_func_op(result_type, id, ptr, 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 OpAtomicCompareExchange:
11520 {
11521 uint32_t result_type = ops[0];
11522 uint32_t id = ops[1];
11523 uint32_t ptr = ops[2];
11524 uint32_t val = ops[6];
11525 uint32_t comp = ops[7];
11526 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011527
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011528 emit_atomic_func_op(result_type, id, ptr, comp, val, op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011529 break;
11530 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011531
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011532 case OpAtomicLoad:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011533 {
11534 // In plain GLSL, we have no atomic loads, so emulate this by fetch adding by 0 and hope compiler figures it out.
11535 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
11536 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen8b236f22019-04-24 09:31:44 +020011537 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011538 bool atomic_image = check_atomic_image(ops[2]);
11539 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
11540 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
11541 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
11542 const char *increment = unsigned_type ? "0u" : "0";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011543 emit_op(ops[0], ops[1],
11544 join(op, "(",
11545 to_non_uniform_aware_expression(ops[2]), ", ", increment, ")"), false);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011546 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011547 break;
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011548 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011549
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010011550 case OpAtomicStore:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011551 {
11552 // In plain GLSL, we have no atomic stores, so emulate this with an atomic exchange where we don't consume the result.
11553 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
11554 uint32_t ptr = ops[0];
11555 // Ignore semantics for now, probably only relevant to CL.
11556 uint32_t val = ops[3];
11557 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011558 statement(op, "(", to_non_uniform_aware_expression(ptr), ", ", to_expression(val), ");");
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020011559 flush_all_atomic_capable_variables();
11560 break;
11561 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011562
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011563 case OpAtomicIIncrement:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011564 case OpAtomicIDecrement:
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011565 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011566 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011567 auto &type = expression_type(ops[2]);
11568 if (type.storage == StorageClassAtomicCounter)
11569 {
11570 // Legacy GLSL stuff, not sure if this is relevant to support.
11571 if (opcode == OpAtomicIIncrement)
11572 GLSL_UFOP(atomicCounterIncrement);
11573 else
11574 GLSL_UFOP(atomicCounterDecrement);
11575 }
11576 else
11577 {
11578 bool atomic_image = check_atomic_image(ops[2]);
11579 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
11580 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
11581 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
11582
11583 const char *increment = nullptr;
11584 if (opcode == OpAtomicIIncrement && unsigned_type)
11585 increment = "1u";
11586 else if (opcode == OpAtomicIIncrement)
11587 increment = "1";
11588 else if (unsigned_type)
11589 increment = "uint(-1)";
11590 else
11591 increment = "-1";
11592
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011593 emit_op(ops[0], ops[1],
11594 join(op, "(", to_non_uniform_aware_expression(ops[2]), ", ", increment, ")"), false);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011595 }
11596
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011597 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011598 break;
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020011599 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011600
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011601 case OpAtomicIAdd:
11602 {
11603 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011604 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011605 break;
11606 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011607
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011608 case OpAtomicISub:
11609 {
11610 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
11611 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011612 auto expr = join(op, "(", to_non_uniform_aware_expression(ops[2]), ", -", to_enclosed_expression(ops[5]), ")");
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011613 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011614 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011615 break;
11616 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011617
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011618 case OpAtomicSMin:
11619 case OpAtomicUMin:
11620 {
11621 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011622 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011623 break;
11624 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011626 case OpAtomicSMax:
11627 case OpAtomicUMax:
11628 {
11629 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011630 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011631 break;
11632 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011633
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011634 case OpAtomicAnd:
11635 {
11636 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011637 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011638 break;
11639 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011640
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011641 case OpAtomicOr:
11642 {
11643 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011644 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011645 break;
11646 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011647
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011648 case OpAtomicXor:
11649 {
11650 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011651 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011652 break;
11653 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011655 // Geometry shaders
11656 case OpEmitVertex:
11657 statement("EmitVertex();");
11658 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011659
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011660 case OpEndPrimitive:
11661 statement("EndPrimitive();");
11662 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011663
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011664 case OpEmitStreamVertex:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011665 {
11666 if (options.es)
11667 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
11668 else if (!options.es && options.version < 400)
11669 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
11670
11671 auto stream_expr = to_expression(ops[0]);
11672 if (expression_type(ops[0]).basetype != SPIRType::Int)
11673 stream_expr = join("int(", stream_expr, ")");
11674 statement("EmitStreamVertex(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011675 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011676 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011677
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011678 case OpEndStreamPrimitive:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011679 {
11680 if (options.es)
11681 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
11682 else if (!options.es && options.version < 400)
11683 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
11684
11685 auto stream_expr = to_expression(ops[0]);
11686 if (expression_type(ops[0]).basetype != SPIRType::Int)
11687 stream_expr = join("int(", stream_expr, ")");
11688 statement("EndStreamPrimitive(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011689 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011690 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011691
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011692 // Textures
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011693 case OpImageSampleExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011694 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011695 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011696 case OpImageSampleProjDrefExplicitLod:
Lubos Lenco80c39412016-09-17 14:33:16 +020011697 case OpImageSampleImplicitLod:
11698 case OpImageSampleProjImplicitLod:
11699 case OpImageSampleDrefImplicitLod:
11700 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011701 case OpImageFetch:
11702 case OpImageGather:
11703 case OpImageDrefGather:
11704 // Gets a bit hairy, so move this to a separate instruction.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011705 emit_texture_op(instruction, false);
11706 break;
11707
11708 case OpImageSparseSampleExplicitLod:
11709 case OpImageSparseSampleProjExplicitLod:
11710 case OpImageSparseSampleDrefExplicitLod:
11711 case OpImageSparseSampleProjDrefExplicitLod:
11712 case OpImageSparseSampleImplicitLod:
11713 case OpImageSparseSampleProjImplicitLod:
11714 case OpImageSparseSampleDrefImplicitLod:
11715 case OpImageSparseSampleProjDrefImplicitLod:
11716 case OpImageSparseFetch:
11717 case OpImageSparseGather:
11718 case OpImageSparseDrefGather:
11719 // Gets a bit hairy, so move this to a separate instruction.
11720 emit_texture_op(instruction, true);
11721 break;
11722
11723 case OpImageSparseTexelsResident:
11724 if (options.es)
11725 SPIRV_CROSS_THROW("Sparse feedback is not supported in GLSL.");
11726 require_extension_internal("GL_ARB_sparse_texture2");
Hans-Kristian Arntzen857e1c42020-06-08 11:40:02 +020011727 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "sparseTexelsResidentARB", int_type, SPIRType::Boolean);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011728 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011729
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011730 case OpImage:
11731 {
11732 uint32_t result_type = ops[0];
11733 uint32_t id = ops[1];
Hans-Kristian Arntzenaaf397c2018-04-27 11:10:10 +020011734
11735 // Suppress usage tracking.
11736 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011737
11738 // When using the image, we need to know which variable it is actually loaded from.
11739 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020011740 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011741 break;
11742 }
11743
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011744 case OpImageQueryLod:
11745 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011746 const char *op = nullptr;
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011747 if (!options.es && options.version < 400)
11748 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011749 require_extension_internal("GL_ARB_texture_query_lod");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011750 // For some reason, the ARB spec is all-caps.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011751 op = "textureQueryLOD";
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011752 }
11753 else if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011754 SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011755 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011756 op = "textureQueryLod";
11757
11758 auto sampler_expr = to_expression(ops[2]);
11759 if (has_decoration(ops[2], DecorationNonUniform))
11760 {
11761 if (maybe_get_backing_variable(ops[2]))
11762 convert_non_uniform_expression(sampler_expr, ops[2]);
11763 else if (*backend.nonuniform_qualifier != '\0')
11764 sampler_expr = join(backend.nonuniform_qualifier, "(", sampler_expr, ")");
11765 }
11766
11767 bool forward = should_forward(ops[3]);
11768 emit_op(ops[0], ops[1],
11769 join(op, "(", sampler_expr, ", ", to_unpacked_expression(ops[3]), ")"),
11770 forward);
11771 inherit_expression_dependencies(ops[1], ops[2]);
11772 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011773 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011774 break;
11775 }
11776
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011777 case OpImageQueryLevels:
11778 {
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011779 uint32_t result_type = ops[0];
11780 uint32_t id = ops[1];
11781
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011782 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011783 require_extension_internal("GL_ARB_texture_query_levels");
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011784 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011785 SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011786
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020011787 auto expr = join("textureQueryLevels(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011788 auto &restype = get<SPIRType>(ops[0]);
11789 expr = bitcast_expression(restype, SPIRType::Int, expr);
11790 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011791 break;
11792 }
11793
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011794 case OpImageQuerySamples:
11795 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011796 auto &type = expression_type(ops[2]);
11797 uint32_t result_type = ops[0];
11798 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011799
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011800 string expr;
11801 if (type.image.sampled == 2)
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011802 expr = join("imageSamples(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011803 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020011804 expr = join("textureSamples(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011805
11806 auto &restype = get<SPIRType>(ops[0]);
11807 expr = bitcast_expression(restype, SPIRType::Int, expr);
11808 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011809 break;
11810 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011811
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011812 case OpSampledImage:
11813 {
11814 uint32_t result_type = ops[0];
11815 uint32_t id = ops[1];
11816 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011817 inherit_expression_dependencies(id, ops[2]);
11818 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011819 break;
11820 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +020011821
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011822 case OpImageQuerySizeLod:
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011823 {
11824 uint32_t result_type = ops[0];
11825 uint32_t id = ops[1];
rdb10fa5f62020-11-09 15:26:46 +010011826 uint32_t img = ops[2];
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011827
rdb10fa5f62020-11-09 15:26:46 +010011828 std::string fname = "textureSize";
11829 if (is_legacy_desktop())
11830 {
11831 auto &type = expression_type(img);
11832 auto &imgtype = get<SPIRType>(type.self);
11833 fname = legacy_tex_op(fname, imgtype, img);
11834 }
11835 else if (is_legacy_es())
11836 SPIRV_CROSS_THROW("textureSize is not supported in ESSL 100.");
11837
11838 auto expr = join(fname, "(", convert_separate_image_to_expression(img), ", ",
Hans-Kristian Arntzen7e23e692018-04-30 12:46:21 +020011839 bitcast_expression(SPIRType::Int, ops[3]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011840 auto &restype = get<SPIRType>(ops[0]);
11841 expr = bitcast_expression(restype, SPIRType::Int, expr);
11842 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011843 break;
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011844 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011845
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011846 // Image load/store
11847 case OpImageRead:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011848 case OpImageSparseRead:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011849 {
11850 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
11851 // not adding the proper qualifiers.
11852 // If it turns out we need to read the image after all, remove the qualifier and recompile.
11853 auto *var = maybe_get_backing_variable(ops[2]);
11854 if (var)
11855 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010011856 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011857 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011858 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011859 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011860 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011861 }
11862 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011863
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011864 uint32_t result_type = ops[0];
11865 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011866
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011867 bool pure;
11868 string imgexpr;
11869 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011870
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011871 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011872 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011873 if (type.image.ms)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011874 SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011875
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +020011876 auto itr =
11877 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 +010011878
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011879 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011880 {
11881 // For non-PLS inputs, we rely on subpass type remapping information to get it right
11882 // since ImageRead always returns 4-component vectors and the backing type is opaque.
11883 if (!var->remapped_components)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011884 SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011885 imgexpr = remap_swizzle(get<SPIRType>(result_type), var->remapped_components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011886 }
11887 else
11888 {
11889 // PLS input could have different number of components than what the SPIR expects, swizzle to
11890 // the appropriate vector size.
11891 uint32_t components = pls_format_to_components(itr->format);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011892 imgexpr = remap_swizzle(get<SPIRType>(result_type), components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011893 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011894 pure = true;
11895 }
11896 else if (type.image.dim == DimSubpassData)
11897 {
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010011898 if (var && subpass_input_is_framebuffer_fetch(var->self))
11899 {
11900 imgexpr = to_expression(var->self);
11901 }
11902 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011903 {
11904 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011905 if (type.image.ms)
11906 {
11907 uint32_t operands = ops[4];
11908 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011909 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11910 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011911
11912 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011913 imgexpr = join("subpassLoad(", to_non_uniform_aware_expression(ops[2]), ", ", to_expression(samples), ")");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011914 }
11915 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011916 imgexpr = join("subpassLoad(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011917 }
11918 else
11919 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011920 if (type.image.ms)
11921 {
11922 uint32_t operands = ops[4];
11923 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011924 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11925 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011926
11927 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011928 imgexpr = join("texelFetch(", to_non_uniform_aware_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011929 to_expression(samples), ")");
11930 }
11931 else
11932 {
11933 // Implement subpass loads via texture barrier style sampling.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011934 imgexpr = join("texelFetch(", to_non_uniform_aware_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011935 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011936 }
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011937 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011938 pure = true;
11939 }
11940 else
11941 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011942 bool sparse = opcode == OpImageSparseRead;
11943 uint32_t sparse_code_id = 0;
11944 uint32_t sparse_texel_id = 0;
11945 if (sparse)
11946 emit_sparse_feedback_temporaries(ops[0], ops[1], sparse_code_id, sparse_texel_id);
11947
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010011948 // imageLoad only accepts int coords, not uint.
11949 auto coord_expr = to_expression(ops[3]);
11950 auto target_coord_type = expression_type(ops[3]);
11951 target_coord_type.basetype = SPIRType::Int;
11952 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
11953
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011954 // Plain image load/store.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011955 if (sparse)
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011956 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011957 if (type.image.ms)
11958 {
11959 uint32_t operands = ops[4];
11960 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011961 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11962 "operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011963
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011964 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011965 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_non_uniform_aware_expression(ops[2]), ", ",
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011966 coord_expr, ", ", to_expression(samples), ", ", to_expression(sparse_texel_id), ");");
11967 }
11968 else
11969 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011970 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_non_uniform_aware_expression(ops[2]), ", ",
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011971 coord_expr, ", ", to_expression(sparse_texel_id), ");");
11972 }
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020011973 imgexpr = join(type_to_glsl(get<SPIRType>(result_type)), "(", to_expression(sparse_code_id), ", ",
11974 to_expression(sparse_texel_id), ")");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011975 }
11976 else
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011977 {
11978 if (type.image.ms)
11979 {
11980 uint32_t operands = ops[4];
11981 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011982 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11983 "operand mask was used.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011984
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011985 uint32_t samples = ops[5];
11986 imgexpr =
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011987 join("imageLoad(", to_non_uniform_aware_expression(ops[2]), ", ", coord_expr, ", ", to_expression(samples), ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011988 }
11989 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020011990 imgexpr = join("imageLoad(", to_non_uniform_aware_expression(ops[2]), ", ", coord_expr, ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011991 }
11992
11993 if (!sparse)
11994 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011995 pure = false;
11996 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011997
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011998 if (var && var->forwardable)
11999 {
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010012000 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
12001 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012002
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012003 // We only need to track dependencies if we're reading from image load/store.
12004 if (!pure)
12005 {
12006 e.loaded_from = var->self;
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010012007 if (forward)
12008 var->dependees.push_back(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012009 }
12010 }
12011 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010012012 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010012013
12014 inherit_expression_dependencies(id, ops[2]);
12015 if (type.image.ms)
12016 inherit_expression_dependencies(id, ops[5]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012017 break;
12018 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012019
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012020 case OpImageTexelPointer:
12021 {
12022 uint32_t result_type = ops[0];
12023 uint32_t id = ops[1];
Mark Satterthwaitec4f97042019-08-26 11:28:13 -040012024
12025 auto coord_expr = to_expression(ops[3]);
12026 auto target_coord_type = expression_type(ops[3]);
12027 target_coord_type.basetype = SPIRType::Int;
12028 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
12029
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010012030 auto expr = join(to_expression(ops[2]), ", ", coord_expr);
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010012031 auto &e = set<SPIRExpression>(id, expr, result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012032
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012033 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012034 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012035 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen6edbf0c2019-10-24 11:30:20 +020012036 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012037 break;
12038 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012039
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012040 case OpImageWrite:
12041 {
12042 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
12043 // not adding the proper qualifiers.
12044 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
12045 auto *var = maybe_get_backing_variable(ops[0]);
12046 if (var)
12047 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010012048 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012049 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012050 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012051 flags.clear(DecorationNonWritable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012052 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012053 }
12054 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012055
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012056 auto &type = expression_type(ops[0]);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012057 auto &value_type = expression_type(ops[2]);
12058 auto store_type = value_type;
12059 store_type.vecsize = 4;
12060
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010012061 // imageStore only accepts int coords, not uint.
12062 auto coord_expr = to_expression(ops[1]);
12063 auto target_coord_type = expression_type(ops[1]);
12064 target_coord_type.basetype = SPIRType::Int;
12065 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
12066
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012067 if (type.image.ms)
12068 {
12069 uint32_t operands = ops[3];
12070 if (operands != ImageOperandsSampleMask || length != 5)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012071 SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012072 uint32_t samples = ops[4];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012073 statement("imageStore(", to_non_uniform_aware_expression(ops[0]), ", ", coord_expr, ", ", to_expression(samples), ", ",
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010012074 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012075 }
12076 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012077 statement("imageStore(", to_non_uniform_aware_expression(ops[0]), ", ", coord_expr, ", ",
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012078 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012079
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012080 if (var && variable_storage_is_aliased(*var))
12081 flush_all_aliased_variables();
12082 break;
12083 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012084
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012085 case OpImageQuerySize:
12086 {
12087 auto &type = expression_type(ops[2]);
12088 uint32_t result_type = ops[0];
12089 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012090
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012091 if (type.basetype == SPIRType::Image)
12092 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012093 string expr;
12094 if (type.image.sampled == 2)
12095 {
rdb10fa5f62020-11-09 15:26:46 +010012096 if (!options.es && options.version < 430)
12097 require_extension_internal("GL_ARB_shader_image_size");
12098 else if (options.es && options.version < 310)
12099 SPIRV_CROSS_THROW("At least ESSL 3.10 required for imageSize.");
12100
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012101 // The size of an image is always constant.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012102 expr = join("imageSize(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012103 }
12104 else
12105 {
12106 // This path is hit for samplerBuffers and multisampled images which do not have LOD.
rdb10fa5f62020-11-09 15:26:46 +010012107 std::string fname = "textureSize";
12108 if (is_legacy())
12109 {
12110 auto &imgtype = get<SPIRType>(type.self);
12111 fname = legacy_tex_op(fname, imgtype, ops[2]);
12112 }
12113 expr = join(fname, "(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012114 }
12115
12116 auto &restype = get<SPIRType>(ops[0]);
12117 expr = bitcast_expression(restype, SPIRType::Int, expr);
12118 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012119 }
12120 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012121 SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012122 break;
12123 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012124
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012125 // Compute
12126 case OpControlBarrier:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012127 case OpMemoryBarrier:
12128 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012129 uint32_t execution_scope = 0;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012130 uint32_t memory;
12131 uint32_t semantics;
12132
12133 if (opcode == OpMemoryBarrier)
12134 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012135 memory = evaluate_constant_u32(ops[0]);
12136 semantics = evaluate_constant_u32(ops[1]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012137 }
12138 else
12139 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012140 execution_scope = evaluate_constant_u32(ops[0]);
12141 memory = evaluate_constant_u32(ops[1]);
12142 semantics = evaluate_constant_u32(ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012143 }
12144
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012145 if (execution_scope == ScopeSubgroup || memory == ScopeSubgroup)
12146 {
crissdb52e272020-10-08 12:14:52 +020012147 // OpControlBarrier with ScopeSubgroup is subgroupBarrier()
12148 if (opcode != OpControlBarrier)
12149 {
12150 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMemBarrier);
12151 }
12152 else
12153 {
12154 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBarrier);
12155 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012156 }
12157
12158 if (execution_scope != ScopeSubgroup && get_entry_point().model == ExecutionModelTessellationControl)
12159 {
12160 // Control shaders only have barriers, and it implies memory barriers.
12161 if (opcode == OpControlBarrier)
12162 statement("barrier();");
12163 break;
12164 }
12165
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012166 // We only care about these flags, acquire/release and friends are not relevant to GLSL.
12167 semantics = mask_relevant_memory_semantics(semantics);
12168
12169 if (opcode == OpMemoryBarrier)
12170 {
12171 // If we are a memory barrier, and the next instruction is a control barrier, check if that memory barrier
12172 // does what we need, so we avoid redundant barriers.
12173 const Instruction *next = get_next_instruction_in_block(instruction);
12174 if (next && next->op == OpControlBarrier)
12175 {
12176 auto *next_ops = stream(*next);
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012177 uint32_t next_memory = evaluate_constant_u32(next_ops[1]);
12178 uint32_t next_semantics = evaluate_constant_u32(next_ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012179 next_semantics = mask_relevant_memory_semantics(next_semantics);
12180
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010012181 bool memory_scope_covered = false;
12182 if (next_memory == memory)
12183 memory_scope_covered = true;
12184 else if (next_semantics == MemorySemanticsWorkgroupMemoryMask)
12185 {
12186 // If we only care about workgroup memory, either Device or Workgroup scope is fine,
12187 // scope does not have to match.
12188 if ((next_memory == ScopeDevice || next_memory == ScopeWorkgroup) &&
12189 (memory == ScopeDevice || memory == ScopeWorkgroup))
12190 {
12191 memory_scope_covered = true;
12192 }
12193 }
12194 else if (memory == ScopeWorkgroup && next_memory == ScopeDevice)
12195 {
12196 // The control barrier has device scope, but the memory barrier just has workgroup scope.
12197 memory_scope_covered = true;
12198 }
12199
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012200 // If we have the same memory scope, and all memory types are covered, we're good.
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010012201 if (memory_scope_covered && (semantics & next_semantics) == semantics)
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012202 break;
12203 }
12204 }
12205
12206 // We are synchronizing some memory or syncing execution,
12207 // so we cannot forward any loads beyond the memory barrier.
12208 if (semantics || opcode == OpControlBarrier)
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012209 {
12210 assert(current_emitting_block);
12211 flush_control_dependent_expressions(current_emitting_block->self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012212 flush_all_active_variables();
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012213 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012214
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012215 if (memory == ScopeWorkgroup) // Only need to consider memory within a group
12216 {
12217 if (semantics == MemorySemanticsWorkgroupMemoryMask)
Hans-Kristian Arntzen67b29912019-12-04 15:06:19 +010012218 {
12219 // OpControlBarrier implies a memory barrier for shared memory as well.
12220 bool implies_shared_barrier = opcode == OpControlBarrier && execution_scope == ScopeWorkgroup;
12221 if (!implies_shared_barrier)
12222 statement("memoryBarrierShared();");
12223 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012224 else if (semantics != 0)
12225 statement("groupMemoryBarrier();");
12226 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012227 else if (memory == ScopeSubgroup)
12228 {
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +020012229 const uint32_t all_barriers =
12230 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012231
12232 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
12233 {
12234 // These are not relevant for GLSL, but assume it means memoryBarrier().
12235 // memoryBarrier() does everything, so no need to test anything else.
12236 statement("subgroupMemoryBarrier();");
12237 }
12238 else if ((semantics & all_barriers) == all_barriers)
12239 {
12240 // Short-hand instead of emitting 3 barriers.
12241 statement("subgroupMemoryBarrier();");
12242 }
12243 else
12244 {
12245 // Pick out individual barriers.
12246 if (semantics & MemorySemanticsWorkgroupMemoryMask)
12247 statement("subgroupMemoryBarrierShared();");
12248 if (semantics & MemorySemanticsUniformMemoryMask)
12249 statement("subgroupMemoryBarrierBuffer();");
12250 if (semantics & MemorySemanticsImageMemoryMask)
12251 statement("subgroupMemoryBarrierImage();");
12252 }
12253 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012254 else
12255 {
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010012256 const uint32_t all_barriers =
12257 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012258
12259 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
12260 {
12261 // These are not relevant for GLSL, but assume it means memoryBarrier().
12262 // memoryBarrier() does everything, so no need to test anything else.
12263 statement("memoryBarrier();");
12264 }
12265 else if ((semantics & all_barriers) == all_barriers)
12266 {
12267 // Short-hand instead of emitting 4 barriers.
12268 statement("memoryBarrier();");
12269 }
12270 else
12271 {
12272 // Pick out individual barriers.
12273 if (semantics & MemorySemanticsWorkgroupMemoryMask)
12274 statement("memoryBarrierShared();");
12275 if (semantics & MemorySemanticsUniformMemoryMask)
12276 statement("memoryBarrierBuffer();");
12277 if (semantics & MemorySemanticsImageMemoryMask)
12278 statement("memoryBarrierImage();");
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012279 }
12280 }
12281
12282 if (opcode == OpControlBarrier)
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012283 {
12284 if (execution_scope == ScopeSubgroup)
12285 statement("subgroupBarrier();");
12286 else
12287 statement("barrier();");
12288 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012289 break;
12290 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012291
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012292 case OpExtInst:
12293 {
12294 uint32_t extension_set = ops[2];
Lou Kramer6671f522017-11-21 14:04:57 +010012295
12296 if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012297 {
Lou Kramer6671f522017-11-21 14:04:57 +010012298 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12299 }
12300 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_ballot)
12301 {
12302 emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12303 }
12304 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
12305 {
12306 emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12307 }
12308 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_trinary_minmax)
12309 {
12310 emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12311 }
12312 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_gcn_shader)
12313 {
12314 emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
12315 }
Lifeng Pan5ca87792019-07-04 16:03:06 +080012316 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_debug_info)
12317 {
12318 break; // Ignore SPIR-V debug information extended instructions.
12319 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012320 else
12321 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012322 statement("// unimplemented ext op ", instruction.op);
12323 break;
12324 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012325
Lou Kramer6671f522017-11-21 14:04:57 +010012326 break;
12327 }
12328
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012329 // Legacy sub-group stuff ...
Lou Kramer6671f522017-11-21 14:04:57 +010012330 case OpSubgroupBallotKHR:
12331 {
Lou Kramer6671f522017-11-21 14:04:57 +010012332 uint32_t result_type = ops[0];
12333 uint32_t id = ops[1];
12334 string expr;
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012335 expr = join("uvec4(unpackUint2x32(ballotARB(" + to_expression(ops[2]) + ")), 0u, 0u)");
Hans-Kristian Arntzen4979d102018-03-12 17:51:14 +010012336 emit_op(result_type, id, expr, should_forward(ops[2]));
Lou Kramer6671f522017-11-21 14:04:57 +010012337
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012338 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzenae2680c2018-03-12 17:42:48 +010012339 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012340 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012341 break;
12342 }
12343
12344 case OpSubgroupFirstInvocationKHR:
12345 {
Lou Kramer6671f522017-11-21 14:04:57 +010012346 uint32_t result_type = ops[0];
12347 uint32_t id = ops[1];
12348 emit_unary_func_op(result_type, id, ops[2], "readFirstInvocationARB");
12349
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012350 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012351 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012352 break;
12353 }
12354
12355 case OpSubgroupReadInvocationKHR:
12356 {
Lou Kramer6671f522017-11-21 14:04:57 +010012357 uint32_t result_type = ops[0];
12358 uint32_t id = ops[1];
12359 emit_binary_func_op(result_type, id, ops[2], ops[3], "readInvocationARB");
12360
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012361 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012362 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012363 break;
12364 }
12365
12366 case OpSubgroupAllKHR:
12367 {
Lou Kramer6671f522017-11-21 14:04:57 +010012368 uint32_t result_type = ops[0];
12369 uint32_t id = ops[1];
12370 emit_unary_func_op(result_type, id, ops[2], "allInvocationsARB");
12371
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012372 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012373 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012374 break;
12375 }
12376
12377 case OpSubgroupAnyKHR:
12378 {
Lou Kramer6671f522017-11-21 14:04:57 +010012379 uint32_t result_type = ops[0];
12380 uint32_t id = ops[1];
12381 emit_unary_func_op(result_type, id, ops[2], "anyInvocationARB");
12382
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012383 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012384 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012385 break;
12386 }
12387
12388 case OpSubgroupAllEqualKHR:
12389 {
Lou Kramer6671f522017-11-21 14:04:57 +010012390 uint32_t result_type = ops[0];
12391 uint32_t id = ops[1];
12392 emit_unary_func_op(result_type, id, ops[2], "allInvocationsEqualARB");
12393
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012394 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012395 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012396 break;
12397 }
12398
12399 case OpGroupIAddNonUniformAMD:
12400 case OpGroupFAddNonUniformAMD:
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], "addInvocationsNonUniformAMD");
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 OpGroupFMinNonUniformAMD:
12412 case OpGroupUMinNonUniformAMD:
12413 case OpGroupSMinNonUniformAMD:
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], "minInvocationsNonUniformAMD");
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 OpGroupFMaxNonUniformAMD:
12425 case OpGroupUMaxNonUniformAMD:
12426 case OpGroupSMaxNonUniformAMD:
12427 {
Lou Kramer6671f522017-11-21 14:04:57 +010012428 uint32_t result_type = ops[0];
12429 uint32_t id = ops[1];
12430 emit_unary_func_op(result_type, id, ops[4], "maxInvocationsNonUniformAMD");
12431
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012432 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012433 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010012434 break;
12435 }
12436
12437 case OpFragmentMaskFetchAMD:
12438 {
12439 auto &type = expression_type(ops[2]);
12440 uint32_t result_type = ops[0];
12441 uint32_t id = ops[1];
12442
12443 if (type.image.dim == spv::DimSubpassData)
12444 {
12445 emit_unary_func_op(result_type, id, ops[2], "fragmentMaskFetchAMD");
12446 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012447 else
Lou Kramer6671f522017-11-21 14:04:57 +010012448 {
12449 emit_binary_func_op(result_type, id, ops[2], ops[3], "fragmentMaskFetchAMD");
12450 }
12451
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012452 require_extension_internal("GL_AMD_shader_fragment_mask");
Lou Kramer6671f522017-11-21 14:04:57 +010012453 break;
12454 }
12455
12456 case OpFragmentFetchAMD:
12457 {
12458 auto &type = expression_type(ops[2]);
12459 uint32_t result_type = ops[0];
12460 uint32_t id = ops[1];
12461
12462 if (type.image.dim == spv::DimSubpassData)
12463 {
12464 emit_binary_func_op(result_type, id, ops[2], ops[4], "fragmentFetchAMD");
12465 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012466 else
Lou Kramer6671f522017-11-21 14:04:57 +010012467 {
12468 emit_trinary_func_op(result_type, id, ops[2], ops[3], ops[4], "fragmentFetchAMD");
12469 }
12470
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012471 require_extension_internal("GL_AMD_shader_fragment_mask");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012472 break;
12473 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012474
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012475 // Vulkan 1.1 sub-group stuff ...
12476 case OpGroupNonUniformElect:
12477 case OpGroupNonUniformBroadcast:
12478 case OpGroupNonUniformBroadcastFirst:
12479 case OpGroupNonUniformBallot:
12480 case OpGroupNonUniformInverseBallot:
12481 case OpGroupNonUniformBallotBitExtract:
12482 case OpGroupNonUniformBallotBitCount:
12483 case OpGroupNonUniformBallotFindLSB:
12484 case OpGroupNonUniformBallotFindMSB:
12485 case OpGroupNonUniformShuffle:
12486 case OpGroupNonUniformShuffleXor:
12487 case OpGroupNonUniformShuffleUp:
12488 case OpGroupNonUniformShuffleDown:
12489 case OpGroupNonUniformAll:
12490 case OpGroupNonUniformAny:
12491 case OpGroupNonUniformAllEqual:
12492 case OpGroupNonUniformFAdd:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020012493 case OpGroupNonUniformIAdd:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012494 case OpGroupNonUniformFMul:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020012495 case OpGroupNonUniformIMul:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012496 case OpGroupNonUniformFMin:
12497 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020012498 case OpGroupNonUniformSMin:
12499 case OpGroupNonUniformSMax:
12500 case OpGroupNonUniformUMin:
12501 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012502 case OpGroupNonUniformBitwiseAnd:
12503 case OpGroupNonUniformBitwiseOr:
12504 case OpGroupNonUniformBitwiseXor:
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +010012505 case OpGroupNonUniformLogicalAnd:
12506 case OpGroupNonUniformLogicalOr:
12507 case OpGroupNonUniformLogicalXor:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012508 case OpGroupNonUniformQuadSwap:
12509 case OpGroupNonUniformQuadBroadcast:
12510 emit_subgroup_op(instruction);
12511 break;
12512
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012513 case OpFUnordEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012514 case OpFUnordNotEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012515 case OpFUnordLessThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012516 case OpFUnordGreaterThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012517 case OpFUnordLessThanEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012518 case OpFUnordGreaterThanEqual:
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020012519 {
12520 // GLSL doesn't specify if floating point comparisons are ordered or unordered,
12521 // but glslang always emits ordered floating point compares for GLSL.
12522 // To get unordered compares, we can test the opposite thing and invert the result.
12523 // This way, we force true when there is any NaN present.
12524 uint32_t op0 = ops[2];
12525 uint32_t op1 = ops[3];
12526
12527 string expr;
12528 if (expression_type(op0).vecsize > 1)
12529 {
12530 const char *comp_op = nullptr;
12531 switch (opcode)
12532 {
12533 case OpFUnordEqual:
12534 comp_op = "notEqual";
12535 break;
12536
12537 case OpFUnordNotEqual:
12538 comp_op = "equal";
12539 break;
12540
12541 case OpFUnordLessThan:
12542 comp_op = "greaterThanEqual";
12543 break;
12544
12545 case OpFUnordLessThanEqual:
12546 comp_op = "greaterThan";
12547 break;
12548
12549 case OpFUnordGreaterThan:
12550 comp_op = "lessThanEqual";
12551 break;
12552
12553 case OpFUnordGreaterThanEqual:
12554 comp_op = "lessThan";
12555 break;
12556
12557 default:
12558 assert(0);
12559 break;
12560 }
12561
12562 expr = join("not(", comp_op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), "))");
12563 }
12564 else
12565 {
12566 const char *comp_op = nullptr;
12567 switch (opcode)
12568 {
12569 case OpFUnordEqual:
12570 comp_op = " != ";
12571 break;
12572
12573 case OpFUnordNotEqual:
12574 comp_op = " == ";
12575 break;
12576
12577 case OpFUnordLessThan:
12578 comp_op = " >= ";
12579 break;
12580
12581 case OpFUnordLessThanEqual:
12582 comp_op = " > ";
12583 break;
12584
12585 case OpFUnordGreaterThan:
12586 comp_op = " <= ";
12587 break;
12588
12589 case OpFUnordGreaterThanEqual:
12590 comp_op = " < ";
12591 break;
12592
12593 default:
12594 assert(0);
12595 break;
12596 }
12597
12598 expr = join("!(", to_enclosed_unpacked_expression(op0), comp_op, to_enclosed_unpacked_expression(op1), ")");
12599 }
12600
12601 emit_op(ops[0], ops[1], expr, should_forward(op0) && should_forward(op1));
12602 inherit_expression_dependencies(ops[1], op0);
12603 inherit_expression_dependencies(ops[1], op1);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012604 break;
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020012605 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020012606
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012607 case OpReportIntersectionKHR:
12608 // NV is same opcode.
12609 forced_temporaries.insert(ops[1]);
12610 if (ray_tracing_is_khr)
12611 GLSL_BFOP(reportIntersectionEXT);
12612 else
12613 GLSL_BFOP(reportIntersectionNV);
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012614 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012615 break;
12616 case OpIgnoreIntersectionNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012617 // KHR variant is a terminator.
Patrick Moursda39a7b2019-02-26 15:43:03 +010012618 statement("ignoreIntersectionNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012619 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012620 break;
12621 case OpTerminateRayNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012622 // KHR variant is a terminator.
Patrick Moursda39a7b2019-02-26 15:43:03 +010012623 statement("terminateRayNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012624 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012625 break;
12626 case OpTraceNV:
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012627 statement("traceNV(", to_non_uniform_aware_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
Patrick Moursc96bab02019-03-26 14:04:39 +010012628 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
12629 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
12630 to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
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 OpTraceRayKHR:
12634 if (!has_decoration(ops[10], DecorationLocation))
12635 SPIRV_CROSS_THROW("A memory declaration object must be used in TraceRayKHR.");
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012636 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 +010012637 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
12638 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
12639 to_expression(ops[9]), ", ", get_decoration(ops[10], DecorationLocation), ");");
12640 flush_control_dependent_expressions(current_emitting_block->self);
12641 break;
Patrick Moursda39a7b2019-02-26 15:43:03 +010012642 case OpExecuteCallableNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010012643 statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012644 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012645 break;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012646 case OpExecuteCallableKHR:
12647 if (!has_decoration(ops[1], DecorationLocation))
12648 SPIRV_CROSS_THROW("A memory declaration object must be used in ExecuteCallableKHR.");
12649 statement("executeCallableEXT(", to_expression(ops[0]), ", ", get_decoration(ops[1], DecorationLocation), ");");
12650 flush_control_dependent_expressions(current_emitting_block->self);
12651 break;
12652
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012653 // Don't bother forwarding temporaries. Avoids having to test expression invalidation with ray query objects.
12654 case OpRayQueryInitializeKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012655 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012656 statement("rayQueryInitializeEXT(",
12657 to_expression(ops[0]), ", ", to_expression(ops[1]), ", ",
12658 to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
12659 to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
12660 to_expression(ops[6]), ", ", to_expression(ops[7]), ");");
12661 break;
12662 case OpRayQueryProceedKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012663 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012664 emit_op(ops[0], ops[1], join("rayQueryProceedEXT(", to_expression(ops[2]), ")"), false);
12665 break;
12666 case OpRayQueryTerminateKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012667 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012668 statement("rayQueryTerminateEXT(", to_expression(ops[0]), ");");
12669 break;
12670 case OpRayQueryGenerateIntersectionKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012671 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012672 statement("rayQueryGenerateIntersectionEXT(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
12673 break;
12674 case OpRayQueryConfirmIntersectionKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012675 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012676 statement("rayQueryConfirmIntersectionEXT(", to_expression(ops[0]), ");");
12677 break;
12678#define GLSL_RAY_QUERY_GET_OP(op) \
12679 case OpRayQueryGet##op##KHR: \
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012680 flush_variable_declaration(ops[2]); \
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012681 emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ")"), false); \
12682 break
12683#define GLSL_RAY_QUERY_GET_OP2(op) \
12684 case OpRayQueryGet##op##KHR: \
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020012685 flush_variable_declaration(ops[2]); \
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012686 emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ", ", "bool(", to_expression(ops[3]), "))"), false); \
12687 break
12688 GLSL_RAY_QUERY_GET_OP(RayTMin);
12689 GLSL_RAY_QUERY_GET_OP(RayFlags);
12690 GLSL_RAY_QUERY_GET_OP(WorldRayOrigin);
12691 GLSL_RAY_QUERY_GET_OP(WorldRayDirection);
12692 GLSL_RAY_QUERY_GET_OP(IntersectionCandidateAABBOpaque);
12693 GLSL_RAY_QUERY_GET_OP2(IntersectionType);
12694 GLSL_RAY_QUERY_GET_OP2(IntersectionT);
12695 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceCustomIndex);
12696 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceId);
12697 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceShaderBindingTableRecordOffset);
12698 GLSL_RAY_QUERY_GET_OP2(IntersectionGeometryIndex);
12699 GLSL_RAY_QUERY_GET_OP2(IntersectionPrimitiveIndex);
12700 GLSL_RAY_QUERY_GET_OP2(IntersectionBarycentrics);
12701 GLSL_RAY_QUERY_GET_OP2(IntersectionFrontFace);
12702 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayDirection);
12703 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayOrigin);
12704 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectToWorld);
12705 GLSL_RAY_QUERY_GET_OP2(IntersectionWorldToObject);
12706#undef GLSL_RAY_QUERY_GET_OP
12707#undef GLSL_RAY_QUERY_GET_OP2
12708
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012709 case OpConvertUToAccelerationStructureKHR:
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020012710 require_extension_internal("GL_EXT_ray_tracing");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010012711 GLSL_UFOP(accelerationStructureEXT);
12712 break;
Patrick Moursda39a7b2019-02-26 15:43:03 +010012713
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012714 case OpConvertUToPtr:
12715 {
12716 auto &type = get<SPIRType>(ops[0]);
12717 if (type.storage != StorageClassPhysicalStorageBufferEXT)
12718 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertUToPtr.");
12719
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +020012720 auto &in_type = expression_type(ops[2]);
12721 if (in_type.vecsize == 2)
12722 require_extension_internal("GL_EXT_buffer_reference_uvec2");
12723
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012724 auto op = type_to_glsl(type);
12725 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
12726 break;
12727 }
12728
12729 case OpConvertPtrToU:
12730 {
12731 auto &type = get<SPIRType>(ops[0]);
12732 auto &ptr_type = expression_type(ops[2]);
12733 if (ptr_type.storage != StorageClassPhysicalStorageBufferEXT)
12734 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertPtrToU.");
12735
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +020012736 if (type.vecsize == 2)
12737 require_extension_internal("GL_EXT_buffer_reference_uvec2");
12738
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012739 auto op = type_to_glsl(type);
12740 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
12741 break;
12742 }
12743
lifpan876627d2019-04-08 19:45:31 +080012744 case OpUndef:
12745 // Undefined value has been declared.
12746 break;
12747
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020012748 case OpLine:
12749 {
12750 emit_line_directive(ops[0], ops[1]);
12751 break;
12752 }
12753
Lifeng Pan5ca87792019-07-04 16:03:06 +080012754 case OpNoLine:
12755 break;
12756
Chip Davis50dce102019-07-13 15:57:33 -050012757 case OpDemoteToHelperInvocationEXT:
12758 if (!options.vulkan_semantics)
12759 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
12760 require_extension_internal("GL_EXT_demote_to_helper_invocation");
12761 statement(backend.demote_literal, ";");
12762 break;
12763
12764 case OpIsHelperInvocationEXT:
12765 if (!options.vulkan_semantics)
12766 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
12767 require_extension_internal("GL_EXT_demote_to_helper_invocation");
Chip Davis12a86542019-07-18 17:32:35 -050012768 emit_op(ops[0], ops[1], "helperInvocationEXT()", false);
Chip Davis50dce102019-07-13 15:57:33 -050012769 break;
12770
Chip Davis2eff4202019-08-04 00:07:20 -050012771 case OpBeginInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012772 // If the interlock is complex, we emit this elsewhere.
12773 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050012774 {
Erfan Ahmadi43eecb22021-10-19 09:39:55 +033012775 statement("SPIRV_Cross_beginInvocationInterlock();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020012776 flush_all_active_variables();
12777 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050012778 }
12779 break;
12780
12781 case OpEndInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012782 // If the interlock is complex, we emit this elsewhere.
12783 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050012784 {
Erfan Ahmadi43eecb22021-10-19 09:39:55 +033012785 statement("SPIRV_Cross_endInvocationInterlock();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020012786 flush_all_active_variables();
12787 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050012788 }
12789 break;
12790
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012791 default:
12792 statement("// unimplemented op ", instruction.op);
12793 break;
12794 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012795}
12796
Bill Hollingsa759e2c2016-10-19 14:09:51 -070012797// Appends function arguments, mapped from global variables, beyond the specified arg index.
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012798// This is used when a function call uses fewer arguments than the function defines.
Bill Hollingsa759e2c2016-10-19 14:09:51 -070012799// This situation may occur if the function signature has been dynamically modified to
12800// extract global variables referenced from within the function, and convert them to
12801// function arguments. This is necessary for shader languages that do not support global
12802// access to shader input content from within a function (eg. Metal). Each additional
12803// function args uses the name of the global variable. Function nesting will modify the
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012804// functions and function calls all the way up the nesting chain.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020012805void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<string> &arglist)
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012806{
Bill Hollingsac00c602016-10-24 09:24:24 -040012807 auto &args = func.arguments;
Bill Hollings943191a2016-10-27 10:20:01 -040012808 uint32_t arg_cnt = uint32_t(args.size());
Bill Hollingsac00c602016-10-24 09:24:24 -040012809 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010012810 {
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012811 auto &arg = args[arg_idx];
12812 assert(arg.alias_global_variable);
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012813
12814 // If the underlying variable needs to be declared
12815 // (ie. a local variable with deferred declaration), do so now.
12816 uint32_t var_id = get<SPIRVariable>(arg.id).basevariable;
12817 if (var_id)
12818 flush_variable_declaration(var_id);
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +020012819
Chip Davis39dce882019-08-02 15:11:19 -050012820 arglist.push_back(to_func_call_arg(arg, arg.id));
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010012821 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012822}
12823
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012824string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
12825{
Hans-Kristian Arntzena0c13e42019-10-07 10:31:42 +020012826 if (type.type_alias != TypeID(0) &&
12827 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
12828 {
12829 return to_member_name(get<SPIRType>(type.type_alias), index);
12830 }
12831
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012832 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012833 if (index < memb.size() && !memb[index].alias.empty())
12834 return memb[index].alias;
12835 else
Hans-Kristian Arntzen1c6df1b2017-07-29 21:44:20 +020012836 return join("_m", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012837}
12838
Chip Davis3bfb2f92018-12-03 02:06:33 -060012839string CompilerGLSL::to_member_reference(uint32_t, const SPIRType &type, uint32_t index, bool)
Chip Davis3a9af962018-09-26 20:06:05 -050012840{
12841 return join(".", to_member_name(type, index));
12842}
12843
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020012844string CompilerGLSL::to_multi_member_reference(const SPIRType &type, const SmallVector<uint32_t> &indices)
12845{
12846 string ret;
12847 auto *member_type = &type;
12848 for (auto &index : indices)
12849 {
12850 ret += join(".", to_member_name(*member_type, index));
12851 member_type = &get<SPIRType>(member_type->member_types[index]);
12852 }
12853 return ret;
12854}
12855
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012856void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
12857{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012858 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012859 if (index < memb.size() && !memb[index].alias.empty())
12860 {
12861 auto &name = memb[index].alias;
12862 if (name.empty())
12863 return;
12864
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020012865 ParsedIR::sanitize_identifier(name, true, true);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012866 update_name_cache(type.member_name_cache, name);
12867 }
12868}
12869
Bill Hollingsb332bae2017-03-01 13:07:40 -050012870// Checks whether the ID is a row_major matrix that requires conversion before use
Bill Hollings13583622016-12-14 02:12:52 -050012871bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012872{
Bill Hollings13583622016-12-14 02:12:52 -050012873 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010012874 // Legacy targets do not support row major.
12875 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050012876 return false;
12877
Hans-Kristian Arntzen120af422020-10-14 16:07:10 +020012878 auto *e = maybe_get<SPIRExpression>(id);
12879 if (e)
12880 return e->need_transpose;
12881 else
12882 return has_decoration(id, DecorationRowMajor);
Bill Hollings343677e2016-12-11 11:01:08 -050012883}
12884
Bill Hollings13583622016-12-14 02:12:52 -050012885// Checks whether the member is a row_major matrix that requires conversion before use
12886bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index)
Bill Hollings343677e2016-12-11 11:01:08 -050012887{
Bill Hollings13583622016-12-14 02:12:52 -050012888 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010012889 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050012890 return false;
12891
12892 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +010012893 if (!has_member_decoration(type.self, index, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -050012894 return false;
12895
12896 // Only square row-major matrices can be converted at this time.
12897 // Converting non-square matrices will require defining custom GLSL function that
12898 // swaps matrix elements while retaining the original dimensional form of the matrix.
12899 const auto mbr_type = get<SPIRType>(type.member_types[index]);
12900 if (mbr_type.columns != mbr_type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +010012901 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -050012902
12903 return true;
Bill Hollings343677e2016-12-11 11:01:08 -050012904}
12905
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020012906// Checks if we need to remap physical type IDs when declaring the type in a buffer.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020012907bool CompilerGLSL::member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const
Bill Hollingsb332bae2017-03-01 13:07:40 -050012908{
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020012909 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID);
12910}
12911
12912// Checks whether the member is in packed data type, that might need to be unpacked.
12913bool CompilerGLSL::member_is_packed_physical_type(const SPIRType &type, uint32_t index) const
12914{
12915 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
Bill Hollingsb332bae2017-03-01 13:07:40 -050012916}
12917
Bill Hollings13583622016-12-14 02:12:52 -050012918// Wraps the expression string in a function call that converts the
12919// row_major matrix result of the expression to a column_major matrix.
12920// Base implementation uses the standard library transpose() function.
12921// Subclasses may override to use a different function.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020012922string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t /* physical_type_id */,
12923 bool /*is_packed*/)
Bill Hollings343677e2016-12-11 11:01:08 -050012924{
12925 strip_enclosed_expression(exp_str);
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012926 if (!is_matrix(exp_type))
12927 {
12928 auto column_index = exp_str.find_last_of('[');
12929 if (column_index == string::npos)
12930 return exp_str;
12931
12932 auto column_expr = exp_str.substr(column_index);
12933 exp_str.resize(column_index);
12934
12935 auto transposed_expr = type_to_glsl_constructor(exp_type) + "(";
12936
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020012937 // Loading a column from a row-major matrix. Unroll the load.
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012938 for (uint32_t c = 0; c < exp_type.vecsize; c++)
12939 {
12940 transposed_expr += join(exp_str, '[', c, ']', column_expr);
12941 if (c + 1 < exp_type.vecsize)
12942 transposed_expr += ", ";
12943 }
12944
12945 transposed_expr += ")";
12946 return transposed_expr;
12947 }
rdbbf719942020-11-05 17:09:33 +010012948 else if (options.version < 120)
12949 {
12950 // GLSL 110, ES 100 do not have transpose(), so emulate it. Note that
12951 // these GLSL versions do not support non-square matrices.
12952 if (exp_type.vecsize == 2 && exp_type.columns == 2)
12953 {
12954 if (!requires_transpose_2x2)
12955 {
12956 requires_transpose_2x2 = true;
12957 force_recompile();
12958 }
12959 }
12960 else if (exp_type.vecsize == 3 && exp_type.columns == 3)
12961 {
12962 if (!requires_transpose_3x3)
12963 {
12964 requires_transpose_3x3 = true;
12965 force_recompile();
12966 }
12967 }
12968 else if (exp_type.vecsize == 4 && exp_type.columns == 4)
12969 {
12970 if (!requires_transpose_4x4)
12971 {
12972 requires_transpose_4x4 = true;
12973 force_recompile();
12974 }
12975 }
12976 else
12977 SPIRV_CROSS_THROW("Non-square matrices are not supported in legacy GLSL, cannot transpose.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010012978 return join("spvTranspose(", exp_str, ")");
rdbbf719942020-11-05 17:09:33 +010012979 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012980 else
12981 return join("transpose(", exp_str, ")");
Bill Hollings343677e2016-12-11 11:01:08 -050012982}
12983
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020012984string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012985{
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020012986 string type_name = type_to_glsl(type, id);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +020012987 remap_variable_type_name(type, name, type_name);
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +020012988 return join(type_name, " ", name, type_to_array_glsl(type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012989}
12990
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020012991bool CompilerGLSL::variable_decl_is_remapped_storage(const SPIRVariable &var, StorageClass storage) const
Hans-Kristian Arntzenf2b5fb32021-03-26 17:23:44 +010012992{
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020012993 return var.storage == storage;
Hans-Kristian Arntzenf2b5fb32021-03-26 17:23:44 +010012994}
12995
Bill Hollings484931d2017-02-28 21:44:36 -050012996// Emit a structure member. Subclasses may override to modify output,
12997// or to dynamically add a padding member if needed.
Bill Hollingsdc694272017-03-11 12:17:22 -050012998void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
msiglreithd096f5c2017-11-27 16:00:56 +010012999 const string &qualifier, uint32_t)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013000{
Bill Hollings484931d2017-02-28 21:44:36 -050013001 auto &membertype = get<SPIRType>(member_type_id);
13002
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013003 Bitset memberflags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013004 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013005 if (index < memb.size())
13006 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013007
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020013008 string qualifiers;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013009 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
13010 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013011
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020013012 if (is_block)
13013 qualifiers = to_interpolation_qualifiers(memberflags);
13014
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013015 statement(layout_for_member(type, index), qualifiers, qualifier, flags_to_qualifiers_glsl(membertype, memberflags),
Bill Hollings484931d2017-02-28 21:44:36 -050013016 variable_decl(membertype, to_member_name(type, index)), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013017}
13018
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +020013019void CompilerGLSL::emit_struct_padding_target(const SPIRType &)
13020{
13021}
13022
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013023string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013024{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013025 // GL_EXT_buffer_reference variables can be marked as restrict.
13026 if (flags.get(DecorationRestrictPointerEXT))
13027 return "restrict ";
13028
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013029 string qual;
13030
Hans-Kristian Arntzenac11a912021-07-26 22:05:55 +020013031 if (type_is_floating_point(type) && flags.get(DecorationNoContraction) && backend.support_precise_qualifier)
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013032 qual = "precise ";
13033
Hans-Kristian Arntzenac11a912021-07-26 22:05:55 +020013034 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
13035 bool type_supports_precision =
13036 type.basetype == SPIRType::Float || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
13037 type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
13038 type.basetype == SPIRType::Sampler;
13039
13040 if (!type_supports_precision)
13041 return qual;
13042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013043 if (options.es)
13044 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +020013045 auto &execution = get_entry_point();
13046
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013047 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013048 {
13049 bool implied_fmediump = type.basetype == SPIRType::Float &&
13050 options.fragment.default_float_precision == Options::Mediump &&
13051 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013052
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013053 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
13054 options.fragment.default_int_precision == Options::Mediump &&
13055 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013056
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013057 qual += (implied_fmediump || implied_imediump) ? "" : "mediump ";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013058 }
13059 else
13060 {
13061 bool implied_fhighp =
13062 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
13063 execution.model == ExecutionModelFragment) ||
13064 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013066 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
13067 ((options.fragment.default_int_precision == Options::Highp &&
13068 execution.model == ExecutionModelFragment) ||
13069 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013070
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013071 qual += (implied_fhighp || implied_ihighp) ? "" : "highp ";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013072 }
13073 }
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010013074 else if (backend.allow_precision_qualifiers)
13075 {
13076 // Vulkan GLSL supports precision qualifiers, even in desktop profiles, which is convenient.
13077 // 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 +010013078 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013079 qual += "mediump ";
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010013080 }
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013081
13082 return qual;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013083}
13084
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013085string CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013086{
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013087 auto &type = expression_type(id);
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013088 bool use_precision_qualifiers = backend.allow_precision_qualifiers;
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013089 if (use_precision_qualifiers && (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage))
13090 {
13091 // Force mediump for the sampler type. We cannot declare 16-bit or smaller image types.
13092 auto &result_type = get<SPIRType>(type.image.type);
13093 if (result_type.width < 32)
13094 return "mediump ";
13095 }
13096 return flags_to_qualifiers_glsl(type, ir.meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013097}
13098
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013099void CompilerGLSL::fixup_io_block_patch_qualifiers(const SPIRVariable &var)
13100{
13101 // Works around weird behavior in glslangValidator where
13102 // a patch out block is translated to just block members getting the decoration.
13103 // To make glslang not complain when we compile again, we have to transform this back to a case where
13104 // the variable itself has Patch decoration, and not members.
13105 auto &type = get<SPIRType>(var.basetype);
13106 if (has_decoration(type.self, DecorationBlock))
13107 {
13108 uint32_t member_count = uint32_t(type.member_types.size());
13109 for (uint32_t i = 0; i < member_count; i++)
13110 {
13111 if (has_member_decoration(type.self, i, DecorationPatch))
13112 {
13113 set_decoration(var.self, DecorationPatch);
13114 break;
13115 }
13116 }
13117
13118 if (has_decoration(var.self, DecorationPatch))
13119 for (uint32_t i = 0; i < member_count; i++)
13120 unset_member_decoration(type.self, i, DecorationPatch);
13121 }
13122}
13123
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013124string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
13125{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013126 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013127 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013128
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013129 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013130
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013131 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
13132 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013133
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020013134 res += to_interpolation_qualifiers(flags);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010013135 if (var)
13136 res += to_storage_qualifiers_glsl(*var);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010013137
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013138 auto &type = expression_type(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013139 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
13140 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013141 if (flags.get(DecorationCoherent))
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013142 res += "coherent ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013143 if (flags.get(DecorationRestrict))
Hans-Kristian Arntzen11dfcb62017-08-29 15:54:22 +020013144 res += "restrict ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013145
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013146 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013147 res += "readonly ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013148
13149 bool formatted_load = type.image.format == ImageFormatUnknown;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013150 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013151 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013152 res += "writeonly ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013153 formatted_load = false;
13154 }
13155
13156 if (formatted_load)
13157 {
13158 if (!options.es)
13159 require_extension_internal("GL_EXT_shader_image_load_formatted");
13160 else
13161 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_image_load_formatted in ESSL.");
13162 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013163 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013164
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013165 res += to_precision_qualifiers_glsl(id);
13166
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013167 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013168}
13169
13170string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
13171{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013172 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013173 auto &type = expression_type(arg.id);
13174 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013175
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013176 if (type.pointer)
13177 {
13178 if (arg.write_count && arg.read_count)
13179 direction = "inout ";
13180 else if (arg.write_count)
13181 direction = "out ";
13182 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013183
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020013184 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 +010013185}
13186
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020013187string CompilerGLSL::to_initializer_expression(const SPIRVariable &var)
13188{
Bill Hollings974a0812021-10-21 16:11:33 -040013189 return to_unpacked_expression(var.initializer);
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020013190}
13191
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013192string CompilerGLSL::to_zero_initialized_expression(uint32_t type_id)
13193{
13194#ifndef NDEBUG
13195 auto &type = get<SPIRType>(type_id);
13196 assert(type.storage == StorageClassPrivate || type.storage == StorageClassFunction ||
13197 type.storage == StorageClassGeneric);
13198#endif
13199 uint32_t id = ir.increase_bound_by(1);
13200 ir.make_constant_null(id, type_id, false);
13201 return constant_expression(get<SPIRConstant>(id));
13202}
13203
13204bool CompilerGLSL::type_can_zero_initialize(const SPIRType &type) const
13205{
13206 if (type.pointer)
13207 return false;
13208
13209 if (!type.array.empty() && options.flatten_multidimensional_arrays)
13210 return false;
13211
13212 for (auto &literal : type.array_size_literal)
13213 if (!literal)
13214 return false;
13215
13216 for (auto &memb : type.member_types)
13217 if (!type_can_zero_initialize(get<SPIRType>(memb)))
13218 return false;
13219
13220 return true;
13221}
13222
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013223string CompilerGLSL::variable_decl(const SPIRVariable &variable)
13224{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013225 // Ignore the pointer type since GLSL doesn't have pointers.
Chip Davis3bfb2f92018-12-03 02:06:33 -060013226 auto &type = get_variable_data_type(variable);
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +020013227
Hans-Kristian Arntzen97796e02021-02-26 12:50:24 +010013228 if (type.pointer_depth > 1 && !backend.support_pointer_to_pointer)
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +010013229 SPIRV_CROSS_THROW("Cannot declare pointer-to-pointer types.");
13230
Hans-Kristian Arntzenb0f7dee2017-06-17 10:56:24 +020013231 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 +020013232
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010013233 if (variable.loop_variable && variable.static_expression)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013234 {
13235 uint32_t expr = variable.static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013236 if (ir.ids[expr].get_type() != TypeUndef)
Bill Hollings974a0812021-10-21 16:11:33 -040013237 res += join(" = ", to_unpacked_expression(variable.static_expression));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013238 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
13239 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013240 }
Hans-Kristian Arntzenc9946292021-04-14 11:27:05 +020013241 else if (variable.initializer && !variable_decl_is_remapped_storage(variable, StorageClassWorkgroup))
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013242 {
13243 uint32_t expr = variable.initializer;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013244 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020013245 res += join(" = ", to_initializer_expression(variable));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013246 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
13247 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013248 }
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013250 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013251}
13252
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013253const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013254{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013255 auto &flags = ir.meta[variable.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013256 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013257 return "mediump ";
13258 else
13259 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013260}
13261
13262string CompilerGLSL::pls_decl(const PlsRemap &var)
13263{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013264 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013266 SPIRType type;
13267 type.vecsize = pls_format_to_components(var.format);
13268 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013269
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013270 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
13271 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013272}
13273
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +010013274uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type) const
13275{
13276 return to_array_size_literal(type, uint32_t(type.array.size() - 1));
13277}
13278
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020013279uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t index) const
13280{
13281 assert(type.array.size() == type.array_size_literal.size());
13282
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010013283 if (type.array_size_literal[index])
13284 {
13285 return type.array[index];
13286 }
13287 else
13288 {
13289 // Use the default spec constant value.
13290 // This is the best we can do.
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020013291 return evaluate_constant_u32(type.array[index]);
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010013292 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020013293}
13294
13295string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index)
13296{
13297 assert(type.array.size() == type.array_size_literal.size());
13298
13299 auto &size = type.array[index];
13300 if (!type.array_size_literal[index])
13301 return to_expression(size);
13302 else if (size)
13303 return convert_to_string(size);
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020013304 else if (!backend.unsized_array_supported)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020013305 {
13306 // For runtime-sized arrays, we can work around
13307 // lack of standard support for this by simply having
13308 // a single element array.
13309 //
13310 // Runtime length arrays must always be the last element
13311 // in an interface block.
13312 return "1";
13313 }
13314 else
13315 return "";
13316}
13317
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013318string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
13319{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013320 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
13321 {
13322 // We are using a wrapped pointer type, and we should not emit any array declarations here.
13323 return "";
13324 }
13325
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020013326 if (type.array.empty())
13327 return "";
13328
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013329 if (options.flatten_multidimensional_arrays)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013330 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013331 string res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013332 res += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013333 for (auto i = uint32_t(type.array.size()); i; i--)
13334 {
13335 res += enclose_expression(to_array_size(type, i - 1));
13336 if (i > 1)
13337 res += " * ";
13338 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013339 res += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013340 return res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013341 }
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013342 else
13343 {
13344 if (type.array.size() > 1)
13345 {
13346 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013347 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013348 else if (options.es && options.version < 310)
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020013349 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
13350 "Try using --flatten-multidimensional-arrays or set "
13351 "options.flatten_multidimensional_arrays to true.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020013352 }
13353
13354 string res;
13355 for (auto i = uint32_t(type.array.size()); i; i--)
13356 {
13357 res += "[";
13358 res += to_array_size(type, i - 1);
13359 res += "]";
13360 }
13361 return res;
13362 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013363}
13364
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013365string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013366{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013367 auto &imagetype = get<SPIRType>(type.image.type);
13368 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013369
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013370 switch (imagetype.basetype)
13371 {
13372 case SPIRType::Int:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013373 case SPIRType::Short:
13374 case SPIRType::SByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013375 res = "i";
13376 break;
13377 case SPIRType::UInt:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013378 case SPIRType::UShort:
13379 case SPIRType::UByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013380 res = "u";
13381 break;
13382 default:
13383 break;
13384 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013385
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013386 // For half image types, we will force mediump for the sampler, and cast to f16 after any sampling operation.
13387 // We cannot express a true half texture type in GLSL. Neither for short integer formats for that matter.
13388
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020013389 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020013390 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010013391 else if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
13392 subpass_input_is_framebuffer_fetch(id))
13393 {
13394 SPIRType sampled_type = get<SPIRType>(type.image.type);
13395 sampled_type.vecsize = 4;
13396 return type_to_glsl(sampled_type);
13397 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020013398
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013399 // If we're emulating subpassInput with samplers, force sampler2D
13400 // so we don't have to specify format.
13401 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +020013402 {
13403 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
13404 if (type.image.dim == DimBuffer && type.image.sampled == 1)
13405 res += "sampler";
13406 else
13407 res += type.image.sampled == 2 ? "image" : "texture";
13408 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013409 else
13410 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013411
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013412 switch (type.image.dim)
13413 {
13414 case Dim1D:
13415 res += "1D";
13416 break;
13417 case Dim2D:
13418 res += "2D";
13419 break;
13420 case Dim3D:
13421 res += "3D";
13422 break;
13423 case DimCube:
13424 res += "Cube";
13425 break;
Sidney Justfbb4df32019-01-06 12:21:59 -080013426 case DimRect:
13427 if (options.es)
13428 SPIRV_CROSS_THROW("Rectangle textures are not supported on OpenGL ES.");
13429
13430 if (is_legacy_desktop())
13431 require_extension_internal("GL_ARB_texture_rectangle");
13432
13433 res += "2DRect";
13434 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013436 case DimBuffer:
13437 if (options.es && options.version < 320)
miomioreimu4407c0d2022-01-10 16:49:45 +080013438 require_extension_internal("GL_EXT_texture_buffer");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013439 else if (!options.es && options.version < 300)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013440 require_extension_internal("GL_EXT_texture_buffer_object");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013441 res += "Buffer";
13442 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013443
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013444 case DimSubpassData:
13445 res += "2D";
13446 break;
13447 default:
Sidney Justfbb4df32019-01-06 12:21:59 -080013448 SPIRV_CROSS_THROW("Only 1D, 2D, 2DRect, 3D, Buffer, InputTarget and Cube textures supported.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013449 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013450
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020013451 if (type.image.ms)
13452 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013453 if (type.image.arrayed)
Rob Fischer21990632016-09-17 17:01:50 +090013454 {
Lubos Lenco52158642016-09-17 15:56:23 +020013455 if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013456 require_extension_internal("GL_EXT_texture_array");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013457 res += "Array";
Rob Fischer21990632016-09-17 17:01:50 +090013458 }
Hans-Kristian Arntzena3ae8612018-02-09 12:37:17 +010013459
13460 // "Shadow" state in GLSL only exists for samplers and combined image samplers.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013461 if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) &&
Bill Hollingsfd252b22021-11-08 15:59:45 -050013462 is_depth_image(type, id))
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013463 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013464 res += "Shadow";
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013465 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013466
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013467 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013468}
13469
13470string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
13471{
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020013472 if (backend.use_array_constructor && type.array.size() > 1)
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020013473 {
13474 if (options.flatten_multidimensional_arrays)
crissdb52e272020-10-08 12:14:52 +020013475 SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, "
13476 "e.g. float[][]().");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020013477 else if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013478 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020013479 else if (options.es && options.version < 310)
13480 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
13481 }
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020013482
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013483 auto e = type_to_glsl(type);
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020013484 if (backend.use_array_constructor)
13485 {
13486 for (uint32_t i = 0; i < type.array.size(); i++)
13487 e += "[]";
13488 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013489 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013490}
13491
Bill Hollingsb41e1482017-05-29 20:45:05 -040013492// The optional id parameter indicates the object whose type we are trying
13493// to find the description for. It is optional. Most type descriptions do not
13494// depend on a specific object's use of that type.
13495string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013496{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013497 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
13498 {
13499 // Need to create a magic type name which compacts the entire type information.
13500 string name = type_to_glsl(get_pointee_type(type));
13501 for (size_t i = 0; i < type.array.size(); i++)
13502 {
13503 if (type.array_size_literal[i])
13504 name += join(type.array[i], "_");
13505 else
13506 name += join("id", type.array[i], "_");
13507 }
13508 name += "Pointer";
13509 return name;
13510 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013512 switch (type.basetype)
13513 {
13514 case SPIRType::Struct:
13515 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013516 if (backend.explicit_struct_type)
13517 return join("struct ", to_name(type.self));
13518 else
13519 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013520
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013521 case SPIRType::Image:
13522 case SPIRType::SampledImage:
Bill Hollingsb41e1482017-05-29 20:45:05 -040013523 return image_type_glsl(type, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013524
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013525 case SPIRType::Sampler:
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +020013526 // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
13527 // this distinction into the type system.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020013528 return comparison_ids.count(id) ? "samplerShadow" : "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013529
Hans-Kristian Arntzen6b0e5582020-04-21 14:25:18 +020013530 case SPIRType::AccelerationStructure:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013531 return ray_tracing_is_khr ? "accelerationStructureEXT" : "accelerationStructureNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +010013532
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013533 case SPIRType::RayQuery:
13534 return "rayQueryEXT";
13535
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013536 case SPIRType::Void:
13537 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013538
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013539 default:
13540 break;
13541 }
13542
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020013543 if (type.basetype == SPIRType::UInt && is_legacy())
13544 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
13545
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013546 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
13547 {
13548 switch (type.basetype)
13549 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013550 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013551 return "bool";
Chip Davis117ccf42018-11-01 17:20:07 -050013552 case SPIRType::SByte:
13553 return backend.basic_int8_type;
13554 case SPIRType::UByte:
13555 return backend.basic_uint8_type;
13556 case SPIRType::Short:
13557 return backend.basic_int16_type;
13558 case SPIRType::UShort:
13559 return backend.basic_uint16_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013560 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050013561 return backend.basic_int_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013562 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050013563 return backend.basic_uint_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013564 case SPIRType::AtomicCounter:
13565 return "atomic_uint";
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013566 case SPIRType::Half:
13567 return "float16_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013568 case SPIRType::Float:
13569 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013570 case SPIRType::Double:
13571 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013572 case SPIRType::Int64:
13573 return "int64_t";
13574 case SPIRType::UInt64:
13575 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013576 default:
13577 return "???";
13578 }
13579 }
13580 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
13581 {
13582 switch (type.basetype)
13583 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013584 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013585 return join("bvec", type.vecsize);
Chip Davis117ccf42018-11-01 17:20:07 -050013586 case SPIRType::SByte:
13587 return join("i8vec", type.vecsize);
13588 case SPIRType::UByte:
13589 return join("u8vec", type.vecsize);
13590 case SPIRType::Short:
13591 return join("i16vec", type.vecsize);
13592 case SPIRType::UShort:
13593 return join("u16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013594 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050013595 return join("ivec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013596 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050013597 return join("uvec", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013598 case SPIRType::Half:
13599 return join("f16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013600 case SPIRType::Float:
13601 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013602 case SPIRType::Double:
13603 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013604 case SPIRType::Int64:
13605 return join("i64vec", type.vecsize);
13606 case SPIRType::UInt64:
13607 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013608 default:
13609 return "???";
13610 }
13611 }
13612 else if (type.vecsize == type.columns) // Simple Matrix builtin
13613 {
13614 switch (type.basetype)
13615 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013616 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013617 return join("bmat", type.vecsize);
13618 case SPIRType::Int:
13619 return join("imat", type.vecsize);
13620 case SPIRType::UInt:
13621 return join("umat", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013622 case SPIRType::Half:
13623 return join("f16mat", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013624 case SPIRType::Float:
13625 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013626 case SPIRType::Double:
13627 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013628 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013629 default:
13630 return "???";
13631 }
13632 }
13633 else
13634 {
13635 switch (type.basetype)
13636 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020013637 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013638 return join("bmat", type.columns, "x", type.vecsize);
13639 case SPIRType::Int:
13640 return join("imat", type.columns, "x", type.vecsize);
13641 case SPIRType::UInt:
13642 return join("umat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010013643 case SPIRType::Half:
13644 return join("f16mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013645 case SPIRType::Float:
13646 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020013647 case SPIRType::Double:
13648 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020013649 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013650 default:
13651 return "???";
13652 }
13653 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013654}
13655
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013656void CompilerGLSL::add_variable(unordered_set<string> &variables_primary,
13657 const unordered_set<string> &variables_secondary, string &name)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013658{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013659 if (name.empty())
13660 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013661
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020013662 ParsedIR::sanitize_underscores(name);
13663 if (ParsedIR::is_globally_reserved_identifier(name, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013664 {
13665 name.clear();
13666 return;
13667 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013668
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013669 update_name_cache(variables_primary, variables_secondary, name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +010013670}
13671
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013672void CompilerGLSL::add_local_variable_name(uint32_t id)
13673{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013674 add_variable(local_variable_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013675}
13676
13677void CompilerGLSL::add_resource_name(uint32_t id)
13678{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010013679 add_variable(resource_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013680}
13681
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +020013682void CompilerGLSL::add_header_line(const std::string &line)
13683{
13684 header_lines.push_back(line);
13685}
13686
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010013687bool CompilerGLSL::has_extension(const std::string &ext) const
13688{
13689 auto itr = find(begin(forced_extensions), end(forced_extensions), ext);
13690 return itr != end(forced_extensions);
13691}
13692
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013693void CompilerGLSL::require_extension(const std::string &ext)
13694{
13695 if (!has_extension(ext))
13696 forced_extensions.push_back(ext);
13697}
13698
13699void CompilerGLSL::require_extension_internal(const string &ext)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013700{
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010013701 if (backend.supports_extensions && !has_extension(ext))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013702 {
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010013703 forced_extensions.push_back(ext);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013704 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013705 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013706}
13707
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013708void CompilerGLSL::flatten_buffer_block(VariableID id)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013709{
13710 auto &var = get<SPIRVariable>(id);
13711 auto &type = get<SPIRType>(var.basetype);
13712 auto name = to_name(type.self, false);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010013713 auto &flags = ir.meta[type.self].decoration.decoration_flags;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013714
13715 if (!type.array.empty())
13716 SPIRV_CROSS_THROW(name + " is an array of UBOs.");
13717 if (type.basetype != SPIRType::Struct)
13718 SPIRV_CROSS_THROW(name + " is not a struct.");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013719 if (!flags.get(DecorationBlock))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013720 SPIRV_CROSS_THROW(name + " is not a block.");
13721 if (type.member_types.empty())
13722 SPIRV_CROSS_THROW(name + " is an empty struct.");
13723
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080013724 flattened_buffer_blocks.insert(id);
13725}
13726
Lukas Hermanns6673a672019-10-22 11:06:16 -040013727bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) const
13728{
13729 return false; // GLSL itself does not need to translate array builtin types to non-array builtin types
13730}
13731
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013732bool CompilerGLSL::check_atomic_image(uint32_t id)
13733{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013734 auto &type = expression_type(id);
13735 if (type.storage == StorageClassImage)
13736 {
13737 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013738 require_extension_internal("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013740 auto *var = maybe_get_backing_variable(id);
13741 if (var)
13742 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010013743 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013744 if (flags.get(DecorationNonWritable) || flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013745 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013746 flags.clear(DecorationNonWritable);
13747 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013748 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013749 }
13750 }
13751 return true;
13752 }
13753 else
13754 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013755}
13756
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013757void CompilerGLSL::add_function_overload(const SPIRFunction &func)
13758{
13759 Hasher hasher;
13760 for (auto &arg : func.arguments)
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010013761 {
13762 // Parameters can vary with pointer type or not,
13763 // but that will not change the signature in GLSL/HLSL,
13764 // so strip the pointer type before hashing.
Chip Davisfc02b3d2019-01-08 12:54:40 -060013765 uint32_t type_id = get_pointee_type_id(arg.type);
Bill Hollingse0910312018-06-24 15:06:12 -040013766 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020013767
13768 if (!combined_image_samplers.empty())
13769 {
13770 // If we have combined image samplers, we cannot really trust the image and sampler arguments
13771 // we pass down to callees, because they may be shuffled around.
13772 // Ignore these arguments, to make sure that functions need to differ in some other way
13773 // to be considered different overloads.
Bill Hollingse0910312018-06-24 15:06:12 -040013774 if (type.basetype == SPIRType::SampledImage ||
13775 (type.basetype == SPIRType::Image && type.image.sampled == 1) || type.basetype == SPIRType::Sampler)
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020013776 {
13777 continue;
13778 }
13779 }
13780
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010013781 hasher.u32(type_id);
13782 }
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013783 uint64_t types_hash = hasher.get();
13784
13785 auto function_name = to_name(func.self);
13786 auto itr = function_overloads.find(function_name);
13787 if (itr != end(function_overloads))
13788 {
13789 // There exists a function with this name already.
13790 auto &overloads = itr->second;
13791 if (overloads.count(types_hash) != 0)
13792 {
13793 // Overload conflict, assign a new name.
13794 add_resource_name(func.self);
13795 function_overloads[to_name(func.self)].insert(types_hash);
13796 }
13797 else
13798 {
13799 // Can reuse the name.
13800 overloads.insert(types_hash);
13801 }
13802 }
13803 else
13804 {
13805 // First time we see this function name.
13806 add_resource_name(func.self);
13807 function_overloads[to_name(func.self)].insert(types_hash);
13808 }
13809}
13810
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013811void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013812{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013813 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013814 add_function_overload(func);
13815
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013816 // Avoid shadow declarations.
13817 local_variable_names = resource_names;
13818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013819 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013820
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013821 auto &type = get<SPIRType>(func.return_type);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013822 decl += flags_to_qualifiers_glsl(type, return_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013823 decl += type_to_glsl(type);
Hans-Kristian Arntzen9fa91f72018-02-05 09:34:54 +010013824 decl += type_to_array_glsl(type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013825 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013826
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013827 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013828 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020013829 // If we need complex fallback in GLSL, we just wrap main() in a function
13830 // and interlock the entire shader ...
13831 if (interlocked_is_complex)
13832 decl += "spvMainInterlockedBody";
13833 else
13834 decl += "main";
13835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013836 processing_entry_point = true;
13837 }
13838 else
Bill Hollings1c180782017-11-05 21:34:42 -050013839 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013840
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013841 decl += "(";
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020013842 SmallVector<string> arglist;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013843 for (auto &arg : func.arguments)
13844 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013845 // Do not pass in separate images or samplers if we're remapping
13846 // to combined image samplers.
13847 if (skip_argument(arg.id))
13848 continue;
13849
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013850 // Might change the variable name if it already exists in this function.
13851 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
13852 // to use same name for variables.
13853 // 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 +020013854 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013855
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013856 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013858 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
13859 auto *var = maybe_get<SPIRVariable>(arg.id);
13860 if (var)
13861 var->parameter = &arg;
13862 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013863
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +020013864 for (auto &arg : func.shadow_arguments)
13865 {
13866 // Might change the variable name if it already exists in this function.
13867 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
13868 // to use same name for variables.
13869 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
13870 add_local_variable_name(arg.id);
13871
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013872 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013873
13874 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
13875 auto *var = maybe_get<SPIRVariable>(arg.id);
13876 if (var)
13877 var->parameter = &arg;
13878 }
13879
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013880 decl += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013881 decl += ")";
13882 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013883}
13884
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013885void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013886{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013887 // Avoid potential cycles.
13888 if (func.active)
13889 return;
13890 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013891
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013892 // If we depend on a function, emit that function before we emit our own function.
13893 for (auto block : func.blocks)
13894 {
13895 auto &b = get<SPIRBlock>(block);
13896 for (auto &i : b.ops)
13897 {
13898 auto ops = stream(i);
13899 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013900
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013901 if (op == OpFunctionCall)
13902 {
13903 // Recursively emit functions which are called.
13904 uint32_t id = ops[2];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013905 emit_function(get<SPIRFunction>(id), ir.meta[ops[1]].decoration.decoration_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013906 }
13907 }
13908 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013909
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020013910 if (func.entry_line.file_id != 0)
13911 emit_line_directive(func.entry_line.file_id, func.entry_line.line_literal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013912 emit_function_prototype(func, return_flags);
13913 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013914
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013915 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +020013916 emit_entry_point_declarations();
13917
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013918 current_function = &func;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013919 auto &entry_block = get<SPIRBlock>(func.entry_block);
13920
Hans-Kristian Arntzen30343f32020-02-24 13:22:52 +010013921 sort(begin(func.constant_arrays_needed_on_stack), end(func.constant_arrays_needed_on_stack));
13922 for (auto &array : func.constant_arrays_needed_on_stack)
13923 {
13924 auto &c = get<SPIRConstant>(array);
13925 auto &type = get<SPIRType>(c.constant_type);
13926 statement(variable_decl(type, join("_", array, "_array_copy")), " = ", constant_expression(c), ";");
13927 }
13928
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013929 for (auto &v : func.local_variables)
13930 {
13931 auto &var = get<SPIRVariable>(v);
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020013932 var.deferred_declaration = false;
13933
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020013934 if (variable_decl_is_remapped_storage(var, StorageClassWorkgroup))
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020013935 {
13936 // Special variable type which cannot have initializer,
13937 // need to be declared as standalone variables.
13938 // Comes from MSL which can push global variables as local variables in main function.
13939 add_local_variable_name(var.self);
13940 statement(variable_decl(var), ";");
13941 var.deferred_declaration = false;
13942 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020013943 else if (var.storage == StorageClassPrivate)
13944 {
13945 // These variables will not have had their CFG usage analyzed, so move it to the entry block.
13946 // Comes from MSL which can push global variables as local variables in main function.
13947 // We could just declare them right now, but we would miss out on an important initialization case which is
13948 // LUT declaration in MSL.
13949 // If we don't declare the variable when it is assigned we're forced to go through a helper function
13950 // which copies elements one by one.
13951 add_local_variable_name(var.self);
Hans-Kristian Arntzenf8592ec2020-04-21 11:20:49 +020013952
13953 if (var.initializer)
13954 {
13955 statement(variable_decl(var), ";");
13956 var.deferred_declaration = false;
13957 }
13958 else
13959 {
13960 auto &dominated = entry_block.dominated_variables;
13961 if (find(begin(dominated), end(dominated), var.self) == end(dominated))
13962 entry_block.dominated_variables.push_back(var.self);
13963 var.deferred_declaration = true;
13964 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020013965 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020013966 else if (var.storage == StorageClassFunction && var.remapped_variable && var.static_expression)
13967 {
13968 // No need to declare this variable, it has a static expression.
13969 var.deferred_declaration = false;
13970 }
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020013971 else if (expression_is_lvalue(v))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013972 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013973 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013974
Hans-Kristian Arntzenf1415212020-06-19 10:51:00 +020013975 // Loop variables should never be declared early, they are explicitly emitted in a loop.
13976 if (var.initializer && !var.loop_variable)
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +010013977 statement(variable_decl_function_local(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013978 else
13979 {
13980 // Don't declare variable until first use to declutter the GLSL output quite a lot.
13981 // If we don't touch the variable before first branch,
13982 // declare it then since we need variable declaration to be in top scope.
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020013983 var.deferred_declaration = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013984 }
13985 }
13986 else
13987 {
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020013988 // 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 +010013989 // For these types (non-lvalue), we enforce forwarding through a shadowed variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013990 // This means that when we OpStore to these variables, we just write in the expression ID directly.
13991 // This breaks any kind of branching, since the variable must be statically assigned.
13992 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
13993 var.statically_assigned = true;
13994 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013995
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013996 var.loop_variable_enable = false;
Hans-Kristian Arntzenb847c882016-11-18 17:06:49 +010013997
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013998 // Loop variables are never declared outside their for-loop, so block any implicit declaration.
13999 if (var.loop_variable)
14000 var.deferred_declaration = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014001 }
14002
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020014003 // Enforce declaration order for regression testing purposes.
14004 for (auto &block_id : func.blocks)
14005 {
14006 auto &block = get<SPIRBlock>(block_id);
14007 sort(begin(block.dominated_variables), end(block.dominated_variables));
14008 }
14009
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020014010 for (auto &line : current_function->fixup_hooks_in)
14011 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040014012
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014013 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014014
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014015 end_scope();
14016 processing_entry_point = false;
14017 statement("");
Hans-Kristian Arntzend81bfc52019-06-13 10:31:37 +020014018
14019 // Make sure deferred declaration state for local variables is cleared when we are done with function.
14020 // We risk declaring Private/Workgroup variables in places we are not supposed to otherwise.
14021 for (auto &v : func.local_variables)
14022 {
14023 auto &var = get<SPIRVariable>(v);
14024 var.deferred_declaration = false;
14025 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014026}
14027
14028void CompilerGLSL::emit_fixup()
14029{
Hans-Kristian Arntzen5ea576e2020-09-28 14:09:39 +020014030 if (is_vertex_like_shader())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014031 {
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020014032 if (options.vertex.fixup_clipspace)
14033 {
14034 const char *suffix = backend.float_literal_suffix ? "f" : "";
14035 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
14036 }
14037
14038 if (options.vertex.flip_vert_y)
14039 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014040 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014041}
14042
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014043void CompilerGLSL::flush_phi(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014044{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014045 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014046 if (child.ignore_phi_from_block == from)
14047 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014048
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014049 unordered_set<uint32_t> temporary_phi_variables;
14050
14051 for (auto itr = begin(child.phi_variables); itr != end(child.phi_variables); ++itr)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014052 {
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014053 auto &phi = *itr;
14054
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014055 if (phi.parent == from)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014056 {
14057 auto &var = get<SPIRVariable>(phi.function_variable);
14058
14059 // A Phi variable might be a loop variable, so flush to static expression.
14060 if (var.loop_variable && !var.loop_variable_enable)
14061 var.static_expression = phi.local_variable;
14062 else
14063 {
14064 flush_variable_declaration(phi.function_variable);
14065
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014066 // Check if we are going to write to a Phi variable that another statement will read from
14067 // as part of another Phi node in our target block.
14068 // For this case, we will need to copy phi.function_variable to a temporary, and use that for future reads.
14069 // This is judged to be extremely rare, so deal with it here using a simple, but suboptimal algorithm.
14070 bool need_saved_temporary =
14071 find_if(itr + 1, end(child.phi_variables), [&](const SPIRBlock::Phi &future_phi) -> bool {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014072 return future_phi.local_variable == ID(phi.function_variable) && future_phi.parent == from;
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014073 }) != end(child.phi_variables);
14074
14075 if (need_saved_temporary)
14076 {
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014077 // Need to make sure we declare the phi variable with a copy at the right scope.
14078 // We cannot safely declare a temporary here since we might be inside a continue block.
14079 if (!var.allocate_temporary_copy)
14080 {
14081 var.allocate_temporary_copy = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014082 force_recompile();
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014083 }
14084 statement("_", phi.function_variable, "_copy", " = ", to_name(phi.function_variable), ";");
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014085 temporary_phi_variables.insert(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014086 }
14087
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014088 // This might be called in continue block, so make sure we
Hans-Kristian Arntzen91753632017-09-25 10:16:45 +020014089 // use this to emit ESSL 1.0 compliant increments/decrements.
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014090 auto lhs = to_expression(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014091
14092 string rhs;
14093 if (temporary_phi_variables.count(phi.local_variable))
14094 rhs = join("_", phi.local_variable, "_copy");
14095 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060014096 rhs = to_pointer_expression(phi.local_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014097
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020014098 if (!optimize_read_modify_write(get<SPIRType>(var.basetype), lhs, rhs))
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014099 statement(lhs, " = ", rhs, ";");
14100 }
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010014101
14102 register_write(phi.function_variable);
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014103 }
14104 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014105}
14106
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014107void CompilerGLSL::branch_to_continue(BlockID from, BlockID to)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014108{
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014109 auto &to_block = get<SPIRBlock>(to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010014110 if (from == to)
14111 return;
14112
14113 assert(is_continue(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014114 if (to_block.complex_continue)
14115 {
14116 // Just emit the whole block chain as is.
14117 auto usage_counts = expression_usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014118
14119 emit_block_chain(to_block);
14120
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020014121 // Expression usage counts are moot after returning from the continue block.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014122 expression_usage_counts = usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014123 }
14124 else
14125 {
14126 auto &from_block = get<SPIRBlock>(from);
14127 bool outside_control_flow = false;
14128 uint32_t loop_dominator = 0;
14129
14130 // FIXME: Refactor this to not use the old loop_dominator tracking.
14131 if (from_block.merge_block)
14132 {
14133 // If we are a loop header, we don't set the loop dominator,
14134 // so just use "self" here.
14135 loop_dominator = from;
14136 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014137 else if (from_block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014138 {
14139 loop_dominator = from_block.loop_dominator;
14140 }
14141
14142 if (loop_dominator != 0)
14143 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014144 auto &cfg = get_cfg_for_current_function();
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014145
14146 // For non-complex continue blocks, we implicitly branch to the continue block
14147 // by having the continue block be part of the loop header in for (; ; continue-block).
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014148 outside_control_flow = cfg.node_terminates_control_flow_in_sub_graph(loop_dominator, from);
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014149 }
14150
14151 // Some simplification for for-loops. We always end up with a useless continue;
14152 // statement since we branch to a loop block.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014153 // 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 +010014154 // we can avoid writing out an explicit continue statement.
14155 // Similar optimization to return statements if we know we're outside flow control.
14156 if (!outside_control_flow)
14157 statement("continue;");
14158 }
14159}
14160
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014161void CompilerGLSL::branch(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014162{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014163 flush_phi(from, to);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010014164 flush_control_dependent_expressions(from);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014165
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014166 bool to_is_continue = is_continue(to);
14167
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014168 // This is only a continue if we branch to our loop dominator.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014169 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 +020014170 {
14171 // This can happen if we had a complex continue block which was emitted.
14172 // Once the continue block tries to branch to the loop header, just emit continue;
14173 // and end the chain here.
14174 statement("continue;");
14175 }
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010014176 else if (from != to && is_break(to))
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014177 {
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010014178 // We cannot break to ourselves, so check explicitly for from != to.
14179 // This case can trigger if a loop header is all three of these things:
14180 // - Continue block
14181 // - Loop header
14182 // - Break merge target all at once ...
14183
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014184 // Very dirty workaround.
14185 // Switch constructs are able to break, but they cannot break out of a loop at the same time.
14186 // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block,
14187 // write to the ladder here, and defer the break.
14188 // 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 +020014189 if (current_emitting_switch && is_loop_break(to) &&
14190 current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) &&
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014191 get<SPIRBlock>(current_emitting_switch->loop_dominator).merge_block == to)
14192 {
14193 if (!current_emitting_switch->need_ladder_break)
14194 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014195 force_recompile();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014196 current_emitting_switch->need_ladder_break = true;
14197 }
14198
14199 statement("_", current_emitting_switch->self, "_ladder_break = true;");
14200 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014201 statement("break;");
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014202 }
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014203 else if (to_is_continue || from == to)
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010014204 {
14205 // For from == to case can happen for a do-while loop which branches into itself.
14206 // We don't mark these cases as continue blocks, but the only possible way to branch into
14207 // ourselves is through means of continue blocks.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014208
14209 // If we are merging to a continue block, there is no need to emit the block chain for continue here.
14210 // We can branch to the continue block after we merge execution.
14211
14212 // Here we make use of structured control flow rules from spec:
14213 // 2.11: - the merge block declared by a header block cannot be a merge block declared by any other header block
14214 // - each header block must strictly dominate its merge block, unless the merge block is unreachable in the CFG
14215 // If we are branching to a merge block, we must be inside a construct which dominates the merge block.
14216 auto &block_meta = ir.block_meta[to];
14217 bool branching_to_merge =
14218 (block_meta & (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT |
14219 ParsedIR::BLOCK_META_LOOP_MERGE_BIT)) != 0;
14220 if (!to_is_continue || !branching_to_merge)
14221 branch_to_continue(from, to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010014222 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014223 else if (!is_conditional(to))
14224 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014225
14226 // It is important that we check for break before continue.
14227 // A block might serve two purposes, a break block for the inner scope, and
14228 // a continue block in the outer scope.
14229 // Inner scope always takes precedence.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014230}
14231
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014232void CompilerGLSL::branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014233{
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020014234 auto &from_block = get<SPIRBlock>(from);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014235 BlockID merge_block = from_block.merge == SPIRBlock::MergeSelection ? from_block.next_block : BlockID(0);
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020014236
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014237 // If we branch directly to our selection merge target, we don't need a code path.
14238 bool true_block_needs_code = true_block != merge_block || flush_phi_required(from, true_block);
14239 bool false_block_needs_code = false_block != merge_block || flush_phi_required(from, false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014240
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014241 if (!true_block_needs_code && !false_block_needs_code)
14242 return;
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020014243
Hans-Kristian Arntzen449f68e2021-06-03 12:19:10 +020014244 // We might have a loop merge here. Only consider selection flattening constructs.
14245 // Loop hints are handled explicitly elsewhere.
14246 if (from_block.hint == SPIRBlock::HintFlatten || from_block.hint == SPIRBlock::HintDontFlatten)
14247 emit_block_hints(from_block);
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014248
14249 if (true_block_needs_code)
Hans-Kristian Arntzen54cc0b02020-09-17 12:02:43 +020014250 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014251 statement("if (", to_expression(cond), ")");
14252 begin_scope();
14253 branch(from, true_block);
14254 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014255
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014256 if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014257 {
14258 statement("else");
14259 begin_scope();
14260 branch(from, false_block);
14261 end_scope();
14262 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014263 }
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020014264 else if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014265 {
14266 // Only need false path, use negative conditional.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014267 statement("if (!", to_enclosed_expression(cond), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014268 begin_scope();
14269 branch(from, false_block);
14270 end_scope();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014271 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014272}
14273
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014274// FIXME: This currently cannot handle complex continue blocks
14275// as in do-while.
14276// This should be seen as a "trivial" continue block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014277string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014278{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014279 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014280
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014281 // While emitting the continue block, declare_temporary will check this
14282 // if we have to emit temporaries.
14283 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014284
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020014285 SmallVector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014286
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014287 // Capture all statements into our list.
14288 auto *old = redirect_statement;
14289 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014290
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014291 // Stamp out all blocks one after each other.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014292 while ((ir.block_meta[block->self] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) == 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014293 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014294 // Write out all instructions we have in this block.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014295 emit_block_instructions(*block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014297 // For plain branchless for/while continue blocks.
14298 if (block->next_block)
14299 {
14300 flush_phi(continue_block, block->next_block);
14301 block = &get<SPIRBlock>(block->next_block);
14302 }
14303 // For do while blocks. The last block will be a select block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014304 else if (block->true_block && follow_true_block)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014305 {
14306 flush_phi(continue_block, block->true_block);
14307 block = &get<SPIRBlock>(block->true_block);
14308 }
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014309 else if (block->false_block && follow_false_block)
14310 {
14311 flush_phi(continue_block, block->false_block);
14312 block = &get<SPIRBlock>(block->false_block);
14313 }
14314 else
14315 {
14316 SPIRV_CROSS_THROW("Invalid continue block detected!");
14317 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014318 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014320 // Restore old pointer.
14321 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014323 // Somewhat ugly, strip off the last ';' since we use ',' instead.
14324 // Ideally, we should select this behavior in statement().
14325 for (auto &s : statements)
14326 {
14327 if (!s.empty() && s.back() == ';')
Corentin Wallezef9ee492016-10-05 13:01:31 -040014328 s.erase(s.size() - 1, 1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014329 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014330
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014331 current_continue_block = nullptr;
14332 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014333}
14334
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014335void CompilerGLSL::emit_while_loop_initializers(const SPIRBlock &block)
14336{
14337 // While loops do not take initializers, so declare all of them outside.
14338 for (auto &loop_var : block.loop_variables)
14339 {
14340 auto &var = get<SPIRVariable>(loop_var);
14341 statement(variable_decl(var), ";");
14342 }
14343}
14344
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014345string CompilerGLSL::emit_for_loop_initializers(const SPIRBlock &block)
14346{
14347 if (block.loop_variables.empty())
14348 return "";
14349
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014350 bool same_types = for_loop_initializers_are_same_type(block);
14351 // We can only declare for loop initializers if all variables are of same type.
14352 // If we cannot do this, declare individual variables before the loop header.
14353
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010014354 // We might have a loop variable candidate which was not assigned to for some reason.
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014355 uint32_t missing_initializers = 0;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010014356 for (auto &variable : block.loop_variables)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014357 {
14358 uint32_t expr = get<SPIRVariable>(variable).static_expression;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010014359
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014360 // Sometimes loop variables are initialized with OpUndef, but we can just declare
14361 // a plain variable without initializer in this case.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014362 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014363 missing_initializers++;
14364 }
14365
14366 if (block.loop_variables.size() == 1 && missing_initializers == 0)
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014367 {
14368 return variable_decl(get<SPIRVariable>(block.loop_variables.front()));
14369 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014370 else if (!same_types || missing_initializers == uint32_t(block.loop_variables.size()))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014371 {
14372 for (auto &loop_var : block.loop_variables)
14373 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
14374 return "";
14375 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014376 else
14377 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014378 // We have a mix of loop variables, either ones with a clear initializer, or ones without.
14379 // Separate the two streams.
14380 string expr;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014381
14382 for (auto &loop_var : block.loop_variables)
14383 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014384 uint32_t static_expr = get<SPIRVariable>(loop_var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014385 if (static_expr == 0 || ir.ids[static_expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014386 {
14387 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
14388 }
14389 else
14390 {
Chip Davis3bfb2f92018-12-03 02:06:33 -060014391 auto &var = get<SPIRVariable>(loop_var);
14392 auto &type = get_variable_data_type(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014393 if (expr.empty())
14394 {
14395 // For loop initializers are of the form <type id = value, id = value, id = value, etc ...
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014396 expr = join(to_qualifiers_glsl(var.self), type_to_glsl(type), " ");
14397 }
14398 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060014399 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014400 expr += ", ";
Chip Davis3bfb2f92018-12-03 02:06:33 -060014401 // In MSL, being based on C++, the asterisk marking a pointer
14402 // binds to the identifier, not the type.
14403 if (type.pointer)
14404 expr += "* ";
14405 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014406
Chip Davis3bfb2f92018-12-03 02:06:33 -060014407 expr += join(to_name(loop_var), " = ", to_pointer_expression(var.static_expression));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014408 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014409 }
14410 return expr;
14411 }
14412}
14413
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014414bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
14415{
14416 if (block.loop_variables.size() <= 1)
14417 return true;
14418
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014419 uint32_t expected = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014420 Bitset expected_flags;
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014421 for (auto &var : block.loop_variables)
14422 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014423 // Don't care about uninitialized variables as they will not be part of the initializers.
14424 uint32_t expr = get<SPIRVariable>(var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014425 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014426 continue;
14427
14428 if (expected == 0)
14429 {
14430 expected = get<SPIRVariable>(var).basetype;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014431 expected_flags = get_decoration_bitset(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014432 }
14433 else if (expected != get<SPIRVariable>(var).basetype)
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014434 return false;
14435
14436 // Precision flags and things like that must also match.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014437 if (expected_flags != get_decoration_bitset(var))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010014438 return false;
14439 }
14440
14441 return true;
14442}
14443
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014444bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
14445{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014446 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014447
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014448 if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014449 {
14450 uint32_t current_count = statement_count;
14451 // If we're trying to create a true for loop,
14452 // we need to make sure that all opcodes before branch statement do not actually emit any code.
14453 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014454 emit_block_instructions(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014455
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014456 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014457
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014458 // This can work! We only did trivial things which could be forwarded in block body!
14459 if (current_count == statement_count && condition_is_temporary)
14460 {
14461 switch (continue_type)
14462 {
14463 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014464 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010014465 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
14466 flush_undeclared_variables(block);
14467
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014468 // Important that we do this in this order because
14469 // emitting the continue block can invalidate the condition expression.
14470 auto initializer = emit_for_loop_initializers(block);
14471 auto condition = to_expression(block.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014472
14473 // Condition might have to be inverted.
14474 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14475 condition = join("!", enclose_expression(condition));
14476
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014477 emit_block_hints(block);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014478 if (method != SPIRBlock::MergeToSelectContinueForLoop)
14479 {
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014480 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014481 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
14482 }
14483 else
14484 statement("for (", initializer, "; ", condition, "; )");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014485 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014486 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014487
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014488 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014489 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010014490 // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
14491 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014492 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014493 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014494
14495 auto condition = to_expression(block.condition);
14496 // Condition might have to be inverted.
14497 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14498 condition = join("!", enclose_expression(condition));
14499
14500 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014501 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014502 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014503
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014504 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020014505 block.disable_block_optimization = true;
14506 force_recompile();
14507 begin_scope(); // We'll see an end_scope() later.
14508 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014509 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014510
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014511 begin_scope();
14512 return true;
14513 }
14514 else
14515 {
14516 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014517 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014518 begin_scope(); // We'll see an end_scope() later.
14519 return false;
14520 }
14521 }
14522 else if (method == SPIRBlock::MergeToDirectForLoop)
14523 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014524 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014525
Hans-Kristian Arntzen5ff11cc2016-11-18 16:45:11 +010014526 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
14527 flush_undeclared_variables(child);
14528
14529 uint32_t current_count = statement_count;
14530
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014531 // If we're trying to create a true for loop,
14532 // we need to make sure that all opcodes before branch statement do not actually emit any code.
14533 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014534 emit_block_instructions(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014535
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014536 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014538 if (current_count == statement_count && condition_is_temporary)
14539 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014540 uint32_t target_block = child.true_block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014542 switch (continue_type)
14543 {
14544 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014545 {
14546 // Important that we do this in this order because
14547 // emitting the continue block can invalidate the condition expression.
14548 auto initializer = emit_for_loop_initializers(block);
14549 auto condition = to_expression(child.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014550
14551 // Condition might have to be inverted.
14552 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
14553 {
14554 condition = join("!", enclose_expression(condition));
14555 target_block = child.false_block;
14556 }
14557
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014558 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014559 emit_block_hints(block);
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014560 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014561 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010014562 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014563
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014564 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014565 {
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014566 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014567 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014568
14569 auto condition = to_expression(child.condition);
14570 // Condition might have to be inverted.
14571 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
14572 {
14573 condition = join("!", enclose_expression(condition));
14574 target_block = child.false_block;
14575 }
14576
14577 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014578 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014579 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014580
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014581 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020014582 block.disable_block_optimization = true;
14583 force_recompile();
14584 begin_scope(); // We'll see an end_scope() later.
14585 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014586 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014587
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014588 begin_scope();
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014589 branch(child.self, target_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014590 return true;
14591 }
14592 else
14593 {
14594 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014595 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014596 begin_scope(); // We'll see an end_scope() later.
14597 return false;
14598 }
14599 }
14600 else
14601 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014602}
14603
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014604void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014605{
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014606 for (auto &v : block.dominated_variables)
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014607 flush_variable_declaration(v);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014608}
14609
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014610void CompilerGLSL::emit_hoisted_temporaries(SmallVector<pair<TypeID, ID>> &temporaries)
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014611{
14612 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
14613 // Need to sort these to ensure that reference output is stable.
14614 sort(begin(temporaries), end(temporaries),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014615 [](const pair<TypeID, ID> &a, const pair<TypeID, ID> &b) { return a.second < b.second; });
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014616
14617 for (auto &tmp : temporaries)
14618 {
14619 add_local_variable_name(tmp.second);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014620 auto &flags = ir.meta[tmp.second].decoration.decoration_flags;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014621 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010014622
14623 // Not all targets support pointer literals, so don't bother with that case.
14624 string initializer;
14625 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
14626 initializer = join(" = ", to_zero_initialized_expression(tmp.first));
14627
14628 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), initializer, ";");
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014629
14630 hoisted_temporaries.insert(tmp.second);
14631 forced_temporaries.insert(tmp.second);
14632
14633 // The temporary might be read from before it's assigned, set up the expression now.
14634 set<SPIRExpression>(tmp.second, to_name(tmp.second), tmp.first, true);
14635 }
14636}
14637
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014638void CompilerGLSL::emit_block_chain(SPIRBlock &block)
14639{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014640 bool select_branch_to_true_block = false;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014641 bool select_branch_to_false_block = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014642 bool skip_direct_branch = false;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014643 bool emitted_loop_header_variables = false;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014644 bool force_complex_continue_block = false;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020014645 ValueSaver<uint32_t> loop_level_saver(current_loop_level);
14646
14647 if (block.merge == SPIRBlock::MergeLoop)
14648 add_loop_level();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014649
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014650 emit_hoisted_temporaries(block.declare_temporary);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014651
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014652 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
14653 if (block.continue_block)
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010014654 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014655 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010014656 // If we know we cannot emit a loop, mark the block early as a complex loop so we don't force unnecessary recompiles.
14657 if (continue_type == SPIRBlock::ComplexLoop)
14658 block.complex_continue = true;
14659 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014660
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010014661 // If we have loop variables, stop masking out access to the variable now.
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020014662 for (auto var_id : block.loop_variables)
14663 {
14664 auto &var = get<SPIRVariable>(var_id);
14665 var.loop_variable_enable = true;
14666 // We're not going to declare the variable directly, so emit a copy here.
14667 emit_variable_temporary_copies(var);
14668 }
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010014669
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020014670 // Remember deferred declaration state. We will restore it before returning.
14671 SmallVector<bool, 64> rearm_dominated_variables(block.dominated_variables.size());
14672 for (size_t i = 0; i < block.dominated_variables.size(); i++)
14673 {
14674 uint32_t var_id = block.dominated_variables[i];
14675 auto &var = get<SPIRVariable>(var_id);
14676 rearm_dominated_variables[i] = var.deferred_declaration;
14677 }
14678
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014679 // This is the method often used by spirv-opt to implement loops.
14680 // The loop header goes straight into the continue block.
14681 // However, don't attempt this on ESSL 1.0, because if a loop variable is used in a continue block,
14682 // it *MUST* be used in the continue block. This loop method will not work.
14683 if (!is_legacy_es() && block_is_loop_candidate(block, SPIRBlock::MergeToSelectContinueForLoop))
14684 {
14685 flush_undeclared_variables(block);
14686 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
14687 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014688 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14689 select_branch_to_false_block = true;
14690 else
14691 select_branch_to_true_block = true;
14692
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014693 emitted_loop_header_variables = true;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014694 force_complex_continue_block = true;
14695 }
14696 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014697 // 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 +010014698 else if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014699 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014700 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014701 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
14702 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014703 // The body of while, is actually just the true (or false) block, so always branch there unconditionally.
14704 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
14705 select_branch_to_false_block = true;
14706 else
14707 select_branch_to_true_block = true;
14708
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014709 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014710 }
14711 }
14712 // This is the newer loop behavior in glslang which branches from Loop header directly to
14713 // a new block, which in turn has a OpBranchSelection without a selection merge.
14714 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
14715 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014716 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014717 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014718 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014719 skip_direct_branch = true;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014720 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014721 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014722 }
14723 else if (continue_type == SPIRBlock::DoWhileLoop)
14724 {
Hans-Kristian Arntzenb3f6e3d2018-01-24 19:46:53 +010014725 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014726 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014727 emitted_loop_header_variables = true;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014728 // We have some temporaries where the loop header is the dominator.
14729 // We risk a case where we have code like:
14730 // for (;;) { create-temporary; break; } consume-temporary;
14731 // so force-declare temporaries here.
14732 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014733 statement("do");
14734 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014735
14736 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014737 }
14738 else if (block.merge == SPIRBlock::MergeLoop)
14739 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014740 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020014741 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014742 emitted_loop_header_variables = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014743
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014744 // We have a generic loop without any distinguishable pattern like for, while or do while.
14745 get<SPIRBlock>(block.continue_block).complex_continue = true;
14746 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014747
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010014748 // We have some temporaries where the loop header is the dominator.
14749 // We risk a case where we have code like:
14750 // for (;;) { create-temporary; break; } consume-temporary;
14751 // so force-declare temporaries here.
14752 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen449f68e2021-06-03 12:19:10 +020014753 emit_block_hints(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014754 statement("for (;;)");
14755 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014756
14757 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014758 }
14759 else
14760 {
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014761 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014762 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014763
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014764 // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
14765 // as writes to said loop variables might have been masked out, we need a recompile.
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014766 if (!emitted_loop_header_variables && !block.loop_variables.empty())
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014767 {
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +010014768 force_recompile_guarantee_forward_progress();
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014769 for (auto var : block.loop_variables)
14770 get<SPIRVariable>(var).loop_variable = false;
14771 block.loop_variables.clear();
14772 }
14773
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014774 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014775 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014776
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014777 // Handle end of block.
14778 switch (block.terminator)
14779 {
14780 case SPIRBlock::Direct:
14781 // True when emitting complex continue block.
14782 if (block.loop_dominator == block.next_block)
14783 {
14784 branch(block.self, block.next_block);
14785 emit_next_block = false;
14786 }
14787 // True if MergeToDirectForLoop succeeded.
14788 else if (skip_direct_branch)
14789 emit_next_block = false;
14790 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
14791 {
14792 branch(block.self, block.next_block);
14793 emit_next_block = false;
14794 }
14795 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014796
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014797 case SPIRBlock::Select:
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014798 // True if MergeToSelectForLoop or MergeToSelectContinueForLoop succeeded.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014799 if (select_branch_to_true_block)
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014800 {
14801 if (force_complex_continue_block)
14802 {
14803 assert(block.true_block == block.continue_block);
14804
14805 // We're going to emit a continue block directly here, so make sure it's marked as complex.
14806 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
14807 bool old_complex = complex_continue;
14808 complex_continue = true;
14809 branch(block.self, block.true_block);
14810 complex_continue = old_complex;
14811 }
14812 else
14813 branch(block.self, block.true_block);
14814 }
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014815 else if (select_branch_to_false_block)
14816 {
14817 if (force_complex_continue_block)
14818 {
14819 assert(block.false_block == block.continue_block);
14820
14821 // We're going to emit a continue block directly here, so make sure it's marked as complex.
14822 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
14823 bool old_complex = complex_continue;
14824 complex_continue = true;
14825 branch(block.self, block.false_block);
14826 complex_continue = old_complex;
14827 }
14828 else
14829 branch(block.self, block.false_block);
14830 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014831 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014832 branch(block.self, block.condition, block.true_block, block.false_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014833 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014835 case SPIRBlock::MultiSelect:
14836 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014837 auto &type = expression_type(block.condition);
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014838 bool unsigned_case = type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort ||
14839 type.basetype == SPIRType::UByte || type.basetype == SPIRType::UInt64;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014840
Hans-Kristian Arntzen45baf242019-03-20 10:42:38 +010014841 if (block.merge == SPIRBlock::MergeNone)
14842 SPIRV_CROSS_THROW("Switch statement is not structured");
14843
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014844 if (!backend.support_64bit_switch && (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64))
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010014845 {
14846 // SPIR-V spec suggests this is allowed, but we cannot support it in higher level languages.
14847 SPIRV_CROSS_THROW("Cannot use 64-bit switch selectors.");
14848 }
14849
14850 const char *label_suffix = "";
14851 if (type.basetype == SPIRType::UInt && backend.uint32_t_literal_suffix)
14852 label_suffix = "u";
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014853 else if (type.basetype == SPIRType::Int64 && backend.support_64bit_switch)
14854 label_suffix = "l";
14855 else if (type.basetype == SPIRType::UInt64 && backend.support_64bit_switch)
14856 label_suffix = "ul";
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010014857 else if (type.basetype == SPIRType::UShort)
14858 label_suffix = backend.uint16_t_literal_suffix;
14859 else if (type.basetype == SPIRType::Short)
14860 label_suffix = backend.int16_t_literal_suffix;
14861
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014862 SPIRBlock *old_emitting_switch = current_emitting_switch;
14863 current_emitting_switch = &block;
14864
14865 if (block.need_ladder_break)
14866 statement("bool _", block.self, "_ladder_break = false;");
14867
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014868 // Find all unique case constructs.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014869 unordered_map<uint32_t, SmallVector<uint64_t>> case_constructs;
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014870 SmallVector<uint32_t> block_declaration_order;
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014871 SmallVector<uint64_t> literals_to_merge;
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014872
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014873 // If a switch case branches to the default block for some reason, we can just remove that literal from consideration
14874 // and let the default: block handle it.
14875 // 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.
14876 // We only need to consider possible fallthrough if order[i] branches to order[i + 1].
Sebastián Aedo75e37522021-11-12 10:17:38 -030014877 auto &cases = get_case_list(block);
14878 for (auto &c : cases)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014879 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014880 if (c.block != block.next_block && c.block != block.default_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014881 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014882 if (!case_constructs.count(c.block))
14883 block_declaration_order.push_back(c.block);
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014884 case_constructs[c.block].push_back(c.value);
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014885 }
14886 else if (c.block == block.next_block && block.default_block != block.next_block)
14887 {
14888 // We might have to flush phi inside specific case labels.
14889 // If we can piggyback on default:, do so instead.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014890 literals_to_merge.push_back(c.value);
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014891 }
14892 }
14893
14894 // Empty literal array -> default.
14895 if (block.default_block != block.next_block)
14896 {
14897 auto &default_block = get<SPIRBlock>(block.default_block);
14898
14899 // We need to slide in the default block somewhere in this chain
14900 // if there are fall-through scenarios since the default is declared separately in OpSwitch.
14901 // Only consider trivial fall-through cases here.
14902 size_t num_blocks = block_declaration_order.size();
14903 bool injected_block = false;
14904
14905 for (size_t i = 0; i < num_blocks; i++)
14906 {
14907 auto &case_block = get<SPIRBlock>(block_declaration_order[i]);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014908 if (execution_is_direct_branch(case_block, default_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014909 {
14910 // Fallthrough to default block, we must inject the default block here.
14911 block_declaration_order.insert(begin(block_declaration_order) + i + 1, block.default_block);
14912 injected_block = true;
14913 break;
14914 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014915 else if (execution_is_direct_branch(default_block, case_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014916 {
14917 // Default case is falling through to another case label, we must inject the default block here.
14918 block_declaration_order.insert(begin(block_declaration_order) + i, block.default_block);
14919 injected_block = true;
14920 break;
14921 }
14922 }
14923
14924 // Order does not matter.
14925 if (!injected_block)
14926 block_declaration_order.push_back(block.default_block);
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014927 else if (is_legacy_es())
14928 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 +020014929
14930 case_constructs[block.default_block] = {};
14931 }
14932
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014933 size_t num_blocks = block_declaration_order.size();
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014934
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014935 const auto to_case_label = [](uint64_t literal, uint32_t width, bool is_unsigned_case) -> string
14936 {
14937 if (is_unsigned_case)
14938 return convert_to_string(literal);
14939
14940 // For smaller cases, the literals are compiled as 32 bit wide
14941 // literals so we don't need to care for all sizes specifically.
14942 if (width <= 32)
14943 {
14944 return convert_to_string(int64_t(int32_t(literal)));
14945 }
14946
14947 return convert_to_string(int64_t(literal));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014948 };
14949
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014950 const auto to_legacy_case_label = [&](uint32_t condition, const SmallVector<uint64_t> &labels,
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020014951 const char *suffix) -> string {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014952 string ret;
14953 size_t count = labels.size();
14954 for (size_t i = 0; i < count; i++)
14955 {
14956 if (i)
14957 ret += " || ";
14958 ret += join(count > 1 ? "(" : "", to_enclosed_expression(condition), " == ", labels[i], suffix,
14959 count > 1 ? ")" : "");
14960 }
14961 return ret;
14962 };
14963
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014964 // We need to deal with a complex scenario for OpPhi. If we have case-fallthrough and Phi in the picture,
14965 // we need to flush phi nodes outside the switch block in a branch,
14966 // and skip any Phi handling inside the case label to make fall-through work as expected.
14967 // This kind of code-gen is super awkward and it's a last resort. Normally we would want to handle this
14968 // inside the case label if at all possible.
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014969 for (size_t i = 1; backend.support_case_fallthrough && i < num_blocks; i++)
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014970 {
14971 if (flush_phi_required(block.self, block_declaration_order[i]) &&
14972 flush_phi_required(block_declaration_order[i - 1], block_declaration_order[i]))
14973 {
14974 uint32_t target_block = block_declaration_order[i];
14975
14976 // Make sure we flush Phi, it might have been marked to be ignored earlier.
14977 get<SPIRBlock>(target_block).ignore_phi_from_block = 0;
14978
14979 auto &literals = case_constructs[target_block];
14980
14981 if (literals.empty())
14982 {
14983 // Oh boy, gotta make a complete negative test instead! o.o
14984 // Find all possible literals that would *not* make us enter the default block.
14985 // If none of those literals match, we flush Phi ...
14986 SmallVector<string> conditions;
14987 for (size_t j = 0; j < num_blocks; j++)
14988 {
14989 auto &negative_literals = case_constructs[block_declaration_order[j]];
14990 for (auto &case_label : negative_literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020014991 conditions.push_back(join(to_enclosed_expression(block.condition),
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030014992 " != ", to_case_label(case_label, type.width, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014993 }
14994
14995 statement("if (", merge(conditions, " && "), ")");
14996 begin_scope();
14997 flush_phi(block.self, target_block);
14998 end_scope();
14999 }
15000 else
15001 {
15002 SmallVector<string> conditions;
15003 conditions.reserve(literals.size());
15004 for (auto &case_label : literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020015005 conditions.push_back(join(to_enclosed_expression(block.condition),
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015006 " == ", to_case_label(case_label, type.width, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015007 statement("if (", merge(conditions, " || "), ")");
15008 begin_scope();
15009 flush_phi(block.self, target_block);
15010 end_scope();
15011 }
15012
15013 // Mark the block so that we don't flush Phi from header to case label.
15014 get<SPIRBlock>(target_block).ignore_phi_from_block = block.self;
15015 }
15016 }
15017
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015018 // If there is only one default block, and no cases, this is a case where SPIRV-opt decided to emulate
15019 // non-structured exits with the help of a switch block.
15020 // 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 -030015021 bool degenerate_switch = block.default_block != block.merge_block && cases.empty();
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015022
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015023 if (degenerate_switch || is_legacy_es())
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015024 {
15025 // ESSL 1.0 is not guaranteed to support do/while.
15026 if (is_legacy_es())
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020015027 {
15028 uint32_t counter = statement_count;
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010015029 statement("for (int spvDummy", counter, " = 0; spvDummy", counter,
15030 " < 1; spvDummy", counter, "++)");
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020015031 }
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015032 else
15033 statement("do");
15034 }
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015035 else
15036 {
15037 emit_block_hints(block);
Bill Hollings974a0812021-10-21 16:11:33 -040015038 statement("switch (", to_unpacked_expression(block.condition), ")");
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015039 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015040 begin_scope();
15041
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015042 for (size_t i = 0; i < num_blocks; i++)
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015043 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015044 uint32_t target_block = block_declaration_order[i];
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015045 auto &literals = case_constructs[target_block];
15046
15047 if (literals.empty())
15048 {
15049 // Default case.
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015050 if (!degenerate_switch)
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015051 {
15052 if (is_legacy_es())
15053 statement("else");
15054 else
15055 statement("default:");
15056 }
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015057 }
15058 else
15059 {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015060 if (is_legacy_es())
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015061 {
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020015062 statement((i ? "else " : ""), "if (", to_legacy_case_label(block.condition, literals, label_suffix),
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015063 ")");
15064 }
15065 else
15066 {
15067 for (auto &case_literal : literals)
15068 {
15069 // 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 -030015070 statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015071 }
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015072 }
15073 }
15074
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015075 auto &case_block = get<SPIRBlock>(target_block);
Hans-Kristian Arntzen581ed0f2019-06-27 15:10:17 +020015076 if (backend.support_case_fallthrough && i + 1 < num_blocks &&
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020015077 execution_is_direct_branch(case_block, get<SPIRBlock>(block_declaration_order[i + 1])))
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015078 {
15079 // We will fall through here, so just terminate the block chain early.
15080 // We still need to deal with Phi potentially.
15081 // No need for a stack-like thing here since we only do fall-through when there is a
15082 // single trivial branch to fall-through target..
15083 current_emitting_switch_fallthrough = true;
15084 }
15085 else
15086 current_emitting_switch_fallthrough = false;
15087
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015088 if (!degenerate_switch)
15089 begin_scope();
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015090 branch(block.self, target_block);
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015091 if (!degenerate_switch)
15092 end_scope();
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015093
15094 current_emitting_switch_fallthrough = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015095 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015096
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015097 // 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 +020015098 // This is supposed to emit all cases where we branch from header to merge block directly.
15099 // There are two main scenarios where cannot rely on default fallthrough.
15100 // - There is an explicit default: label already.
15101 // In this case, literals_to_merge need to form their own "default" case, so that we avoid executing that block.
15102 // - Header -> Merge requires flushing PHI. In this case, we need to collect all cases and flush PHI there.
15103 bool header_merge_requires_phi = flush_phi_required(block.self, block.next_block);
15104 bool need_fallthrough_block = block.default_block == block.next_block || !literals_to_merge.empty();
15105 if ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015106 {
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015107 for (auto &case_literal : literals_to_merge)
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015108 statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015109
15110 if (block.default_block == block.next_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015111 {
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015112 if (is_legacy_es())
15113 statement("else");
15114 else
15115 statement("default:");
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015116 }
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015117
15118 begin_scope();
15119 flush_phi(block.self, block.next_block);
15120 statement("break;");
15121 end_scope();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015122 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015123
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015124 if (degenerate_switch && !is_legacy_es())
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015125 end_scope_decl("while(false)");
15126 else
15127 end_scope();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015128
15129 if (block.need_ladder_break)
15130 {
15131 statement("if (_", block.self, "_ladder_break)");
15132 begin_scope();
15133 statement("break;");
15134 end_scope();
15135 }
15136
15137 current_emitting_switch = old_emitting_switch;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015138 break;
15139 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015140
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015141 case SPIRBlock::Return:
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015142 {
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020015143 for (auto &line : current_function->fixup_hooks_out)
15144 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040015145
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015146 if (processing_entry_point)
15147 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015148
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015149 auto &cfg = get_cfg_for_current_function();
15150
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015151 if (block.return_value)
15152 {
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015153 auto &type = expression_type(block.return_value);
15154 if (!type.array.empty() && !backend.can_return_array)
15155 {
15156 // If we cannot return arrays, we will have a special out argument we can write to instead.
15157 // The backend is responsible for setting this up, and redirection the return values as appropriate.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010015158 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020015159 {
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020015160 emit_array_copy("spvReturnValue", 0, block.return_value, StorageClassFunction,
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +020015161 get_expression_effective_storage_class(block.return_value));
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020015162 }
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015163
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015164 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 {
15167 statement("return;");
15168 }
15169 }
15170 else
15171 {
15172 // OpReturnValue can return Undef, so don't emit anything for this case.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010015173 if (ir.ids[block.return_value].get_type() != TypeUndef)
Bill Hollings974a0812021-10-21 16:11:33 -040015174 statement("return ", to_unpacked_expression(block.return_value), ";");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015175 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015176 }
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015177 else if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015178 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015179 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015180 // If this block is the very final block and not called from control flow,
15181 // we do not need an explicit return which looks out of place. Just end the function here.
15182 // In the very weird case of for(;;) { return; } executing return is unconditional,
15183 // but we actually need a return here ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015184 statement("return;");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015185 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015186 break;
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020015187 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015188
Bill Hollings35e92e62021-09-12 16:28:21 -040015189 // 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 +020015190 case SPIRBlock::Kill:
Bill Hollings943191a2016-10-27 10:20:01 -040015191 statement(backend.discard_literal, ";");
Bill Hollings35e92e62021-09-12 16:28:21 -040015192 if (block.return_value)
Bill Hollings974a0812021-10-21 16:11:33 -040015193 statement("return ", to_unpacked_expression(block.return_value), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015194 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015195
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010015196 case SPIRBlock::Unreachable:
15197 emit_next_block = false;
15198 break;
15199
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010015200 case SPIRBlock::IgnoreIntersection:
15201 statement("ignoreIntersectionEXT;");
15202 break;
15203
15204 case SPIRBlock::TerminateRay:
15205 statement("terminateRayEXT;");
15206 break;
15207
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015208 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015209 SPIRV_CROSS_THROW("Unimplemented block terminator.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015210 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015211
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015212 if (block.next_block && emit_next_block)
15213 {
15214 // If we hit this case, we're dealing with an unconditional branch, which means we will output
15215 // that block after this. If we had selection merge, we already flushed phi variables.
15216 if (block.merge != SPIRBlock::MergeSelection)
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020015217 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015218 flush_phi(block.self, block.next_block);
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020015219 // For a direct branch, need to remember to invalidate expressions in the next linear block instead.
15220 get<SPIRBlock>(block.next_block).invalidate_expressions = block.invalidate_expressions;
15221 }
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015222
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015223 // For switch fallthrough cases, we terminate the chain here, but we still need to handle Phi.
15224 if (!current_emitting_switch_fallthrough)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015225 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015226 // For merge selects we might have ignored the fact that a merge target
15227 // could have been a break; or continue;
15228 // We will need to deal with it here.
15229 if (is_loop_break(block.next_block))
15230 {
15231 // Cannot check for just break, because switch statements will also use break.
15232 assert(block.merge == SPIRBlock::MergeSelection);
15233 statement("break;");
15234 }
15235 else if (is_continue(block.next_block))
15236 {
15237 assert(block.merge == SPIRBlock::MergeSelection);
15238 branch_to_continue(block.self, block.next_block);
15239 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015240 else if (BlockID(block.self) != block.next_block)
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015241 emit_block_chain(get<SPIRBlock>(block.next_block));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015242 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015243 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015244
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015245 if (block.merge == SPIRBlock::MergeLoop)
15246 {
15247 if (continue_type == SPIRBlock::DoWhileLoop)
15248 {
15249 // Make sure that we run the continue block to get the expressions set, but this
15250 // should become an empty string.
15251 // We have no fallbacks if we cannot forward everything to temporaries ...
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015252 const auto &continue_block = get<SPIRBlock>(block.continue_block);
Hans-Kristian Arntzen8bfb04d2019-03-06 12:20:13 +010015253 bool positive_test = execution_is_noop(get<SPIRBlock>(continue_block.true_block),
15254 get<SPIRBlock>(continue_block.loop_dominator));
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015255
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015256 uint32_t current_count = statement_count;
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015257 auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015258 if (statement_count != current_count)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015259 {
15260 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
15261 get<SPIRBlock>(block.continue_block).complex_continue = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015262 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015263 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015264
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015265 // Might have to invert the do-while test here.
15266 auto condition = to_expression(continue_block.condition);
15267 if (!positive_test)
15268 condition = join("!", enclose_expression(condition));
15269
15270 end_scope_decl(join("while (", condition, ")"));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015271 }
15272 else
15273 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015274
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020015275 loop_level_saver.release();
15276
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015277 // We cannot break out of two loops at once, so don't check for break; here.
15278 // Using block.self as the "from" block isn't quite right, but it has the same scope
15279 // and dominance structure, so it's fine.
15280 if (is_continue(block.merge_block))
15281 branch_to_continue(block.self, block.merge_block);
15282 else
15283 emit_block_chain(get<SPIRBlock>(block.merge_block));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015284 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020015285
15286 // Forget about control dependent expressions now.
15287 block.invalidate_expressions.clear();
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020015288
15289 // After we return, we must be out of scope, so if we somehow have to re-emit this function,
15290 // re-declare variables if necessary.
15291 assert(rearm_dominated_variables.size() == block.dominated_variables.size());
15292 for (size_t i = 0; i < block.dominated_variables.size(); i++)
15293 {
15294 uint32_t var = block.dominated_variables[i];
15295 get<SPIRVariable>(var).deferred_declaration = rearm_dominated_variables[i];
15296 }
Hans-Kristian Arntzen25c74b32019-07-10 12:57:12 +020015297
15298 // Just like for deferred declaration, we need to forget about loop variable enable
15299 // if our block chain is reinstantiated later.
15300 for (auto &var_id : block.loop_variables)
15301 get<SPIRVariable>(var_id).loop_variable_enable = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015302}
15303
15304void CompilerGLSL::begin_scope()
15305{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015306 statement("{");
15307 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015308}
15309
15310void CompilerGLSL::end_scope()
15311{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015312 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015313 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015314 indent--;
15315 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015316}
15317
Chip Daviscb359342019-09-05 23:14:12 -050015318void CompilerGLSL::end_scope(const string &trailer)
15319{
15320 if (!indent)
15321 SPIRV_CROSS_THROW("Popping empty indent stack.");
15322 indent--;
15323 statement("}", trailer);
15324}
15325
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015326void CompilerGLSL::end_scope_decl()
15327{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015328 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015329 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015330 indent--;
15331 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015332}
15333
15334void CompilerGLSL::end_scope_decl(const string &decl)
15335{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015336 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015337 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015338 indent--;
15339 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015340}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020015341
15342void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
15343{
15344 // If our variable is remapped, and we rely on type-remapping information as
15345 // well, then we cannot pass the variable as a function parameter.
15346 // Fixing this is non-trivial without stamping out variants of the same function,
15347 // so for now warn about this and suggest workarounds instead.
15348 for (uint32_t i = 0; i < length; i++)
15349 {
15350 auto *var = maybe_get<SPIRVariable>(args[i]);
15351 if (!var || !var->remapped_variable)
15352 continue;
15353
15354 auto &type = get<SPIRType>(var->basetype);
15355 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
15356 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010015357 SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
15358 "This will not work correctly because type-remapping information is lost. "
15359 "To workaround, please consider not passing the subpass input as a function parameter, "
15360 "or use in/out variables instead which do not need type remapping information.");
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020015361 }
15362 }
15363}
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010015364
15365const Instruction *CompilerGLSL::get_next_instruction_in_block(const Instruction &instr)
15366{
15367 // FIXME: This is kind of hacky. There should be a cleaner way.
15368 auto offset = uint32_t(&instr - current_emitting_block->ops.data());
15369 if ((offset + 1) < current_emitting_block->ops.size())
15370 return &current_emitting_block->ops[offset + 1];
15371 else
15372 return nullptr;
15373}
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010015374
15375uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
15376{
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010015377 return semantics & (MemorySemanticsAtomicCounterMemoryMask | MemorySemanticsImageMemoryMask |
15378 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask |
15379 MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010015380}
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015381
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020015382void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t, uint32_t rhs_id, StorageClass, StorageClass)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010015383{
15384 statement(lhs, " = ", to_expression(rhs_id), ";");
15385}
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015386
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015387bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id)
15388{
15389 if (!backend.force_gl_in_out_block)
15390 return false;
15391 // This path is only relevant for GL backends.
15392
15393 auto *var = maybe_get<SPIRVariable>(target_id);
15394 if (!var || var->storage != StorageClassOutput)
15395 return false;
15396
15397 if (!is_builtin_variable(*var) || BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInSampleMask)
15398 return false;
15399
15400 auto &type = expression_type(source_id);
15401 string array_expr;
15402 if (type.array_size_literal.back())
15403 {
15404 array_expr = convert_to_string(type.array.back());
15405 if (type.array.back() == 0)
15406 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
15407 }
15408 else
15409 array_expr = to_expression(type.array.back());
15410
15411 SPIRType target_type;
15412 target_type.basetype = SPIRType::Int;
15413
15414 statement("for (int i = 0; i < int(", array_expr, "); i++)");
15415 begin_scope();
15416 statement(to_expression(target_id), "[i] = ",
15417 bitcast_expression(target_type, type.basetype, join(to_expression(source_id), "[i]")),
15418 ";");
15419 end_scope();
15420
15421 return true;
15422}
15423
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015424void 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 +010015425{
15426 if (!backend.force_gl_in_out_block)
15427 return;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015428 // This path is only relevant for GL backends.
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015429
15430 auto *var = maybe_get<SPIRVariable>(source_id);
15431 if (!var)
15432 return;
15433
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015434 if (var->storage != StorageClassInput && var->storage != StorageClassOutput)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015435 return;
15436
15437 auto &type = get_variable_data_type(*var);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015438 if (type.array.empty())
15439 return;
15440
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015441 auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015442 bool is_builtin = is_builtin_variable(*var) &&
15443 (builtin == BuiltInPointSize ||
15444 builtin == BuiltInPosition ||
15445 builtin == BuiltInSampleMask);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015446 bool is_tess = is_tessellation_shader();
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010015447 bool is_patch = has_decoration(var->self, DecorationPatch);
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015448 bool is_sample_mask = is_builtin && builtin == BuiltInSampleMask;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015449
15450 // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
15451 // We must unroll the array load.
15452 // For builtins, we couldn't catch this case normally,
15453 // because this is resolved in the OpAccessChain in most cases.
15454 // If we load the entire array, we have no choice but to unroll here.
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010015455 if (!is_patch && (is_builtin || is_tess))
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015456 {
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015457 auto new_expr = join("_", target_id, "_unrolled");
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015458 statement(variable_decl(type, new_expr, target_id), ";");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015459 string array_expr;
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010015460 if (type.array_size_literal.back())
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015461 {
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010015462 array_expr = convert_to_string(type.array.back());
15463 if (type.array.back() == 0)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015464 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
15465 }
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015466 else
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010015467 array_expr = to_expression(type.array.back());
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015468
15469 // The array size might be a specialization constant, so use a for-loop instead.
15470 statement("for (int i = 0; i < int(", array_expr, "); i++)");
15471 begin_scope();
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015472 if (is_builtin && !is_sample_mask)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015473 statement(new_expr, "[i] = gl_in[i].", expr, ";");
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015474 else if (is_sample_mask)
15475 {
15476 SPIRType target_type;
15477 target_type.basetype = SPIRType::Int;
15478 statement(new_expr, "[i] = ", bitcast_expression(target_type, type.basetype, join(expr, "[i]")), ";");
15479 }
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010015480 else
15481 statement(new_expr, "[i] = ", expr, "[i];");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010015482 end_scope();
15483
15484 expr = move(new_expr);
15485 }
15486}
15487
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020015488void CompilerGLSL::cast_from_variable_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015489{
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015490 // We will handle array cases elsewhere.
15491 if (!expr_type.array.empty())
15492 return;
15493
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020015494 auto *var = maybe_get_backing_variable(source_id);
15495 if (var)
15496 source_id = var->self;
15497
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015498 // Only interested in standalone builtin variables.
15499 if (!has_decoration(source_id, DecorationBuiltIn))
15500 return;
15501
15502 auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
15503 auto expected_type = expr_type.basetype;
15504
15505 // TODO: Fill in for more builtins.
15506 switch (builtin)
15507 {
15508 case BuiltInLayer:
15509 case BuiltInPrimitiveId:
15510 case BuiltInViewportIndex:
15511 case BuiltInInstanceId:
15512 case BuiltInInstanceIndex:
15513 case BuiltInVertexId:
15514 case BuiltInVertexIndex:
15515 case BuiltInSampleId:
Chip Davisfcad0192018-08-28 13:47:29 -050015516 case BuiltInBaseVertex:
15517 case BuiltInBaseInstance:
15518 case BuiltInDrawIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020015519 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020015520 case BuiltInInstanceCustomIndexNV:
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015521 case BuiltInSampleMask:
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +020015522 case BuiltInPrimitiveShadingRateKHR:
15523 case BuiltInShadingRateKHR:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015524 expected_type = SPIRType::Int;
15525 break;
15526
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020015527 case BuiltInGlobalInvocationId:
15528 case BuiltInLocalInvocationId:
15529 case BuiltInWorkgroupId:
15530 case BuiltInLocalInvocationIndex:
15531 case BuiltInWorkgroupSize:
15532 case BuiltInNumWorkgroups:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020015533 case BuiltInIncomingRayFlagsNV:
15534 case BuiltInLaunchIdNV:
15535 case BuiltInLaunchSizeNV:
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020015536 expected_type = SPIRType::UInt;
15537 break;
15538
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015539 default:
15540 break;
15541 }
15542
15543 if (expected_type != expr_type.basetype)
15544 expr = bitcast_expression(expr_type, expected_type, expr);
15545}
15546
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020015547void CompilerGLSL::cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015548{
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015549 auto *var = maybe_get_backing_variable(target_id);
15550 if (var)
15551 target_id = var->self;
15552
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015553 // Only interested in standalone builtin variables.
15554 if (!has_decoration(target_id, DecorationBuiltIn))
15555 return;
15556
15557 auto builtin = static_cast<BuiltIn>(get_decoration(target_id, DecorationBuiltIn));
15558 auto expected_type = expr_type.basetype;
15559
15560 // TODO: Fill in for more builtins.
15561 switch (builtin)
15562 {
15563 case BuiltInLayer:
15564 case BuiltInPrimitiveId:
15565 case BuiltInViewportIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020015566 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010015567 case BuiltInSampleMask:
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +020015568 case BuiltInPrimitiveShadingRateKHR:
15569 case BuiltInShadingRateKHR:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020015570 expected_type = SPIRType::Int;
15571 break;
15572
15573 default:
15574 break;
15575 }
15576
15577 if (expected_type != expr_type.basetype)
15578 {
15579 auto type = expr_type;
15580 type.basetype = expected_type;
15581 expr = bitcast_expression(type, expr_type.basetype, expr);
15582 }
15583}
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015584
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015585void CompilerGLSL::convert_non_uniform_expression(string &expr, uint32_t ptr_id)
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015586{
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020015587 if (*backend.nonuniform_qualifier == '\0')
15588 return;
15589
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015590 auto *var = maybe_get_backing_variable(ptr_id);
15591 if (!var)
15592 return;
15593
15594 if (var->storage != StorageClassUniformConstant &&
15595 var->storage != StorageClassStorageBuffer &&
15596 var->storage != StorageClassUniform)
15597 return;
15598
15599 auto &backing_type = get<SPIRType>(var->basetype);
15600 if (backing_type.array.empty())
15601 return;
15602
15603 // If we get here, we know we're accessing an arrayed resource which
15604 // might require nonuniform qualifier.
15605
15606 auto start_array_index = expr.find_first_of('[');
15607
15608 if (start_array_index == string::npos)
15609 return;
15610
15611 // We've opened a bracket, track expressions until we can close the bracket.
15612 // This must be our resource index.
15613 size_t end_array_index = string::npos;
15614 unsigned bracket_count = 1;
15615 for (size_t index = start_array_index + 1; index < expr.size(); index++)
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015616 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015617 if (expr[index] == ']')
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015618 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015619 if (--bracket_count == 0)
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015620 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015621 end_array_index = index;
15622 break;
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015623 }
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010015624 }
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015625 else if (expr[index] == '[')
15626 bracket_count++;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015627 }
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020015628
15629 assert(bracket_count == 0);
15630
15631 // Doesn't really make sense to declare a non-arrayed image with nonuniformEXT, but there's
15632 // nothing we can do here to express that.
15633 if (start_array_index == string::npos || end_array_index == string::npos || end_array_index < start_array_index)
15634 return;
15635
15636 start_array_index++;
15637
15638 expr = join(expr.substr(0, start_array_index), backend.nonuniform_qualifier, "(",
15639 expr.substr(start_array_index, end_array_index - start_array_index), ")",
15640 expr.substr(end_array_index, string::npos));
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020015641}
15642
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +020015643void CompilerGLSL::emit_block_hints(const SPIRBlock &block)
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015644{
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +020015645 if ((options.es && options.version < 310) || (!options.es && options.version < 140))
15646 return;
15647
15648 switch (block.hint)
15649 {
15650 case SPIRBlock::HintFlatten:
15651 require_extension_internal("GL_EXT_control_flow_attributes");
15652 statement("SPIRV_CROSS_FLATTEN");
15653 break;
15654 case SPIRBlock::HintDontFlatten:
15655 require_extension_internal("GL_EXT_control_flow_attributes");
15656 statement("SPIRV_CROSS_BRANCH");
15657 break;
15658 case SPIRBlock::HintUnroll:
15659 require_extension_internal("GL_EXT_control_flow_attributes");
15660 statement("SPIRV_CROSS_UNROLL");
15661 break;
15662 case SPIRBlock::HintDontUnroll:
15663 require_extension_internal("GL_EXT_control_flow_attributes");
15664 statement("SPIRV_CROSS_LOOP");
15665 break;
15666 default:
15667 break;
15668 }
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015669}
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +010015670
15671void CompilerGLSL::preserve_alias_on_reset(uint32_t id)
15672{
15673 preserved_aliases[id] = get_name(id);
15674}
15675
15676void CompilerGLSL::reset_name_caches()
15677{
15678 for (auto &preserved : preserved_aliases)
15679 set_name(preserved.first, preserved.second);
15680
15681 preserved_aliases.clear();
15682 resource_names.clear();
15683 block_input_names.clear();
15684 block_output_names.clear();
15685 block_ubo_names.clear();
15686 block_ssbo_names.clear();
15687 block_names.clear();
15688 function_overloads.clear();
15689}
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015690
15691void CompilerGLSL::fixup_type_alias()
15692{
15693 // 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 +020015694 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020015695 if (!type.type_alias)
15696 return;
15697
15698 if (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015699 {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020015700 // Top-level block types should never alias anything else.
15701 type.type_alias = 0;
15702 }
15703 else if (type_is_block_like(type) && type.self == ID(self))
15704 {
15705 // A block-like type is any type which contains Offset decoration, but not top-level blocks,
15706 // i.e. blocks which are placed inside buffers.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015707 // Become the master.
15708 ir.for_each_typed_id<SPIRType>([&](uint32_t other_id, SPIRType &other_type) {
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020015709 if (other_id == self)
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015710 return;
15711
15712 if (other_type.type_alias == type.type_alias)
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020015713 other_type.type_alias = self;
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015714 });
15715
15716 this->get<SPIRType>(type.type_alias).type_alias = self;
15717 type.type_alias = 0;
15718 }
15719 });
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015720}
15721
15722void CompilerGLSL::reorder_type_alias()
15723{
15724 // Reorder declaration of types so that the master of the type alias is always emitted first.
15725 // 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
15726 // 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 +020015727 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020015728
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015729 auto &type_ids = ir.ids_for_type[TypeType];
15730 for (auto alias_itr = begin(type_ids); alias_itr != end(type_ids); ++alias_itr)
15731 {
15732 auto &type = get<SPIRType>(*alias_itr);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015733 if (type.type_alias != TypeID(0) &&
15734 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015735 {
15736 // We will skip declaring this type, so make sure the type_alias type comes before.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015737 auto master_itr = find(begin(type_ids), end(type_ids), ID(type.type_alias));
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020015738 assert(master_itr != end(type_ids));
15739
15740 if (alias_itr < master_itr)
15741 {
15742 // Must also swap the type order for the constant-type joined array.
15743 auto &joined_types = ir.ids_for_constant_or_type;
15744 auto alt_alias_itr = find(begin(joined_types), end(joined_types), *alias_itr);
15745 auto alt_master_itr = find(begin(joined_types), end(joined_types), *master_itr);
15746 assert(alt_alias_itr != end(joined_types));
15747 assert(alt_master_itr != end(joined_types));
15748
15749 swap(*alias_itr, *master_itr);
15750 swap(*alt_alias_itr, *alt_master_itr);
15751 }
15752 }
15753 }
15754}
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020015755
15756void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
15757{
15758 // If we are redirecting statements, ignore the line directive.
15759 // Common case here is continue blocks.
15760 if (redirect_statement)
15761 return;
15762
15763 if (options.emit_line_directives)
15764 {
15765 require_extension_internal("GL_GOOGLE_cpp_style_line_directive");
15766 statement_no_indent("#line ", line_literal, " \"", get<SPIRString>(file_id).str, "\"");
15767 }
15768}
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020015769
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010015770void 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 +010015771 SmallVector<uint32_t> chain)
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015772{
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015773 // Fully unroll all member/array indices one by one.
15774
15775 auto &lhs_type = get<SPIRType>(lhs_type_id);
15776 auto &rhs_type = get<SPIRType>(rhs_type_id);
15777
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015778 if (!lhs_type.array.empty())
15779 {
15780 // Could use a loop here to support specialization constants, but it gets rather complicated with nested array types,
15781 // and this is a rather obscure opcode anyways, keep it simple unless we are forced to.
15782 uint32_t array_size = to_array_size_literal(lhs_type);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015783 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015784
15785 for (uint32_t i = 0; i < array_size; i++)
15786 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015787 chain.back() = i;
15788 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 +010015789 }
15790 }
15791 else if (lhs_type.basetype == SPIRType::Struct)
15792 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015793 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015794 uint32_t member_count = uint32_t(lhs_type.member_types.size());
15795 for (uint32_t i = 0; i < member_count; i++)
15796 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015797 chain.back() = i;
15798 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 +010015799 }
15800 }
15801 else
15802 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015803 // Need to handle unpack/packing fixups since this can differ wildly between the logical types,
15804 // particularly in MSL.
15805 // To deal with this, we emit access chains and go through emit_store_statement
15806 // to deal with all the special cases we can encounter.
15807
15808 AccessChainMeta lhs_meta, rhs_meta;
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010015809 auto lhs = access_chain_internal(lhs_id, chain.data(), uint32_t(chain.size()),
15810 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &lhs_meta);
15811 auto rhs = access_chain_internal(rhs_id, chain.data(), uint32_t(chain.size()),
15812 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &rhs_meta);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010015813
15814 uint32_t id = ir.increase_bound_by(2);
15815 lhs_id = id;
15816 rhs_id = id + 1;
15817
15818 {
15819 auto &lhs_expr = set<SPIRExpression>(lhs_id, move(lhs), lhs_type_id, true);
15820 lhs_expr.need_transpose = lhs_meta.need_transpose;
15821
15822 if (lhs_meta.storage_is_packed)
15823 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypePacked);
15824 if (lhs_meta.storage_physical_type != 0)
15825 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID, lhs_meta.storage_physical_type);
15826
15827 forwarded_temporaries.insert(lhs_id);
15828 suppressed_usage_tracking.insert(lhs_id);
15829 }
15830
15831 {
15832 auto &rhs_expr = set<SPIRExpression>(rhs_id, move(rhs), rhs_type_id, true);
15833 rhs_expr.need_transpose = rhs_meta.need_transpose;
15834
15835 if (rhs_meta.storage_is_packed)
15836 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypePacked);
15837 if (rhs_meta.storage_physical_type != 0)
15838 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID, rhs_meta.storage_physical_type);
15839
15840 forwarded_temporaries.insert(rhs_id);
15841 suppressed_usage_tracking.insert(rhs_id);
15842 }
15843
15844 emit_store_statement(lhs_id, rhs_id);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015845 }
15846}
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010015847
15848bool CompilerGLSL::subpass_input_is_framebuffer_fetch(uint32_t id) const
15849{
15850 if (!has_decoration(id, DecorationInputAttachmentIndex))
15851 return false;
15852
15853 uint32_t input_attachment_index = get_decoration(id, DecorationInputAttachmentIndex);
15854 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
15855 if (remap.first == input_attachment_index)
15856 return true;
15857
15858 return false;
15859}
15860
15861const SPIRVariable *CompilerGLSL::find_subpass_input_by_attachment_index(uint32_t index) const
15862{
15863 const SPIRVariable *ret = nullptr;
15864 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
15865 if (has_decoration(var.self, DecorationInputAttachmentIndex) &&
15866 get_decoration(var.self, DecorationInputAttachmentIndex) == index)
15867 {
15868 ret = &var;
15869 }
15870 });
15871 return ret;
15872}
15873
15874const SPIRVariable *CompilerGLSL::find_color_output_by_location(uint32_t location) const
15875{
15876 const SPIRVariable *ret = nullptr;
15877 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
15878 if (var.storage == StorageClassOutput && get_decoration(var.self, DecorationLocation) == location)
15879 ret = &var;
15880 });
15881 return ret;
15882}
15883
15884void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs()
15885{
15886 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
15887 {
15888 auto *subpass_var = find_subpass_input_by_attachment_index(remap.first);
15889 auto *output_var = find_color_output_by_location(remap.second);
15890 if (!subpass_var)
15891 continue;
15892 if (!output_var)
crissdb52e272020-10-08 12:14:52 +020015893 SPIRV_CROSS_THROW("Need to declare the corresponding fragment output variable to be able "
15894 "to read from it.");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010015895 if (is_array(get<SPIRType>(output_var->basetype)))
15896 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs.");
15897
15898 auto &func = get<SPIRFunction>(get_entry_point().self);
15899 func.fixup_hooks_in.push_back([=]() {
15900 if (is_legacy())
15901 {
15902 statement(to_expression(subpass_var->self), " = ", "gl_LastFragData[",
15903 get_decoration(output_var->self, DecorationLocation), "];");
15904 }
15905 else
15906 {
15907 uint32_t num_rt_components = this->get<SPIRType>(output_var->basetype).vecsize;
15908 statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ",
15909 to_expression(output_var->self), ";");
15910 }
15911 });
15912 }
15913}
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020015914
15915bool CompilerGLSL::variable_is_depth_or_compare(VariableID id) const
15916{
Bill Hollingsfd252b22021-11-08 15:59:45 -050015917 return is_depth_image(get<SPIRType>(get<SPIRVariable>(id).basetype), id);
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020015918}
crissdb52e272020-10-08 12:14:52 +020015919
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015920const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extension_name(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015921{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015922 static const char *const retval[CandidateCount] = { "GL_KHR_shader_subgroup_ballot",
15923 "GL_KHR_shader_subgroup_basic",
15924 "GL_KHR_shader_subgroup_vote",
15925 "GL_NV_gpu_shader_5",
15926 "GL_NV_shader_thread_group",
15927 "GL_NV_shader_thread_shuffle",
15928 "GL_ARB_shader_ballot",
15929 "GL_ARB_shader_group_vote",
15930 "GL_AMD_gcn_shader" };
crissdb52e272020-10-08 12:14:52 +020015931 return retval[c];
15932}
15933
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015934SmallVector<std::string> CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_names(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015935{
15936 switch (c)
15937 {
15938 case ARB_shader_ballot:
15939 return { "GL_ARB_shader_int64" };
15940 case AMD_gcn_shader:
15941 return { "GL_AMD_gpu_shader_int64", "GL_NV_gpu_shader5" };
15942 default:
15943 return {};
15944 }
15945}
15946
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015947const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_predicate(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015948{
15949 switch (c)
15950 {
15951 case ARB_shader_ballot:
15952 return "defined(GL_ARB_shader_int64)";
15953 case AMD_gcn_shader:
15954 return "(defined(GL_AMD_gpu_shader_int64) || defined(GL_NV_gpu_shader5))";
15955 default:
15956 return "";
15957 }
15958}
15959
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015960CompilerGLSL::ShaderSubgroupSupportHelper::FeatureVector CompilerGLSL::ShaderSubgroupSupportHelper::
15961 get_feature_dependencies(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015962{
15963 switch (feature)
15964 {
15965 case SubgroupAllEqualT:
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010015966 return { SubgroupBroadcast_First, SubgroupAll_Any_AllEqualBool };
crissdb52e272020-10-08 12:14:52 +020015967 case SubgroupElect:
15968 return { SubgroupBallotFindLSB_MSB, SubgroupBallot, SubgroupInvocationID };
15969 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
15970 return { SubgroupMask };
15971 case SubgroupBallotBitCount:
15972 return { SubgroupBallot };
15973 default:
15974 return {};
15975 }
15976}
15977
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015978CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::
15979 get_feature_dependency_mask(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015980{
15981 return build_mask(get_feature_dependencies(feature));
15982}
15983
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015984bool CompilerGLSL::ShaderSubgroupSupportHelper::can_feature_be_implemented_without_extensions(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015985{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015986 static const bool retval[FeatureCount] = { false, false, false, false, false, false,
15987 true, // SubgroupBalloFindLSB_MSB
15988 false, false, false, false,
15989 true, // SubgroupMemBarrier - replaced with workgroup memory barriers
15990 false, false, true, false };
crissdb52e272020-10-08 12:14:52 +020015991
15992 return retval[feature];
15993}
15994
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015995CompilerGLSL::ShaderSubgroupSupportHelper::Candidate CompilerGLSL::ShaderSubgroupSupportHelper::
15996 get_KHR_extension_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015997{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015998 static const Candidate extensions[FeatureCount] = {
crissdb52e272020-10-08 12:14:52 +020015999 KHR_shader_subgroup_ballot, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic,
16000 KHR_shader_subgroup_basic, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_vote,
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010016001 KHR_shader_subgroup_vote, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic,
16002 KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot
crissdb52e272020-10-08 12:14:52 +020016003 };
16004
16005 return extensions[feature];
16006}
16007
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016008void CompilerGLSL::ShaderSubgroupSupportHelper::request_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016009{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016010 feature_mask |= (FeatureMask(1) << feature) | get_feature_dependency_mask(feature);
crissdb52e272020-10-08 12:14:52 +020016011}
16012
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016013bool CompilerGLSL::ShaderSubgroupSupportHelper::is_feature_requested(Feature feature) const
crissdb52e272020-10-08 12:14:52 +020016014{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016015 return (feature_mask & (1u << feature)) != 0;
crissdb52e272020-10-08 12:14:52 +020016016}
16017
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016018CompilerGLSL::ShaderSubgroupSupportHelper::Result CompilerGLSL::ShaderSubgroupSupportHelper::resolve() const
crissdb52e272020-10-08 12:14:52 +020016019{
16020 Result res;
16021
16022 for (uint32_t i = 0u; i < FeatureCount; ++i)
16023 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016024 if (feature_mask & (1u << i))
crissdb52e272020-10-08 12:14:52 +020016025 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016026 auto feature = static_cast<Feature>(i);
16027 std::unordered_set<uint32_t> unique_candidates;
crissdb52e272020-10-08 12:14:52 +020016028
16029 auto candidates = get_candidates_for_feature(feature);
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016030 unique_candidates.insert(candidates.begin(), candidates.end());
crissdb52e272020-10-08 12:14:52 +020016031
16032 auto deps = get_feature_dependencies(feature);
16033 for (Feature d : deps)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016034 {
16035 candidates = get_candidates_for_feature(d);
16036 if (!candidates.empty())
16037 unique_candidates.insert(candidates.begin(), candidates.end());
16038 }
crissdb52e272020-10-08 12:14:52 +020016039
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016040 for (uint32_t c : unique_candidates)
16041 ++res.weights[static_cast<Candidate>(c)];
crissdb52e272020-10-08 12:14:52 +020016042 }
16043 }
16044
16045 return res;
16046}
16047
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016048CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
16049 get_candidates_for_feature(Feature ft, const Result &r)
crissdb52e272020-10-08 12:14:52 +020016050{
16051 auto c = get_candidates_for_feature(ft);
16052 auto cmp = [&r](Candidate a, Candidate b) {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016053 if (r.weights[a] == r.weights[b])
16054 return a < b; // Prefer candidates with lower enum value
16055 return r.weights[a] > r.weights[b];
crissdb52e272020-10-08 12:14:52 +020016056 };
16057 std::sort(c.begin(), c.end(), cmp);
crissdb52e272020-10-08 12:14:52 +020016058 return c;
16059}
16060
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016061CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
16062 get_candidates_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016063{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016064 switch (feature)
crissdb52e272020-10-08 12:14:52 +020016065 {
16066 case SubgroupMask:
16067 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
16068 case SubgroupSize:
16069 return { KHR_shader_subgroup_basic, NV_shader_thread_group, AMD_gcn_shader, ARB_shader_ballot };
16070 case SubgroupInvocationID:
16071 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot };
16072 case SubgroupID:
16073 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
16074 case NumSubgroups:
16075 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010016076 case SubgroupBroadcast_First:
crissdb52e272020-10-08 12:14:52 +020016077 return { KHR_shader_subgroup_ballot, NV_shader_thread_shuffle, ARB_shader_ballot };
16078 case SubgroupBallotFindLSB_MSB:
16079 return { KHR_shader_subgroup_ballot, NV_shader_thread_group };
16080 case SubgroupAll_Any_AllEqualBool:
16081 return { KHR_shader_subgroup_vote, NV_gpu_shader_5, ARB_shader_group_vote, AMD_gcn_shader };
16082 case SubgroupAllEqualT:
16083 return {}; // depends on other features only
16084 case SubgroupElect:
16085 return {}; // depends on other features only
16086 case SubgroupBallot:
16087 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
16088 case SubgroupBarrier:
16089 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot, AMD_gcn_shader };
16090 case SubgroupMemBarrier:
16091 return { KHR_shader_subgroup_basic };
16092 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
16093 return {};
16094 case SubgroupBallotBitExtract:
16095 return { NV_shader_thread_group };
16096 case SubgroupBallotBitCount:
16097 return {};
16098 default:
16099 return {};
16100 }
16101}
16102
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016103CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::build_mask(
16104 const SmallVector<Feature> &features)
crissdb52e272020-10-08 12:14:52 +020016105{
16106 FeatureMask mask = 0;
crissdb52e272020-10-08 12:14:52 +020016107 for (Feature f : features)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016108 mask |= FeatureMask(1) << f;
crissdb52e272020-10-08 12:14:52 +020016109 return mask;
16110}
16111
16112CompilerGLSL::ShaderSubgroupSupportHelper::Result::Result()
16113{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016114 for (auto &weight : weights)
16115 weight = 0;
crissdb52e272020-10-08 12:14:52 +020016116
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016117 // Make sure KHR_shader_subgroup extensions are always prefered.
16118 const uint32_t big_num = FeatureCount;
16119 weights[KHR_shader_subgroup_ballot] = big_num;
16120 weights[KHR_shader_subgroup_basic] = big_num;
16121 weights[KHR_shader_subgroup_vote] = big_num;
crissdb52e272020-10-08 12:14:52 +020016122}
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020016123
16124void CompilerGLSL::request_workaround_wrapper_overload(TypeID id)
16125{
16126 // Must be ordered to maintain deterministic output, so vector is appropriate.
16127 if (find(begin(workaround_ubo_load_overload_types), end(workaround_ubo_load_overload_types), id) ==
16128 end(workaround_ubo_load_overload_types))
16129 {
16130 force_recompile();
16131 workaround_ubo_load_overload_types.push_back(id);
16132 }
16133}
16134
16135void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID loaded_type, ID ptr)
16136{
16137 // Loading row-major matrices from UBOs on older AMD Windows OpenGL drivers is problematic.
16138 // To load these types correctly, we must first wrap them in a dummy function which only purpose is to
16139 // ensure row_major decoration is actually respected.
16140 auto *var = maybe_get_backing_variable(ptr);
16141 if (!var)
16142 return;
16143
16144 auto &backing_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016145 bool is_ubo = backing_type.basetype == SPIRType::Struct && backing_type.storage == StorageClassUniform &&
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020016146 has_decoration(backing_type.self, DecorationBlock);
16147 if (!is_ubo)
16148 return;
16149
16150 auto *type = &get<SPIRType>(loaded_type);
16151 bool rewrite = false;
16152
16153 if (is_matrix(*type))
16154 {
16155 // To avoid adding a lot of unnecessary meta tracking to forward the row_major state,
16156 // we will simply look at the base struct itself. It is exceptionally rare to mix and match row-major/col-major state.
16157 // If there is any row-major action going on, we apply the workaround.
16158 // It is harmless to apply the workaround to column-major matrices, so this is still a valid solution.
16159 // If an access chain occurred, the workaround is not required, so loading vectors or scalars don't need workaround.
16160 type = &backing_type;
16161 }
16162
16163 if (type->basetype == SPIRType::Struct)
16164 {
16165 // If we're loading a struct where any member is a row-major matrix, apply the workaround.
16166 for (uint32_t i = 0; i < uint32_t(type->member_types.size()); i++)
16167 {
16168 if (combined_decoration_for_member(*type, i).get(DecorationRowMajor))
16169 {
16170 rewrite = true;
16171 break;
16172 }
16173 }
16174 }
16175
16176 if (rewrite)
16177 {
16178 request_workaround_wrapper_overload(loaded_type);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010016179 expr = join("spvWorkaroundRowMajor(", expr, ")");
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020016180 }
16181}
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +010016182
16183void CompilerGLSL::mask_stage_output_by_location(uint32_t location, uint32_t component)
16184{
16185 masked_output_locations.insert({ location, component });
16186}
16187
16188void CompilerGLSL::mask_stage_output_by_builtin(BuiltIn builtin)
16189{
16190 masked_output_builtins.insert(builtin);
16191}
16192
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016193bool CompilerGLSL::is_stage_output_variable_masked(const SPIRVariable &var) const
16194{
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016195 auto &type = get<SPIRType>(var.basetype);
16196 bool is_block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016197 // Blocks by themselves are never masked. Must be masked per-member.
16198 if (is_block)
16199 return false;
16200
16201 bool is_builtin = has_decoration(var.self, DecorationBuiltIn);
16202
16203 if (is_builtin)
16204 {
16205 return is_stage_output_builtin_masked(BuiltIn(get_decoration(var.self, DecorationBuiltIn)));
16206 }
16207 else
16208 {
16209 if (!has_decoration(var.self, DecorationLocation))
16210 return false;
16211
16212 return is_stage_output_location_masked(
16213 get_decoration(var.self, DecorationLocation),
16214 get_decoration(var.self, DecorationComponent));
16215 }
16216}
16217
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016218bool 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 +020016219{
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016220 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016221 bool is_block = has_decoration(type.self, DecorationBlock);
16222 if (!is_block)
16223 return false;
16224
16225 BuiltIn builtin = BuiltInMax;
16226 if (is_member_builtin(type, index, &builtin))
16227 {
16228 return is_stage_output_builtin_masked(builtin);
16229 }
16230 else
16231 {
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016232 uint32_t location = get_declared_member_location(var, index, strip_array);
16233 uint32_t component = get_member_decoration(type.self, index, DecorationComponent);
16234 return is_stage_output_location_masked(location, component);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020016235 }
16236}
16237
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +010016238bool CompilerGLSL::is_stage_output_location_masked(uint32_t location, uint32_t component) const
16239{
16240 return masked_output_locations.count({ location, component }) != 0;
16241}
16242
16243bool CompilerGLSL::is_stage_output_builtin_masked(spv::BuiltIn builtin) const
16244{
16245 return masked_output_builtins.count(builtin) != 0;
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016246}
16247
16248uint32_t CompilerGLSL::get_declared_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const
16249{
16250 auto &block_type = get<SPIRType>(var.basetype);
16251 if (has_member_decoration(block_type.self, mbr_idx, DecorationLocation))
16252 return get_member_decoration(block_type.self, mbr_idx, DecorationLocation);
16253 else
16254 return get_accumulated_member_location(var, mbr_idx, strip_array);
16255}
16256
16257uint32_t CompilerGLSL::get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const
16258{
16259 auto &type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
16260 uint32_t location = get_decoration(var.self, DecorationLocation);
16261
16262 for (uint32_t i = 0; i < mbr_idx; i++)
16263 {
16264 auto &mbr_type = get<SPIRType>(type.member_types[i]);
16265
16266 // Start counting from any place we have a new location decoration.
16267 if (has_member_decoration(type.self, mbr_idx, DecorationLocation))
16268 location = get_member_decoration(type.self, mbr_idx, DecorationLocation);
16269
Hans-Kristian Arntzen96ba0442021-04-20 13:03:58 +020016270 uint32_t location_count = type_to_location_count(mbr_type);
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020016271 location += location_count;
16272 }
16273
16274 return location;
16275}
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020016276
16277StorageClass CompilerGLSL::get_expression_effective_storage_class(uint32_t ptr)
16278{
16279 auto *var = maybe_get_backing_variable(ptr);
16280
16281 // If the expression has been lowered to a temporary, we need to use the Generic storage class.
16282 // We're looking for the effective storage class of a given expression.
16283 // An access chain or forwarded OpLoads from such access chains
16284 // will generally have the storage class of the underlying variable, but if the load was not forwarded
16285 // we have lost any address space qualifiers.
16286 bool forced_temporary = ir.ids[ptr].get_type() == TypeExpression && !get<SPIRExpression>(ptr).access_chain &&
16287 (forced_temporaries.count(ptr) != 0 || forwarded_temporaries.count(ptr) == 0);
16288
16289 if (var && !forced_temporary)
16290 {
16291 if (variable_decl_is_remapped_storage(*var, StorageClassWorkgroup))
16292 return StorageClassWorkgroup;
16293 if (variable_decl_is_remapped_storage(*var, StorageClassStorageBuffer))
16294 return StorageClassStorageBuffer;
16295
16296 // Normalize SSBOs to StorageBuffer here.
16297 if (var->storage == StorageClassUniform &&
16298 has_decoration(get<SPIRType>(var->basetype).self, DecorationBufferBlock))
16299 return StorageClassStorageBuffer;
16300 else
16301 return var->storage;
16302 }
16303 else
16304 return expression_type(ptr).storage;
16305}
Hans-Kristian Arntzen96ba0442021-04-20 13:03:58 +020016306
16307uint32_t CompilerGLSL::type_to_location_count(const SPIRType &type) const
16308{
16309 uint32_t count;
16310 if (type.basetype == SPIRType::Struct)
16311 {
16312 uint32_t mbr_count = uint32_t(type.member_types.size());
16313 count = 0;
16314 for (uint32_t i = 0; i < mbr_count; i++)
16315 count += type_to_location_count(get<SPIRType>(type.member_types[i]));
16316 }
16317 else
16318 {
16319 count = type.columns > 1 ? type.columns : 1;
16320 }
16321
16322 uint32_t dim_count = uint32_t(type.array.size());
16323 for (uint32_t i = 0; i < dim_count; i++)
16324 count *= to_array_size_literal(type, i);
16325
16326 return count;
16327}