blob: a8129641190527dadb221560cb3aac68a24e7ae8 [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.
Hans-Kristian Arntzenc716a9a2022-02-16 12:12:27 +0100309 if (iteration_count >= options.force_recompile_max_debug_iterations && !is_force_recompile_forward_progress)
310 SPIRV_CROSS_THROW("Maximum compilation loops detected and no forward progress was made. Must be a SPIRV-Cross bug!");
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +0100311
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();
Hans-Kristian Arntzen23662662022-05-18 12:26:20 +0200319 composite_insert_overwritten.clear();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200320 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100321
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200322 // Clear temporary usage tracking.
323 expression_usage_counts.clear();
324 forwarded_temporaries.clear();
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +0200325 suppressed_usage_tracking.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100326
Lukas Hermanns50ac6862019-09-18 14:03:54 -0400327 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -0400328 flushed_phi_variables.clear();
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400329
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +0200330 current_emitting_switch_stack.clear();
331
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +0100332 reset_name_caches();
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200333
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100334 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, SPIRFunction &func) {
335 func.active = false;
336 func.flush_undeclared = true;
337 });
338
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +0100339 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) { var.dependees.clear(); });
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100340
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400341 ir.reset_all_of_type<SPIRExpression>();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100342 ir.reset_all_of_type<SPIRAccessChain>();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100343
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200344 statement_count = 0;
345 indent = 0;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +0200346 current_loop_level = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100347}
348
349void CompilerGLSL::remap_pls_variables()
350{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200351 for (auto &input : pls_inputs)
352 {
353 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200355 bool input_is_target = false;
356 if (var.storage == StorageClassUniformConstant)
357 {
358 auto &type = get<SPIRType>(var.basetype);
359 input_is_target = type.image.dim == DimSubpassData;
360 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100361
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200362 if (var.storage != StorageClassInput && !input_is_target)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100363 SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200364 var.remapped_variable = true;
365 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100366
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200367 for (auto &output : pls_outputs)
368 {
369 auto &var = get<SPIRVariable>(output.id);
370 if (var.storage != StorageClassOutput)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100371 SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200372 var.remapped_variable = true;
373 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100374}
375
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200376void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100377{
378 subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200379 inout_color_attachments.push_back({ color_location, coherent });
380}
381
382bool CompilerGLSL::location_is_framebuffer_fetch(uint32_t location) const
383{
384 return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
385 [&](const std::pair<uint32_t, bool> &elem) {
386 return elem.first == location;
387 }) != end(inout_color_attachments);
388}
389
390bool CompilerGLSL::location_is_non_coherent_framebuffer_fetch(uint32_t location) const
391{
392 return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
393 [&](const std::pair<uint32_t, bool> &elem) {
394 return elem.first == location && !elem.second;
395 }) != end(inout_color_attachments);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100396}
397
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200398void CompilerGLSL::find_static_extensions()
399{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100400 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
401 if (type.basetype == SPIRType::Double)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200402 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100403 if (options.es)
404 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
405 if (!options.es && options.version < 400)
406 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200407 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100408 else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100409 {
Hans-Kristian Arntzendf21a992022-06-07 15:39:37 +0200410 if (options.es && options.version < 310) // GL_NV_gpu_shader5 fallback requires 310.
411 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile before version 310.");
412 require_extension_internal("GL_ARB_gpu_shader_int64");
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100413 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100414 else if (type.basetype == SPIRType::Half)
415 {
416 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_float16");
417 if (options.vulkan_semantics)
418 require_extension_internal("GL_EXT_shader_16bit_storage");
419 }
420 else if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
421 {
422 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int8");
423 if (options.vulkan_semantics)
424 require_extension_internal("GL_EXT_shader_8bit_storage");
425 }
426 else if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
427 {
428 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int16");
429 if (options.vulkan_semantics)
430 require_extension_internal("GL_EXT_shader_16bit_storage");
431 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100432 });
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200433
434 auto &execution = get_entry_point();
435 switch (execution.model)
436 {
437 case ExecutionModelGLCompute:
438 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200439 require_extension_internal("GL_ARB_compute_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200440 if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100441 SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200442 break;
443
444 case ExecutionModelGeometry:
445 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200446 require_extension_internal("GL_EXT_geometry_shader");
robfb1820e2017-06-17 10:06:46 +0900447 if (!options.es && options.version < 150)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200448 require_extension_internal("GL_ARB_geometry_shader4");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200449
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100450 if (execution.flags.get(ExecutionModeInvocations) && execution.invocations != 1)
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200451 {
452 // Instanced GS is part of 400 core or this extension.
453 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200454 require_extension_internal("GL_ARB_gpu_shader5");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200455 }
456 break;
457
458 case ExecutionModelTessellationEvaluation:
459 case ExecutionModelTessellationControl:
460 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200461 require_extension_internal("GL_EXT_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200462 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200463 require_extension_internal("GL_ARB_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200464 break;
465
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100466 case ExecutionModelRayGenerationKHR:
467 case ExecutionModelIntersectionKHR:
468 case ExecutionModelAnyHitKHR:
469 case ExecutionModelClosestHitKHR:
470 case ExecutionModelMissKHR:
471 case ExecutionModelCallableKHR:
472 // NV enums are aliases.
Patrick Moursc74d7a42019-03-25 15:06:01 +0100473 if (options.es || options.version < 460)
474 SPIRV_CROSS_THROW("Ray tracing shaders require non-es profile with version 460 or above.");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100475 if (!options.vulkan_semantics)
476 SPIRV_CROSS_THROW("Ray tracing requires Vulkan semantics.");
477
478 // Need to figure out if we should target KHR or NV extension based on capabilities.
479 for (auto &cap : ir.declared_capabilities)
480 {
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +0200481 if (cap == CapabilityRayTracingKHR || cap == CapabilityRayQueryKHR ||
482 cap == CapabilityRayTraversalPrimitiveCullingKHR)
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100483 {
484 ray_tracing_is_khr = true;
485 break;
486 }
487 }
488
489 if (ray_tracing_is_khr)
490 {
491 // In KHR ray tracing we pass payloads by pointer instead of location,
492 // so make sure we assign locations properly.
493 ray_tracing_khr_fixup_locations();
494 require_extension_internal("GL_EXT_ray_tracing");
495 }
496 else
497 require_extension_internal("GL_NV_ray_tracing");
Patrick Moursc74d7a42019-03-25 15:06:01 +0100498 break;
499
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +0200500 case ExecutionModelMeshEXT:
Hans-Kristian Arntzen4c345162022-09-05 12:31:22 +0200501 case ExecutionModelTaskEXT:
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +0200502 if (options.es || options.version < 450)
503 SPIRV_CROSS_THROW("Mesh shaders require GLSL 450 or above.");
504 if (!options.vulkan_semantics)
505 SPIRV_CROSS_THROW("Mesh shaders require Vulkan semantics.");
506 require_extension_internal("GL_EXT_mesh_shader");
507 break;
508
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200509 default:
510 break;
511 }
512
513 if (!pls_inputs.empty() || !pls_outputs.empty())
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100514 {
515 if (execution.model != ExecutionModelFragment)
516 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_pixel_local_storage in fragment shaders.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200517 require_extension_internal("GL_EXT_shader_pixel_local_storage");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100518 }
519
520 if (!inout_color_attachments.empty())
521 {
522 if (execution.model != ExecutionModelFragment)
523 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
524 if (options.vulkan_semantics)
525 SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +0200526
527 bool has_coherent = false;
528 bool has_incoherent = false;
529
530 for (auto &att : inout_color_attachments)
531 {
532 if (att.second)
533 has_coherent = true;
534 else
535 has_incoherent = true;
536 }
537
538 if (has_coherent)
539 require_extension_internal("GL_EXT_shader_framebuffer_fetch");
540 if (has_incoherent)
541 require_extension_internal("GL_EXT_shader_framebuffer_fetch_non_coherent");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100542 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +0200543
544 if (options.separate_shader_objects && !options.es && options.version < 410)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200545 require_extension_internal("GL_ARB_separate_shader_objects");
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200546
547 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
548 {
549 if (!options.vulkan_semantics)
550 SPIRV_CROSS_THROW("GL_EXT_buffer_reference is only supported in Vulkan GLSL.");
551 if (options.es && options.version < 320)
552 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires ESSL 320.");
553 else if (!options.es && options.version < 450)
554 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires GLSL 450.");
555 require_extension_internal("GL_EXT_buffer_reference");
556 }
557 else if (ir.addressing_model != AddressingModelLogical)
558 {
559 SPIRV_CROSS_THROW("Only Logical and PhysicalStorageBuffer64EXT addressing models are supported.");
560 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200561
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100562 // Check for nonuniform qualifier and passthrough.
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200563 // Instead of looping over all decorations to find this, just look at capabilities.
564 for (auto &cap : ir.declared_capabilities)
565 {
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200566 switch (cap)
567 {
568 case CapabilityShaderNonUniformEXT:
Mateusz Kielan127224d2020-04-18 21:21:43 +0200569 if (!options.vulkan_semantics)
570 require_extension_internal("GL_NV_gpu_shader5");
571 else
572 require_extension_internal("GL_EXT_nonuniform_qualifier");
573 break;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200574 case CapabilityRuntimeDescriptorArrayEXT:
575 if (!options.vulkan_semantics)
576 SPIRV_CROSS_THROW("GL_EXT_nonuniform_qualifier is only supported in Vulkan GLSL.");
577 require_extension_internal("GL_EXT_nonuniform_qualifier");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100578 break;
579
580 case CapabilityGeometryShaderPassthroughNV:
581 if (execution.model == ExecutionModelGeometry)
582 {
583 require_extension_internal("GL_NV_geometry_shader_passthrough");
584 execution.geometry_passthrough = true;
585 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200586 break;
587
Hans-Kristian Arntzendc940842020-12-07 12:16:02 +0100588 case CapabilityVariablePointers:
589 case CapabilityVariablePointersStorageBuffer:
590 SPIRV_CROSS_THROW("VariablePointers capability is not supported in GLSL.");
591
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200592 case CapabilityMultiView:
593 if (options.vulkan_semantics)
594 require_extension_internal("GL_EXT_multiview");
595 else
596 {
597 require_extension_internal("GL_OVR_multiview2");
598 if (options.ovr_multiview_view_count == 0)
599 SPIRV_CROSS_THROW("ovr_multiview_view_count must be non-zero when using GL_OVR_multiview2.");
600 if (get_execution_model() != ExecutionModelVertex)
601 SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
602 }
603 break;
604
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +0200605 case CapabilityRayQueryKHR:
606 if (options.es || options.version < 460 || !options.vulkan_semantics)
607 SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
608 require_extension_internal("GL_EXT_ray_query");
609 ray_tracing_is_khr = true;
610 break;
611
612 case CapabilityRayTraversalPrimitiveCullingKHR:
613 if (options.es || options.version < 460 || !options.vulkan_semantics)
614 SPIRV_CROSS_THROW("RayQuery requires Vulkan GLSL 460.");
615 require_extension_internal("GL_EXT_ray_flags_primitive_culling");
616 ray_tracing_is_khr = true;
617 break;
618
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200619 default:
620 break;
621 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200622 }
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +0200623
624 if (options.ovr_multiview_view_count)
625 {
626 if (options.vulkan_semantics)
627 SPIRV_CROSS_THROW("OVR_multiview2 cannot be used with Vulkan semantics.");
628 if (get_execution_model() != ExecutionModelVertex)
629 SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders.");
630 require_extension_internal("GL_OVR_multiview2");
631 }
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +0200632
633 // KHR one is likely to get promoted at some point, so if we don't see an explicit SPIR-V extension, assume KHR.
634 for (auto &ext : ir.declared_extensions)
635 if (ext == "SPV_NV_fragment_shader_barycentric")
636 barycentric_is_nv = true;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200637}
638
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100639void CompilerGLSL::ray_tracing_khr_fixup_locations()
640{
641 uint32_t location = 0;
642 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen66fb0bd2021-01-22 11:22:10 +0100643 // Incoming payload storage can also be used for tracing.
644 if (var.storage != StorageClassRayPayloadKHR && var.storage != StorageClassCallableDataKHR &&
645 var.storage != StorageClassIncomingRayPayloadKHR && var.storage != StorageClassIncomingCallableDataKHR)
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100646 return;
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +0100647 if (is_hidden_variable(var))
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100648 return;
649 set_decoration(var.self, DecorationLocation, location++);
650 });
651}
652
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100653string CompilerGLSL::compile()
654{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200655 ir.fixup_reserved_names();
656
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200657 if (!options.vulkan_semantics)
Mateusz Kielan127224d2020-04-18 21:21:43 +0200658 {
659 // only NV_gpu_shader5 supports divergent indexing on OpenGL, and it does so without extra qualifiers
660 backend.nonuniform_qualifier = "";
Yuwen Wuf40dba42022-08-24 11:07:12 +0800661 backend.needs_row_major_load_workaround = options.enable_row_major_load_workaround;
Mateusz Kielan127224d2020-04-18 21:21:43 +0200662 }
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200663 backend.allow_precision_qualifiers = options.vulkan_semantics || options.es;
Hans-Kristian Arntzenf708b492018-01-09 09:16:33 +0100664 backend.force_gl_in_out_block = true;
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +0100665 backend.supports_extensions = true;
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +0200666 backend.use_array_constructor = true;
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100667 backend.workgroup_size_is_hidden = true;
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +0200668 backend.requires_relaxed_precision_analysis = options.es || options.vulkan_semantics;
669 backend.support_precise_qualifier =
670 (!options.es && options.version >= 400) || (options.es && options.version >= 320);
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +0200671
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +0200672 if (is_legacy_es())
673 backend.support_case_fallthrough = false;
674
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200675 // Scan the SPIR-V to find trivial uses of extensions.
Hans-Kristian Arntzen4ab5bbb2022-03-10 15:38:57 +0100676 fixup_anonymous_struct_names();
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200677 fixup_type_alias();
678 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200679 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200680 find_static_extensions();
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +0100681 fixup_image_load_store_access();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100682 update_active_builtins();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +0100683 analyze_image_and_sampler_usage();
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200684 analyze_interlocked_resource_usage();
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100685 if (!inout_color_attachments.empty())
686 emit_inout_fragment_outputs_copy_to_subpass_inputs();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200687
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200688 // Shaders might cast unrelated data to pointers of non-block types.
689 // Find all such instances and make sure we can cast the pointers to a synthesized block type.
690 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
691 analyze_non_block_pointer_types();
692
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200693 uint32_t pass_count = 0;
694 do
695 {
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +0100696 reset(pass_count);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100697
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200698 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100699
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200700 emit_header();
701 emit_resources();
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200702 emit_extension_workarounds(get_execution_model());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100703
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200704 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100705
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200706 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200707 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100708
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200709 // Implement the interlocked wrapper function at the end.
710 // The body was implemented in lieu of main().
711 if (interlocked_is_complex)
712 {
713 statement("void main()");
714 begin_scope();
715 statement("// Interlocks were used in a way not compatible with GLSL, this is very slow.");
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330716 statement("SPIRV_Cross_beginInvocationInterlock();");
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200717 statement("spvMainInterlockedBody();");
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330718 statement("SPIRV_Cross_endInvocationInterlock();");
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200719 end_scope();
720 }
721
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100722 // Entry point in GLSL is always main().
723 get_entry_point().name = "main";
724
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200725 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100726}
727
Bill Hollingsc5c07362016-11-27 12:34:04 -0500728std::string CompilerGLSL::get_partial_source()
729{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200730 return buffer.str();
Bill Hollingsc5c07362016-11-27 12:34:04 -0500731}
732
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200733void CompilerGLSL::build_workgroup_size(SmallVector<string> &arguments, const SpecializationConstant &wg_x,
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +0100734 const SpecializationConstant &wg_y, const SpecializationConstant &wg_z)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100735{
736 auto &execution = get_entry_point();
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100737 bool builtin_workgroup = execution.workgroup_size.constant != 0;
738 bool use_local_size_id = !builtin_workgroup && execution.flags.get(ExecutionModeLocalSizeId);
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100739
740 if (wg_x.id)
741 {
742 if (options.vulkan_semantics)
743 arguments.push_back(join("local_size_x_id = ", wg_x.constant_id));
744 else
745 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(wg_x.id).specialization_constant_macro_name));
746 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100747 else if (use_local_size_id && execution.workgroup_size.id_x)
748 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(execution.workgroup_size.id_x).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100749 else
750 arguments.push_back(join("local_size_x = ", execution.workgroup_size.x));
751
752 if (wg_y.id)
753 {
754 if (options.vulkan_semantics)
755 arguments.push_back(join("local_size_y_id = ", wg_y.constant_id));
756 else
757 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(wg_y.id).specialization_constant_macro_name));
758 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100759 else if (use_local_size_id && execution.workgroup_size.id_y)
760 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(execution.workgroup_size.id_y).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100761 else
762 arguments.push_back(join("local_size_y = ", execution.workgroup_size.y));
763
764 if (wg_z.id)
765 {
766 if (options.vulkan_semantics)
767 arguments.push_back(join("local_size_z_id = ", wg_z.constant_id));
768 else
769 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(wg_z.id).specialization_constant_macro_name));
770 }
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100771 else if (use_local_size_id && execution.workgroup_size.id_z)
772 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(execution.workgroup_size.id_z).scalar()));
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100773 else
774 arguments.push_back(join("local_size_z = ", execution.workgroup_size.z));
775}
776
crissdb52e272020-10-08 12:14:52 +0200777void CompilerGLSL::request_subgroup_feature(ShaderSubgroupSupportHelper::Feature feature)
778{
779 if (options.vulkan_semantics)
780 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200781 auto khr_extension = ShaderSubgroupSupportHelper::get_KHR_extension_for_feature(feature);
782 require_extension_internal(ShaderSubgroupSupportHelper::get_extension_name(khr_extension));
crissdb52e272020-10-08 12:14:52 +0200783 }
784 else
785 {
786 if (!shader_subgroup_supporter.is_feature_requested(feature))
787 force_recompile();
788 shader_subgroup_supporter.request_feature(feature);
789 }
790}
791
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100792void CompilerGLSL::emit_header()
793{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200794 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200795 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100796
Ben Claytone9621822017-10-09 10:33:42 +0100797 if (!options.es && options.version < 420)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200798 {
Ben Claytone9621822017-10-09 10:33:42 +0100799 // Needed for binding = # on UBOs, etc.
800 if (options.enable_420pack_extension)
801 {
802 statement("#ifdef GL_ARB_shading_language_420pack");
803 statement("#extension GL_ARB_shading_language_420pack : require");
804 statement("#endif");
805 }
806 // Needed for: layout(early_fragment_tests) in;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100807 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200808 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200809 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100810
Chip Davis1df47db2019-07-10 22:42:39 -0500811 // Needed for: layout(post_depth_coverage) in;
812 if (execution.flags.get(ExecutionModePostDepthCoverage))
813 require_extension_internal("GL_ARB_post_depth_coverage");
814
Chip Davis2eff4202019-08-04 00:07:20 -0500815 // Needed for: layout({pixel,sample}_interlock_[un]ordered) in;
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330816 bool interlock_used = execution.flags.get(ExecutionModePixelInterlockOrderedEXT) ||
817 execution.flags.get(ExecutionModePixelInterlockUnorderedEXT) ||
818 execution.flags.get(ExecutionModeSampleInterlockOrderedEXT) ||
819 execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT);
820
821 if (interlock_used)
Chip Davis2eff4202019-08-04 00:07:20 -0500822 {
823 if (options.es)
824 {
825 if (options.version < 310)
826 SPIRV_CROSS_THROW("At least ESSL 3.10 required for fragment shader interlock.");
827 require_extension_internal("GL_NV_fragment_shader_interlock");
828 }
829 else
830 {
831 if (options.version < 420)
832 require_extension_internal("GL_ARB_shader_image_load_store");
833 require_extension_internal("GL_ARB_fragment_shader_interlock");
834 }
835 }
836
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200837 for (auto &ext : forced_extensions)
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200838 {
Hans-Kristian Arntzendf21a992022-06-07 15:39:37 +0200839 if (ext == "GL_ARB_gpu_shader_int64")
840 {
841 statement("#if defined(GL_ARB_gpu_shader_int64)");
842 statement("#extension GL_ARB_gpu_shader_int64 : require");
843 if (!options.vulkan_semantics || options.es)
844 {
845 statement("#elif defined(GL_NV_gpu_shader5)");
846 statement("#extension GL_NV_gpu_shader5 : require");
847 }
848 statement("#else");
849 statement("#error No extension available for 64-bit integers.");
850 statement("#endif");
851 }
852 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16")
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200853 {
854 // Special case, this extension has a potential fallback to another vendor extension in normal GLSL.
855 // GL_AMD_gpu_shader_half_float is a superset, so try that first.
856 statement("#if defined(GL_AMD_gpu_shader_half_float)");
857 statement("#extension GL_AMD_gpu_shader_half_float : require");
Chip Davis1fb27b42018-10-31 09:43:03 -0500858 if (!options.vulkan_semantics)
859 {
860 statement("#elif defined(GL_NV_gpu_shader5)");
861 statement("#extension GL_NV_gpu_shader5 : require");
862 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100863 else
864 {
865 statement("#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)");
866 statement("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
867 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200868 statement("#else");
869 statement("#error No extension available for FP16.");
870 statement("#endif");
871 }
Hans-Kristian Arntzendf21a992022-06-07 15:39:37 +0200872 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int8")
873 {
874 if (options.vulkan_semantics)
875 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require");
876 else
877 {
878 statement("#if defined(GL_EXT_shader_explicit_arithmetic_types_int8)");
879 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require");
880 statement("#elif defined(GL_NV_gpu_shader5)");
881 statement("#extension GL_NV_gpu_shader5 : require");
882 statement("#else");
883 statement("#error No extension available for Int8.");
884 statement("#endif");
885 }
886 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100887 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16")
Chip Davis1fb27b42018-10-31 09:43:03 -0500888 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100889 if (options.vulkan_semantics)
890 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
891 else
892 {
Hans-Kristian Arntzendf21a992022-06-07 15:39:37 +0200893 statement("#if defined(GL_EXT_shader_explicit_arithmetic_types_int16)");
894 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
895 statement("#elif defined(GL_AMD_gpu_shader_int16)");
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100896 statement("#extension GL_AMD_gpu_shader_int16 : require");
Przemog10408c592021-05-05 21:41:53 +0200897 statement("#elif defined(GL_NV_gpu_shader5)");
898 statement("#extension GL_NV_gpu_shader5 : require");
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100899 statement("#else");
900 statement("#error No extension available for Int16.");
901 statement("#endif");
902 }
Chip Davis1fb27b42018-10-31 09:43:03 -0500903 }
Chip Davis5fe1ecc2019-08-02 21:02:05 -0500904 else if (ext == "GL_ARB_post_depth_coverage")
905 {
906 if (options.es)
907 statement("#extension GL_EXT_post_depth_coverage : require");
908 else
909 {
910 statement("#if defined(GL_ARB_post_depth_coverge)");
911 statement("#extension GL_ARB_post_depth_coverage : require");
912 statement("#else");
913 statement("#extension GL_EXT_post_depth_coverage : require");
914 statement("#endif");
915 }
916 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +0200917 else if (!options.vulkan_semantics && ext == "GL_ARB_shader_draw_parameters")
918 {
919 // Soft-enable this extension on plain GLSL.
920 statement("#ifdef ", ext);
921 statement("#extension ", ext, " : enable");
922 statement("#endif");
923 }
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +0200924 else if (ext == "GL_EXT_control_flow_attributes")
925 {
926 // These are just hints so we can conditionally enable and fallback in the shader.
927 statement("#if defined(GL_EXT_control_flow_attributes)");
928 statement("#extension GL_EXT_control_flow_attributes : require");
929 statement("#define SPIRV_CROSS_FLATTEN [[flatten]]");
930 statement("#define SPIRV_CROSS_BRANCH [[dont_flatten]]");
931 statement("#define SPIRV_CROSS_UNROLL [[unroll]]");
932 statement("#define SPIRV_CROSS_LOOP [[dont_unroll]]");
933 statement("#else");
934 statement("#define SPIRV_CROSS_FLATTEN");
935 statement("#define SPIRV_CROSS_BRANCH");
936 statement("#define SPIRV_CROSS_UNROLL");
937 statement("#define SPIRV_CROSS_LOOP");
938 statement("#endif");
939 }
Erfan Ahmadi43eecb22021-10-19 09:39:55 +0330940 else if (ext == "GL_NV_fragment_shader_interlock")
941 {
942 statement("#extension GL_NV_fragment_shader_interlock : require");
943 statement("#define SPIRV_Cross_beginInvocationInterlock() beginInvocationInterlockNV()");
944 statement("#define SPIRV_Cross_endInvocationInterlock() endInvocationInterlockNV()");
945 }
946 else if (ext == "GL_ARB_fragment_shader_interlock")
947 {
948 statement("#ifdef GL_ARB_fragment_shader_interlock");
949 statement("#extension GL_ARB_fragment_shader_interlock : enable");
950 statement("#define SPIRV_Cross_beginInvocationInterlock() beginInvocationInterlockARB()");
951 statement("#define SPIRV_Cross_endInvocationInterlock() endInvocationInterlockARB()");
952 statement("#elif defined(GL_INTEL_fragment_shader_ordering)");
953 statement("#extension GL_INTEL_fragment_shader_ordering : enable");
954 statement("#define SPIRV_Cross_beginInvocationInterlock() beginFragmentShaderOrderingINTEL()");
955 statement("#define SPIRV_Cross_endInvocationInterlock()");
956 statement("#endif");
957 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200958 else
959 statement("#extension ", ext, " : require");
960 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100961
crissdb52e272020-10-08 12:14:52 +0200962 if (!options.vulkan_semantics)
963 {
964 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200965 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +0200966
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200967 for (uint32_t feature_index = 0; feature_index < Supp::FeatureCount; feature_index++)
crissdb52e272020-10-08 12:14:52 +0200968 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200969 auto feature = static_cast<Supp::Feature>(feature_index);
crissdb52e272020-10-08 12:14:52 +0200970 if (!shader_subgroup_supporter.is_feature_requested(feature))
971 continue;
972
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200973 auto exts = Supp::get_candidates_for_feature(feature, result);
crissdb52e272020-10-08 12:14:52 +0200974 if (exts.empty())
975 continue;
976
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200977 statement("");
crissdb52e272020-10-08 12:14:52 +0200978
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200979 for (auto &ext : exts)
980 {
981 const char *name = Supp::get_extension_name(ext);
982 const char *extra_predicate = Supp::get_extra_required_extension_predicate(ext);
983 auto extra_names = Supp::get_extra_required_extension_names(ext);
984 statement(&ext != &exts.front() ? "#elif" : "#if", " defined(", name, ")",
985 (*extra_predicate != '\0' ? " && " : ""), extra_predicate);
986 for (const auto &e : extra_names)
crissdb52e272020-10-08 12:14:52 +0200987 statement("#extension ", e, " : enable");
988 statement("#extension ", name, " : require");
989 }
990
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200991 if (!Supp::can_feature_be_implemented_without_extensions(feature))
crissdb52e272020-10-08 12:14:52 +0200992 {
993 statement("#else");
994 statement("#error No extensions available to emulate requested subgroup feature.");
995 }
996
997 statement("#endif");
998 }
999 }
1000
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +02001001 for (auto &header : header_lines)
1002 statement(header);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001003
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001004 SmallVector<string> inputs;
1005 SmallVector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001006
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001007 switch (execution.model)
1008 {
Hans-Kristian Arntzend75666b2021-06-28 12:55:37 +02001009 case ExecutionModelVertex:
1010 if (options.ovr_multiview_view_count)
1011 inputs.push_back(join("num_views = ", options.ovr_multiview_view_count));
1012 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001013 case ExecutionModelGeometry:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001014 if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001015 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001016 if (execution.flags.get(ExecutionModeInputPoints))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001017 inputs.push_back("points");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001018 if (execution.flags.get(ExecutionModeInputLines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001019 inputs.push_back("lines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001020 if (execution.flags.get(ExecutionModeInputLinesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001021 inputs.push_back("lines_adjacency");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001022 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001023 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001024 if (execution.flags.get(ExecutionModeInputTrianglesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001025 inputs.push_back("triangles_adjacency");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001026
1027 if (!execution.geometry_passthrough)
1028 {
1029 // For passthrough, these are implies and cannot be declared in shader.
1030 outputs.push_back(join("max_vertices = ", execution.output_vertices));
1031 if (execution.flags.get(ExecutionModeOutputTriangleStrip))
1032 outputs.push_back("triangle_strip");
1033 if (execution.flags.get(ExecutionModeOutputPoints))
1034 outputs.push_back("points");
1035 if (execution.flags.get(ExecutionModeOutputLineStrip))
1036 outputs.push_back("line_strip");
1037 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001038 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001039
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001040 case ExecutionModelTessellationControl:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001041 if (execution.flags.get(ExecutionModeOutputVertices))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001042 outputs.push_back(join("vertices = ", execution.output_vertices));
1043 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001044
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001045 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001046 if (execution.flags.get(ExecutionModeQuads))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001047 inputs.push_back("quads");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001048 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001049 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001050 if (execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001051 inputs.push_back("isolines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001052 if (execution.flags.get(ExecutionModePointMode))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001053 inputs.push_back("point_mode");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001054
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001055 if (!execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001056 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001057 if (execution.flags.get(ExecutionModeVertexOrderCw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001058 inputs.push_back("cw");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001059 if (execution.flags.get(ExecutionModeVertexOrderCcw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +02001060 inputs.push_back("ccw");
1061 }
1062
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001063 if (execution.flags.get(ExecutionModeSpacingFractionalEven))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001064 inputs.push_back("fractional_even_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001065 if (execution.flags.get(ExecutionModeSpacingFractionalOdd))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001066 inputs.push_back("fractional_odd_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001067 if (execution.flags.get(ExecutionModeSpacingEqual))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001068 inputs.push_back("equal_spacing");
1069 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001070
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001071 case ExecutionModelGLCompute:
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02001072 case ExecutionModelTaskEXT:
1073 case ExecutionModelMeshEXT:
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001074 {
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01001075 if (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId))
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001076 {
1077 SpecializationConstant wg_x, wg_y, wg_z;
1078 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
1079
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001080 // If there are any spec constants on legacy GLSL, defer declaration, we need to set up macro
1081 // declarations before we can emit the work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001082 if (options.vulkan_semantics ||
1083 ((wg_x.id == ConstantID(0)) && (wg_y.id == ConstantID(0)) && (wg_z.id == ConstantID(0))))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001084 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001085 }
1086 else
1087 {
1088 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
1089 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
1090 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
1091 }
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02001092
1093 if (execution.model == ExecutionModelMeshEXT)
1094 {
1095 outputs.push_back(join("max_vertices = ", execution.output_vertices));
1096 outputs.push_back(join("max_primitives = ", execution.output_primitives));
1097 if (execution.flags.get(ExecutionModeOutputTrianglesEXT))
1098 outputs.push_back("triangles");
1099 else if (execution.flags.get(ExecutionModeOutputLinesEXT))
1100 outputs.push_back("lines");
1101 else if (execution.flags.get(ExecutionModeOutputPoints))
1102 outputs.push_back("points");
1103 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001104 break;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001105 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001106
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001107 case ExecutionModelFragment:
1108 if (options.es)
1109 {
1110 switch (options.fragment.default_float_precision)
1111 {
1112 case Options::Lowp:
1113 statement("precision lowp float;");
1114 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001115
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001116 case Options::Mediump:
1117 statement("precision mediump float;");
1118 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001119
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001120 case Options::Highp:
1121 statement("precision highp float;");
1122 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001123
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001124 default:
1125 break;
1126 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001128 switch (options.fragment.default_int_precision)
1129 {
1130 case Options::Lowp:
1131 statement("precision lowp int;");
1132 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001133
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001134 case Options::Mediump:
1135 statement("precision mediump int;");
1136 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001137
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001138 case Options::Highp:
1139 statement("precision highp int;");
1140 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001141
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001142 default:
1143 break;
1144 }
1145 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001146
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001147 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001148 inputs.push_back("early_fragment_tests");
Chip Davis1df47db2019-07-10 22:42:39 -05001149 if (execution.flags.get(ExecutionModePostDepthCoverage))
1150 inputs.push_back("post_depth_coverage");
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +01001151
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301152 if (interlock_used)
1153 statement("#if defined(GL_ARB_fragment_shader_interlock)");
1154
Chip Davis2eff4202019-08-04 00:07:20 -05001155 if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301156 statement("layout(pixel_interlock_ordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001157 else if (execution.flags.get(ExecutionModePixelInterlockUnorderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301158 statement("layout(pixel_interlock_unordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001159 else if (execution.flags.get(ExecutionModeSampleInterlockOrderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301160 statement("layout(sample_interlock_ordered) in;");
Chip Davis2eff4202019-08-04 00:07:20 -05001161 else if (execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT))
Erfan Ahmadi43eecb22021-10-19 09:39:55 +03301162 statement("layout(sample_interlock_unordered) in;");
1163
1164 if (interlock_used)
1165 {
1166 statement("#elif !defined(GL_INTEL_fragment_shader_ordering)");
1167 statement("#error Fragment Shader Interlock/Ordering extension missing!");
1168 statement("#endif");
1169 }
Chip Davis2eff4202019-08-04 00:07:20 -05001170
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +01001171 if (!options.es && execution.flags.get(ExecutionModeDepthGreater))
1172 statement("layout(depth_greater) out float gl_FragDepth;");
1173 else if (!options.es && execution.flags.get(ExecutionModeDepthLess))
1174 statement("layout(depth_less) out float gl_FragDepth;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001175
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001176 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001178 default:
1179 break;
1180 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001181
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +02001182 for (auto &cap : ir.declared_capabilities)
1183 if (cap == CapabilityRayTraversalPrimitiveCullingKHR)
1184 statement("layout(primitive_culling);");
1185
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001186 if (!inputs.empty())
1187 statement("layout(", merge(inputs), ") in;");
1188 if (!outputs.empty())
1189 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001190
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001191 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001192}
1193
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +01001194bool CompilerGLSL::type_is_empty(const SPIRType &type)
1195{
1196 return type.basetype == SPIRType::Struct && type.member_types.empty();
1197}
1198
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001199void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001200{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001201 // Struct types can be stamped out multiple times
1202 // with just different offsets, matrix layouts, etc ...
1203 // Type-punning with these types is legal, which complicates things
1204 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzen294259e2018-03-05 16:27:04 +01001205 // 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 +02001206 if (type.type_alias != TypeID(0) &&
1207 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001208 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001209
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001210 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001211 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001212
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001213 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001214 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001215
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001216 type.member_name_cache.clear();
1217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001218 uint32_t i = 0;
1219 bool emitted = false;
1220 for (auto &member : type.member_types)
1221 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001222 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05001223 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001224 i++;
1225 emitted = true;
1226 }
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02001227
1228 // Don't declare empty structs in GLSL, this is not allowed.
1229 if (type_is_empty(type) && !backend.supports_empty_struct)
1230 {
1231 statement("int empty_struct_member;");
1232 emitted = true;
1233 }
1234
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +02001235 if (has_extended_decoration(type.self, SPIRVCrossDecorationPaddingTarget))
1236 emit_struct_padding_target(type);
1237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001238 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001240 if (emitted)
1241 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001242}
1243
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001244string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001245{
1246 string res;
1247 //if (flags & (1ull << DecorationSmooth))
1248 // res += "smooth ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001249 if (flags.get(DecorationFlat))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001250 res += "flat ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001251 if (flags.get(DecorationNoPerspective))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001252 res += "noperspective ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001253 if (flags.get(DecorationCentroid))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001254 res += "centroid ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001255 if (flags.get(DecorationPatch))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001256 res += "patch ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001257 if (flags.get(DecorationSample))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001258 res += "sample ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001259 if (flags.get(DecorationInvariant))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001260 res += "invariant ";
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02001261 if (flags.get(DecorationPerPrimitiveEXT))
1262 res += "perprimitiveEXT ";
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001263
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001264 if (flags.get(DecorationExplicitInterpAMD))
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001265 {
1266 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +01001267 res += "__explicitInterpAMD ";
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001268 }
1269
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02001270 if (flags.get(DecorationPerVertexKHR))
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001271 {
1272 if (options.es && options.version < 320)
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02001273 SPIRV_CROSS_THROW("pervertexEXT requires ESSL 320.");
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001274 else if (!options.es && options.version < 450)
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02001275 SPIRV_CROSS_THROW("pervertexEXT requires GLSL 450.");
1276
1277 if (barycentric_is_nv)
1278 {
1279 require_extension_internal("GL_NV_fragment_shader_barycentric");
1280 res += "pervertexNV ";
1281 }
1282 else
1283 {
1284 require_extension_internal("GL_EXT_fragment_shader_barycentric");
1285 res += "pervertexEXT ";
1286 }
Hans-Kristian Arntzen206ee8f2021-06-30 15:58:13 +02001287 }
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001288
1289 return res;
1290}
1291
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001292string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
1293{
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001294 if (is_legacy())
1295 return "";
1296
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001297 bool is_block = has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001298 if (!is_block)
1299 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001300
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001301 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001302 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +02001303 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001304 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001305
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001306 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001307
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001308 if (has_member_decoration(type.self, index, DecorationPassthroughNV))
1309 attr.push_back("passthrough");
1310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001311 // We can only apply layouts on members in block interfaces.
1312 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
1313 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
1314 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
1315 //
1316 // We would like to go from (SPIR-V style):
1317 //
1318 // struct Foo { layout(row_major) mat4 matrix; };
1319 // buffer UBO { Foo foo; };
1320 //
1321 // to
1322 //
1323 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
1324 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
1325 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001326
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001327 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001328 attr.push_back("row_major");
1329 // We don't emit any global layouts, so column_major is default.
1330 //if (flags & (1ull << DecorationColMajor))
1331 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001332
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001333 if (dec.decoration_flags.get(DecorationLocation) && can_use_io_location(type.storage, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001334 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001335
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001336 // Can only declare component if we can declare location.
1337 if (dec.decoration_flags.get(DecorationComponent) && can_use_io_location(type.storage, true))
1338 {
1339 if (!options.es)
1340 {
1341 if (options.version < 440 && options.version >= 140)
1342 require_extension_internal("GL_ARB_enhanced_layouts");
1343 else if (options.version < 140)
1344 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
1345 attr.push_back(join("component = ", dec.component));
1346 }
1347 else
1348 SPIRV_CROSS_THROW("Component decoration is not supported in ES targets.");
1349 }
1350
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001351 // 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 +02001352 // This is only done selectively in GLSL as needed.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02001353 if (has_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset) &&
1354 dec.decoration_flags.get(DecorationOffset))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001355 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001356 else if (type.storage == StorageClassOutput && dec.decoration_flags.get(DecorationOffset))
1357 attr.push_back(join("xfb_offset = ", dec.offset));
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001358
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001359 if (attr.empty())
1360 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001361
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001362 string res = "layout(";
1363 res += merge(attr);
1364 res += ") ";
1365 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001366}
1367
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001368const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001369{
Brad Davis76204002018-06-20 10:25:38 -07001370 if (options.es && is_desktop_only_format(format))
1371 SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001372
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001373 switch (format)
1374 {
1375 case ImageFormatRgba32f:
1376 return "rgba32f";
1377 case ImageFormatRgba16f:
1378 return "rgba16f";
1379 case ImageFormatR32f:
1380 return "r32f";
1381 case ImageFormatRgba8:
1382 return "rgba8";
1383 case ImageFormatRgba8Snorm:
1384 return "rgba8_snorm";
1385 case ImageFormatRg32f:
1386 return "rg32f";
1387 case ImageFormatRg16f:
1388 return "rg16f";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001389 case ImageFormatRgba32i:
1390 return "rgba32i";
1391 case ImageFormatRgba16i:
1392 return "rgba16i";
1393 case ImageFormatR32i:
1394 return "r32i";
1395 case ImageFormatRgba8i:
1396 return "rgba8i";
1397 case ImageFormatRg32i:
1398 return "rg32i";
1399 case ImageFormatRg16i:
1400 return "rg16i";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001401 case ImageFormatRgba32ui:
1402 return "rgba32ui";
1403 case ImageFormatRgba16ui:
1404 return "rgba16ui";
1405 case ImageFormatR32ui:
1406 return "r32ui";
1407 case ImageFormatRgba8ui:
1408 return "rgba8ui";
1409 case ImageFormatRg32ui:
1410 return "rg32ui";
1411 case ImageFormatRg16ui:
1412 return "rg16ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001413 case ImageFormatR11fG11fB10f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001414 return "r11f_g11f_b10f";
1415 case ImageFormatR16f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001416 return "r16f";
1417 case ImageFormatRgb10A2:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001418 return "rgb10_a2";
1419 case ImageFormatR8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001420 return "r8";
1421 case ImageFormatRg8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001422 return "rg8";
1423 case ImageFormatR16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001424 return "r16";
1425 case ImageFormatRg16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001426 return "rg16";
1427 case ImageFormatRgba16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001428 return "rgba16";
1429 case ImageFormatR16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001430 return "r16_snorm";
1431 case ImageFormatRg16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001432 return "rg16_snorm";
1433 case ImageFormatRgba16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001434 return "rgba16_snorm";
1435 case ImageFormatR8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001436 return "r8_snorm";
1437 case ImageFormatRg8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001438 return "rg8_snorm";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001439 case ImageFormatR8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001440 return "r8ui";
1441 case ImageFormatRg8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001442 return "rg8ui";
1443 case ImageFormatR16ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001444 return "r16ui";
1445 case ImageFormatRgb10a2ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001446 return "rgb10_a2ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001447 case ImageFormatR8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001448 return "r8i";
1449 case ImageFormatRg8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001450 return "rg8i";
1451 case ImageFormatR16i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001452 return "r16i";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001453 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001454 case ImageFormatUnknown:
1455 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001456 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001457}
1458
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001459uint32_t CompilerGLSL::type_to_packed_base_size(const SPIRType &type, BufferPackingStandard)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001460{
1461 switch (type.basetype)
1462 {
1463 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02001464 case SPIRType::Int64:
1465 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001466 return 8;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001467 case SPIRType::Float:
1468 case SPIRType::Int:
1469 case SPIRType::UInt:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001470 return 4;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001471 case SPIRType::Half:
Chip Davis117ccf42018-11-01 17:20:07 -05001472 case SPIRType::Short:
1473 case SPIRType::UShort:
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001474 return 2;
Chip Davis117ccf42018-11-01 17:20:07 -05001475 case SPIRType::SByte:
1476 case SPIRType::UByte:
1477 return 1;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001478
1479 default:
1480 SPIRV_CROSS_THROW("Unrecognized type in type_to_packed_base_size.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001481 }
1482}
1483
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001484uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bitset &flags,
1485 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001486{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001487 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1488 // and is 64-bit.
1489 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1490 {
1491 if (!type.pointer)
1492 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1493
1494 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1495 {
1496 if (packing_is_vec4_padded(packing) && type_is_array_of_pointers(type))
1497 return 16;
1498 else
1499 return 8;
1500 }
1501 else
1502 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1503 }
1504
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001505 if (!type.array.empty())
1506 {
1507 uint32_t minimum_alignment = 1;
1508 if (packing_is_vec4_padded(packing))
1509 minimum_alignment = 16;
1510
1511 auto *tmp = &get<SPIRType>(type.parent_type);
1512 while (!tmp->array.empty())
1513 tmp = &get<SPIRType>(tmp->parent_type);
1514
1515 // Get the alignment of the base type, then maybe round up.
1516 return max(minimum_alignment, type_to_packed_alignment(*tmp, flags, packing));
1517 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001518
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001519 if (type.basetype == SPIRType::Struct)
1520 {
1521 // Rule 9. Structs alignments are maximum alignment of its members.
Hans-Kristian Arntzen8c632da2019-01-28 11:02:28 +01001522 uint32_t alignment = 1;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001523 for (uint32_t i = 0; i < type.member_types.size(); i++)
1524 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001525 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +02001526 alignment =
1527 max(alignment, type_to_packed_alignment(get<SPIRType>(type.member_types[i]), member_flags, packing));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001528 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001529
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001530 // In std140, struct alignment is rounded up to 16.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001531 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001532 alignment = max(alignment, 16u);
1533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001534 return alignment;
1535 }
1536 else
1537 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001538 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1539
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001540 // Alignment requirement for scalar block layout is always the alignment for the most basic component.
1541 if (packing_is_scalar(packing))
1542 return base_alignment;
1543
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001544 // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle
1545 // a vec4, this is handled outside since that part knows our current offset.
1546 if (type.columns == 1 && packing_is_hlsl(packing))
1547 return base_alignment;
1548
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001549 // From 7.6.2.2 in GL 4.5 core spec.
1550 // Rule 1
1551 if (type.vecsize == 1 && type.columns == 1)
1552 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001553
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001554 // Rule 2
1555 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
1556 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001557
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001558 // Rule 3
1559 if (type.vecsize == 3 && type.columns == 1)
1560 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001561
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001562 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001563
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001564 // Rule 5. Column-major matrices are stored as arrays of
1565 // vectors.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001566 if (flags.get(DecorationColMajor) && type.columns > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001567 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001568 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001569 return 4 * base_alignment;
1570 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001571 return 4 * base_alignment;
1572 else
1573 return type.vecsize * base_alignment;
1574 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001576 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001577
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001578 // Rule 7.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001579 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001580 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001581 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001582 return 4 * base_alignment;
1583 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001584 return 4 * base_alignment;
1585 else
1586 return type.columns * base_alignment;
1587 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001588
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001589 // Rule 8 implied.
1590 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001591
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001592 SPIRV_CROSS_THROW("Did not find suitable rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001593}
1594
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001595uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, const Bitset &flags,
1596 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001597{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001598 // Array stride is equal to aligned size of the underlying type.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001599 uint32_t parent = type.parent_type;
1600 assert(parent);
1601
1602 auto &tmp = get<SPIRType>(parent);
1603
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001604 uint32_t size = type_to_packed_size(tmp, flags, packing);
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001605 uint32_t alignment = type_to_packed_alignment(type, flags, packing);
1606 return (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001607}
1608
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001609uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001610{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001611 if (!type.array.empty())
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001612 {
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001613 uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing);
1614
1615 // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size,
1616 // so that it is possible to pack other vectors into the last element.
1617 if (packing_is_hlsl(packing) && type.basetype != SPIRType::Struct)
1618 packed_size -= (4 - type.vecsize) * (type.width / 8);
1619
1620 return packed_size;
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001621 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001622
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001623 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1624 // and is 64-bit.
1625 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1626 {
1627 if (!type.pointer)
1628 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1629
1630 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1631 return 8;
1632 else
1633 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1634 }
1635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001636 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001637
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001638 if (type.basetype == SPIRType::Struct)
1639 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001640 uint32_t pad_alignment = 1;
1641
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001642 for (uint32_t i = 0; i < type.member_types.size(); i++)
1643 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001644 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001645 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001646
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001647 uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
1648 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001649
1650 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1651 // GL 4.5 spec, 7.6.2.2.
1652 if (member_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001653 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001654 else
1655 pad_alignment = 1;
1656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001657 size = (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001658 size += type_to_packed_size(member_type, member_flags, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001659 }
1660 }
1661 else
1662 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001663 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1664
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001665 if (packing_is_scalar(packing))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001666 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001667 size = type.vecsize * type.columns * base_alignment;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001668 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001669 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001670 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001671 if (type.columns == 1)
1672 size = type.vecsize * base_alignment;
1673
1674 if (flags.get(DecorationColMajor) && type.columns > 1)
1675 {
1676 if (packing_is_vec4_padded(packing))
1677 size = type.columns * 4 * base_alignment;
1678 else if (type.vecsize == 3)
1679 size = type.columns * 4 * base_alignment;
1680 else
1681 size = type.columns * type.vecsize * base_alignment;
1682 }
1683
1684 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
1685 {
1686 if (packing_is_vec4_padded(packing))
1687 size = type.vecsize * 4 * base_alignment;
1688 else if (type.columns == 3)
1689 size = type.vecsize * 4 * base_alignment;
1690 else
1691 size = type.vecsize * type.columns * base_alignment;
1692 }
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001693
1694 // For matrices in HLSL, the last element has a size which depends on its vector size,
1695 // so that it is possible to pack other vectors into the last element.
1696 if (packing_is_hlsl(packing) && type.columns > 1)
1697 size -= (4 - type.vecsize) * (type.width / 8);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001698 }
1699 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001700
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001701 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001702}
1703
msiglreithd096f5c2017-11-27 16:00:56 +01001704bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001705 uint32_t *failed_validation_index, uint32_t start_offset,
1706 uint32_t end_offset)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001707{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001708 // This is very tricky and error prone, but try to be exhaustive and correct here.
1709 // SPIR-V doesn't directly say if we're using std430 or std140.
1710 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
1711 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
1712 // 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).
1713 //
1714 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
1715 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
1716 //
1717 // The only two differences between std140 and std430 are related to padding alignment/array stride
1718 // in arrays and structs. In std140 they take minimum vec4 alignment.
1719 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001720
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001721 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001722 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001723
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001724 bool is_top_level_block =
1725 has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
1726
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001727 for (uint32_t i = 0; i < type.member_types.size(); i++)
1728 {
1729 auto &memb_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001730 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001731
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001732 // Verify alignment rules.
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001733 uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001734
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001735 // This is a rather dirty workaround to deal with some cases of OpSpecConstantOp used as array size, e.g:
1736 // layout(constant_id = 0) const int s = 10;
1737 // const int S = s + 5; // SpecConstantOp
1738 // buffer Foo { int data[S]; }; // <-- Very hard for us to deduce a fixed value here,
1739 // we would need full implementation of compile-time constant folding. :(
1740 // If we are the last member of a struct, there might be cases where the actual size of that member is irrelevant
1741 // for our analysis (e.g. unsized arrays).
1742 // This lets us simply ignore that there are spec constant op sized arrays in our buffers.
1743 // Querying size of this member will fail, so just don't call it unless we have to.
1744 //
1745 // This is likely "best effort" we can support without going into unacceptably complicated workarounds.
1746 bool member_can_be_unsized =
1747 is_top_level_block && size_t(i + 1) == type.member_types.size() && !memb_type.array.empty();
1748
1749 uint32_t packed_size = 0;
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001750 if (!member_can_be_unsized || packing_is_hlsl(packing))
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001751 packed_size = type_to_packed_size(memb_type, member_flags, packing);
1752
1753 // 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 +02001754 if (packing_is_hlsl(packing))
1755 {
1756 // If a member straddles across a vec4 boundary, alignment is actually vec4.
1757 uint32_t begin_word = offset / 16;
1758 uint32_t end_word = (offset + packed_size - 1) / 16;
1759 if (begin_word != end_word)
1760 packed_alignment = max(packed_alignment, 16u);
1761 }
1762
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001763 uint32_t actual_offset = type_struct_member_offset(type, i);
1764 // Field is not in the specified range anymore and we can ignore any further fields.
1765 if (actual_offset >= end_offset)
1766 break;
1767
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001768 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001769 offset = (offset + alignment - 1) & ~(alignment - 1);
1770
1771 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1772 // GL 4.5 spec, 7.6.2.2.
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001773 if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001774 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001775 else
1776 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001777
msiglreithd096f5c2017-11-27 16:00:56 +01001778 // Only care about packing if we are in the given range
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001779 if (actual_offset >= start_offset)
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001780 {
msiglreithd096f5c2017-11-27 16:00:56 +01001781 // We only care about offsets in std140, std430, etc ...
1782 // For EnhancedLayout variants, we have the flexibility to choose our own offsets.
1783 if (!packing_has_flexible_offset(packing))
1784 {
msiglreithd096f5c2017-11-27 16:00:56 +01001785 if (actual_offset != offset) // This cannot be the packing we're looking for.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001786 {
1787 if (failed_validation_index)
1788 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001789 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001790 }
msiglreithd096f5c2017-11-27 16:00:56 +01001791 }
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001792 else if ((actual_offset & (alignment - 1)) != 0)
1793 {
1794 // We still need to verify that alignment rules are observed, even if we have explicit offset.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001795 if (failed_validation_index)
1796 *failed_validation_index = i;
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001797 return false;
1798 }
msiglreithd096f5c2017-11-27 16:00:56 +01001799
1800 // Verify array stride rules.
1801 if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
1802 type_struct_member_array_stride(type, i))
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001803 {
1804 if (failed_validation_index)
1805 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001806 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001807 }
msiglreithd096f5c2017-11-27 16:00:56 +01001808
1809 // Verify that sub-structs also follow packing rules.
1810 // We cannot use enhanced layouts on substructs, so they better be up to spec.
1811 auto substruct_packing = packing_to_substruct_packing(packing);
1812
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001813 if (!memb_type.pointer && !memb_type.member_types.empty() &&
1814 !buffer_is_packing_standard(memb_type, substruct_packing))
1815 {
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001816 if (failed_validation_index)
1817 *failed_validation_index = i;
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001818 return false;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001819 }
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001820 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001821
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001822 // Bump size.
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001823 offset = actual_offset + packed_size;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001824 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001825
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001826 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001827}
1828
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001829bool CompilerGLSL::can_use_io_location(StorageClass storage, bool block)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001830{
1831 // Location specifiers are must have in SPIR-V, but they aren't really supported in earlier versions of GLSL.
1832 // Be very explicit here about how to solve the issue.
1833 if ((get_execution_model() != ExecutionModelVertex && storage == StorageClassInput) ||
1834 (get_execution_model() != ExecutionModelFragment && storage == StorageClassOutput))
1835 {
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001836 uint32_t minimum_desktop_version = block ? 440 : 410;
1837 // ARB_enhanced_layouts vs ARB_separate_shader_objects ...
1838
1839 if (!options.es && options.version < minimum_desktop_version && !options.separate_shader_objects)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001840 return false;
1841 else if (options.es && options.version < 310)
1842 return false;
1843 }
1844
1845 if ((get_execution_model() == ExecutionModelVertex && storage == StorageClassInput) ||
1846 (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput))
1847 {
1848 if (options.es && options.version < 300)
1849 return false;
1850 else if (!options.es && options.version < 330)
1851 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001852 }
1853
Hans-Kristian Arntzen1389aa32019-03-19 11:20:25 +01001854 if (storage == StorageClassUniform || storage == StorageClassUniformConstant || storage == StorageClassPushConstant)
Andrei Alexeyev4a430242018-04-07 22:14:35 +03001855 {
1856 if (options.es && options.version < 310)
1857 return false;
1858 else if (!options.es && options.version < 430)
1859 return false;
1860 }
1861
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001862 return true;
1863}
1864
1865string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
1866{
Hans-Kristian Arntzen62d223a2016-09-21 08:20:04 +02001867 // FIXME: Come up with a better solution for when to disable layouts.
1868 // Having layouts depend on extensions as well as which types
1869 // of layouts are used. For now, the simple solution is to just disable
1870 // layouts for legacy versions.
1871 if (is_legacy())
rob42fe8c32016-09-18 13:18:33 +09001872 return "";
1873
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01001874 if (subpass_input_is_framebuffer_fetch(var.self))
1875 return "";
1876
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001877 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001878
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001879 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001880 auto &flags = get_decoration_bitset(var.self);
1881 auto &typeflags = get_decoration_bitset(type.self);
1882
1883 if (flags.get(DecorationPassthroughNV))
1884 attr.push_back("passthrough");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001885
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001886 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
1887 attr.push_back("push_constant");
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01001888 else if (var.storage == StorageClassShaderRecordBufferKHR)
1889 attr.push_back(ray_tracing_is_khr ? "shaderRecordEXT" : "shaderRecordNV");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001890
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001891 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001892 attr.push_back("row_major");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001893 if (flags.get(DecorationColMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001894 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001895
1896 if (options.vulkan_semantics)
1897 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001898 if (flags.get(DecorationInputAttachmentIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001899 attr.push_back(join("input_attachment_index = ", get_decoration(var.self, DecorationInputAttachmentIndex)));
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001900 }
1901
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001902 bool is_block = has_decoration(type.self, DecorationBlock);
1903 if (flags.get(DecorationLocation) && can_use_io_location(var.storage, is_block))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001904 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001905 Bitset combined_decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001906 for (uint32_t i = 0; i < ir.meta[type.self].members.size(); i++)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001907 combined_decoration.merge_or(combined_decoration_for_member(type, i));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001908
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001909 // If our members have location decorations, we don't need to
1910 // emit location decorations at the top as well (looks weird).
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001911 if (!combined_decoration.get(DecorationLocation))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001912 attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation)));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001913 }
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001914
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02001915 if (get_execution_model() == ExecutionModelFragment && var.storage == StorageClassOutput &&
1916 location_is_non_coherent_framebuffer_fetch(get_decoration(var.self, DecorationLocation)))
1917 {
1918 attr.push_back("noncoherent");
1919 }
1920
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001921 // Transform feedback
1922 bool uses_enhanced_layouts = false;
1923 if (is_block && var.storage == StorageClassOutput)
1924 {
1925 // For blocks, there is a restriction where xfb_stride/xfb_buffer must only be declared on the block itself,
1926 // since all members must match the same xfb_buffer. The only thing we will declare for members of the block
1927 // is the xfb_offset.
1928 uint32_t member_count = uint32_t(type.member_types.size());
1929 bool have_xfb_buffer_stride = false;
1930 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001931 bool have_geom_stream = false;
1932 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001933
1934 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride))
1935 {
1936 have_xfb_buffer_stride = true;
1937 xfb_buffer = get_decoration(var.self, DecorationXfbBuffer);
1938 xfb_stride = get_decoration(var.self, DecorationXfbStride);
1939 }
1940
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001941 if (flags.get(DecorationStream))
1942 {
1943 have_geom_stream = true;
1944 geom_stream = get_decoration(var.self, DecorationStream);
1945 }
1946
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001947 // Verify that none of the members violate our assumption.
1948 for (uint32_t i = 0; i < member_count; i++)
1949 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001950 if (has_member_decoration(type.self, i, DecorationStream))
1951 {
1952 uint32_t member_geom_stream = get_member_decoration(type.self, i, DecorationStream);
1953 if (have_geom_stream && member_geom_stream != geom_stream)
1954 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
1955 have_geom_stream = true;
1956 geom_stream = member_geom_stream;
1957 }
1958
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001959 // Only members with an Offset decoration participate in XFB.
1960 if (!has_member_decoration(type.self, i, DecorationOffset))
1961 continue;
1962 have_any_xfb_offset = true;
1963
1964 if (has_member_decoration(type.self, i, DecorationXfbBuffer))
1965 {
1966 uint32_t buffer_index = get_member_decoration(type.self, i, DecorationXfbBuffer);
1967 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
1968 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
1969 have_xfb_buffer_stride = true;
1970 xfb_buffer = buffer_index;
1971 }
1972
1973 if (has_member_decoration(type.self, i, DecorationXfbStride))
1974 {
1975 uint32_t stride = get_member_decoration(type.self, i, DecorationXfbStride);
1976 if (have_xfb_buffer_stride && stride != xfb_stride)
1977 SPIRV_CROSS_THROW("IO block member XfbStride mismatch.");
1978 have_xfb_buffer_stride = true;
1979 xfb_stride = stride;
1980 }
1981 }
1982
1983 if (have_xfb_buffer_stride && have_any_xfb_offset)
1984 {
1985 attr.push_back(join("xfb_buffer = ", xfb_buffer));
1986 attr.push_back(join("xfb_stride = ", xfb_stride));
1987 uses_enhanced_layouts = true;
1988 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001989
1990 if (have_geom_stream)
1991 {
1992 if (get_execution_model() != ExecutionModelGeometry)
1993 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
1994 if (options.es)
1995 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
1996 if (options.version < 400)
1997 require_extension_internal("GL_ARB_transform_feedback3");
1998 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
1999 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002000 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002001 else if (var.storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002002 {
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01002003 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) && flags.get(DecorationOffset))
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002004 {
2005 // XFB for standalone variables, we can emit all decorations.
2006 attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer)));
2007 attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride)));
2008 attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset)));
2009 uses_enhanced_layouts = true;
2010 }
2011
2012 if (flags.get(DecorationStream))
2013 {
2014 if (get_execution_model() != ExecutionModelGeometry)
2015 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
2016 if (options.es)
2017 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
2018 if (options.version < 400)
2019 require_extension_internal("GL_ARB_transform_feedback3");
2020 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
2021 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002022 }
2023
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02002024 // Can only declare Component if we can declare location.
2025 if (flags.get(DecorationComponent) && can_use_io_location(var.storage, is_block))
2026 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002027 uses_enhanced_layouts = true;
2028 attr.push_back(join("component = ", get_decoration(var.self, DecorationComponent)));
2029 }
2030
2031 if (uses_enhanced_layouts)
2032 {
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02002033 if (!options.es)
2034 {
2035 if (options.version < 440 && options.version >= 140)
2036 require_extension_internal("GL_ARB_enhanced_layouts");
2037 else if (options.version < 140)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002038 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in targets below GLSL 1.40.");
2039 if (!options.es && options.version < 440)
2040 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02002041 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002042 else if (options.es)
2043 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in ESSL.");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02002044 }
2045
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02002046 if (flags.get(DecorationIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002047 attr.push_back(join("index = ", get_decoration(var.self, DecorationIndex)));
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02002048
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02002049 // Do not emit set = decoration in regular GLSL output, but
2050 // we need to preserve it in Vulkan GLSL mode.
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002051 if (var.storage != StorageClassPushConstant && var.storage != StorageClassShaderRecordBufferKHR)
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02002052 {
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02002053 if (flags.get(DecorationDescriptorSet) && options.vulkan_semantics)
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002054 attr.push_back(join("set = ", get_decoration(var.self, DecorationDescriptorSet)));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02002055 }
2056
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002057 bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002058 bool ssbo_block = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferKHR ||
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002059 (var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
2060 bool emulated_ubo = var.storage == StorageClassPushConstant && options.emit_push_constant_as_uniform_buffer;
2061 bool ubo_block = var.storage == StorageClassUniform && typeflags.get(DecorationBlock);
2062
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02002063 // GL 3.0/GLSL 1.30 is not considered legacy, but it doesn't have UBOs ...
2064 bool can_use_buffer_blocks = (options.es && options.version >= 300) || (!options.es && options.version >= 140);
2065
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02002066 // pretend no UBOs when options say so
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002067 if (ubo_block && options.emit_uniform_buffer_as_plain_uniforms)
2068 can_use_buffer_blocks = false;
2069
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02002070 bool can_use_binding;
2071 if (options.es)
2072 can_use_binding = options.version >= 310;
2073 else
2074 can_use_binding = options.enable_420pack_extension || (options.version >= 420);
2075
Hans-Kristian Arntzen938040b2018-04-03 16:58:05 +02002076 // Make sure we don't emit binding layout for a classic uniform on GLSL 1.30.
2077 if (!can_use_buffer_blocks && var.storage == StorageClassUniform)
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02002078 can_use_binding = false;
2079
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002080 if (var.storage == StorageClassShaderRecordBufferKHR)
Patrick Mours8d64d5e2019-06-05 13:29:01 +02002081 can_use_binding = false;
2082
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002083 if (can_use_binding && flags.get(DecorationBinding))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002084 attr.push_back(join("binding = ", get_decoration(var.self, DecorationBinding)));
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02002085
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002086 if (var.storage != StorageClassOutput && flags.get(DecorationOffset))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002087 attr.push_back(join("offset = ", get_decoration(var.self, DecorationOffset)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002088
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002089 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
2090 // If SPIR-V does not comply with either layout, we cannot really work around it.
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01002091 if (can_use_buffer_blocks && (ubo_block || emulated_ubo))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002092 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002093 attr.push_back(buffer_to_packing_standard(type, false));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002094 }
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02002095 else if (can_use_buffer_blocks && (push_constant_block || ssbo_block))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002096 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002097 attr.push_back(buffer_to_packing_standard(type, true));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002098 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002099
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002100 // For images, the type itself adds a layout qualifer.
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02002101 // Only emit the format for storage images.
2102 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002103 {
2104 const char *fmt = format_to_glsl(type.image.format);
2105 if (fmt)
2106 attr.push_back(fmt);
2107 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002109 if (attr.empty())
2110 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002111
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002112 string res = "layout(";
2113 res += merge(attr);
2114 res += ") ";
2115 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002116}
2117
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002118string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type, bool support_std430_without_scalar_layout)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002119{
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002120 if (support_std430_without_scalar_layout && buffer_is_packing_standard(type, BufferPackingStd430))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002121 return "std430";
2122 else if (buffer_is_packing_standard(type, BufferPackingStd140))
2123 return "std140";
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002124 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalar))
2125 {
2126 require_extension_internal("GL_EXT_scalar_block_layout");
2127 return "scalar";
2128 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002129 else if (support_std430_without_scalar_layout &&
2130 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002131 {
2132 if (options.es && !options.vulkan_semantics)
2133 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
2134 "not support GL_ARB_enhanced_layouts.");
2135 if (!options.es && !options.vulkan_semantics && options.version < 440)
2136 require_extension_internal("GL_ARB_enhanced_layouts");
2137
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002138 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002139 return "std430";
2140 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002141 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
2142 {
2143 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
2144 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
2145 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
2146 if (options.es && !options.vulkan_semantics)
2147 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
2148 "not support GL_ARB_enhanced_layouts.");
2149 if (!options.es && !options.vulkan_semantics && options.version < 440)
2150 require_extension_internal("GL_ARB_enhanced_layouts");
2151
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002152 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002153 return "std140";
2154 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002155 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalarEnhancedLayout))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002156 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002157 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002158 require_extension_internal("GL_EXT_scalar_block_layout");
2159 return "scalar";
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002160 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002161 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
2162 buffer_is_packing_standard(type, BufferPackingStd430))
2163 {
2164 // UBOs can support std430 with GL_EXT_scalar_block_layout.
2165 require_extension_internal("GL_EXT_scalar_block_layout");
2166 return "std430";
2167 }
2168 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
2169 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
2170 {
2171 // UBOs can support std430 with GL_EXT_scalar_block_layout.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002172 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02002173 require_extension_internal("GL_EXT_scalar_block_layout");
2174 return "std430";
2175 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002176 else
2177 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02002178 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 +02002179 "layouts. You can try flattening this block to support a more flexible layout.");
2180 }
2181}
2182
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002183void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
2184{
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01002185 if (flattened_buffer_blocks.count(var.self))
2186 emit_buffer_block_flattened(var);
2187 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002188 emit_push_constant_block_vulkan(var);
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01002189 else if (options.emit_push_constant_as_uniform_buffer)
2190 emit_buffer_block_native(var);
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002191 else
2192 emit_push_constant_block_glsl(var);
2193}
2194
2195void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
2196{
2197 emit_buffer_block(var);
2198}
2199
2200void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
2201{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002202 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
2203 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002204
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +02002205 unset_decoration(var.self, DecorationBinding);
2206 unset_decoration(var.self, DecorationDescriptorSet);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002207
2208#if 0
2209 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002210 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002211 "Remap to location with reflection API first or disable these decorations.");
2212#endif
2213
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002214 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
2215 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +02002216 bool block_flag = has_decoration(type.self, DecorationBlock);
2217 unset_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002218
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002219 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002220
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002221 if (block_flag)
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +02002222 set_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002223
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002224 emit_uniform(var);
2225 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002226}
2227
2228void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
2229{
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002230 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02002231 bool ubo_block = var.storage == StorageClassUniform && has_decoration(type.self, DecorationBlock);
Laszlo Agocs7bc31492019-05-11 16:30:33 +02002232
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002233 if (flattened_buffer_blocks.count(var.self))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002234 emit_buffer_block_flattened(var);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02002235 else if (is_legacy() || (!options.es && options.version == 130) ||
2236 (ubo_block && options.emit_uniform_buffer_as_plain_uniforms))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002237 emit_buffer_block_legacy(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002238 else
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002239 emit_buffer_block_native(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002240}
2241
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002242void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
2243{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002244 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02002245 bool ssbo = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002246 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002247 if (ssbo)
2248 SPIRV_CROSS_THROW("SSBOs not supported in legacy targets.");
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002249
2250 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
2251 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002252 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002253 bool block_flag = block_flags.get(DecorationBlock);
2254 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002255 emit_struct(type);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002256 if (block_flag)
2257 block_flags.set(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002258 emit_uniform(var);
2259 statement("");
2260}
2261
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002262void CompilerGLSL::emit_buffer_reference_block(uint32_t type_id, bool forward_declaration)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002263{
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002264 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002265 string buffer_name;
2266
2267 if (forward_declaration)
2268 {
2269 // Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
2270 // Allow aliased name since we might be declaring the block twice. Once with buffer reference (forward declared) and one proper declaration.
2271 // The names must match up.
2272 buffer_name = to_name(type.self, false);
2273
2274 // Shaders never use the block by interface name, so we don't
2275 // have to track this other than updating name caches.
2276 // If we have a collision for any reason, just fallback immediately.
2277 if (ir.meta[type.self].decoration.alias.empty() ||
2278 block_ssbo_names.find(buffer_name) != end(block_ssbo_names) ||
2279 resource_names.find(buffer_name) != end(resource_names))
2280 {
2281 buffer_name = join("_", type.self);
2282 }
2283
2284 // Make sure we get something unique for both global name scope and block name scope.
2285 // See GLSL 4.5 spec: section 4.3.9 for details.
2286 add_variable(block_ssbo_names, resource_names, buffer_name);
2287
2288 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2289 // This cannot conflict with anything else, so we're safe now.
2290 // We cannot reuse this fallback name in neither global scope (blocked by block_names) nor block name scope.
2291 if (buffer_name.empty())
2292 buffer_name = join("_", type.self);
2293
2294 block_names.insert(buffer_name);
2295 block_ssbo_names.insert(buffer_name);
Hans-Kristian Arntzene07f0a92020-11-23 16:36:49 +01002296
2297 // Ensure we emit the correct name when emitting non-forward pointer type.
2298 ir.meta[type.self].decoration.alias = buffer_name;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002299 }
2300 else if (type.basetype != SPIRType::Struct)
2301 buffer_name = type_to_glsl(type);
2302 else
2303 buffer_name = to_name(type.self, false);
2304
2305 if (!forward_declaration)
2306 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002307 auto itr = physical_storage_type_to_alignment.find(type_id);
2308 uint32_t alignment = 0;
2309 if (itr != physical_storage_type_to_alignment.end())
2310 alignment = itr->second.alignment;
2311
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002312 if (type.basetype == SPIRType::Struct)
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002313 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002314 SmallVector<std::string> attributes;
2315 attributes.push_back("buffer_reference");
2316 if (alignment)
2317 attributes.push_back(join("buffer_reference_align = ", alignment));
2318 attributes.push_back(buffer_to_packing_standard(type, true));
2319
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002320 auto flags = ir.get_buffer_block_type_flags(type);
2321 string decorations;
2322 if (flags.get(DecorationRestrict))
2323 decorations += " restrict";
2324 if (flags.get(DecorationCoherent))
2325 decorations += " coherent";
2326 if (flags.get(DecorationNonReadable))
2327 decorations += " writeonly";
2328 if (flags.get(DecorationNonWritable))
2329 decorations += " readonly";
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002330
2331 statement("layout(", merge(attributes), ")", decorations, " buffer ", buffer_name);
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002332 }
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01002333 else if (alignment)
2334 statement("layout(buffer_reference, buffer_reference_align = ", alignment, ") buffer ", buffer_name);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002335 else
2336 statement("layout(buffer_reference) buffer ", buffer_name);
2337
2338 begin_scope();
2339
2340 if (type.basetype == SPIRType::Struct)
2341 {
2342 type.member_name_cache.clear();
2343
2344 uint32_t i = 0;
2345 for (auto &member : type.member_types)
2346 {
2347 add_member_name(type, i);
2348 emit_struct_member(type, member, i);
2349 i++;
2350 }
2351 }
2352 else
2353 {
2354 auto &pointee_type = get_pointee_type(type);
2355 statement(type_to_glsl(pointee_type), " value", type_to_array_glsl(pointee_type), ";");
2356 }
2357
2358 end_scope_decl();
2359 statement("");
2360 }
2361 else
2362 {
2363 statement("layout(buffer_reference) buffer ", buffer_name, ";");
2364 }
2365}
2366
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002367void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002368{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002369 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002370
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002371 Bitset flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002372 bool ssbo = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferKHR ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002373 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002374 bool is_restrict = ssbo && flags.get(DecorationRestrict);
2375 bool is_writeonly = ssbo && flags.get(DecorationNonReadable);
2376 bool is_readonly = ssbo && flags.get(DecorationNonWritable);
2377 bool is_coherent = ssbo && flags.get(DecorationCoherent);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02002378
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002379 // 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 +02002380 auto buffer_name = to_name(type.self, false);
2381
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002382 auto &block_namespace = ssbo ? block_ssbo_names : block_ubo_names;
2383
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002384 // Shaders never use the block by interface name, so we don't
2385 // have to track this other than updating name caches.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002386 // If we have a collision for any reason, just fallback immediately.
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01002387 if (ir.meta[type.self].decoration.alias.empty() || block_namespace.find(buffer_name) != end(block_namespace) ||
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002388 resource_names.find(buffer_name) != end(resource_names))
2389 {
Hans-Kristian Arntzenaab31072017-09-29 12:16:53 +02002390 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002391 }
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002392
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002393 // Make sure we get something unique for both global name scope and block name scope.
2394 // See GLSL 4.5 spec: section 4.3.9 for details.
2395 add_variable(block_namespace, resource_names, buffer_name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002396
2397 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2398 // This cannot conflict with anything else, so we're safe now.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002399 // 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 +01002400 if (buffer_name.empty())
2401 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2402
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002403 block_names.insert(buffer_name);
2404 block_namespace.insert(buffer_name);
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002405
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002406 // Save for post-reflection later.
2407 declared_block_names[var.self] = buffer_name;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002408
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02002409 statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
2410 is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
2411 buffer_name);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002412
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002413 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002414
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002415 type.member_name_cache.clear();
2416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002417 uint32_t i = 0;
2418 for (auto &member : type.member_types)
2419 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002420 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002421 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002422 i++;
2423 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002424
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +01002425 // var.self can be used as a backup name for the block name,
2426 // so we need to make sure we don't disturb the name here on a recompile.
2427 // It will need to be reset if we have to recompile.
2428 preserve_alias_on_reset(var.self);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002429 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002430 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
2431 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002432}
2433
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002434void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002435{
2436 auto &type = get<SPIRType>(var.basetype);
2437
2438 // Block names should never alias.
2439 auto buffer_name = to_name(type.self, false);
2440 size_t buffer_size = (get_declared_struct_size(type) + 15) / 16;
2441
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002442 SPIRType::BaseType basic_type;
2443 if (get_common_basic_type(type, basic_type))
2444 {
2445 SPIRType tmp;
2446 tmp.basetype = basic_type;
Hans-Kristian Arntzenefba6102017-01-22 08:53:52 +01002447 tmp.vecsize = 4;
2448 if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt)
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002449 SPIRV_CROSS_THROW("Basic types in a flattened UBO must be float, int or uint.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002450
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002451 auto flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002452 statement("uniform ", flags_to_qualifiers_glsl(tmp, flags), type_to_glsl(tmp), " ", buffer_name, "[",
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01002453 buffer_size, "];");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002454 }
2455 else
2456 SPIRV_CROSS_THROW("All basic types in a flattened block must be the same.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002457}
2458
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002459const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002460{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002461 auto &execution = get_entry_point();
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002462
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002463 if (subpass_input_is_framebuffer_fetch(var.self))
2464 return "";
2465
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002466 if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
2467 {
2468 if (is_legacy() && execution.model == ExecutionModelVertex)
2469 return var.storage == StorageClassInput ? "attribute " : "varying ";
2470 else if (is_legacy() && execution.model == ExecutionModelFragment)
2471 return "varying "; // Fragment outputs are renamed so they never hit this case.
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002472 else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
2473 {
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02002474 uint32_t loc = get_decoration(var.self, DecorationLocation);
2475 bool is_inout = location_is_framebuffer_fetch(loc);
2476 if (is_inout)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002477 return "inout ";
2478 else
2479 return "out ";
2480 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002481 else
2482 return var.storage == StorageClassInput ? "in " : "out ";
2483 }
2484 else if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
2485 var.storage == StorageClassPushConstant)
2486 {
2487 return "uniform ";
2488 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002489 else if (var.storage == StorageClassRayPayloadKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002490 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002491 return ray_tracing_is_khr ? "rayPayloadEXT " : "rayPayloadNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002492 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002493 else if (var.storage == StorageClassIncomingRayPayloadKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002494 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002495 return ray_tracing_is_khr ? "rayPayloadInEXT " : "rayPayloadInNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002496 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002497 else if (var.storage == StorageClassHitAttributeKHR)
Patrick Moursda39a7b2019-02-26 15:43:03 +01002498 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002499 return ray_tracing_is_khr ? "hitAttributeEXT " : "hitAttributeNV ";
Patrick Moursda39a7b2019-02-26 15:43:03 +01002500 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002501 else if (var.storage == StorageClassCallableDataKHR)
Patrick Mours78917862019-06-03 15:25:21 +02002502 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002503 return ray_tracing_is_khr ? "callableDataEXT " : "callableDataNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002504 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002505 else if (var.storage == StorageClassIncomingCallableDataKHR)
Patrick Mours78917862019-06-03 15:25:21 +02002506 {
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01002507 return ray_tracing_is_khr ? "callableDataInEXT " : "callableDataInNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002508 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002509
2510 return "";
2511}
2512
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002513void CompilerGLSL::emit_flattened_io_block_member(const std::string &basename, const SPIRType &type, const char *qual,
2514 const SmallVector<uint32_t> &indices)
2515{
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002516 uint32_t member_type_id = type.self;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002517 const SPIRType *member_type = &type;
2518 const SPIRType *parent_type = nullptr;
2519 auto flattened_name = basename;
2520 for (auto &index : indices)
2521 {
2522 flattened_name += "_";
2523 flattened_name += to_member_name(*member_type, index);
2524 parent_type = member_type;
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002525 member_type_id = member_type->member_types[index];
2526 member_type = &get<SPIRType>(member_type_id);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002527 }
2528
2529 assert(member_type->basetype != SPIRType::Struct);
2530
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002531 // We're overriding struct member names, so ensure we do so on the primary type.
2532 if (parent_type->type_alias)
2533 parent_type = &get<SPIRType>(parent_type->type_alias);
2534
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002535 // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row,
2536 // which is not allowed.
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02002537 ParsedIR::sanitize_underscores(flattened_name);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002538
2539 uint32_t last_index = indices.back();
2540
2541 // Pass in the varying qualifier here so it will appear in the correct declaration order.
2542 // Replace member name while emitting it so it encodes both struct name and member name.
2543 auto backup_name = get_member_name(parent_type->self, last_index);
2544 auto member_name = to_member_name(*parent_type, last_index);
2545 set_member_name(parent_type->self, last_index, flattened_name);
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002546 emit_struct_member(*parent_type, member_type_id, last_index, qual);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002547 // Restore member name.
2548 set_member_name(parent_type->self, last_index, member_name);
2549}
2550
2551void CompilerGLSL::emit_flattened_io_block_struct(const std::string &basename, const SPIRType &type, const char *qual,
2552 const SmallVector<uint32_t> &indices)
2553{
2554 auto sub_indices = indices;
2555 sub_indices.push_back(0);
2556
2557 const SPIRType *member_type = &type;
2558 for (auto &index : indices)
2559 member_type = &get<SPIRType>(member_type->member_types[index]);
2560
2561 assert(member_type->basetype == SPIRType::Struct);
2562
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002563 if (!member_type->array.empty())
2564 SPIRV_CROSS_THROW("Cannot flatten array of structs in I/O blocks.");
2565
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002566 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
2567 {
2568 sub_indices.back() = i;
2569 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
2570 emit_flattened_io_block_struct(basename, type, qual, sub_indices);
2571 else
2572 emit_flattened_io_block_member(basename, type, qual, sub_indices);
2573 }
2574}
2575
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002576void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual)
2577{
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002578 auto &var_type = get<SPIRType>(var.basetype);
2579 if (!var_type.array.empty())
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002580 SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings.");
2581
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002582 // Emit flattened types based on the type alias. Normally, we are never supposed to emit
2583 // struct declarations for aliased types.
2584 auto &type = var_type.type_alias ? get<SPIRType>(var_type.type_alias) : var_type;
2585
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002586 auto old_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002587 // Emit the members as if they are part of a block to get all qualifiers.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002588 ir.meta[type.self].decoration.decoration_flags.set(DecorationBlock);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002589
Hans-Kristian Arntzena8df0802017-11-22 11:19:54 +01002590 type.member_name_cache.clear();
2591
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002592 SmallVector<uint32_t> member_indices;
2593 member_indices.push_back(0);
2594 auto basename = to_name(var.self);
2595
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002596 uint32_t i = 0;
2597 for (auto &member : type.member_types)
2598 {
2599 add_member_name(type, i);
2600 auto &membertype = get<SPIRType>(member);
2601
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002602 member_indices.back() = i;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002603 if (membertype.basetype == SPIRType::Struct)
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002604 emit_flattened_io_block_struct(basename, type, qual, member_indices);
2605 else
2606 emit_flattened_io_block_member(basename, type, qual, member_indices);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002607 i++;
2608 }
2609
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002610 ir.meta[type.self].decoration.decoration_flags = old_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002611
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002612 // Treat this variable as fully flattened from now on.
2613 flattened_structs[var.self] = true;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002614}
2615
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002616void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
2617{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002618 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002619
rdbdf5e3732020-11-12 22:59:28 +01002620 if (var.storage == StorageClassInput && type.basetype == SPIRType::Double &&
2621 !options.es && options.version < 410)
2622 {
2623 require_extension_internal("GL_ARB_vertex_attrib_64bit");
2624 }
2625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002626 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002627 bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002628 const char *qual = to_storage_qualifiers_glsl(var);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002629
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002630 if (block)
2631 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002632 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2633 // I/O variables which are struct types.
2634 // To support this, flatten the struct into separate varyings instead.
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002635 if (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2636 (!options.es && options.version < 150))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002637 {
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002638 // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320.
2639 // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150).
2640 emit_flattened_io_block(var, qual);
2641 }
2642 else
2643 {
2644 if (options.es && options.version < 320)
2645 {
2646 // Geometry and tessellation extensions imply this extension.
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01002647 if (!has_extension("GL_EXT_geometry_shader") && !has_extension("GL_EXT_tessellation_shader"))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002648 require_extension_internal("GL_EXT_shader_io_blocks");
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002649 }
2650
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +01002651 // Workaround to make sure we can emit "patch in/out" correctly.
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02002652 fixup_io_block_patch_primitive_qualifiers(var);
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +01002653
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002654 // Block names should never alias.
2655 auto block_name = to_name(type.self, false);
2656
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002657 // The namespace for I/O blocks is separate from other variables in GLSL.
2658 auto &block_namespace = type.storage == StorageClassInput ? block_input_names : block_output_names;
2659
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002660 // Shaders never use the block by interface name, so we don't
2661 // have to track this other than updating name caches.
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002662 if (block_name.empty() || block_namespace.find(block_name) != end(block_namespace))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002663 block_name = get_fallback_name(type.self);
2664 else
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002665 block_namespace.insert(block_name);
2666
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002667 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2668 // This cannot conflict with anything else, so we're safe now.
2669 if (block_name.empty())
2670 block_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2671
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002672 // Instance names cannot alias block names.
2673 resource_names.insert(block_name);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002674
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02002675 const char *block_qualifier;
2676 if (has_decoration(var.self, DecorationPatch))
2677 block_qualifier = "patch ";
2678 else if (has_decoration(var.self, DecorationPerPrimitiveEXT))
2679 block_qualifier = "perprimitiveEXT ";
2680 else
2681 block_qualifier = "";
2682
2683 statement(layout_for_variable(var), block_qualifier, qual, block_name);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002684 begin_scope();
2685
2686 type.member_name_cache.clear();
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002687
2688 uint32_t i = 0;
2689 for (auto &member : type.member_types)
2690 {
2691 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002692 emit_struct_member(type, member, i);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002693 i++;
2694 }
2695
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002696 add_resource_name(var.self);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002697 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
2698 statement("");
2699 }
2700 }
2701 else
2702 {
2703 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2704 // I/O variables which are struct types.
2705 // To support this, flatten the struct into separate varyings instead.
2706 if (type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002707 (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2708 (!options.es && options.version < 150)))
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002709 {
2710 emit_flattened_io_block(var, qual);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002711 }
2712 else
2713 {
2714 add_resource_name(var.self);
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002715
2716 // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays.
2717 // Opt for unsized as it's the more "correct" variant to use.
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +01002718 bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() &&
2719 !has_decoration(var.self, DecorationPatch) &&
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002720 (get_entry_point().model == ExecutionModelTessellationControl ||
2721 get_entry_point().model == ExecutionModelTessellationEvaluation);
2722
2723 uint32_t old_array_size = 0;
2724 bool old_array_size_literal = true;
2725
2726 if (control_point_input_array)
2727 {
2728 swap(type.array.back(), old_array_size);
2729 swap(type.array_size_literal.back(), old_array_size_literal);
2730 }
2731
Chip Davis3bfb2f92018-12-03 02:06:33 -06002732 statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
2733 variable_decl(type, to_name(var.self), var.self), ";");
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002734
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002735 if (control_point_input_array)
2736 {
2737 swap(type.array.back(), old_array_size);
2738 swap(type.array_size_literal.back(), old_array_size_literal);
2739 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002740 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002741 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002742}
2743
2744void CompilerGLSL::emit_uniform(const SPIRVariable &var)
2745{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002746 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002747 if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002748 {
2749 if (!options.es && options.version < 420)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002750 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002751 else if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002752 SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002753 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002754
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002755 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002756 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002757}
2758
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002759string CompilerGLSL::constant_value_macro_name(uint32_t id)
2760{
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002761 return join("SPIRV_CROSS_CONSTANT_ID_", id);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002762}
2763
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002764void CompilerGLSL::emit_specialization_constant_op(const SPIRConstantOp &constant)
2765{
2766 auto &type = get<SPIRType>(constant.basetype);
Hans-Kristian Arntzen48b5a902022-01-18 12:31:28 +01002767 add_resource_name(constant.self);
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002768 auto name = to_name(constant.self);
2769 statement("const ", variable_decl(type, name), " = ", constant_op_expression(constant), ";");
2770}
2771
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01002772int CompilerGLSL::get_constant_mapping_to_workgroup_component(const SPIRConstant &c) const
2773{
2774 auto &entry_point = get_entry_point();
2775 int index = -1;
2776
2777 // Need to redirect specialization constants which are used as WorkGroupSize to the builtin,
2778 // since the spec constant declarations are never explicitly declared.
2779 if (entry_point.workgroup_size.constant == 0 && entry_point.flags.get(ExecutionModeLocalSizeId))
2780 {
2781 if (c.self == entry_point.workgroup_size.id_x)
2782 index = 0;
2783 else if (c.self == entry_point.workgroup_size.id_y)
2784 index = 1;
2785 else if (c.self == entry_point.workgroup_size.id_z)
2786 index = 2;
2787 }
2788
2789 return index;
2790}
2791
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002792void CompilerGLSL::emit_constant(const SPIRConstant &constant)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002793{
2794 auto &type = get<SPIRType>(constant.constant_type);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002795
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002796 SpecializationConstant wg_x, wg_y, wg_z;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002797 ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002798
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002799 // This specialization constant is implicitly declared by emitting layout() in;
2800 if (constant.self == workgroup_size_id)
2801 return;
2802
2803 // These specialization constants are implicitly declared by emitting layout() in;
2804 // In legacy GLSL, we will still need to emit macros for these, so a layout() in; declaration
2805 // later can use macro overrides for work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002806 bool is_workgroup_size_constant = ConstantID(constant.self) == wg_x.id || ConstantID(constant.self) == wg_y.id ||
2807 ConstantID(constant.self) == wg_z.id;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002808
2809 if (options.vulkan_semantics && is_workgroup_size_constant)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002810 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002811 // Vulkan GLSL does not need to declare workgroup spec constants explicitly, it is handled in layout().
2812 return;
2813 }
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002814 else if (!options.vulkan_semantics && is_workgroup_size_constant &&
2815 !has_decoration(constant.self, DecorationSpecId))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002816 {
2817 // 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 +02002818 return;
2819 }
2820
Hans-Kristian Arntzen48b5a902022-01-18 12:31:28 +01002821 add_resource_name(constant.self);
2822 auto name = to_name(constant.self);
2823
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002824 // Only scalars have constant IDs.
2825 if (has_decoration(constant.self, DecorationSpecId))
2826 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002827 if (options.vulkan_semantics)
2828 {
2829 statement("layout(constant_id = ", get_decoration(constant.self, DecorationSpecId), ") const ",
2830 variable_decl(type, name), " = ", constant_expression(constant), ";");
2831 }
2832 else
2833 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002834 const string &macro_name = constant.specialization_constant_macro_name;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002835 statement("#ifndef ", macro_name);
2836 statement("#define ", macro_name, " ", constant_expression(constant));
2837 statement("#endif");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002838
2839 // For workgroup size constants, only emit the macros.
2840 if (!is_workgroup_size_constant)
2841 statement("const ", variable_decl(type, name), " = ", macro_name, ";");
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002842 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002843 }
2844 else
2845 {
2846 statement("const ", variable_decl(type, name), " = ", constant_expression(constant), ";");
2847 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002848}
2849
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +02002850void CompilerGLSL::emit_entry_point_declarations()
2851{
2852}
2853
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002854void CompilerGLSL::replace_illegal_names(const unordered_set<string> &keywords)
2855{
2856 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
2857 if (is_hidden_variable(var))
2858 return;
2859
2860 auto *meta = ir.find_meta(var.self);
2861 if (!meta)
2862 return;
2863
2864 auto &m = meta->decoration;
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002865 if (keywords.find(m.alias) != end(keywords))
2866 m.alias = join("_", m.alias);
2867 });
2868
2869 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, const SPIRFunction &func) {
2870 auto *meta = ir.find_meta(func.self);
2871 if (!meta)
2872 return;
2873
2874 auto &m = meta->decoration;
2875 if (keywords.find(m.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002876 m.alias = join("_", m.alias);
2877 });
2878
2879 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
2880 auto *meta = ir.find_meta(type.self);
2881 if (!meta)
2882 return;
2883
2884 auto &m = meta->decoration;
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002885 if (keywords.find(m.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002886 m.alias = join("_", m.alias);
2887
2888 for (auto &memb : meta->members)
Hans-Kristian Arntzenddb3c652021-01-04 09:59:26 +01002889 if (keywords.find(memb.alias) != end(keywords))
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002890 memb.alias = join("_", memb.alias);
2891 });
2892}
2893
Robert Konrad76936562016-08-13 00:14:52 +02002894void CompilerGLSL::replace_illegal_names()
2895{
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002896 // clang-format off
2897 static const unordered_set<string> keywords = {
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002898 "abs", "acos", "acosh", "all", "any", "asin", "asinh", "atan", "atanh",
2899 "atomicAdd", "atomicCompSwap", "atomicCounter", "atomicCounterDecrement", "atomicCounterIncrement",
2900 "atomicExchange", "atomicMax", "atomicMin", "atomicOr", "atomicXor",
2901 "bitCount", "bitfieldExtract", "bitfieldInsert", "bitfieldReverse",
2902 "ceil", "cos", "cosh", "cross", "degrees",
2903 "dFdx", "dFdxCoarse", "dFdxFine",
2904 "dFdy", "dFdyCoarse", "dFdyFine",
2905 "distance", "dot", "EmitStreamVertex", "EmitVertex", "EndPrimitive", "EndStreamPrimitive", "equal", "exp", "exp2",
Chip Davis0d949e12018-11-05 14:55:56 -06002906 "faceforward", "findLSB", "findMSB", "float16BitsToInt16", "float16BitsToUint16", "floatBitsToInt", "floatBitsToUint", "floor", "fma", "fract",
2907 "frexp", "fwidth", "fwidthCoarse", "fwidthFine",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002908 "greaterThan", "greaterThanEqual", "groupMemoryBarrier",
2909 "imageAtomicAdd", "imageAtomicAnd", "imageAtomicCompSwap", "imageAtomicExchange", "imageAtomicMax", "imageAtomicMin", "imageAtomicOr", "imageAtomicXor",
Chip Davis0d949e12018-11-05 14:55:56 -06002910 "imageLoad", "imageSamples", "imageSize", "imageStore", "imulExtended", "int16BitsToFloat16", "intBitsToFloat", "interpolateAtOffset", "interpolateAtCentroid", "interpolateAtSample",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002911 "inverse", "inversesqrt", "isinf", "isnan", "ldexp", "length", "lessThan", "lessThanEqual", "log", "log2",
2912 "matrixCompMult", "max", "memoryBarrier", "memoryBarrierAtomicCounter", "memoryBarrierBuffer", "memoryBarrierImage", "memoryBarrierShared",
2913 "min", "mix", "mod", "modf", "noise", "noise1", "noise2", "noise3", "noise4", "normalize", "not", "notEqual",
Chip Davis0d949e12018-11-05 14:55:56 -06002914 "outerProduct", "packDouble2x32", "packHalf2x16", "packInt2x16", "packInt4x16", "packSnorm2x16", "packSnorm4x8",
2915 "packUint2x16", "packUint4x16", "packUnorm2x16", "packUnorm4x8", "pow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002916 "radians", "reflect", "refract", "round", "roundEven", "sign", "sin", "sinh", "smoothstep", "sqrt", "step",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002917 "tan", "tanh", "texelFetch", "texelFetchOffset", "texture", "textureGather", "textureGatherOffset", "textureGatherOffsets",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002918 "textureGrad", "textureGradOffset", "textureLod", "textureLodOffset", "textureOffset", "textureProj", "textureProjGrad",
2919 "textureProjGradOffset", "textureProjLod", "textureProjLodOffset", "textureProjOffset", "textureQueryLevels", "textureQueryLod", "textureSamples", "textureSize",
Chip Davis0d949e12018-11-05 14:55:56 -06002920 "transpose", "trunc", "uaddCarry", "uint16BitsToFloat16", "uintBitsToFloat", "umulExtended", "unpackDouble2x32", "unpackHalf2x16", "unpackInt2x16", "unpackInt4x16",
2921 "unpackSnorm2x16", "unpackSnorm4x8", "unpackUint2x16", "unpackUint4x16", "unpackUnorm2x16", "unpackUnorm4x8", "usubBorrow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002922
Pascal Muetschardaced6052018-05-04 14:53:32 -07002923 "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002924 "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard",
2925 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4",
2926 "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float",
2927 "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray",
2928 "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
2929 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect",
2930 "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant",
2931 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002932 "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp",
2933 "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump",
2934 "namespace", "noinline", "noperspective", "out", "output", "packed", "partition", "patch", "precise", "precision", "public", "readonly",
2935 "resource", "restrict", "return", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002936 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
2937 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002938 "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "shared", "short", "sizeof", "smooth", "static",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002939 "struct", "subroutine", "superp", "switch", "template", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D",
2940 "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube",
2941 "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
2942 "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002943 "usamplerCubeArray", "using", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile",
2944 "while", "writeonly",
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002945 };
2946 // clang-format on
Bas Zalmstraf537adf2016-10-27 12:51:22 +02002947
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002948 replace_illegal_names(keywords);
Robert Konrad76936562016-08-13 00:14:52 +02002949}
2950
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002951void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
2952{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002953 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002954 uint32_t location = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002955 if (m.decoration_flags.get(DecorationLocation))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002956 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002957
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002958 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
2959 // do the access chain part of this for us.
2960 auto &type = get<SPIRType>(var.basetype);
2961
2962 if (type.array.empty())
2963 {
2964 // Redirect the write to a specific render target in legacy GLSL.
2965 m.alias = join("gl_FragData[", location, "]");
Lubos Lenco52158642016-09-17 15:56:23 +02002966
2967 if (is_legacy_es() && location != 0)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002968 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002969 }
2970 else if (type.array.size() == 1)
2971 {
2972 // If location is non-zero, we probably have to add an offset.
2973 // This gets really tricky since we'd have to inject an offset in the access chain.
2974 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
2975 m.alias = "gl_FragData";
2976 if (location != 0)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002977 SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
2978 "This is unimplemented in SPIRV-Cross.");
Hans-Kristian Arntzen6cc96242016-09-17 18:46:10 +02002979
Lubos Lenco80c39412016-09-17 14:33:16 +02002980 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002981 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002982 }
2983 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002984 SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002985
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002986 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 +01002987}
2988
2989void CompilerGLSL::replace_fragment_outputs()
2990{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002991 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002992 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002993
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +01002994 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer && var.storage == StorageClassOutput)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002995 replace_fragment_output(var);
2996 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002997}
2998
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002999string CompilerGLSL::remap_swizzle(const SPIRType &out_type, uint32_t input_components, const string &expr)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003000{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003001 if (out_type.vecsize == input_components)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02003002 return expr;
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01003003 else if (input_components == 1 && !backend.can_swizzle_scalar)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02003004 return join(type_to_glsl(out_type), "(", expr, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003005 else
3006 {
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02003007 // FIXME: This will not work with packed expressions.
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02003008 auto e = enclose_expression(expr) + ".";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003009 // Just clamp the swizzle index if we have more outputs than inputs.
3010 for (uint32_t c = 0; c < out_type.vecsize; c++)
3011 e += index_to_swizzle(min(c, input_components - 1));
3012 if (backend.swizzle_is_function && out_type.vecsize > 1)
3013 e += "()";
Hans-Kristian Arntzenffad50b2017-12-12 13:01:10 +01003014
3015 remove_duplicate_swizzle(e);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003016 return e;
3017 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003018}
3019
3020void CompilerGLSL::emit_pls()
3021{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02003022 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003023 if (execution.model != ExecutionModelFragment)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003024 SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003025
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003026 if (!options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003027 SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003028
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003029 if (options.version < 300)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003030 SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003031
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003032 if (!pls_inputs.empty())
3033 {
3034 statement("__pixel_local_inEXT _PLSIn");
3035 begin_scope();
3036 for (auto &input : pls_inputs)
3037 statement(pls_decl(input), ";");
3038 end_scope_decl();
3039 statement("");
3040 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003042 if (!pls_outputs.empty())
3043 {
3044 statement("__pixel_local_outEXT _PLSOut");
3045 begin_scope();
3046 for (auto &output : pls_outputs)
3047 statement(pls_decl(output), ";");
3048 end_scope_decl();
3049 statement("");
3050 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003051}
3052
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01003053void CompilerGLSL::fixup_image_load_store_access()
3054{
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01003055 if (!options.enable_storage_image_qualifier_deduction)
3056 return;
3057
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003058 ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01003059 auto &vartype = expression_type(var);
Hans-Kristian Arntzenb691b7d2020-04-03 12:26:13 +02003060 if (vartype.basetype == SPIRType::Image && vartype.image.sampled == 2)
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01003061 {
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01003062 // Very old glslangValidator and HLSL compilers do not emit required qualifiers here.
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01003063 // Solve this by making the image access as restricted as possible and loosen up if we need to.
3064 // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
3065
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +02003066 if (!has_decoration(var, DecorationNonWritable) && !has_decoration(var, DecorationNonReadable))
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01003067 {
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +02003068 set_decoration(var, DecorationNonWritable);
3069 set_decoration(var, DecorationNonReadable);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01003070 }
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01003071 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003072 });
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01003073}
3074
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003075static bool is_block_builtin(BuiltIn builtin)
3076{
3077 return builtin == BuiltInPosition || builtin == BuiltInPointSize || builtin == BuiltInClipDistance ||
3078 builtin == BuiltInCullDistance;
3079}
3080
3081bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage)
3082{
3083 // If the builtin block uses XFB, we need to force explicit redeclaration of the builtin block.
3084
3085 if (storage != StorageClassOutput)
3086 return false;
3087 bool should_force = false;
3088
3089 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
3090 if (should_force)
3091 return;
3092
3093 auto &type = this->get<SPIRType>(var.basetype);
3094 bool block = has_decoration(type.self, DecorationBlock);
3095 if (var.storage == storage && block && is_builtin_variable(var))
3096 {
3097 uint32_t member_count = uint32_t(type.member_types.size());
3098 for (uint32_t i = 0; i < member_count; i++)
3099 {
3100 if (has_member_decoration(type.self, i, DecorationBuiltIn) &&
3101 is_block_builtin(BuiltIn(get_member_decoration(type.self, i, DecorationBuiltIn))) &&
3102 has_member_decoration(type.self, i, DecorationOffset))
3103 {
3104 should_force = true;
3105 }
3106 }
3107 }
3108 else if (var.storage == storage && !block && is_builtin_variable(var))
3109 {
3110 if (is_block_builtin(BuiltIn(get_decoration(type.self, DecorationBuiltIn))) &&
3111 has_decoration(var.self, DecorationOffset))
3112 {
3113 should_force = true;
3114 }
3115 }
3116 });
3117
Hans-Kristian Arntzen3776d892021-01-07 12:14:49 +01003118 // If we're declaring clip/cull planes with control points we need to force block declaration.
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003119 if ((get_execution_model() == ExecutionModelTessellationControl ||
3120 get_execution_model() == ExecutionModelMeshEXT) &&
Hans-Kristian Arntzen3776d892021-01-07 12:14:49 +01003121 (clip_distance_count || cull_distance_count))
3122 {
3123 should_force = true;
3124 }
3125
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003126 return should_force;
3127}
3128
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003129void CompilerGLSL::fixup_implicit_builtin_block_names(ExecutionModel model)
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003130{
3131 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
3132 auto &type = this->get<SPIRType>(var.basetype);
3133 bool block = has_decoration(type.self, DecorationBlock);
3134 if ((var.storage == StorageClassOutput || var.storage == StorageClassInput) && block &&
3135 is_builtin_variable(var))
3136 {
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003137 if (model != ExecutionModelMeshEXT)
3138 {
3139 // Make sure the array has a supported name in the code.
3140 if (var.storage == StorageClassOutput)
3141 set_name(var.self, "gl_out");
3142 else if (var.storage == StorageClassInput)
3143 set_name(var.self, "gl_in");
3144 }
3145 else
3146 {
3147 auto flags = get_buffer_block_flags(var.self);
3148 if (flags.get(DecorationPerPrimitiveEXT))
3149 set_name(var.self, "gl_MeshPrimitivesEXT");
3150 else
3151 set_name(var.self, "gl_MeshVerticesEXT");
3152 }
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003153 }
3154 });
3155}
3156
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003157void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
3158{
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003159 Bitset emitted_builtins;
3160 Bitset global_builtins;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003161 const SPIRVariable *block_var = nullptr;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003162 bool emitted_block = false;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003163 bool builtin_array = false;
3164
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003165 // Need to use declared size in the type.
3166 // These variables might have been declared, but not statically used, so we haven't deduced their size yet.
3167 uint32_t cull_distance_size = 0;
3168 uint32_t clip_distance_size = 0;
3169
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003170 bool have_xfb_buffer_stride = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003171 bool have_geom_stream = false;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003172 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003173 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzendfffbb12020-01-27 15:56:47 +01003174 std::unordered_map<uint32_t, uint32_t> builtin_xfb_offsets;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003175
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003176 const auto builtin_is_per_vertex_set = [](BuiltIn builtin) -> bool {
3177 return builtin == BuiltInPosition || builtin == BuiltInPointSize ||
3178 builtin == BuiltInClipDistance || builtin == BuiltInCullDistance;
3179 };
3180
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003181 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003182 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003183 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003184 Bitset builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003185
3186 if (var.storage == storage && block && is_builtin_variable(var))
3187 {
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003188 uint32_t index = 0;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003189 for (auto &m : ir.meta[type.self].members)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003190 {
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003191 if (m.builtin && builtin_is_per_vertex_set(m.builtin_type))
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003192 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003193 builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003194 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003195 cull_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003196 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003197 clip_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003198
3199 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationOffset))
3200 {
3201 have_any_xfb_offset = true;
3202 builtin_xfb_offsets[m.builtin_type] = m.offset;
3203 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003204
3205 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
3206 {
3207 uint32_t stream = m.stream;
3208 if (have_geom_stream && geom_stream != stream)
3209 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3210 have_geom_stream = true;
3211 geom_stream = stream;
3212 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003213 }
3214 index++;
3215 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003216
3217 if (storage == StorageClassOutput && has_decoration(var.self, DecorationXfbBuffer) &&
3218 has_decoration(var.self, DecorationXfbStride))
3219 {
3220 uint32_t buffer_index = get_decoration(var.self, DecorationXfbBuffer);
3221 uint32_t stride = get_decoration(var.self, DecorationXfbStride);
3222 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
3223 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3224 if (have_xfb_buffer_stride && stride != xfb_stride)
3225 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3226 have_xfb_buffer_stride = true;
3227 xfb_buffer = buffer_index;
3228 xfb_stride = stride;
3229 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003230
3231 if (storage == StorageClassOutput && has_decoration(var.self, DecorationStream))
3232 {
3233 uint32_t stream = get_decoration(var.self, DecorationStream);
3234 if (have_geom_stream && geom_stream != stream)
3235 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3236 have_geom_stream = true;
3237 geom_stream = stream;
3238 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003239 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003240 else if (var.storage == storage && !block && is_builtin_variable(var))
3241 {
3242 // While we're at it, collect all declared global builtins (HLSL mostly ...).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003243 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003244 if (m.builtin && builtin_is_per_vertex_set(m.builtin_type))
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003245 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003246 global_builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003247 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003248 cull_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003249 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02003250 clip_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003251
3252 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationXfbStride) &&
3253 m.decoration_flags.get(DecorationXfbBuffer) && m.decoration_flags.get(DecorationOffset))
3254 {
3255 have_any_xfb_offset = true;
3256 builtin_xfb_offsets[m.builtin_type] = m.offset;
3257 uint32_t buffer_index = m.xfb_buffer;
3258 uint32_t stride = m.xfb_stride;
3259 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
3260 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3261 if (have_xfb_buffer_stride && stride != xfb_stride)
3262 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
3263 have_xfb_buffer_stride = true;
3264 xfb_buffer = buffer_index;
3265 xfb_stride = stride;
3266 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003267
3268 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
3269 {
3270 uint32_t stream = get_decoration(var.self, DecorationStream);
3271 if (have_geom_stream && geom_stream != stream)
3272 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
3273 have_geom_stream = true;
3274 geom_stream = stream;
3275 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003276 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003277 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003278
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003279 if (builtins.empty())
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003280 return;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003281
3282 if (emitted_block)
3283 SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
3284
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003285 emitted_builtins = builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003286 emitted_block = true;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003287 builtin_array = !type.array.empty();
3288 block_var = &var;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003289 });
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003290
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01003291 global_builtins =
3292 Bitset(global_builtins.get_lower() & ((1ull << BuiltInPosition) | (1ull << BuiltInPointSize) |
3293 (1ull << BuiltInClipDistance) | (1ull << BuiltInCullDistance)));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003294
3295 // Try to collect all other declared builtins.
3296 if (!emitted_block)
3297 emitted_builtins = global_builtins;
3298
3299 // Can't declare an empty interface block.
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003300 if (emitted_builtins.empty())
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003301 return;
3302
3303 if (storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003304 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003305 SmallVector<string> attr;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003306 if (have_xfb_buffer_stride && have_any_xfb_offset)
3307 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003308 if (!options.es)
3309 {
3310 if (options.version < 440 && options.version >= 140)
3311 require_extension_internal("GL_ARB_enhanced_layouts");
3312 else if (options.version < 140)
3313 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
3314 if (!options.es && options.version < 440)
3315 require_extension_internal("GL_ARB_enhanced_layouts");
3316 }
3317 else if (options.es)
3318 SPIRV_CROSS_THROW("Need GL_ARB_enhanced_layouts for xfb_stride or xfb_buffer.");
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003319 attr.push_back(join("xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003320 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003321
3322 if (have_geom_stream)
3323 {
3324 if (get_execution_model() != ExecutionModelGeometry)
3325 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
3326 if (options.es)
3327 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
3328 if (options.version < 400)
3329 require_extension_internal("GL_ARB_transform_feedback3");
3330 attr.push_back(join("stream = ", geom_stream));
3331 }
3332
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003333 if (model == ExecutionModelMeshEXT)
3334 statement("out gl_MeshPerVertexEXT");
3335 else if (!attr.empty())
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02003336 statement("layout(", merge(attr), ") out gl_PerVertex");
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003337 else
3338 statement("out gl_PerVertex");
3339 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003340 else
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01003341 {
3342 // If we have passthrough, there is no way PerVertex cannot be passthrough.
3343 if (get_entry_point().geometry_passthrough)
3344 statement("layout(passthrough) in gl_PerVertex");
3345 else
3346 statement("in gl_PerVertex");
3347 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003348
3349 begin_scope();
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003350 if (emitted_builtins.get(BuiltInPosition))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003351 {
3352 auto itr = builtin_xfb_offsets.find(BuiltInPosition);
3353 if (itr != end(builtin_xfb_offsets))
3354 statement("layout(xfb_offset = ", itr->second, ") vec4 gl_Position;");
3355 else
3356 statement("vec4 gl_Position;");
3357 }
3358
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003359 if (emitted_builtins.get(BuiltInPointSize))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003360 {
3361 auto itr = builtin_xfb_offsets.find(BuiltInPointSize);
3362 if (itr != end(builtin_xfb_offsets))
3363 statement("layout(xfb_offset = ", itr->second, ") float gl_PointSize;");
3364 else
3365 statement("float gl_PointSize;");
3366 }
3367
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003368 if (emitted_builtins.get(BuiltInClipDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003369 {
3370 auto itr = builtin_xfb_offsets.find(BuiltInClipDistance);
3371 if (itr != end(builtin_xfb_offsets))
3372 statement("layout(xfb_offset = ", itr->second, ") float gl_ClipDistance[", clip_distance_size, "];");
3373 else
3374 statement("float gl_ClipDistance[", clip_distance_size, "];");
3375 }
3376
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003377 if (emitted_builtins.get(BuiltInCullDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003378 {
3379 auto itr = builtin_xfb_offsets.find(BuiltInCullDistance);
3380 if (itr != end(builtin_xfb_offsets))
3381 statement("layout(xfb_offset = ", itr->second, ") float gl_CullDistance[", cull_distance_size, "];");
3382 else
3383 statement("float gl_CullDistance[", cull_distance_size, "];");
3384 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003385
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003386 if (builtin_array)
3387 {
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003388 if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
3389 end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]"));
3390 else
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01003391 end_scope_decl(join(to_name(block_var->self), "[]"));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003392 }
3393 else
3394 end_scope_decl();
3395 statement("");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003396}
3397
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003398void CompilerGLSL::declare_undefined_values()
3399{
3400 bool emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003401 ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003402 auto &type = this->get<SPIRType>(undef.basetype);
3403 // OpUndef can be void for some reason ...
3404 if (type.basetype == SPIRType::Void)
3405 return;
3406
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003407 string initializer;
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003408 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003409 initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
3410
crissdb52e272020-10-08 12:14:52 +02003411 statement(variable_decl(type, to_name(undef.self), undef.self), initializer, ";");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003412 emitted = true;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003413 });
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003414
3415 if (emitted)
3416 statement("");
3417}
3418
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003419bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const
3420{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003421 bool statically_assigned = var.statically_assigned && var.static_expression != ID(0) && var.remapped_variable;
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003422
3423 if (statically_assigned)
3424 {
3425 auto *constant = maybe_get<SPIRConstant>(var.static_expression);
3426 if (constant && constant->is_used_as_lut)
3427 return true;
3428 }
3429
3430 return false;
3431}
3432
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003433void CompilerGLSL::emit_resources()
3434{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02003435 auto &execution = get_entry_point();
3436
Robert Konrad76936562016-08-13 00:14:52 +02003437 replace_illegal_names();
3438
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003439 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
3440 // with builtins.
3441 if (execution.model == ExecutionModelFragment && is_legacy())
3442 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003443
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003444 // Emit PLS blocks if we have such variables.
3445 if (!pls_inputs.empty() || !pls_outputs.empty())
3446 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003447
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003448 switch (execution.model)
3449 {
3450 case ExecutionModelGeometry:
3451 case ExecutionModelTessellationControl:
3452 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003453 case ExecutionModelMeshEXT:
3454 fixup_implicit_builtin_block_names(execution.model);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003455 break;
3456
3457 default:
3458 break;
3459 }
3460
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003461 // Emit custom gl_PerVertex for SSO compatibility.
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003462 if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment)
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003463 {
3464 switch (execution.model)
3465 {
3466 case ExecutionModelGeometry:
3467 case ExecutionModelTessellationControl:
3468 case ExecutionModelTessellationEvaluation:
3469 emit_declared_builtin_block(StorageClassInput, execution.model);
3470 emit_declared_builtin_block(StorageClassOutput, execution.model);
3471 break;
3472
3473 case ExecutionModelVertex:
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02003474 case ExecutionModelMeshEXT:
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003475 emit_declared_builtin_block(StorageClassOutput, execution.model);
3476 break;
3477
3478 default:
3479 break;
3480 }
3481 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003482 else if (should_force_emit_builtin_block(StorageClassOutput))
3483 {
3484 emit_declared_builtin_block(StorageClassOutput, execution.model);
3485 }
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01003486 else if (execution.geometry_passthrough)
3487 {
3488 // Need to declare gl_in with Passthrough.
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003489 // 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 +01003490 emit_declared_builtin_block(StorageClassInput, execution.model);
3491 }
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003492 else
3493 {
3494 // Need to redeclare clip/cull distance with explicit size to use them.
3495 // SPIR-V mandates these builtins have a size declared.
3496 const char *storage = execution.model == ExecutionModelFragment ? "in" : "out";
3497 if (clip_distance_count != 0)
3498 statement(storage, " float gl_ClipDistance[", clip_distance_count, "];");
3499 if (cull_distance_count != 0)
3500 statement(storage, " float gl_CullDistance[", cull_distance_count, "];");
3501 if (clip_distance_count != 0 || cull_distance_count != 0)
3502 statement("");
3503 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003504
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003505 if (position_invariant)
3506 {
3507 statement("invariant gl_Position;");
3508 statement("");
3509 }
3510
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003511 bool emitted = false;
3512
3513 // If emitted Vulkan GLSL,
3514 // emit specialization constants as actual floats,
3515 // spec op expressions will redirect to the constant name.
3516 //
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003517 {
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +02003518 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003519 for (auto &id_ : ir.ids_for_constant_or_type)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003520 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003521 auto &id = ir.ids[id_];
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003522
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003523 if (id.get_type() == TypeConstant)
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003524 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003525 auto &c = id.get<SPIRConstant>();
3526
3527 bool needs_declaration = c.specialization || c.is_used_as_lut;
3528
3529 if (needs_declaration)
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003530 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003531 if (!options.vulkan_semantics && c.specialization)
3532 {
3533 c.specialization_constant_macro_name =
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02003534 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003535 }
3536 emit_constant(c);
3537 emitted = true;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003538 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003539 }
3540 else if (id.get_type() == TypeConstantOp)
3541 {
3542 emit_specialization_constant_op(id.get<SPIRConstantOp>());
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003543 emitted = true;
3544 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003545 else if (id.get_type() == TypeType)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003546 {
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003547 auto *type = &id.get<SPIRType>();
3548
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003549 bool is_natural_struct = type->basetype == SPIRType::Struct && type->array.empty() && !type->pointer &&
3550 (!has_decoration(type->self, DecorationBlock) &&
3551 !has_decoration(type->self, DecorationBufferBlock));
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003552
3553 // Special case, ray payload and hit attribute blocks are not really blocks, just regular structs.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003554 if (type->basetype == SPIRType::Struct && type->pointer &&
3555 has_decoration(type->self, DecorationBlock) &&
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003556 (type->storage == StorageClassRayPayloadKHR || type->storage == StorageClassIncomingRayPayloadKHR ||
3557 type->storage == StorageClassHitAttributeKHR))
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003558 {
3559 type = &get<SPIRType>(type->parent_type);
3560 is_natural_struct = true;
3561 }
3562
3563 if (is_natural_struct)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003564 {
3565 if (emitted)
3566 statement("");
3567 emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003568
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003569 emit_struct(*type);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003570 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003571 }
3572 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003573 }
3574
3575 if (emitted)
3576 statement("");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003577
3578 // If we needed to declare work group size late, check here.
3579 // If the work group size depends on a specialization constant, we need to declare the layout() block
3580 // after constants (and their macros) have been declared.
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01003581 if (execution.model == ExecutionModelGLCompute && !options.vulkan_semantics &&
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01003582 (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003583 {
3584 SpecializationConstant wg_x, wg_y, wg_z;
3585 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
3586
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003587 if ((wg_x.id != ConstantID(0)) || (wg_y.id != ConstantID(0)) || (wg_z.id != ConstantID(0)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003588 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02003589 SmallVector<string> inputs;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003590 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
3591 statement("layout(", merge(inputs), ") in;");
3592 statement("");
3593 }
3594 }
3595
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003596 emitted = false;
3597
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003598 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
3599 {
3600 for (auto type : physical_storage_non_block_pointer_types)
3601 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003602 emit_buffer_reference_block(type, false);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003603 }
3604
3605 // Output buffer reference blocks.
3606 // Do this in two stages, one with forward declaration,
3607 // and one without. Buffer reference blocks can reference themselves
3608 // to support things like linked lists.
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003609 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
3610 if (type.basetype == SPIRType::Struct && type.pointer &&
3611 type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003612 type.storage == StorageClassPhysicalStorageBufferEXT)
3613 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003614 emit_buffer_reference_block(self, true);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003615 }
3616 });
3617
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003618 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
3619 if (type.basetype == SPIRType::Struct &&
3620 type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003621 type.storage == StorageClassPhysicalStorageBufferEXT)
3622 {
Hans-Kristian Arntzenf1b411c2021-11-07 15:43:57 +01003623 emit_buffer_reference_block(self, false);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003624 }
3625 });
3626 }
3627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003628 // Output UBOs and SSBOs
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003629 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003630 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003631
Patrick Mours78917862019-06-03 15:25:21 +02003632 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform ||
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003633 type.storage == StorageClassShaderRecordBufferKHR;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003634 bool has_block_flags = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
3635 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
3636
3637 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
3638 has_block_flags)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003639 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003640 emit_buffer_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003641 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003642 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003643
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003644 // Output push constant blocks
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003645 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003646 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003647 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
3648 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003649 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003650 emit_push_constant_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003651 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003652 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003653
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02003654 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003655
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003656 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003657 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003658 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003659
3660 // If we're remapping separate samplers and images, only emit the combined samplers.
3661 if (skip_separate_image_sampler)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003662 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003663 // Sampler buffers are always used without a sampler, and they will also work in regular GL.
3664 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
3665 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
3666 bool separate_sampler = type.basetype == SPIRType::Sampler;
3667 if (!sampler_buffer && (separate_image || separate_sampler))
3668 return;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003669 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003670
3671 if (var.storage != StorageClassFunction && type.pointer &&
Patrick Moursda39a7b2019-02-26 15:43:03 +01003672 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter ||
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01003673 type.storage == StorageClassRayPayloadKHR || type.storage == StorageClassIncomingRayPayloadKHR ||
3674 type.storage == StorageClassCallableDataKHR || type.storage == StorageClassIncomingCallableDataKHR ||
3675 type.storage == StorageClassHitAttributeKHR) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003676 !is_hidden_variable(var))
3677 {
3678 emit_uniform(var);
3679 emitted = true;
3680 }
3681 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003683 if (emitted)
3684 statement("");
3685 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003686
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003687 bool emitted_base_instance = false;
3688
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003689 // Output in/out interfaces.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003690 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003691 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003692
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003693 bool is_hidden = is_hidden_variable(var);
3694
3695 // Unused output I/O variables might still be required to implement framebuffer fetch.
3696 if (var.storage == StorageClassOutput && !is_legacy() &&
Hans-Kristian Arntzen26a49862021-05-21 14:21:13 +02003697 location_is_framebuffer_fetch(get_decoration(var.self, DecorationLocation)) != 0)
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003698 {
3699 is_hidden = false;
3700 }
3701
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003702 if (var.storage != StorageClassFunction && type.pointer &&
3703 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003704 interface_variable_exists_in_entry_point(var.self) && !is_hidden)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003705 {
xinhou4b0584c2021-11-26 10:06:42 +08003706 if (options.es && get_execution_model() == ExecutionModelVertex && var.storage == StorageClassInput &&
3707 type.array.size() == 1)
3708 {
3709 SPIRV_CROSS_THROW("OpenGL ES doesn't support array input variables in vertex shader.");
3710 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003711 emit_interface_block(var);
3712 emitted = true;
3713 }
3714 else if (is_builtin_variable(var))
3715 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003716 auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003717 // For gl_InstanceIndex emulation on GLES, the API user needs to
3718 // supply this uniform.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003719
3720 // The draw parameter extension is soft-enabled on GL with some fallbacks.
3721 if (!options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003722 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003723 if (!emitted_base_instance &&
3724 ((options.vertex.support_nonzero_base_instance && builtin == BuiltInInstanceIndex) ||
3725 (builtin == BuiltInBaseInstance)))
3726 {
3727 statement("#ifdef GL_ARB_shader_draw_parameters");
3728 statement("#define SPIRV_Cross_BaseInstance gl_BaseInstanceARB");
3729 statement("#else");
3730 // A crude, but simple workaround which should be good enough for non-indirect draws.
3731 statement("uniform int SPIRV_Cross_BaseInstance;");
3732 statement("#endif");
3733 emitted = true;
3734 emitted_base_instance = true;
3735 }
3736 else if (builtin == BuiltInBaseVertex)
3737 {
3738 statement("#ifdef GL_ARB_shader_draw_parameters");
3739 statement("#define SPIRV_Cross_BaseVertex gl_BaseVertexARB");
3740 statement("#else");
3741 // A crude, but simple workaround which should be good enough for non-indirect draws.
3742 statement("uniform int SPIRV_Cross_BaseVertex;");
3743 statement("#endif");
3744 }
3745 else if (builtin == BuiltInDrawIndex)
3746 {
3747 statement("#ifndef GL_ARB_shader_draw_parameters");
3748 // Cannot really be worked around.
3749 statement("#error GL_ARB_shader_draw_parameters is not supported.");
3750 statement("#endif");
3751 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003752 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003753 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003754 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003755
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003756 // Global variables.
3757 for (auto global : global_variables)
3758 {
3759 auto &var = get<SPIRVariable>(global);
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +01003760 if (is_hidden_variable(var, true))
3761 continue;
3762
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003763 if (var.storage != StorageClassOutput)
3764 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003765 if (!variable_is_lut(var))
3766 {
3767 add_resource_name(var.self);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003768
3769 string initializer;
3770 if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate &&
3771 !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var)))
3772 {
3773 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var)));
3774 }
3775
3776 statement(variable_decl(var), initializer, ";");
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003777 emitted = true;
3778 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003779 }
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +01003780 else if (var.initializer && maybe_get<SPIRConstant>(var.initializer) != nullptr)
3781 {
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003782 emit_output_variable_initializer(var);
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +01003783 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003784 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003785
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003786 if (emitted)
3787 statement("");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003788
3789 declare_undefined_values();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003790}
3791
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003792void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var)
3793{
3794 // If a StorageClassOutput variable has an initializer, we need to initialize it in main().
3795 auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
3796 auto &type = get<SPIRType>(var.basetype);
3797 bool is_patch = has_decoration(var.self, DecorationPatch);
3798 bool is_block = has_decoration(type.self, DecorationBlock);
3799 bool is_control_point = get_execution_model() == ExecutionModelTessellationControl && !is_patch;
3800
3801 if (is_block)
3802 {
3803 uint32_t member_count = uint32_t(type.member_types.size());
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003804 bool type_is_array = type.array.size() == 1;
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003805 uint32_t array_size = 1;
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003806 if (type_is_array)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003807 array_size = to_array_size_literal(type);
3808 uint32_t iteration_count = is_control_point ? 1 : array_size;
3809
3810 // If the initializer is a block, we must initialize each block member one at a time.
3811 for (uint32_t i = 0; i < member_count; i++)
3812 {
3813 // These outputs might not have been properly declared, so don't initialize them in that case.
3814 if (has_member_decoration(type.self, i, DecorationBuiltIn))
3815 {
3816 if (get_member_decoration(type.self, i, DecorationBuiltIn) == BuiltInCullDistance &&
3817 !cull_distance_count)
3818 continue;
3819
3820 if (get_member_decoration(type.self, i, DecorationBuiltIn) == BuiltInClipDistance &&
3821 !clip_distance_count)
3822 continue;
3823 }
3824
3825 // We need to build a per-member array first, essentially transposing from AoS to SoA.
3826 // This code path hits when we have an array of blocks.
3827 string lut_name;
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003828 if (type_is_array)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003829 {
3830 lut_name = join("_", var.self, "_", i, "_init");
3831 uint32_t member_type_id = get<SPIRType>(var.basetype).member_types[i];
3832 auto &member_type = get<SPIRType>(member_type_id);
3833 auto array_type = member_type;
3834 array_type.parent_type = member_type_id;
3835 array_type.array.push_back(array_size);
3836 array_type.array_size_literal.push_back(true);
3837
3838 SmallVector<string> exprs;
3839 exprs.reserve(array_size);
3840 auto &c = get<SPIRConstant>(var.initializer);
3841 for (uint32_t j = 0; j < array_size; j++)
3842 exprs.push_back(to_expression(get<SPIRConstant>(c.subconstants[j]).subconstants[i]));
3843 statement("const ", type_to_glsl(array_type), " ", lut_name, type_to_array_glsl(array_type), " = ",
3844 type_to_glsl_constructor(array_type), "(", merge(exprs, ", "), ");");
3845 }
3846
3847 for (uint32_t j = 0; j < iteration_count; j++)
3848 {
3849 entry_func.fixup_hooks_in.push_back([=, &var]() {
3850 AccessChainMeta meta;
3851 auto &c = this->get<SPIRConstant>(var.initializer);
3852
3853 uint32_t invocation_id = 0;
3854 uint32_t member_index_id = 0;
3855 if (is_control_point)
3856 {
3857 uint32_t ids = ir.increase_bound_by(3);
3858 SPIRType uint_type;
3859 uint_type.basetype = SPIRType::UInt;
3860 uint_type.width = 32;
3861 set<SPIRType>(ids, uint_type);
3862 set<SPIRExpression>(ids + 1, builtin_to_glsl(BuiltInInvocationId, StorageClassInput), ids, true);
3863 set<SPIRConstant>(ids + 2, ids, i, false);
3864 invocation_id = ids + 1;
3865 member_index_id = ids + 2;
3866 }
3867
3868 if (is_patch)
3869 {
3870 statement("if (gl_InvocationID == 0)");
3871 begin_scope();
3872 }
3873
Hans-Kristian Arntzenc033a932021-01-06 12:59:57 +01003874 if (type_is_array && !is_control_point)
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003875 {
3876 uint32_t indices[2] = { j, i };
3877 auto chain = access_chain_internal(var.self, indices, 2, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
3878 statement(chain, " = ", lut_name, "[", j, "];");
3879 }
3880 else if (is_control_point)
3881 {
3882 uint32_t indices[2] = { invocation_id, member_index_id };
3883 auto chain = access_chain_internal(var.self, indices, 2, 0, &meta);
3884 statement(chain, " = ", lut_name, "[", builtin_to_glsl(BuiltInInvocationId, StorageClassInput), "];");
3885 }
3886 else
3887 {
3888 auto chain =
3889 access_chain_internal(var.self, &i, 1, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
3890 statement(chain, " = ", to_expression(c.subconstants[i]), ";");
3891 }
3892
3893 if (is_patch)
3894 end_scope();
3895 });
3896 }
3897 }
3898 }
3899 else if (is_control_point)
3900 {
3901 auto lut_name = join("_", var.self, "_init");
3902 statement("const ", type_to_glsl(type), " ", lut_name, type_to_array_glsl(type),
3903 " = ", to_expression(var.initializer), ";");
3904 entry_func.fixup_hooks_in.push_back([&, lut_name]() {
3905 statement(to_expression(var.self), "[gl_InvocationID] = ", lut_name, "[gl_InvocationID];");
3906 });
3907 }
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +01003908 else if (has_decoration(var.self, DecorationBuiltIn) &&
3909 BuiltIn(get_decoration(var.self, DecorationBuiltIn)) == BuiltInSampleMask)
3910 {
3911 // We cannot copy the array since gl_SampleMask is unsized in GLSL. Unroll time! <_<
3912 entry_func.fixup_hooks_in.push_back([&] {
3913 auto &c = this->get<SPIRConstant>(var.initializer);
3914 uint32_t num_constants = uint32_t(c.subconstants.size());
3915 for (uint32_t i = 0; i < num_constants; i++)
3916 {
3917 // Don't use to_expression on constant since it might be uint, just fish out the raw int.
3918 statement(to_expression(var.self), "[", i, "] = ",
3919 convert_to_string(this->get<SPIRConstant>(c.subconstants[i]).scalar_i32()), ";");
3920 }
3921 });
3922 }
Hans-Kristian Arntzen39fee932021-01-05 12:50:36 +01003923 else
3924 {
3925 auto lut_name = join("_", var.self, "_init");
3926 statement("const ", type_to_glsl(type), " ", lut_name,
3927 type_to_array_glsl(type), " = ", to_expression(var.initializer), ";");
3928 entry_func.fixup_hooks_in.push_back([&, lut_name, is_patch]() {
3929 if (is_patch)
3930 {
3931 statement("if (gl_InvocationID == 0)");
3932 begin_scope();
3933 }
3934 statement(to_expression(var.self), " = ", lut_name, ";");
3935 if (is_patch)
3936 end_scope();
3937 });
3938 }
3939}
3940
crissdb52e272020-10-08 12:14:52 +02003941void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
3942{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01003943 static const char *workaround_types[] = { "int", "ivec2", "ivec3", "ivec4", "uint", "uvec2", "uvec3", "uvec4",
3944 "float", "vec2", "vec3", "vec4", "double", "dvec2", "dvec3", "dvec4" };
crissdb52e272020-10-08 12:14:52 +02003945
3946 if (!options.vulkan_semantics)
3947 {
3948 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003949 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +02003950
3951 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMask))
3952 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003953 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupMask, result);
crissdb52e272020-10-08 12:14:52 +02003954
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003955 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003956 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003957 const char *name = Supp::get_extension_name(e);
3958 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003959
crissdb52e272020-10-08 12:14:52 +02003960 switch (e)
3961 {
3962 case Supp::NV_shader_thread_group:
3963 statement("#define gl_SubgroupEqMask uvec4(gl_ThreadEqMaskNV, 0u, 0u, 0u)");
3964 statement("#define gl_SubgroupGeMask uvec4(gl_ThreadGeMaskNV, 0u, 0u, 0u)");
3965 statement("#define gl_SubgroupGtMask uvec4(gl_ThreadGtMaskNV, 0u, 0u, 0u)");
3966 statement("#define gl_SubgroupLeMask uvec4(gl_ThreadLeMaskNV, 0u, 0u, 0u)");
3967 statement("#define gl_SubgroupLtMask uvec4(gl_ThreadLtMaskNV, 0u, 0u, 0u)");
3968 break;
3969 case Supp::ARB_shader_ballot:
3970 statement("#define gl_SubgroupEqMask uvec4(unpackUint2x32(gl_SubGroupEqMaskARB), 0u, 0u)");
3971 statement("#define gl_SubgroupGeMask uvec4(unpackUint2x32(gl_SubGroupGeMaskARB), 0u, 0u)");
3972 statement("#define gl_SubgroupGtMask uvec4(unpackUint2x32(gl_SubGroupGtMaskARB), 0u, 0u)");
3973 statement("#define gl_SubgroupLeMask uvec4(unpackUint2x32(gl_SubGroupLeMaskARB), 0u, 0u)");
3974 statement("#define gl_SubgroupLtMask uvec4(unpackUint2x32(gl_SubGroupLtMaskARB), 0u, 0u)");
3975 break;
3976 default:
3977 break;
3978 }
3979 }
3980 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003981 statement("");
crissdb52e272020-10-08 12:14:52 +02003982 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003983
crissdb52e272020-10-08 12:14:52 +02003984 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupSize))
3985 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003986 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupSize, result);
crissdb52e272020-10-08 12:14:52 +02003987
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003988 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003989 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003990 const char *name = Supp::get_extension_name(e);
3991 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003992
crissdb52e272020-10-08 12:14:52 +02003993 switch (e)
3994 {
3995 case Supp::NV_shader_thread_group:
3996 statement("#define gl_SubgroupSize gl_WarpSizeNV");
3997 break;
3998 case Supp::ARB_shader_ballot:
3999 statement("#define gl_SubgroupSize gl_SubGroupSizeARB");
4000 break;
4001 case Supp::AMD_gcn_shader:
4002 statement("#define gl_SubgroupSize uint(gl_SIMDGroupSizeAMD)");
4003 break;
4004 default:
4005 break;
4006 }
4007 }
4008 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004009 statement("");
crissdb52e272020-10-08 12:14:52 +02004010 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004011
crissdb52e272020-10-08 12:14:52 +02004012 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInvocationID))
4013 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004014 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupInvocationID, result);
crissdb52e272020-10-08 12:14:52 +02004015
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004016 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004017 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004018 const char *name = Supp::get_extension_name(e);
4019 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004020
crissdb52e272020-10-08 12:14:52 +02004021 switch (e)
4022 {
4023 case Supp::NV_shader_thread_group:
4024 statement("#define gl_SubgroupInvocationID gl_ThreadInWarpNV");
4025 break;
4026 case Supp::ARB_shader_ballot:
4027 statement("#define gl_SubgroupInvocationID gl_SubGroupInvocationARB");
4028 break;
4029 default:
4030 break;
4031 }
4032 }
4033 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004034 statement("");
crissdb52e272020-10-08 12:14:52 +02004035 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004036
crissdb52e272020-10-08 12:14:52 +02004037 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupID))
4038 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004039 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupID, result);
crissdb52e272020-10-08 12:14:52 +02004040
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004041 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004042 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004043 const char *name = Supp::get_extension_name(e);
4044 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004045
crissdb52e272020-10-08 12:14:52 +02004046 switch (e)
4047 {
4048 case Supp::NV_shader_thread_group:
4049 statement("#define gl_SubgroupID gl_WarpIDNV");
4050 break;
4051 default:
4052 break;
4053 }
4054 }
4055 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004056 statement("");
crissdb52e272020-10-08 12:14:52 +02004057 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004058
crissdb52e272020-10-08 12:14:52 +02004059 if (shader_subgroup_supporter.is_feature_requested(Supp::NumSubgroups))
4060 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004061 auto exts = Supp::get_candidates_for_feature(Supp::NumSubgroups, result);
crissdb52e272020-10-08 12:14:52 +02004062
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004063 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004064 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004065 const char *name = Supp::get_extension_name(e);
4066 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004067
crissdb52e272020-10-08 12:14:52 +02004068 switch (e)
4069 {
4070 case Supp::NV_shader_thread_group:
4071 statement("#define gl_NumSubgroups gl_WarpsPerSMNV");
4072 break;
4073 default:
4074 break;
4075 }
4076 }
4077 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004078 statement("");
crissdb52e272020-10-08 12:14:52 +02004079 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004080
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01004081 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBroadcast_First))
crissdb52e272020-10-08 12:14:52 +02004082 {
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01004083 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBroadcast_First, result);
crissdb52e272020-10-08 12:14:52 +02004084
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004085 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004086 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004087 const char *name = Supp::get_extension_name(e);
4088 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004089
crissdb52e272020-10-08 12:14:52 +02004090 switch (e)
4091 {
4092 case Supp::NV_shader_thread_shuffle:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004093 for (const char *t : workaround_types)
4094 {
4095 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02004096 " value) { return shuffleNV(value, findLSB(ballotThreadNV(true)), gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004097 }
4098 for (const char *t : workaround_types)
4099 {
4100 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02004101 " value, uint id) { return shuffleNV(value, id, gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004102 }
crissdb52e272020-10-08 12:14:52 +02004103 break;
4104 case Supp::ARB_shader_ballot:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004105 for (const char *t : workaround_types)
4106 {
4107 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02004108 " value) { return readFirstInvocationARB(value); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004109 }
4110 for (const char *t : workaround_types)
4111 {
4112 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02004113 " value, uint id) { return readInvocationARB(value, id); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004114 }
crissdb52e272020-10-08 12:14:52 +02004115 break;
4116 default:
4117 break;
4118 }
4119 }
4120 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004121 statement("");
crissdb52e272020-10-08 12:14:52 +02004122 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004123
crissdb52e272020-10-08 12:14:52 +02004124 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotFindLSB_MSB))
4125 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004126 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallotFindLSB_MSB, result);
crissdb52e272020-10-08 12:14:52 +02004127
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004128 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004129 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004130 const char *name = Supp::get_extension_name(e);
4131 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004132
crissdb52e272020-10-08 12:14:52 +02004133 switch (e)
4134 {
4135 case Supp::NV_shader_thread_group:
4136 statement("uint subgroupBallotFindLSB(uvec4 value) { return findLSB(value.x); }");
4137 statement("uint subgroupBallotFindMSB(uvec4 value) { return findMSB(value.x); }");
4138 break;
4139 default:
4140 break;
4141 }
4142 }
4143 statement("#else");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004144 statement("uint subgroupBallotFindLSB(uvec4 value)");
4145 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004146 statement("int firstLive = findLSB(value.x);");
4147 statement("return uint(firstLive != -1 ? firstLive : (findLSB(value.y) + 32));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004148 end_scope();
4149 statement("uint subgroupBallotFindMSB(uvec4 value)");
4150 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004151 statement("int firstLive = findMSB(value.y);");
4152 statement("return uint(firstLive != -1 ? (firstLive + 32) : findMSB(value.x));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004153 end_scope();
crissdb52e272020-10-08 12:14:52 +02004154 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004155 statement("");
crissdb52e272020-10-08 12:14:52 +02004156 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004157
crissdb52e272020-10-08 12:14:52 +02004158 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAll_Any_AllEqualBool))
4159 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004160 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupAll_Any_AllEqualBool, result);
crissdb52e272020-10-08 12:14:52 +02004161
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004162 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004163 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004164 const char *name = Supp::get_extension_name(e);
4165 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004166
crissdb52e272020-10-08 12:14:52 +02004167 switch (e)
4168 {
4169 case Supp::NV_gpu_shader_5:
4170 statement("bool subgroupAll(bool value) { return allThreadsNV(value); }");
4171 statement("bool subgroupAny(bool value) { return anyThreadNV(value); }");
4172 statement("bool subgroupAllEqual(bool value) { return allThreadsEqualNV(value); }");
4173 break;
4174 case Supp::ARB_shader_group_vote:
4175 statement("bool subgroupAll(bool v) { return allInvocationsARB(v); }");
4176 statement("bool subgroupAny(bool v) { return anyInvocationARB(v); }");
4177 statement("bool subgroupAllEqual(bool v) { return allInvocationsEqualARB(v); }");
4178 break;
4179 case Supp::AMD_gcn_shader:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004180 statement("bool subgroupAll(bool value) { return ballotAMD(value) == ballotAMD(true); }");
4181 statement("bool subgroupAny(bool value) { return ballotAMD(value) != 0ull; }");
4182 statement("bool subgroupAllEqual(bool value) { uint64_t b = ballotAMD(value); return b == 0ull || "
4183 "b == ballotAMD(true); }");
crissdb52e272020-10-08 12:14:52 +02004184 break;
4185 default:
4186 break;
4187 }
4188 }
4189 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004190 statement("");
crissdb52e272020-10-08 12:14:52 +02004191 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004192
crissdb52e272020-10-08 12:14:52 +02004193 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAllEqualT))
4194 {
4195 statement("#ifndef GL_KHR_shader_subgroup_vote");
4196 statement(
4197 "#define _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(type) bool subgroupAllEqual(type value) { return "
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004198 "subgroupAllEqual(subgroupBroadcastFirst(value) == value); }");
4199 for (const char *t : workaround_types)
4200 statement("_SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(", t, ")");
crissdb52e272020-10-08 12:14:52 +02004201 statement("#undef _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND");
4202 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004203 statement("");
crissdb52e272020-10-08 12:14:52 +02004204 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004205
crissdb52e272020-10-08 12:14:52 +02004206 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallot))
4207 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004208 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallot, result);
crissdb52e272020-10-08 12:14:52 +02004209
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004210 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02004211 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004212 const char *name = Supp::get_extension_name(e);
4213 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02004214
crissdb52e272020-10-08 12:14:52 +02004215 switch (e)
4216 {
4217 case Supp::NV_shader_thread_group:
4218 statement("uvec4 subgroupBallot(bool v) { return uvec4(ballotThreadNV(v), 0u, 0u, 0u); }");
4219 break;
4220 case Supp::ARB_shader_ballot:
4221 statement("uvec4 subgroupBallot(bool v) { return uvec4(unpackUint2x32(ballotARB(v)), 0u, 0u); }");
4222 break;
4223 default:
4224 break;
4225 }
4226 }
4227 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004228 statement("");
crissdb52e272020-10-08 12:14:52 +02004229 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004230
crissdb52e272020-10-08 12:14:52 +02004231 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupElect))
4232 {
4233 statement("#ifndef GL_KHR_shader_subgroup_basic");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004234 statement("bool subgroupElect()");
4235 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004236 statement("uvec4 activeMask = subgroupBallot(true);");
4237 statement("uint firstLive = subgroupBallotFindLSB(activeMask);");
4238 statement("return gl_SubgroupInvocationID == firstLive;");
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 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004243
crissdb52e272020-10-08 12:14:52 +02004244 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBarrier))
4245 {
4246 // Extensions we're using in place of GL_KHR_shader_subgroup_basic state
4247 // that subgroup execute in lockstep so this barrier is implicit.
devsh6c5f3942020-10-31 21:46:59 +01004248 // However the GL 4.6 spec also states that `barrier` implies a shared memory barrier,
4249 // and a specific test of optimizing scans by leveraging lock-step invocation execution,
4250 // has shown that a `memoryBarrierShared` is needed in place of a `subgroupBarrier`.
4251 // https://github.com/buildaworldnet/IrrlichtBAW/commit/d8536857991b89a30a6b65d29441e51b64c2c7ad#diff-9f898d27be1ea6fc79b03d9b361e299334c1a347b6e4dc344ee66110c6aa596aR19
crissdb52e272020-10-08 12:14:52 +02004252 statement("#ifndef GL_KHR_shader_subgroup_basic");
devsh6c5f3942020-10-31 21:46:59 +01004253 statement("void subgroupBarrier() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02004254 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004255 statement("");
crissdb52e272020-10-08 12:14:52 +02004256 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004257
crissdb52e272020-10-08 12:14:52 +02004258 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMemBarrier))
4259 {
4260 if (model == spv::ExecutionModelGLCompute)
4261 {
4262 statement("#ifndef GL_KHR_shader_subgroup_basic");
4263 statement("void subgroupMemoryBarrier() { groupMemoryBarrier(); }");
4264 statement("void subgroupMemoryBarrierBuffer() { groupMemoryBarrier(); }");
devsh6c5f3942020-10-31 21:46:59 +01004265 statement("void subgroupMemoryBarrierShared() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02004266 statement("void subgroupMemoryBarrierImage() { groupMemoryBarrier(); }");
4267 statement("#endif");
4268 }
4269 else
4270 {
4271 statement("#ifndef GL_KHR_shader_subgroup_basic");
4272 statement("void subgroupMemoryBarrier() { memoryBarrier(); }");
4273 statement("void subgroupMemoryBarrierBuffer() { memoryBarrierBuffer(); }");
4274 statement("void subgroupMemoryBarrierImage() { memoryBarrierImage(); }");
4275 statement("#endif");
4276 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004277 statement("");
crissdb52e272020-10-08 12:14:52 +02004278 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004279
crissdb52e272020-10-08 12:14:52 +02004280 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInverseBallot_InclBitCount_ExclBitCout))
4281 {
4282 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4283 statement("bool subgroupInverseBallot(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004284 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004285 statement("return any(notEqual(value.xy & gl_SubgroupEqMask.xy, uvec2(0u)));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004286 end_scope();
crissdb52e272020-10-08 12:14:52 +02004287
4288 statement("uint subgroupBallotInclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004289 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004290 statement("uvec2 v = value.xy & gl_SubgroupLeMask.xy;");
4291 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004292 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004293 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004294 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004295 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004296 statement_no_indent("#endif");
4297 end_scope();
crissdb52e272020-10-08 12:14:52 +02004298
4299 statement("uint subgroupBallotExclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004300 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004301 statement("uvec2 v = value.xy & gl_SubgroupLtMask.xy;");
4302 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004303 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004304 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004305 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004306 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004307 statement_no_indent("#endif");
4308 end_scope();
crissdb52e272020-10-08 12:14:52 +02004309 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004310 statement("");
crissdb52e272020-10-08 12:14:52 +02004311 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004312
crissdb52e272020-10-08 12:14:52 +02004313 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitCount))
4314 {
4315 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4316 statement("uint subgroupBallotBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004317 begin_scope();
crissdb52e272020-10-08 12:14:52 +02004318 statement("ivec2 c = bitCount(value.xy);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004319 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004320 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004321 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004322 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004323 statement_no_indent("#endif");
4324 end_scope();
crissdb52e272020-10-08 12:14:52 +02004325 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004326 statement("");
crissdb52e272020-10-08 12:14:52 +02004327 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004328
crissdb52e272020-10-08 12:14:52 +02004329 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitExtract))
4330 {
4331 statement("#ifndef GL_KHR_shader_subgroup_ballot");
4332 statement("bool subgroupBallotBitExtract(uvec4 value, uint index)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004333 begin_scope();
4334 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02004335 statement("uint shifted = value.x >> index;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004336 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02004337 statement("uint shifted = value[index >> 5u] >> (index & 0x1fu);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004338 statement_no_indent("#endif");
crissdb52e272020-10-08 12:14:52 +02004339 statement("return (shifted & 1u) != 0u;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004340 end_scope();
crissdb52e272020-10-08 12:14:52 +02004341 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02004342 statement("");
crissdb52e272020-10-08 12:14:52 +02004343 }
4344 }
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02004345
4346 if (!workaround_ubo_load_overload_types.empty())
4347 {
4348 for (auto &type_id : workaround_ubo_load_overload_types)
4349 {
4350 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004351 statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type),
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02004352 " wrap) { return wrap; }");
4353 }
4354 statement("");
4355 }
rdbbf719942020-11-05 17:09:33 +01004356
4357 if (requires_transpose_2x2)
4358 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004359 statement("mat2 spvTranspose(mat2 m)");
rdbbf719942020-11-05 17:09:33 +01004360 begin_scope();
4361 statement("return mat2(m[0][0], m[1][0], m[0][1], m[1][1]);");
4362 end_scope();
4363 statement("");
4364 }
4365
4366 if (requires_transpose_3x3)
4367 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004368 statement("mat3 spvTranspose(mat3 m)");
rdbbf719942020-11-05 17:09:33 +01004369 begin_scope();
4370 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]);");
4371 end_scope();
4372 statement("");
4373 }
4374
4375 if (requires_transpose_4x4)
4376 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004377 statement("mat4 spvTranspose(mat4 m)");
rdbbf719942020-11-05 17:09:33 +01004378 begin_scope();
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01004379 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], "
4380 "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 +01004381 end_scope();
4382 statement("");
4383 }
crissdb52e272020-10-08 12:14:52 +02004384}
4385
Bill Hollingsb321b832016-07-06 20:30:47 -04004386// Returns a string representation of the ID, usable as a function arg.
4387// Default is to simply return the expression representation fo the arg ID.
4388// Subclasses may override to modify the return value.
Chip Davis39dce882019-08-02 15:11:19 -05004389string CompilerGLSL::to_func_call_arg(const SPIRFunction::Parameter &, uint32_t id)
Bill Hollingsb321b832016-07-06 20:30:47 -04004390{
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +02004391 // Make sure that we use the name of the original variable, and not the parameter alias.
4392 uint32_t name_id = id;
4393 auto *var = maybe_get<SPIRVariable>(id);
4394 if (var && var->basevariable)
4395 name_id = var->basevariable;
4396 return to_expression(name_id);
Bill Hollingsb321b832016-07-06 20:30:47 -04004397}
4398
Hans-Kristian Arntzena56b22b2022-02-16 12:12:58 +01004399void CompilerGLSL::force_temporary_and_recompile(uint32_t id)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004400{
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +01004401 auto res = forced_temporaries.insert(id);
4402
4403 // Forcing new temporaries guarantees forward progress.
4404 if (res.second)
4405 force_recompile_guarantee_forward_progress();
4406 else
4407 force_recompile();
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004408}
4409
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02004410uint32_t CompilerGLSL::consume_temporary_in_precision_context(uint32_t type_id, uint32_t id, Options::Precision precision)
4411{
4412 // Constants do not have innate precision.
Hans-Kristian Arntzen92164d32022-05-13 12:14:56 +02004413 auto handle_type = ir.ids[id].get_type();
4414 if (handle_type == TypeConstant || handle_type == TypeConstantOp || handle_type == TypeUndef)
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02004415 return id;
4416
4417 // Ignore anything that isn't 32-bit values.
4418 auto &type = get<SPIRType>(type_id);
4419 if (type.pointer)
4420 return id;
4421 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::UInt && type.basetype != SPIRType::Int)
4422 return id;
4423
4424 if (precision == Options::DontCare)
4425 {
4426 // If precision is consumed as don't care (operations only consisting of constants),
4427 // we need to bind the expression to a temporary,
4428 // otherwise we have no way of controlling the precision later.
4429 auto itr = forced_temporaries.insert(id);
4430 if (itr.second)
4431 force_recompile_guarantee_forward_progress();
4432 return id;
4433 }
4434
4435 auto current_precision = has_decoration(id, DecorationRelaxedPrecision) ? Options::Mediump : Options::Highp;
4436 if (current_precision == precision)
4437 return id;
4438
4439 auto itr = temporary_to_mirror_precision_alias.find(id);
4440 if (itr == temporary_to_mirror_precision_alias.end())
4441 {
4442 uint32_t alias_id = ir.increase_bound_by(1);
4443 auto &m = ir.meta[alias_id];
4444 if (auto *input_m = ir.find_meta(id))
4445 m = *input_m;
4446
4447 const char *prefix;
4448 if (precision == Options::Mediump)
4449 {
4450 set_decoration(alias_id, DecorationRelaxedPrecision);
4451 prefix = "mp_copy_";
4452 }
4453 else
4454 {
4455 unset_decoration(alias_id, DecorationRelaxedPrecision);
4456 prefix = "hp_copy_";
4457 }
4458
4459 auto alias_name = join(prefix, to_name(id));
4460 ParsedIR::sanitize_underscores(alias_name);
4461 set_name(alias_id, alias_name);
4462
4463 emit_op(type_id, alias_id, to_expression(id), true);
4464 temporary_to_mirror_precision_alias[id] = alias_id;
4465 forced_temporaries.insert(id);
4466 forced_temporaries.insert(alias_id);
4467 force_recompile_guarantee_forward_progress();
4468 id = alias_id;
4469 }
4470 else
4471 {
4472 id = itr->second;
4473 }
4474
4475 return id;
4476}
4477
Hans-Kristian Arntzena56b22b2022-02-16 12:12:58 +01004478void CompilerGLSL::handle_invalid_expression(uint32_t id)
4479{
4480 // We tried to read an invalidated expression.
4481 // This means we need another pass at compilation, but next time,
4482 // force temporary variables so that they cannot be invalidated.
4483 force_temporary_and_recompile(id);
Hans-Kristian Arntzen23662662022-05-18 12:26:20 +02004484
4485 // If the invalid expression happened as a result of a CompositeInsert
4486 // overwrite, we must block this from happening next iteration.
4487 if (composite_insert_overwritten.count(id))
4488 block_composite_insert_overwrite.insert(id);
Hans-Kristian Arntzena56b22b2022-02-16 12:12:58 +01004489}
4490
Bill Hollingsb332bae2017-03-01 13:07:40 -05004491// Converts the format of the current expression from packed to unpacked,
4492// by wrapping the expression in a constructor of the appropriate type.
4493// GLSL does not support packed formats, so simply return the expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004494// Subclasses that do will override.
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004495string CompilerGLSL::unpack_expression_type(string expr_str, const SPIRType &, uint32_t, bool, bool)
Bill Hollingsb332bae2017-03-01 13:07:40 -05004496{
4497 return expr_str;
4498}
4499
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01004500// Sometimes we proactively enclosed an expression where it turns out we might have not needed it after all.
4501void CompilerGLSL::strip_enclosed_expression(string &expr)
4502{
4503 if (expr.size() < 2 || expr.front() != '(' || expr.back() != ')')
4504 return;
4505
4506 // Have to make sure that our first and last parens actually enclose everything inside it.
4507 uint32_t paren_count = 0;
4508 for (auto &c : expr)
4509 {
4510 if (c == '(')
4511 paren_count++;
4512 else if (c == ')')
4513 {
4514 paren_count--;
4515
4516 // If we hit 0 and this is not the final char, our first and final parens actually don't
4517 // enclose the expression, and we cannot strip, e.g.: (a + b) * (c + d).
4518 if (paren_count == 0 && &c != &expr.back())
4519 return;
4520 }
4521 }
Corentin Walleze88c88c2017-01-18 17:22:19 -05004522 expr.erase(expr.size() - 1, 1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01004523 expr.erase(begin(expr));
4524}
4525
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004526string CompilerGLSL::enclose_expression(const string &expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004527{
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004528 bool need_parens = false;
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004529
4530 // If the expression starts with a unary we need to enclose to deal with cases where we have back-to-back
4531 // unary expressions.
4532 if (!expr.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004533 {
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004534 auto c = expr.front();
Chip Davis3bfb2f92018-12-03 02:06:33 -06004535 if (c == '-' || c == '+' || c == '!' || c == '~' || c == '&' || c == '*')
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004536 need_parens = true;
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004537 }
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02004538
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004539 if (!need_parens)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004540 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004541 uint32_t paren_count = 0;
4542 for (auto c : expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004543 {
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02004544 if (c == '(' || c == '[')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004545 paren_count++;
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02004546 else if (c == ')' || c == ']')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004547 {
4548 assert(paren_count);
4549 paren_count--;
4550 }
4551 else if (c == ' ' && paren_count == 0)
4552 {
4553 need_parens = true;
4554 break;
4555 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004556 }
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02004557 assert(paren_count == 0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004558 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004559
4560 // If this expression contains any spaces which are not enclosed by parentheses,
4561 // we need to enclose it so we can treat the whole string as an expression.
4562 // This happens when two expressions have been part of a binary op earlier.
4563 if (need_parens)
4564 return join('(', expr, ')');
4565 else
4566 return expr;
4567}
4568
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02004569string CompilerGLSL::dereference_expression(const SPIRType &expr_type, const std::string &expr)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004570{
4571 // If this expression starts with an address-of operator ('&'), then
4572 // just return the part after the operator.
4573 // TODO: Strip parens if unnecessary?
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01004574 if (expr.front() == '&')
Chip Davis3bfb2f92018-12-03 02:06:33 -06004575 return expr.substr(1);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004576 else if (backend.native_pointers)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004577 return join('*', expr);
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02004578 else if (expr_type.storage == StorageClassPhysicalStorageBufferEXT && expr_type.basetype != SPIRType::Struct &&
4579 expr_type.pointer_depth == 1)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004580 {
4581 return join(enclose_expression(expr), ".value");
4582 }
4583 else
4584 return expr;
Chip Davis3bfb2f92018-12-03 02:06:33 -06004585}
4586
4587string CompilerGLSL::address_of_expression(const std::string &expr)
4588{
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004589 if (expr.size() > 3 && expr[0] == '(' && expr[1] == '*' && expr.back() == ')')
4590 {
4591 // If we have an expression which looks like (*foo), taking the address of it is the same as stripping
4592 // the first two and last characters. We might have to enclose the expression.
4593 // This doesn't work for cases like (*foo + 10),
4594 // but this is an r-value expression which we cannot take the address of anyways.
4595 return enclose_expression(expr.substr(2, expr.size() - 3));
4596 }
4597 else if (expr.front() == '*')
4598 {
4599 // If this expression starts with a dereference operator ('*'), then
4600 // just return the part after the operator.
Chip Davis3bfb2f92018-12-03 02:06:33 -06004601 return expr.substr(1);
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004602 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06004603 else
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004604 return join('&', enclose_expression(expr));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004605}
4606
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004607// Just like to_expression except that we enclose the expression inside parentheses if needed.
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004608string CompilerGLSL::to_enclosed_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004609{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004610 return enclose_expression(to_expression(id, register_expression_read));
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004611}
4612
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004613// Used explicitly when we want to read a row-major expression, but without any transpose shenanigans.
4614// need_transpose must be forced to false.
4615string CompilerGLSL::to_unpacked_row_major_matrix_expression(uint32_t id)
4616{
4617 return unpack_expression_type(to_expression(id), expression_type(id),
4618 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
4619 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), true);
4620}
4621
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004622string CompilerGLSL::to_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004623{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02004624 // If we need to transpose, it will also take care of unpacking rules.
4625 auto *e = maybe_get<SPIRExpression>(id);
4626 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004627 bool is_remapped = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4628 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004629
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004630 if (!need_transpose && (is_remapped || is_packed))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004631 {
Hans-Kristian Arntzen1ece67a2019-07-23 17:06:37 +02004632 return unpack_expression_type(to_expression(id, register_expression_read),
4633 get_pointee_type(expression_type_id(id)),
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004634 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004635 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), false);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004636 }
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004637 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004638 return to_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004639}
4640
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004641string CompilerGLSL::to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004642{
Bill Hollings974a0812021-10-21 16:11:33 -04004643 return enclose_expression(to_unpacked_expression(id, register_expression_read));
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004644}
4645
Chip Davis3bfb2f92018-12-03 02:06:33 -06004646string CompilerGLSL::to_dereferenced_expression(uint32_t id, bool register_expression_read)
4647{
4648 auto &type = expression_type(id);
4649 if (type.pointer && should_dereference(id))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004650 return dereference_expression(type, to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004651 else
4652 return to_expression(id, register_expression_read);
4653}
4654
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004655string CompilerGLSL::to_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004656{
4657 auto &type = expression_type(id);
4658 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004659 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004660 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004661 return to_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004662}
4663
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004664string CompilerGLSL::to_enclosed_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004665{
4666 auto &type = expression_type(id);
4667 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004668 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004669 else
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01004670 return to_enclosed_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004671}
4672
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004673string CompilerGLSL::to_extract_component_expression(uint32_t id, uint32_t index)
4674{
4675 auto expr = to_enclosed_expression(id);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004676 if (has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004677 return join(expr, "[", index, "]");
4678 else
4679 return join(expr, ".", index_to_swizzle(index));
4680}
4681
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +01004682string CompilerGLSL::to_extract_constant_composite_expression(uint32_t result_type, const SPIRConstant &c,
4683 const uint32_t *chain, uint32_t length)
4684{
4685 // It is kinda silly if application actually enter this path since they know the constant up front.
4686 // It is useful here to extract the plain constant directly.
4687 SPIRConstant tmp;
4688 tmp.constant_type = result_type;
4689 auto &composite_type = get<SPIRType>(c.constant_type);
4690 assert(composite_type.basetype != SPIRType::Struct && composite_type.array.empty());
4691 assert(!c.specialization);
4692
4693 if (is_matrix(composite_type))
4694 {
4695 if (length == 2)
4696 {
4697 tmp.m.c[0].vecsize = 1;
4698 tmp.m.columns = 1;
4699 tmp.m.c[0].r[0] = c.m.c[chain[0]].r[chain[1]];
4700 }
4701 else
4702 {
4703 assert(length == 1);
4704 tmp.m.c[0].vecsize = composite_type.vecsize;
4705 tmp.m.columns = 1;
4706 tmp.m.c[0] = c.m.c[chain[0]];
4707 }
4708 }
4709 else
4710 {
4711 assert(length == 1);
4712 tmp.m.c[0].vecsize = 1;
4713 tmp.m.columns = 1;
4714 tmp.m.c[0].r[0] = c.m.c[0].r[chain[0]];
4715 }
4716
4717 return constant_expression(tmp);
4718}
4719
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004720string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
4721{
4722 uint32_t size = to_array_size_literal(type);
4723 auto &parent = get<SPIRType>(type.parent_type);
4724 string expr = "{ ";
4725
4726 for (uint32_t i = 0; i < size; i++)
4727 {
4728 auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
4729 if (parent.array.empty())
4730 expr += subexpr;
4731 else
4732 expr += to_rerolled_array_expression(subexpr, parent);
4733
4734 if (i + 1 < size)
4735 expr += ", ";
4736 }
4737
4738 expr += " }";
4739 return expr;
4740}
4741
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01004742string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool block_like_type)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004743{
4744 auto &type = expression_type(id);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004745
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01004746 bool reroll_array = !type.array.empty() &&
4747 (!backend.array_is_value_type ||
4748 (block_like_type && !backend.array_is_value_type_in_buffer_blocks));
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004749
4750 if (reroll_array)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004751 {
4752 // For this case, we need to "re-roll" an array initializer from a temporary.
4753 // We cannot simply pass the array directly, since it decays to a pointer and it cannot
4754 // participate in a struct initializer. E.g.
4755 // float arr[2] = { 1.0, 2.0 };
4756 // Foo foo = { arr }; must be transformed to
4757 // Foo foo = { { arr[0], arr[1] } };
4758 // The array sizes cannot be deduced from specialization constants since we cannot use any loops.
4759
4760 // We're only triggering one read of the array expression, but this is fine since arrays have to be declared
4761 // as temporaries anyways.
4762 return to_rerolled_array_expression(to_enclosed_expression(id), type);
4763 }
4764 else
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02004765 return to_unpacked_expression(id);
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004766}
4767
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004768string CompilerGLSL::to_non_uniform_aware_expression(uint32_t id)
4769{
4770 string expr = to_expression(id);
4771
4772 if (has_decoration(id, DecorationNonUniform))
4773 convert_non_uniform_expression(expr, id);
4774
4775 return expr;
4776}
4777
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004778string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004779{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004780 auto itr = invalid_expressions.find(id);
4781 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004782 handle_invalid_expression(id);
4783
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004784 if (ir.ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004785 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004786 // We might have a more complex chain of dependencies.
4787 // A possible scenario is that we
4788 //
4789 // %1 = OpLoad
4790 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
4791 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
4792 // 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.
4793 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
4794 //
4795 // 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,
4796 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004797 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004798 for (uint32_t dep : expr.expression_dependencies)
4799 if (invalid_expressions.find(dep) != end(invalid_expressions))
4800 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004801 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004802
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004803 if (register_expression_read)
4804 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004805
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004806 switch (ir.ids[id].get_type())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004807 {
4808 case TypeExpression:
4809 {
4810 auto &e = get<SPIRExpression>(id);
4811 if (e.base_expression)
Hans-Kristian Arntzenea781e62016-12-06 17:19:34 +01004812 return to_enclosed_expression(e.base_expression) + e.expression;
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02004813 else if (e.need_transpose)
Bill Hollings607b0d62018-02-11 16:52:57 -05004814 {
Hans-Kristian Arntzen2172b192019-07-22 16:27:47 +02004815 // This should not be reached for access chains, since we always deal explicitly with transpose state
4816 // when consuming an access chain expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004817 uint32_t physical_type_id = get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4818 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02004819 return convert_row_major_matrix(e.expression, get<SPIRType>(e.expression_type), physical_type_id,
4820 is_packed);
Bill Hollings607b0d62018-02-11 16:52:57 -05004821 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004822 else if (flattened_structs.count(id))
4823 {
4824 return load_flattened_struct(e.expression, get<SPIRType>(e.expression_type));
4825 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004826 else
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004827 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02004828 if (is_forcing_recompilation())
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004829 {
4830 // During first compilation phase, certain expression patterns can trigger exponential growth of memory.
4831 // Avoid this by returning dummy expressions during this phase.
4832 // Do not use empty expressions here, because those are sentinels for other cases.
4833 return "_";
4834 }
4835 else
4836 return e.expression;
4837 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004838 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004839
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004840 case TypeConstant:
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004841 {
4842 auto &c = get<SPIRConstant>(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004843 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02004844
4845 // WorkGroupSize may be a constant.
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004846 if (has_decoration(c.self, DecorationBuiltIn))
4847 return builtin_to_glsl(BuiltIn(get_decoration(c.self, DecorationBuiltIn)), StorageClassGeneric);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004848 else if (c.specialization)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004849 {
4850 if (backend.workgroup_size_is_hidden)
4851 {
4852 int wg_index = get_constant_mapping_to_workgroup_component(c);
4853 if (wg_index >= 0)
4854 {
4855 auto wg_size = join(builtin_to_glsl(BuiltInWorkgroupSize, StorageClassInput), vector_swizzle(1, wg_index));
4856 if (type.basetype != SPIRType::UInt)
4857 wg_size = bitcast_expression(type, SPIRType::UInt, wg_size);
4858 return wg_size;
4859 }
4860 }
4861
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004862 return to_name(id);
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01004863 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02004864 else if (c.is_used_as_lut)
4865 return to_name(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004866 else if (type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
4867 return to_name(id);
4868 else if (!type.array.empty() && !backend.can_declare_arrays_inline)
4869 return to_name(id);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004870 else
4871 return constant_expression(c);
4872 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004873
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004874 case TypeConstantOp:
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01004875 return to_name(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004876
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004877 case TypeVariable:
4878 {
4879 auto &var = get<SPIRVariable>(id);
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01004880 // If we try to use a loop variable before the loop header, we have to redirect it to the static expression,
4881 // the variable has not been declared yet.
4882 if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable))
Hans-Kristian Arntzen40b30532022-04-28 14:36:53 +02004883 {
4884 // We might try to load from a loop variable before it has been initialized.
4885 // Prefer static expression and fallback to initializer.
4886 if (var.static_expression)
4887 return to_expression(var.static_expression);
4888 else if (var.initializer)
4889 return to_expression(var.initializer);
4890 else
4891 {
4892 // We cannot declare the variable yet, so have to fake it.
4893 uint32_t undef_id = ir.increase_bound_by(1);
4894 return emit_uninitialized_temporary_expression(get_variable_data_type_id(var), undef_id).expression;
4895 }
4896 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004897 else if (var.deferred_declaration)
4898 {
4899 var.deferred_declaration = false;
4900 return variable_decl(var);
4901 }
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004902 else if (flattened_structs.count(id))
4903 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004904 return load_flattened_struct(to_name(id), get<SPIRType>(var.basetype));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004905 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004906 else
4907 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004908 auto &dec = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004909 if (dec.builtin)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004910 return builtin_to_glsl(dec.builtin_type, var.storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004911 else
4912 return to_name(id);
4913 }
4914 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004915
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02004916 case TypeCombinedImageSampler:
4917 // This type should never be taken the expression of directly.
4918 // The intention is that texture sampling functions will extract the image and samplers
4919 // separately and take their expressions as needed.
4920 // GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
4921 // expression ala sampler2D(texture, sampler).
4922 SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
4923
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004924 case TypeAccessChain:
4925 // We cannot express this type. They only have meaning in other OpAccessChains, OpStore or OpLoad.
4926 SPIRV_CROSS_THROW("Access chains have no default expression representation.");
4927
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004928 default:
4929 return to_name(id);
4930 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004931}
4932
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004933string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
4934{
4935 auto &type = get<SPIRType>(cop.basetype);
4936 bool binary = false;
4937 bool unary = false;
4938 string op;
4939
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004940 if (is_legacy() && is_unsigned_opcode(cop.opcode))
4941 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
4942
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004943 // TODO: Find a clean way to reuse emit_instruction.
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004944 switch (cop.opcode)
4945 {
4946 case OpSConvert:
4947 case OpUConvert:
4948 case OpFConvert:
4949 op = type_to_glsl_constructor(type);
4950 break;
4951
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004952#define GLSL_BOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004953 case Op##opname: \
4954 binary = true; \
4955 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004956 break
4957
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004958#define GLSL_UOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004959 case Op##opname: \
4960 unary = true; \
4961 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004962 break
4963
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004964 GLSL_UOP(SNegate, "-");
4965 GLSL_UOP(Not, "~");
4966 GLSL_BOP(IAdd, "+");
4967 GLSL_BOP(ISub, "-");
4968 GLSL_BOP(IMul, "*");
4969 GLSL_BOP(SDiv, "/");
4970 GLSL_BOP(UDiv, "/");
4971 GLSL_BOP(UMod, "%");
4972 GLSL_BOP(SMod, "%");
4973 GLSL_BOP(ShiftRightLogical, ">>");
4974 GLSL_BOP(ShiftRightArithmetic, ">>");
4975 GLSL_BOP(ShiftLeftLogical, "<<");
4976 GLSL_BOP(BitwiseOr, "|");
4977 GLSL_BOP(BitwiseXor, "^");
4978 GLSL_BOP(BitwiseAnd, "&");
4979 GLSL_BOP(LogicalOr, "||");
4980 GLSL_BOP(LogicalAnd, "&&");
4981 GLSL_UOP(LogicalNot, "!");
4982 GLSL_BOP(LogicalEqual, "==");
4983 GLSL_BOP(LogicalNotEqual, "!=");
4984 GLSL_BOP(IEqual, "==");
4985 GLSL_BOP(INotEqual, "!=");
4986 GLSL_BOP(ULessThan, "<");
4987 GLSL_BOP(SLessThan, "<");
4988 GLSL_BOP(ULessThanEqual, "<=");
4989 GLSL_BOP(SLessThanEqual, "<=");
4990 GLSL_BOP(UGreaterThan, ">");
4991 GLSL_BOP(SGreaterThan, ">");
4992 GLSL_BOP(UGreaterThanEqual, ">=");
4993 GLSL_BOP(SGreaterThanEqual, ">=");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004994
Bill Hollings5fb1ca42021-09-03 18:20:49 -04004995 case OpSRem:
4996 {
4997 uint32_t op0 = cop.arguments[0];
4998 uint32_t op1 = cop.arguments[1];
4999 return join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
5000 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
5001 }
5002
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005003 case OpSelect:
5004 {
5005 if (cop.arguments.size() < 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005006 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005007
5008 // This one is pretty annoying. It's triggered from
5009 // uint(bool), int(bool) from spec constants.
5010 // In order to preserve its compile-time constness in Vulkan GLSL,
5011 // we need to reduce the OpSelect expression back to this simplified model.
5012 // If we cannot, fail.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005013 if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005014 {
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005015 // Implement as a simple cast down below.
5016 }
5017 else
5018 {
5019 // Implement a ternary and pray the compiler understands it :)
5020 return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005021 }
5022 break;
5023 }
5024
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02005025 case OpVectorShuffle:
5026 {
5027 string expr = type_to_glsl_constructor(type);
5028 expr += "(";
5029
5030 uint32_t left_components = expression_type(cop.arguments[0]).vecsize;
5031 string left_arg = to_enclosed_expression(cop.arguments[0]);
5032 string right_arg = to_enclosed_expression(cop.arguments[1]);
5033
5034 for (uint32_t i = 2; i < uint32_t(cop.arguments.size()); i++)
5035 {
5036 uint32_t index = cop.arguments[i];
5037 if (index >= left_components)
5038 expr += right_arg + "." + "xyzw"[index - left_components];
5039 else
5040 expr += left_arg + "." + "xyzw"[index];
5041
5042 if (i + 1 < uint32_t(cop.arguments.size()))
5043 expr += ", ";
5044 }
5045
5046 expr += ")";
5047 return expr;
5048 }
5049
5050 case OpCompositeExtract:
5051 {
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01005052 auto expr = access_chain_internal(cop.arguments[0], &cop.arguments[1], uint32_t(cop.arguments.size() - 1),
5053 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02005054 return expr;
5055 }
5056
5057 case OpCompositeInsert:
5058 SPIRV_CROSS_THROW("OpCompositeInsert spec constant op is not supported.");
5059
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005060 default:
5061 // Some opcodes are unimplemented here, these are currently not possible to test from glslang.
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005062 SPIRV_CROSS_THROW("Unimplemented spec constant op.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005063 }
5064
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005065 uint32_t bit_width = 0;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005066 if (unary || binary || cop.opcode == OpSConvert || cop.opcode == OpUConvert)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005067 bit_width = expression_type(cop.arguments[0]).width;
5068
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005069 SPIRType::BaseType input_type;
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005070 bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005071
5072 switch (cop.opcode)
5073 {
5074 case OpIEqual:
5075 case OpINotEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005076 input_type = to_signed_basetype(bit_width);
5077 break;
5078
5079 case OpSLessThan:
5080 case OpSLessThanEqual:
5081 case OpSGreaterThan:
5082 case OpSGreaterThanEqual:
5083 case OpSMod:
5084 case OpSDiv:
5085 case OpShiftRightArithmetic:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005086 case OpSConvert:
5087 case OpSNegate:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005088 input_type = to_signed_basetype(bit_width);
5089 break;
5090
5091 case OpULessThan:
5092 case OpULessThanEqual:
5093 case OpUGreaterThan:
5094 case OpUGreaterThanEqual:
5095 case OpUMod:
5096 case OpUDiv:
5097 case OpShiftRightLogical:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005098 case OpUConvert:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005099 input_type = to_unsigned_basetype(bit_width);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005100 break;
5101
5102 default:
5103 input_type = type.basetype;
5104 break;
5105 }
5106
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005107#undef GLSL_BOP
5108#undef GLSL_UOP
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005109 if (binary)
5110 {
5111 if (cop.arguments.size() < 2)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005112 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005113
5114 string cast_op0;
5115 string cast_op1;
5116 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, cop.arguments[0],
5117 cop.arguments[1], skip_cast_if_equal_type);
5118
5119 if (type.basetype != input_type && type.basetype != SPIRType::Boolean)
5120 {
5121 expected_type.basetype = input_type;
5122 auto expr = bitcast_glsl_op(type, expected_type);
5123 expr += '(';
5124 expr += join(cast_op0, " ", op, " ", cast_op1);
5125 expr += ')';
5126 return expr;
5127 }
5128 else
5129 return join("(", cast_op0, " ", op, " ", cast_op1, ")");
5130 }
5131 else if (unary)
5132 {
5133 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005134 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005135
5136 // Auto-bitcast to result type as needed.
5137 // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
5138 return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")");
5139 }
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005140 else if (cop.opcode == OpSConvert || cop.opcode == OpUConvert)
5141 {
5142 if (cop.arguments.size() < 1)
5143 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
5144
5145 auto &arg_type = expression_type(cop.arguments[0]);
5146 if (arg_type.width < type.width && input_type != arg_type.basetype)
5147 {
5148 auto expected = arg_type;
5149 expected.basetype = input_type;
5150 return join(op, "(", bitcast_glsl(expected, cop.arguments[0]), ")");
5151 }
5152 else
5153 return join(op, "(", to_expression(cop.arguments[0]), ")");
5154 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005155 else
5156 {
5157 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005158 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005159 return join(op, "(", to_expression(cop.arguments[0]), ")");
5160 }
5161}
5162
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01005163string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_block_like_struct_scope)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005164{
Chip Davis3bfb2f92018-12-03 02:06:33 -06005165 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02005166
Chip Davis3bfb2f92018-12-03 02:06:33 -06005167 if (type.pointer)
5168 {
5169 return backend.null_pointer_literal;
5170 }
5171 else if (!c.subconstants.empty())
5172 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005173 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005174 string res;
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005175
Hans-Kristian Arntzen7b9eaf02022-03-22 12:10:13 +01005176 // Only consider the decay if we are inside a struct scope where we are emitting a member with Offset decoration.
5177 // Outside a block-like struct declaration, we can always bind to a constant array with templated type.
5178 // Should look at ArrayStride here as well, but it's possible to declare a constant struct
5179 // with Offset = 0, using no ArrayStride on the enclosed array type.
5180 // A particular CTS test hits this scenario.
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01005181 bool array_type_decays = inside_block_like_struct_scope &&
Hans-Kristian Arntzen7b9eaf02022-03-22 12:10:13 +01005182 !type.array.empty() && !backend.array_is_value_type_in_buffer_blocks;
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01005183
Lukas Hermanns50ac6862019-09-18 14:03:54 -04005184 // Allow Metal to use the array<T> template to make arrays a value type
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005185 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen57a15df2018-09-10 10:08:02 +02005186 if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02005187 type.array.empty())
5188 {
5189 res = type_to_glsl_constructor(type) + "{ ";
5190 }
Hans-Kristian Arntzenc2655ab2020-03-19 14:21:42 +01005191 else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01005192 !type.array.empty() && !array_type_decays)
Mark Satterthwaited50659a2019-08-13 18:18:48 -04005193 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02005194 res = type_to_glsl_constructor(type) + "({ ";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005195 needs_trailing_tracket = true;
Mark Satterthwaited50659a2019-08-13 18:18:48 -04005196 }
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02005197 else if (backend.use_initializer_list)
5198 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005199 res = "{ ";
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02005200 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005201 else
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02005202 {
5203 res = type_to_glsl_constructor(type) + "(";
5204 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005205
Hans-Kristian Arntzen7b9eaf02022-03-22 12:10:13 +01005206 uint32_t subconstant_index = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005207 for (auto &elem : c.subconstants)
5208 {
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02005209 auto &subc = get<SPIRConstant>(elem);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005210 if (subc.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02005211 res += to_name(elem);
5212 else
Hans-Kristian Arntzen7b9eaf02022-03-22 12:10:13 +01005213 {
5214 if (type.array.empty() && type.basetype == SPIRType::Struct)
5215 {
5216 // When we get down to emitting struct members, override the block-like information.
5217 // For constants, we can freely mix and match block-like state.
5218 inside_block_like_struct_scope =
5219 has_member_decoration(type.self, subconstant_index, DecorationOffset);
5220 }
5221
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01005222 res += constant_expression(subc, inside_block_like_struct_scope);
Hans-Kristian Arntzen7b9eaf02022-03-22 12:10:13 +01005223 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02005224
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005225 if (&elem != &c.subconstants.back())
5226 res += ", ";
Hans-Kristian Arntzen7b9eaf02022-03-22 12:10:13 +01005227
5228 subconstant_index++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005229 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005230
5231 res += backend.use_initializer_list ? " }" : ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005232 if (needs_trailing_tracket)
Mark Satterthwaited50659a2019-08-13 18:18:48 -04005233 res += ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04005234
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005235 return res;
5236 }
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04005237 else if (type.basetype == SPIRType::Struct && type.member_types.size() == 0)
5238 {
5239 // Metal tessellation likes empty structs which are then constant expressions.
Hans-Kristian Arntzen3b5c4c72019-10-24 17:05:55 +02005240 if (backend.supports_empty_struct)
5241 return "{ }";
5242 else if (backend.use_typed_initializer_list)
5243 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "{ 0 }");
5244 else if (backend.use_initializer_list)
5245 return "{ 0 }";
5246 else
5247 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "(0)");
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04005248 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005249 else if (c.columns() == 1)
5250 {
5251 return constant_expression_vector(c, 0);
5252 }
5253 else
5254 {
5255 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
5256 for (uint32_t col = 0; col < c.columns(); col++)
5257 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005258 if (c.specialization_constant_id(col) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005259 res += to_name(c.specialization_constant_id(col));
5260 else
5261 res += constant_expression_vector(c, col);
5262
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005263 if (col + 1 < c.columns())
5264 res += ", ";
5265 }
5266 res += ")";
5267 return res;
5268 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005269}
5270
Frédéric Wang9c44a972022-06-23 11:40:02 +02005271#ifdef _MSC_VER
Frédéric Wang1310f5b2022-06-23 11:34:51 +02005272// snprintf does not exist or is buggy on older MSVC versions, some of them
5273// being used by MinGW. Use sprintf instead and disable corresponding warning.
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005274#pragma warning(push)
5275#pragma warning(disable : 4996)
5276#endif
5277
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005278string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5279{
5280 string res;
5281 float float_value = c.scalar_f16(col, row);
5282
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005283 // There is no literal "hf" in GL_NV_gpu_shader5, so to avoid lots
5284 // of complicated workarounds, just value-cast to the half type always.
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005285 if (std::isnan(float_value) || std::isinf(float_value))
5286 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005287 SPIRType type;
5288 type.basetype = SPIRType::Half;
5289 type.vecsize = 1;
5290 type.columns = 1;
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005291
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005292 if (float_value == numeric_limits<float>::infinity())
5293 res = join(type_to_glsl(type), "(1.0 / 0.0)");
5294 else if (float_value == -numeric_limits<float>::infinity())
5295 res = join(type_to_glsl(type), "(-1.0 / 0.0)");
5296 else if (std::isnan(float_value))
5297 res = join(type_to_glsl(type), "(0.0 / 0.0)");
5298 else
5299 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005300 }
5301 else
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005302 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01005303 SPIRType type;
5304 type.basetype = SPIRType::Half;
5305 type.vecsize = 1;
5306 type.columns = 1;
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005307 res = join(type_to_glsl(type), "(", convert_to_string(float_value, current_locale_radix_character), ")");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005308 }
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005309
5310 return res;
5311}
5312
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005313string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5314{
5315 string res;
5316 float float_value = c.scalar_f32(col, row);
5317
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005318 if (std::isnan(float_value) || std::isinf(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005319 {
5320 // Use special representation.
5321 if (!is_legacy())
5322 {
5323 SPIRType out_type;
5324 SPIRType in_type;
5325 out_type.basetype = SPIRType::Float;
5326 in_type.basetype = SPIRType::UInt;
5327 out_type.vecsize = 1;
5328 in_type.vecsize = 1;
5329 out_type.width = 32;
5330 in_type.width = 32;
5331
5332 char print_buffer[32];
Frédéric Wang1310f5b2022-06-23 11:34:51 +02005333#ifdef _WIN32
5334 sprintf(print_buffer, "0x%xu", c.scalar(col, row));
5335#else
Frédéric Wang99f86132022-06-21 16:28:16 +02005336 snprintf(print_buffer, sizeof(print_buffer), "0x%xu", c.scalar(col, row));
Frédéric Wang1310f5b2022-06-23 11:34:51 +02005337#endif
xndcn02fb8f22021-05-26 22:43:26 +08005338
5339 const char *comment = "inf";
5340 if (float_value == -numeric_limits<float>::infinity())
5341 comment = "-inf";
5342 else if (std::isnan(float_value))
5343 comment = "nan";
5344 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005345 }
5346 else
5347 {
5348 if (float_value == numeric_limits<float>::infinity())
5349 {
5350 if (backend.float_literal_suffix)
5351 res = "(1.0f / 0.0f)";
5352 else
5353 res = "(1.0 / 0.0)";
5354 }
5355 else if (float_value == -numeric_limits<float>::infinity())
5356 {
5357 if (backend.float_literal_suffix)
5358 res = "(-1.0f / 0.0f)";
5359 else
5360 res = "(-1.0 / 0.0)";
5361 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005362 else if (std::isnan(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005363 {
5364 if (backend.float_literal_suffix)
5365 res = "(0.0f / 0.0f)";
5366 else
5367 res = "(0.0 / 0.0)";
5368 }
5369 else
5370 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
5371 }
5372 }
5373 else
5374 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005375 res = convert_to_string(float_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005376 if (backend.float_literal_suffix)
5377 res += "f";
5378 }
5379
5380 return res;
5381}
5382
5383std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
5384{
5385 string res;
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005386 double double_value = c.scalar_f64(col, row);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005387
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005388 if (std::isnan(double_value) || std::isinf(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005389 {
5390 // Use special representation.
5391 if (!is_legacy())
5392 {
5393 SPIRType out_type;
5394 SPIRType in_type;
5395 out_type.basetype = SPIRType::Double;
5396 in_type.basetype = SPIRType::UInt64;
5397 out_type.vecsize = 1;
5398 in_type.vecsize = 1;
5399 out_type.width = 64;
5400 in_type.width = 64;
5401
5402 uint64_t u64_value = c.scalar_u64(col, row);
5403
Hans-Kristian Arntzendf21a992022-06-07 15:39:37 +02005404 if (options.es && options.version < 310) // GL_NV_gpu_shader5 fallback requires 310.
5405 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile before version 310.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005406 require_extension_internal("GL_ARB_gpu_shader_int64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005407
5408 char print_buffer[64];
Frédéric Wang1310f5b2022-06-23 11:34:51 +02005409#ifdef _WIN32
5410 sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
5411 backend.long_long_literal_suffix ? "ull" : "ul");
5412#else
Frédéric Wang99f86132022-06-21 16:28:16 +02005413 snprintf(print_buffer, sizeof(print_buffer), "0x%llx%s", static_cast<unsigned long long>(u64_value),
5414 backend.long_long_literal_suffix ? "ull" : "ul");
Frédéric Wang1310f5b2022-06-23 11:34:51 +02005415#endif
xndcn02fb8f22021-05-26 22:43:26 +08005416
5417 const char *comment = "inf";
5418 if (double_value == -numeric_limits<double>::infinity())
5419 comment = "-inf";
5420 else if (std::isnan(double_value))
5421 comment = "nan";
5422 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005423 }
5424 else
5425 {
5426 if (options.es)
5427 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
5428 if (options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005429 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005430
5431 if (double_value == numeric_limits<double>::infinity())
5432 {
5433 if (backend.double_literal_suffix)
5434 res = "(1.0lf / 0.0lf)";
5435 else
5436 res = "(1.0 / 0.0)";
5437 }
5438 else if (double_value == -numeric_limits<double>::infinity())
5439 {
5440 if (backend.double_literal_suffix)
5441 res = "(-1.0lf / 0.0lf)";
5442 else
5443 res = "(-1.0 / 0.0)";
5444 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01005445 else if (std::isnan(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005446 {
5447 if (backend.double_literal_suffix)
5448 res = "(0.0lf / 0.0lf)";
5449 else
5450 res = "(0.0 / 0.0)";
5451 }
5452 else
5453 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
5454 }
5455 }
5456 else
5457 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01005458 res = convert_to_string(double_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005459 if (backend.double_literal_suffix)
5460 res += "lf";
5461 }
5462
5463 return res;
5464}
5465
Frédéric Wang9c44a972022-06-23 11:40:02 +02005466#ifdef _MSC_VER
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005467#pragma warning(pop)
5468#endif
5469
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005470string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
5471{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005472 auto type = get<SPIRType>(c.constant_type);
5473 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005474
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005475 auto scalar_type = type;
5476 scalar_type.vecsize = 1;
5477
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005478 string res;
Robert Konradea24ee82016-09-23 18:57:18 +02005479 bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005480 bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005481
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005482 if (!type_is_floating_point(type))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005483 {
5484 // Cannot swizzle literal integers as a special case.
5485 swizzle_splat = false;
5486 }
5487
5488 if (splat || swizzle_splat)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005489 {
5490 // Cannot use constant splatting if we have specialization constants somewhere in the vector.
5491 for (uint32_t i = 0; i < c.vector_size(); i++)
5492 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005493 if (c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005494 {
5495 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005496 swizzle_splat = false;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005497 break;
5498 }
5499 }
5500 }
5501
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005502 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005503 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02005504 if (type.width == 64)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005505 {
5506 uint64_t ident = c.scalar_u64(vector, 0);
5507 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005508 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005509 if (ident != c.scalar_u64(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005510 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005511 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005512 swizzle_splat = false;
5513 break;
5514 }
5515 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005516 }
5517 else
5518 {
5519 uint32_t ident = c.scalar(vector, 0);
5520 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005521 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005522 if (ident != c.scalar(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005523 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005524 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005525 swizzle_splat = false;
5526 }
5527 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005528 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005529 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005530
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005531 if (c.vector_size() > 1 && !swizzle_splat)
5532 res += type_to_glsl(type) + "(";
5533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005534 switch (type.basetype)
5535 {
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005536 case SPIRType::Half:
5537 if (splat || swizzle_splat)
5538 {
5539 res += convert_half_to_string(c, vector, 0);
5540 if (swizzle_splat)
5541 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
5542 }
5543 else
5544 {
5545 for (uint32_t i = 0; i < c.vector_size(); i++)
5546 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005547 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005548 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005549 else
5550 res += convert_half_to_string(c, vector, i);
5551
5552 if (i + 1 < c.vector_size())
5553 res += ", ";
5554 }
5555 }
5556 break;
5557
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005558 case SPIRType::Float:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005559 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005560 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005561 res += convert_float_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005562 if (swizzle_splat)
5563 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005564 }
5565 else
5566 {
5567 for (uint32_t i = 0; i < c.vector_size(); i++)
5568 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005569 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005570 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005571 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005572 res += convert_float_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005574 if (i + 1 < c.vector_size())
5575 res += ", ";
5576 }
5577 }
5578 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005579
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005580 case SPIRType::Double:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005581 if (splat || swizzle_splat)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005582 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005583 res += convert_double_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005584 if (swizzle_splat)
5585 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005586 }
5587 else
5588 {
5589 for (uint32_t i = 0; i < c.vector_size(); i++)
5590 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005591 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005592 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005593 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01005594 res += convert_double_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005595
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005596 if (i + 1 < c.vector_size())
5597 res += ", ";
5598 }
5599 }
5600 break;
5601
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005602 case SPIRType::Int64:
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005603 {
5604 auto tmp = type;
5605 tmp.vecsize = 1;
5606 tmp.columns = 1;
5607 auto int64_type = type_to_glsl(tmp);
5608
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005609 if (splat)
5610 {
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005611 res += convert_to_string(c.scalar_i64(vector, 0), int64_type, backend.long_long_literal_suffix);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005612 }
5613 else
5614 {
5615 for (uint32_t i = 0; i < c.vector_size(); i++)
5616 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005617 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005618 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005619 else
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005620 res += convert_to_string(c.scalar_i64(vector, i), int64_type, backend.long_long_literal_suffix);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005621
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005622 if (i + 1 < c.vector_size())
5623 res += ", ";
5624 }
5625 }
5626 break;
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +02005627 }
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005628
5629 case SPIRType::UInt64:
5630 if (splat)
5631 {
5632 res += convert_to_string(c.scalar_u64(vector, 0));
5633 if (backend.long_long_literal_suffix)
5634 res += "ull";
5635 else
5636 res += "ul";
5637 }
5638 else
5639 {
5640 for (uint32_t i = 0; i < c.vector_size(); i++)
5641 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005642 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005643 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005644 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005645 {
5646 res += convert_to_string(c.scalar_u64(vector, i));
5647 if (backend.long_long_literal_suffix)
5648 res += "ull";
5649 else
5650 res += "ul";
5651 }
5652
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005653 if (i + 1 < c.vector_size())
5654 res += ", ";
5655 }
5656 }
5657 break;
5658
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005659 case SPIRType::UInt:
5660 if (splat)
5661 {
5662 res += convert_to_string(c.scalar(vector, 0));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005663 if (is_legacy())
5664 {
5665 // Fake unsigned constant literals with signed ones if possible.
5666 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
5667 if (c.scalar_i32(vector, 0) < 0)
5668 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative.");
5669 }
5670 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005671 res += "u";
5672 }
5673 else
5674 {
5675 for (uint32_t i = 0; i < c.vector_size(); i++)
5676 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005677 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005678 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005679 else
5680 {
5681 res += convert_to_string(c.scalar(vector, i));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005682 if (is_legacy())
5683 {
5684 // Fake unsigned constant literals with signed ones if possible.
5685 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
5686 if (c.scalar_i32(vector, i) < 0)
crissdb52e272020-10-08 12:14:52 +02005687 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made "
5688 "the literal negative.");
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02005689 }
5690 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005691 res += "u";
5692 }
5693
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005694 if (i + 1 < c.vector_size())
5695 res += ", ";
5696 }
5697 }
5698 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005699
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005700 case SPIRType::Int:
5701 if (splat)
5702 res += convert_to_string(c.scalar_i32(vector, 0));
5703 else
5704 {
5705 for (uint32_t i = 0; i < c.vector_size(); i++)
5706 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005707 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005708 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005709 else
5710 res += convert_to_string(c.scalar_i32(vector, i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005711 if (i + 1 < c.vector_size())
5712 res += ", ";
5713 }
5714 }
5715 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005716
Chip Davisca4744a2018-11-02 14:39:55 -05005717 case SPIRType::UShort:
5718 if (splat)
5719 {
5720 res += convert_to_string(c.scalar(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005721 }
5722 else
5723 {
5724 for (uint32_t i = 0; i < c.vector_size(); i++)
5725 {
5726 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005727 res += to_expression(c.specialization_constant_id(vector, i));
Chip Davisca4744a2018-11-02 14:39:55 -05005728 else
5729 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005730 if (*backend.uint16_t_literal_suffix)
Chip Davisca4744a2018-11-02 14:39:55 -05005731 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005732 res += convert_to_string(c.scalar_u16(vector, i));
5733 res += backend.uint16_t_literal_suffix;
Chip Davisca4744a2018-11-02 14:39:55 -05005734 }
Bill Hollingsc48702d2019-03-28 14:23:32 -04005735 else
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005736 {
5737 // If backend doesn't have a literal suffix, we need to value cast.
5738 res += type_to_glsl(scalar_type);
5739 res += "(";
5740 res += convert_to_string(c.scalar_u16(vector, i));
5741 res += ")";
5742 }
Chip Davisca4744a2018-11-02 14:39:55 -05005743 }
5744
5745 if (i + 1 < c.vector_size())
5746 res += ", ";
5747 }
5748 }
5749 break;
5750
5751 case SPIRType::Short:
5752 if (splat)
5753 {
5754 res += convert_to_string(c.scalar_i16(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005755 }
5756 else
5757 {
5758 for (uint32_t i = 0; i < c.vector_size(); i++)
5759 {
5760 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005761 res += to_expression(c.specialization_constant_id(vector, i));
Chip Davisca4744a2018-11-02 14:39:55 -05005762 else
5763 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005764 if (*backend.int16_t_literal_suffix)
5765 {
5766 res += convert_to_string(c.scalar_i16(vector, i));
5767 res += backend.int16_t_literal_suffix;
5768 }
5769 else
5770 {
5771 // If backend doesn't have a literal suffix, we need to value cast.
5772 res += type_to_glsl(scalar_type);
5773 res += "(";
5774 res += convert_to_string(c.scalar_i16(vector, i));
5775 res += ")";
5776 }
Chip Davisca4744a2018-11-02 14:39:55 -05005777 }
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005778
Chip Davisca4744a2018-11-02 14:39:55 -05005779 if (i + 1 < c.vector_size())
5780 res += ", ";
5781 }
5782 }
5783 break;
5784
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005785 case SPIRType::UByte:
5786 if (splat)
5787 {
5788 res += convert_to_string(c.scalar_u8(vector, 0));
5789 }
5790 else
5791 {
5792 for (uint32_t i = 0; i < c.vector_size(); i++)
5793 {
5794 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005795 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005796 else
5797 {
5798 res += type_to_glsl(scalar_type);
5799 res += "(";
5800 res += convert_to_string(c.scalar_u8(vector, i));
5801 res += ")";
5802 }
5803
5804 if (i + 1 < c.vector_size())
5805 res += ", ";
5806 }
5807 }
5808 break;
5809
5810 case SPIRType::SByte:
5811 if (splat)
5812 {
5813 res += convert_to_string(c.scalar_i8(vector, 0));
5814 }
5815 else
5816 {
5817 for (uint32_t i = 0; i < c.vector_size(); i++)
5818 {
5819 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005820 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005821 else
5822 {
5823 res += type_to_glsl(scalar_type);
5824 res += "(";
5825 res += convert_to_string(c.scalar_i8(vector, i));
5826 res += ")";
5827 }
5828
5829 if (i + 1 < c.vector_size())
5830 res += ", ";
5831 }
5832 }
5833 break;
5834
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005835 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005836 if (splat)
5837 res += c.scalar(vector, 0) ? "true" : "false";
5838 else
5839 {
5840 for (uint32_t i = 0; i < c.vector_size(); i++)
5841 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005842 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01005843 res += to_expression(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005844 else
5845 res += c.scalar(vector, i) ? "true" : "false";
5846
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005847 if (i + 1 < c.vector_size())
5848 res += ", ";
5849 }
5850 }
5851 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005852
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005853 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005854 SPIRV_CROSS_THROW("Invalid constant expression basetype.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005855 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005856
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005857 if (c.vector_size() > 1 && !swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005858 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005859
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005860 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005861}
5862
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005863SPIRExpression &CompilerGLSL::emit_uninitialized_temporary_expression(uint32_t type, uint32_t id)
5864{
5865 forced_temporaries.insert(id);
5866 emit_uninitialized_temporary(type, id);
5867 return set<SPIRExpression>(id, to_name(id), type, true);
5868}
5869
5870void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t result_id)
5871{
5872 // If we're declaring temporaries inside continue blocks,
5873 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02005874 if (!block_temporary_hoisting && current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005875 {
5876 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5877 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
5878 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
5879 return tmp.first == result_type && tmp.second == result_id;
5880 }) == end(header.declare_temporary))
5881 {
5882 header.declare_temporary.emplace_back(result_type, result_id);
5883 hoisted_temporaries.insert(result_id);
5884 force_recompile();
5885 }
5886 }
5887 else if (hoisted_temporaries.count(result_id) == 0)
5888 {
5889 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02005890 auto &flags = get_decoration_bitset(result_id);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005891
5892 // The result_id has not been made into an expression yet, so use flags interface.
5893 add_local_variable_name(result_id);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01005894
5895 string initializer;
5896 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
5897 initializer = join(" = ", to_zero_initialized_expression(result_type));
5898
5899 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), initializer, ";");
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005900 }
5901}
5902
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005903string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
5904{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005905 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005906
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005907 // If we're declaring temporaries inside continue blocks,
5908 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02005909 if (!block_temporary_hoisting && current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005910 {
5911 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5912 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005913 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005914 return tmp.first == result_type && tmp.second == result_id;
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01005915 }) == end(header.declare_temporary))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005916 {
5917 header.declare_temporary.emplace_back(result_type, result_id);
Hans-Kristian Arntzen7d223b82018-01-18 12:07:10 +01005918 hoisted_temporaries.insert(result_id);
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02005919 force_recompile_guarantee_forward_progress();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005920 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005921
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005922 return join(to_name(result_id), " = ");
5923 }
Hans-Kristian Arntzenb629ca12017-11-21 09:27:49 +01005924 else if (hoisted_temporaries.count(result_id))
5925 {
5926 // The temporary has already been declared earlier, so just "declare" the temporary by writing to it.
5927 return join(to_name(result_id), " = ");
5928 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005929 else
5930 {
5931 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen35f64d02018-03-24 01:53:08 +01005932 add_local_variable_name(result_id);
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02005933 auto &flags = get_decoration_bitset(result_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02005934 return join(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005935 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005936}
5937
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005938bool CompilerGLSL::expression_is_forwarded(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005939{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005940 return forwarded_temporaries.count(id) != 0;
5941}
5942
5943bool CompilerGLSL::expression_suppresses_usage_tracking(uint32_t id) const
5944{
5945 return suppressed_usage_tracking.count(id) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005946}
5947
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02005948bool CompilerGLSL::expression_read_implies_multiple_reads(uint32_t id) const
5949{
5950 auto *expr = maybe_get<SPIRExpression>(id);
5951 if (!expr)
5952 return false;
5953
5954 // If we're emitting code at a deeper loop level than when we emitted the expression,
5955 // we're probably reading the same expression over and over.
5956 return current_loop_level > expr->emitted_loop_level;
5957}
5958
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005959SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005960 bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005961{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005962 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
5963 {
5964 // Just forward it without temporary.
5965 // If the forward is trivial, we do not force flushing to temporary for this expression.
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005966 forwarded_temporaries.insert(result_id);
5967 if (suppress_usage_tracking)
5968 suppressed_usage_tracking.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005969
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005970 return set<SPIRExpression>(result_id, rhs, result_type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005971 }
5972 else
5973 {
5974 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
5975 statement(declare_temporary(result_type, result_id), rhs, ";");
5976 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
5977 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005978}
5979
5980void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
5981{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005982 bool forward = should_forward(op0);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005983 emit_op(result_type, result_id, join(op, to_enclosed_unpacked_expression(op0)), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005984 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005985}
5986
5987void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
5988{
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +02005989 // Various FP arithmetic opcodes such as add, sub, mul will hit this.
5990 bool force_temporary_precise = backend.support_precise_qualifier &&
5991 has_decoration(result_id, DecorationNoContraction) &&
5992 type_is_floating_point(get<SPIRType>(result_type));
5993 bool forward = should_forward(op0) && should_forward(op1) && !force_temporary_precise;
5994
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005995 emit_op(result_type, result_id,
5996 join(to_enclosed_unpacked_expression(op0), " ", op, " ", to_enclosed_unpacked_expression(op1)), forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005997
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005998 inherit_expression_dependencies(result_id, op0);
5999 inherit_expression_dependencies(result_id, op1);
6000}
6001
Robert Konradf3a82772017-03-24 15:00:48 +01006002void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
6003{
6004 auto &type = get<SPIRType>(result_type);
6005 auto expr = type_to_glsl_constructor(type);
6006 expr += '(';
6007 for (uint32_t i = 0; i < type.vecsize; i++)
6008 {
6009 // Make sure to call to_expression multiple times to ensure
6010 // that these expressions are properly flushed to temporaries if needed.
6011 expr += op;
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02006012 expr += to_extract_component_expression(operand, i);
Robert Konradf3a82772017-03-24 15:00:48 +01006013
6014 if (i + 1 < type.vecsize)
6015 expr += ", ";
6016 }
6017 expr += ')';
6018 emit_op(result_type, result_id, expr, should_forward(operand));
6019
6020 inherit_expression_dependencies(result_id, operand);
6021}
6022
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006023void 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 +02006024 const char *op, bool negate, SPIRType::BaseType expected_type)
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006025{
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02006026 auto &type0 = expression_type(op0);
6027 auto &type1 = expression_type(op1);
6028
6029 SPIRType target_type0 = type0;
6030 SPIRType target_type1 = type1;
6031 target_type0.basetype = expected_type;
6032 target_type1.basetype = expected_type;
6033 target_type0.vecsize = 1;
6034 target_type1.vecsize = 1;
6035
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006036 auto &type = get<SPIRType>(result_type);
6037 auto expr = type_to_glsl_constructor(type);
6038 expr += '(';
6039 for (uint32_t i = 0; i < type.vecsize; i++)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006040 {
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006041 // Make sure to call to_expression multiple times to ensure
6042 // that these expressions are properly flushed to temporaries if needed.
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02006043 if (negate)
6044 expr += "!(";
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02006045
6046 if (expected_type != SPIRType::Unknown && type0.basetype != expected_type)
6047 expr += bitcast_expression(target_type0, type0.basetype, to_extract_component_expression(op0, i));
6048 else
6049 expr += to_extract_component_expression(op0, i);
6050
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006051 expr += ' ';
6052 expr += op;
6053 expr += ' ';
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02006054
6055 if (expected_type != SPIRType::Unknown && type1.basetype != expected_type)
6056 expr += bitcast_expression(target_type1, type1.basetype, to_extract_component_expression(op1, i));
6057 else
6058 expr += to_extract_component_expression(op1, i);
6059
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02006060 if (negate)
6061 expr += ")";
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006062
6063 if (i + 1 < type.vecsize)
6064 expr += ", ";
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006065 }
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006066 expr += ')';
6067 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
6068
6069 inherit_expression_dependencies(result_id, op0);
6070 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006071}
6072
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006073SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
6074 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
6075{
6076 auto &type0 = expression_type(op0);
6077 auto &type1 = expression_type(op1);
6078
6079 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
6080 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
6081 // since equality test is exactly the same.
6082 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
6083
6084 // Create a fake type so we can bitcast to it.
6085 // We only deal with regular arithmetic types here like int, uints and so on.
6086 SPIRType expected_type;
6087 expected_type.basetype = input_type;
6088 expected_type.vecsize = type0.vecsize;
6089 expected_type.columns = type0.columns;
6090 expected_type.width = type0.width;
6091
6092 if (cast)
6093 {
6094 cast_op0 = bitcast_glsl(expected_type, op0);
6095 cast_op1 = bitcast_glsl(expected_type, op1);
6096 }
6097 else
6098 {
6099 // 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 +02006100 cast_op0 = to_enclosed_unpacked_expression(op0);
6101 cast_op1 = to_enclosed_unpacked_expression(op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006102 input_type = type0.basetype;
6103 }
6104
6105 return expected_type;
6106}
6107
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02006108bool CompilerGLSL::emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0)
6109{
6110 // Some bitcasts may require complex casting sequences, and are implemented here.
6111 // Otherwise a simply unary function will do with bitcast_glsl_op.
6112
6113 auto &output_type = get<SPIRType>(result_type);
6114 auto &input_type = expression_type(op0);
6115 string expr;
6116
6117 if (output_type.basetype == SPIRType::Half && input_type.basetype == SPIRType::Float && input_type.vecsize == 1)
6118 expr = join("unpackFloat2x16(floatBitsToUint(", to_unpacked_expression(op0), "))");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006119 else if (output_type.basetype == SPIRType::Float && input_type.basetype == SPIRType::Half &&
6120 input_type.vecsize == 2)
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02006121 expr = join("uintBitsToFloat(packFloat2x16(", to_unpacked_expression(op0), "))");
6122 else
6123 return false;
6124
6125 emit_op(result_type, id, expr, should_forward(op0));
6126 return true;
6127}
6128
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006129void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6130 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
6131{
6132 string cast_op0, cast_op1;
6133 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
6134 auto &out_type = get<SPIRType>(result_type);
6135
6136 // We might have casted away from the result type, so bitcast again.
6137 // For example, arithmetic right shift with uint inputs.
6138 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006139 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02006140 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006141 {
6142 expected_type.basetype = input_type;
6143 expr = bitcast_glsl_op(out_type, expected_type);
6144 expr += '(';
6145 expr += join(cast_op0, " ", op, " ", cast_op1);
6146 expr += ')';
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006147 }
6148 else
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006149 expr += join(cast_op0, " ", op, " ", cast_op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006150
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006151 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006152 inherit_expression_dependencies(result_id, op0);
6153 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006154}
6155
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006156void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
6157{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006158 bool forward = should_forward(op0);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006159 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006160 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006161}
6162
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006163void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6164 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006165{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006166 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006167 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ")"),
6168 forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006169 inherit_expression_dependencies(result_id, op0);
6170 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006171}
6172
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006173void CompilerGLSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6174 const char *op)
6175{
Hans-Kristian Arntzen88e583d2022-05-27 12:12:50 +02006176 auto &type = get<SPIRType>(result_type);
6177 if (type_is_floating_point(type))
6178 {
6179 if (!options.vulkan_semantics)
6180 SPIRV_CROSS_THROW("Floating point atomics requires Vulkan semantics.");
6181 if (options.es)
6182 SPIRV_CROSS_THROW("Floating point atomics requires desktop GLSL.");
6183 require_extension_internal("GL_EXT_shader_atomic_float");
6184 }
6185
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006186 forced_temporaries.insert(result_id);
6187 emit_op(result_type, result_id,
6188 join(op, "(", to_non_uniform_aware_expression(op0), ", ",
6189 to_unpacked_expression(op1), ")"), false);
6190 flush_all_atomic_capable_variables();
6191}
6192
6193void CompilerGLSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id,
6194 uint32_t op0, uint32_t op1, uint32_t op2,
6195 const char *op)
6196{
6197 forced_temporaries.insert(result_id);
6198 emit_op(result_type, result_id,
6199 join(op, "(", to_non_uniform_aware_expression(op0), ", ",
6200 to_unpacked_expression(op1), ", ", to_unpacked_expression(op2), ")"), false);
6201 flush_all_atomic_capable_variables();
6202}
6203
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006204void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op,
6205 SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type)
6206{
6207 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006208 auto &expr_type = expression_type(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006209 auto expected_type = out_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006210
6211 // 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 +01006212 expected_type.basetype = input_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006213 expected_type.width = expr_type.width;
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01006214
6215 string cast_op;
6216 if (expr_type.basetype != input_type)
6217 {
6218 if (expr_type.basetype == SPIRType::Boolean)
6219 cast_op = join(type_to_glsl(expected_type), "(", to_unpacked_expression(op0), ")");
6220 else
6221 cast_op = bitcast_glsl(expected_type, op0);
6222 }
6223 else
6224 cast_op = to_unpacked_expression(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006225
6226 string expr;
6227 if (out_type.basetype != expected_result_type)
6228 {
6229 expected_type.basetype = expected_result_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006230 expected_type.width = out_type.width;
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01006231 if (out_type.basetype == SPIRType::Boolean)
6232 expr = type_to_glsl(out_type);
6233 else
6234 expr = bitcast_glsl_op(out_type, expected_type);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006235 expr += '(';
6236 expr += join(op, "(", cast_op, ")");
6237 expr += ')';
6238 }
6239 else
6240 {
6241 expr += join(op, "(", cast_op, ")");
6242 }
6243
6244 emit_op(result_type, result_id, expr, should_forward(op0));
6245 inherit_expression_dependencies(result_id, op0);
6246}
6247
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006248// Very special case. Handling bitfieldExtract requires us to deal with different bitcasts of different signs
6249// and different vector sizes all at once. Need a special purpose method here.
6250void CompilerGLSL::emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6251 uint32_t op2, const char *op,
6252 SPIRType::BaseType expected_result_type,
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006253 SPIRType::BaseType input_type0, SPIRType::BaseType input_type1,
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006254 SPIRType::BaseType input_type2)
6255{
6256 auto &out_type = get<SPIRType>(result_type);
6257 auto expected_type = out_type;
6258 expected_type.basetype = input_type0;
6259
6260 string cast_op0 =
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006261 expression_type(op0).basetype != input_type0 ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006262
6263 auto op1_expr = to_unpacked_expression(op1);
6264 auto op2_expr = to_unpacked_expression(op2);
6265
6266 // Use value casts here instead. Input must be exactly int or uint, but SPIR-V might be 16-bit.
6267 expected_type.basetype = input_type1;
6268 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006269 string cast_op1 = expression_type(op1).basetype != input_type1 ?
6270 join(type_to_glsl_constructor(expected_type), "(", op1_expr, ")") :
6271 op1_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006272
6273 expected_type.basetype = input_type2;
6274 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006275 string cast_op2 = expression_type(op2).basetype != input_type2 ?
6276 join(type_to_glsl_constructor(expected_type), "(", op2_expr, ")") :
6277 op2_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006278
6279 string expr;
6280 if (out_type.basetype != expected_result_type)
6281 {
6282 expected_type.vecsize = out_type.vecsize;
6283 expected_type.basetype = expected_result_type;
6284 expr = bitcast_glsl_op(out_type, expected_type);
6285 expr += '(';
6286 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6287 expr += ')';
6288 }
6289 else
6290 {
6291 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6292 }
6293
6294 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
6295 inherit_expression_dependencies(result_id, op0);
6296 inherit_expression_dependencies(result_id, op1);
6297 inherit_expression_dependencies(result_id, op2);
6298}
6299
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006300void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6301 uint32_t op2, const char *op, SPIRType::BaseType input_type)
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006302{
6303 auto &out_type = get<SPIRType>(result_type);
6304 auto expected_type = out_type;
6305 expected_type.basetype = input_type;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006306 string cast_op0 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006307 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006308 string cast_op1 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006309 expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_unpacked_expression(op1);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006310 string cast_op2 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02006311 expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_unpacked_expression(op2);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006312
6313 string expr;
6314 if (out_type.basetype != input_type)
6315 {
6316 expr = bitcast_glsl_op(out_type, expected_type);
6317 expr += '(';
6318 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6319 expr += ')';
6320 }
6321 else
6322 {
6323 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
6324 }
6325
6326 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
6327 inherit_expression_dependencies(result_id, op0);
6328 inherit_expression_dependencies(result_id, op1);
6329 inherit_expression_dependencies(result_id, op2);
6330}
6331
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01006332void CompilerGLSL::emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0,
6333 uint32_t op1, const char *op, SPIRType::BaseType input_type)
6334{
6335 // Special purpose method for implementing clustered subgroup opcodes.
6336 // Main difference is that op1 does not participate in any casting, it needs to be a literal.
6337 auto &out_type = get<SPIRType>(result_type);
6338 auto expected_type = out_type;
6339 expected_type.basetype = input_type;
6340 string cast_op0 =
6341 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
6342
6343 string expr;
6344 if (out_type.basetype != input_type)
6345 {
6346 expr = bitcast_glsl_op(out_type, expected_type);
6347 expr += '(';
6348 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
6349 expr += ')';
6350 }
6351 else
6352 {
6353 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
6354 }
6355
6356 emit_op(result_type, result_id, expr, should_forward(op0));
6357 inherit_expression_dependencies(result_id, op0);
6358}
6359
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006360void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6361 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
6362{
6363 string cast_op0, cast_op1;
6364 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
6365 auto &out_type = get<SPIRType>(result_type);
6366
6367 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
6368 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02006369 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006370 {
6371 expected_type.basetype = input_type;
6372 expr = bitcast_glsl_op(out_type, expected_type);
6373 expr += '(';
6374 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
6375 expr += ')';
6376 }
6377 else
6378 {
6379 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
6380 }
6381
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006382 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006383 inherit_expression_dependencies(result_id, op0);
6384 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02006385}
6386
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006387void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6388 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006389{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006390 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006391 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006392 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
6393 to_unpacked_expression(op2), ")"),
6394 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006395
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006396 inherit_expression_dependencies(result_id, op0);
6397 inherit_expression_dependencies(result_id, op1);
6398 inherit_expression_dependencies(result_id, op2);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006399}
6400
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006401void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6402 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006403{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006404 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01006405 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02006406 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
6407 to_unpacked_expression(op2), ", ", to_unpacked_expression(op3), ")"),
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006408 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02006409
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01006410 inherit_expression_dependencies(result_id, op0);
6411 inherit_expression_dependencies(result_id, op1);
6412 inherit_expression_dependencies(result_id, op2);
6413 inherit_expression_dependencies(result_id, op3);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006414}
6415
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006416void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
6417 uint32_t op2, uint32_t op3, const char *op,
6418 SPIRType::BaseType offset_count_type)
6419{
6420 // Only need to cast offset/count arguments. Types of base/insert must be same as result type,
6421 // and bitfieldInsert is sign invariant.
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006422 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006423
6424 auto op0_expr = to_unpacked_expression(op0);
6425 auto op1_expr = to_unpacked_expression(op1);
6426 auto op2_expr = to_unpacked_expression(op2);
6427 auto op3_expr = to_unpacked_expression(op3);
6428
6429 SPIRType target_type;
6430 target_type.vecsize = 1;
6431 target_type.basetype = offset_count_type;
6432
6433 if (expression_type(op2).basetype != offset_count_type)
6434 {
6435 // Value-cast here. Input might be 16-bit. GLSL requires int.
6436 op2_expr = join(type_to_glsl_constructor(target_type), "(", op2_expr, ")");
6437 }
6438
6439 if (expression_type(op3).basetype != offset_count_type)
6440 {
6441 // Value-cast here. Input might be 16-bit. GLSL requires int.
6442 op3_expr = join(type_to_glsl_constructor(target_type), "(", op3_expr, ")");
6443 }
6444
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02006445 emit_op(result_type, result_id, join(op, "(", op0_expr, ", ", op1_expr, ", ", op2_expr, ", ", op3_expr, ")"),
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02006446 forward);
6447
6448 inherit_expression_dependencies(result_id, op0);
6449 inherit_expression_dependencies(result_id, op1);
6450 inherit_expression_dependencies(result_id, op2);
6451 inherit_expression_dependencies(result_id, op3);
6452}
6453
rdbb3bd6742020-11-07 12:43:53 +01006454string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t tex)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006455{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006456 const char *type;
6457 switch (imgtype.image.dim)
6458 {
6459 case spv::Dim1D:
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +02006460 // Force 2D path for ES.
6461 if (options.es)
6462 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
6463 else
6464 type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006465 break;
6466 case spv::Dim2D:
Rob Fischer21990632016-09-17 17:01:50 +09006467 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006468 break;
6469 case spv::Dim3D:
6470 type = "3D";
6471 break;
6472 case spv::DimCube:
6473 type = "Cube";
6474 break;
Sidney Justfbb4df32019-01-06 12:21:59 -08006475 case spv::DimRect:
6476 type = "2DRect";
6477 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006478 case spv::DimBuffer:
6479 type = "Buffer";
6480 break;
6481 case spv::DimSubpassData:
6482 type = "2D";
6483 break;
6484 default:
6485 type = "";
6486 break;
6487 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006488
rdbe8c500c2020-11-05 22:55:44 +01006489 // In legacy GLSL, an extension is required for textureLod in the fragment
6490 // shader or textureGrad anywhere.
6491 bool legacy_lod_ext = false;
6492 auto &execution = get_entry_point();
6493 if (op == "textureGrad" || op == "textureProjGrad" ||
6494 ((op == "textureLod" || op == "textureProjLod") && execution.model != ExecutionModelVertex))
Lubos Lenco0028b4f2016-11-21 22:37:20 +01006495 {
Robert Konradedfc2972017-03-23 13:25:24 +01006496 if (is_legacy_es())
6497 {
rdbe8c500c2020-11-05 22:55:44 +01006498 legacy_lod_ext = true;
6499 require_extension_internal("GL_EXT_shader_texture_lod");
Robert Konradedfc2972017-03-23 13:25:24 +01006500 }
rdbe8c500c2020-11-05 22:55:44 +01006501 else if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02006502 require_extension_internal("GL_ARB_shader_texture_lod");
Lubos Lenco0028b4f2016-11-21 22:37:20 +01006503 }
Lubos Lenco52158642016-09-17 15:56:23 +02006504
Sidney Just5ac55ee2018-06-25 02:11:46 -07006505 if (op == "textureLodOffset" || op == "textureProjLodOffset")
6506 {
6507 if (is_legacy_es())
6508 SPIRV_CROSS_THROW(join(op, " not allowed in legacy ES"));
6509
6510 require_extension_internal("GL_EXT_gpu_shader4");
6511 }
6512
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02006513 // GLES has very limited support for shadow samplers.
Sidney Just5ac55ee2018-06-25 02:11:46 -07006514 // Basically shadow2D and shadow2DProj work through EXT_shadow_samplers,
6515 // everything else can just throw
Bill Hollingsfd252b22021-11-08 15:59:45 -05006516 bool is_comparison = is_depth_image(imgtype, tex);
rdb10fa5f62020-11-09 15:26:46 +01006517 if (is_comparison && is_legacy_es())
Sidney Just5ac55ee2018-06-25 02:11:46 -07006518 {
6519 if (op == "texture" || op == "textureProj")
6520 require_extension_internal("GL_EXT_shadow_samplers");
6521 else
6522 SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
6523 }
6524
rdb10fa5f62020-11-09 15:26:46 +01006525 if (op == "textureSize")
6526 {
6527 if (is_legacy_es())
6528 SPIRV_CROSS_THROW("textureSize not supported in legacy ES");
6529 if (is_comparison)
6530 SPIRV_CROSS_THROW("textureSize not supported on shadow sampler in legacy GLSL");
6531 require_extension_internal("GL_EXT_gpu_shader4");
6532 }
6533
6534 if (op == "texelFetch" && is_legacy_es())
6535 SPIRV_CROSS_THROW("texelFetch not supported in legacy ES");
6536
6537 bool is_es_and_depth = is_legacy_es() && is_comparison;
6538 std::string type_prefix = is_comparison ? "shadow" : "texture";
Sidney Just0f62b5d2018-06-22 01:40:01 -07006539
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006540 if (op == "texture")
Sidney Just5ac55ee2018-06-25 02:11:46 -07006541 return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
Robert Konradedfc2972017-03-23 13:25:24 +01006542 else if (op == "textureLod")
rdbe8c500c2020-11-05 22:55:44 +01006543 return join(type_prefix, type, legacy_lod_ext ? "LodEXT" : "Lod");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006544 else if (op == "textureProj")
Sidney Just5ac55ee2018-06-25 02:11:46 -07006545 return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
Sidney Juste66fd6c2018-03-12 00:59:06 +10006546 else if (op == "textureGrad")
Sidney Just0f62b5d2018-06-22 01:40:01 -07006547 return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006548 else if (op == "textureProjLod")
rdbe8c500c2020-11-05 22:55:44 +01006549 return join(type_prefix, type, legacy_lod_ext ? "ProjLodEXT" : "ProjLod");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006550 else if (op == "textureLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01006551 return join(type_prefix, type, "LodOffset");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006552 else if (op == "textureProjGrad")
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02006553 return join(type_prefix, type,
6554 is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
Sidney Just0f62b5d2018-06-22 01:40:01 -07006555 else if (op == "textureProjLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01006556 return join(type_prefix, type, "ProjLodOffset");
rdb10fa5f62020-11-09 15:26:46 +01006557 else if (op == "textureSize")
6558 return join("textureSize", type);
6559 else if (op == "texelFetch")
6560 return join("texelFetch", type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006561 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006562 {
6563 SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
6564 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006565}
6566
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006567bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
6568{
6569 auto *cleft = maybe_get<SPIRConstant>(left);
6570 auto *cright = maybe_get<SPIRConstant>(right);
6571 auto &lerptype = expression_type(lerp);
6572
6573 // If our targets aren't constants, we cannot use construction.
6574 if (!cleft || !cright)
6575 return false;
6576
6577 // If our targets are spec constants, we cannot use construction.
6578 if (cleft->specialization || cright->specialization)
6579 return false;
6580
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006581 auto &value_type = get<SPIRType>(cleft->constant_type);
6582
6583 if (lerptype.basetype != SPIRType::Boolean)
6584 return false;
6585 if (value_type.basetype == SPIRType::Struct || is_array(value_type))
6586 return false;
6587 if (!backend.use_constructor_splatting && value_type.vecsize != lerptype.vecsize)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006588 return false;
6589
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006590 // Only valid way in SPIR-V 1.4 to use matrices in select is a scalar select.
6591 // matrix(scalar) constructor fills in diagnonals, so gets messy very quickly.
6592 // Just avoid this case.
6593 if (value_type.columns > 1)
6594 return false;
6595
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006596 // 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 +02006597 bool ret = true;
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006598 for (uint32_t row = 0; ret && row < value_type.vecsize; row++)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006599 {
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006600 switch (type.basetype)
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006601 {
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006602 case SPIRType::Short:
6603 case SPIRType::UShort:
6604 ret = cleft->scalar_u16(0, row) == 0 && cright->scalar_u16(0, row) == 1;
6605 break;
Chip Davis117ccf42018-11-01 17:20:07 -05006606
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006607 case SPIRType::Int:
6608 case SPIRType::UInt:
6609 ret = cleft->scalar(0, row) == 0 && cright->scalar(0, row) == 1;
6610 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006611
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006612 case SPIRType::Half:
6613 ret = cleft->scalar_f16(0, row) == 0.0f && cright->scalar_f16(0, row) == 1.0f;
6614 break;
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01006615
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006616 case SPIRType::Float:
6617 ret = cleft->scalar_f32(0, row) == 0.0f && cright->scalar_f32(0, row) == 1.0f;
6618 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006619
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006620 case SPIRType::Double:
6621 ret = cleft->scalar_f64(0, row) == 0.0 && cright->scalar_f64(0, row) == 1.0;
6622 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006623
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006624 case SPIRType::Int64:
6625 case SPIRType::UInt64:
6626 ret = cleft->scalar_u64(0, row) == 0 && cright->scalar_u64(0, row) == 1;
6627 break;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006628
Hans-Kristian Arntzen6382f152021-10-13 15:52:04 +02006629 default:
6630 ret = false;
6631 break;
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02006632 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006633 }
6634
6635 if (ret)
6636 op = type_to_glsl_constructor(type);
6637 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006638}
6639
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006640string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
6641 uint32_t false_value)
6642{
6643 string expr;
6644 auto &lerptype = expression_type(select);
6645
6646 if (lerptype.vecsize == 1)
Chip Davis3bfb2f92018-12-03 02:06:33 -06006647 expr = join(to_enclosed_expression(select), " ? ", to_enclosed_pointer_expression(true_value), " : ",
6648 to_enclosed_pointer_expression(false_value));
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006649 else
6650 {
6651 auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
6652
6653 expr = type_to_glsl_constructor(restype);
6654 expr += "(";
6655 for (uint32_t i = 0; i < restype.vecsize; i++)
6656 {
6657 expr += swiz(select, i);
6658 expr += " ? ";
6659 expr += swiz(true_value, i);
6660 expr += " : ";
6661 expr += swiz(false_value, i);
6662 if (i + 1 < restype.vecsize)
6663 expr += ", ";
6664 }
6665 expr += ")";
6666 }
6667
6668 return expr;
6669}
6670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006671void 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 +01006672{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006673 auto &lerptype = expression_type(lerp);
6674 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006675
Chip Davis3bfb2f92018-12-03 02:06:33 -06006676 // If this results in a variable pointer, assume it may be written through.
6677 if (restype.pointer)
6678 {
6679 register_write(left);
6680 register_write(right);
6681 }
6682
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006683 string mix_op;
Chip Davis6628ea62019-07-10 23:46:40 -05006684 bool has_boolean_mix = *backend.boolean_mix_function &&
Hans-Kristian Arntzen851acf32017-05-04 10:28:30 +02006685 ((options.es && options.version >= 310) || (!options.es && options.version >= 450));
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006686 bool trivial_mix = to_trivial_mix_op(restype, mix_op, left, right, lerp);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006687
Hans-Kristian Arntzen0e7c33f2017-02-11 10:52:34 +01006688 // Cannot use boolean mix when the lerp argument is just one boolean,
6689 // fall back to regular trinary statements.
6690 if (lerptype.vecsize == 1)
6691 has_boolean_mix = false;
6692
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006693 // If we can reduce the mix to a simple cast, do so.
6694 // This helps for cases like int(bool), uint(bool) which is implemented with
6695 // OpSelect bool 1 0.
6696 if (trivial_mix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006697 {
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02006698 emit_unary_func_op(result_type, id, lerp, mix_op.c_str());
6699 }
6700 else if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
6701 {
6702 // Boolean mix not supported on desktop without extension.
6703 // Was added in OpenGL 4.5 with ES 3.1 compat.
6704 //
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006705 // Could use GL_EXT_shader_integer_mix on desktop at least,
6706 // but Apple doesn't support it. :(
6707 // Just implement it as ternary expressions.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02006708 auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006709 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006710 inherit_expression_dependencies(id, left);
6711 inherit_expression_dependencies(id, right);
6712 inherit_expression_dependencies(id, lerp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006713 }
Chip Davis6628ea62019-07-10 23:46:40 -05006714 else if (lerptype.basetype == SPIRType::Boolean)
6715 emit_trinary_func_op(result_type, id, left, right, lerp, backend.boolean_mix_function);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006716 else
6717 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006718}
6719
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006720string CompilerGLSL::to_combined_image_sampler(VariableID image_id, VariableID samp_id)
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006721{
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006722 // Keep track of the array indices we have used to load the image.
6723 // We'll need to use the same array index into the combined image sampler array.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006724 auto image_expr = to_non_uniform_aware_expression(image_id);
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006725 string array_expr;
6726 auto array_index = image_expr.find_first_of('[');
6727 if (array_index != string::npos)
6728 array_expr = image_expr.substr(array_index, string::npos);
6729
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006730 auto &args = current_function->arguments;
6731
6732 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
6733 // all possible combinations into new sampler2D uniforms.
6734 auto *image = maybe_get_backing_variable(image_id);
6735 auto *samp = maybe_get_backing_variable(samp_id);
6736 if (image)
6737 image_id = image->self;
6738 if (samp)
6739 samp_id = samp->self;
6740
6741 auto image_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006742 [image_id](const SPIRFunction::Parameter &param) { return image_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006743
6744 auto sampler_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006745 [samp_id](const SPIRFunction::Parameter &param) { return samp_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006746
6747 if (image_itr != end(args) || sampler_itr != end(args))
6748 {
6749 // If any parameter originates from a parameter, we will find it in our argument list.
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02006750 bool global_image = image_itr == end(args);
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006751 bool global_sampler = sampler_itr == end(args);
Hans-Kristian Arntzenc3ff67c2019-09-17 10:16:47 +02006752 VariableID iid = global_image ? image_id : VariableID(uint32_t(image_itr - begin(args)));
6753 VariableID sid = global_sampler ? samp_id : VariableID(uint32_t(sampler_itr - begin(args)));
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006754
6755 auto &combined = current_function->combined_parameters;
6756 auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02006757 return p.global_image == global_image && p.global_sampler == global_sampler && p.image_id == iid &&
6758 p.sampler_id == sid;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006759 });
6760
6761 if (itr != end(combined))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006762 return to_expression(itr->id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006763 else
6764 {
crissdb52e272020-10-08 12:14:52 +02006765 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler parameter, was "
6766 "build_combined_image_samplers() used "
6767 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006768 }
6769 }
6770 else
6771 {
6772 // For global sampler2D, look directly at the global remapping table.
6773 auto &mapping = combined_image_samplers;
6774 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
6775 return combined.image_id == image_id && combined.sampler_id == samp_id;
6776 });
6777
6778 if (itr != end(combined_image_samplers))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006779 return to_expression(itr->combined_id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006780 else
6781 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006782 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
6783 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006784 }
6785 }
6786}
6787
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02006788bool CompilerGLSL::is_supported_subgroup_op_in_opengl(spv::Op op)
crissdb52e272020-10-08 12:14:52 +02006789{
6790 switch (op)
6791 {
6792 case OpGroupNonUniformElect:
6793 case OpGroupNonUniformBallot:
6794 case OpGroupNonUniformBallotFindLSB:
6795 case OpGroupNonUniformBallotFindMSB:
6796 case OpGroupNonUniformBroadcast:
6797 case OpGroupNonUniformBroadcastFirst:
6798 case OpGroupNonUniformAll:
6799 case OpGroupNonUniformAny:
6800 case OpGroupNonUniformAllEqual:
6801 case OpControlBarrier:
6802 case OpMemoryBarrier:
6803 case OpGroupNonUniformBallotBitCount:
6804 case OpGroupNonUniformBallotBitExtract:
6805 case OpGroupNonUniformInverseBallot:
6806 return true;
6807 default:
6808 return false;
6809 }
6810}
6811
Bill Hollings5aafb282016-04-23 21:47:41 -04006812void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
6813{
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006814 if (options.vulkan_semantics && combined_image_samplers.empty())
6815 {
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006816 emit_binary_func_op(result_type, result_id, image_id, samp_id,
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02006817 type_to_glsl(get<SPIRType>(result_type), result_id).c_str());
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006818 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006819 else
Hans-Kristian Arntzen02808002018-04-27 09:34:13 +02006820 {
6821 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
6822 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true);
6823 }
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02006824
6825 // Make sure to suppress usage tracking and any expression invalidation.
6826 // It is illegal to create temporaries of opaque types.
6827 forwarded_temporaries.erase(result_id);
Bill Hollings5aafb282016-04-23 21:47:41 -04006828}
6829
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006830static inline bool image_opcode_is_sample_no_dref(Op op)
6831{
6832 switch (op)
6833 {
6834 case OpImageSampleExplicitLod:
6835 case OpImageSampleImplicitLod:
6836 case OpImageSampleProjExplicitLod:
6837 case OpImageSampleProjImplicitLod:
6838 case OpImageFetch:
6839 case OpImageRead:
6840 case OpImageSparseSampleExplicitLod:
6841 case OpImageSparseSampleImplicitLod:
6842 case OpImageSparseSampleProjExplicitLod:
6843 case OpImageSparseSampleProjImplicitLod:
6844 case OpImageSparseFetch:
6845 case OpImageSparseRead:
6846 return true;
6847
6848 default:
6849 return false;
6850 }
6851}
6852
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006853void CompilerGLSL::emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id, uint32_t &feedback_id,
6854 uint32_t &texel_id)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006855{
6856 // Need to allocate two temporaries.
6857 if (options.es)
6858 SPIRV_CROSS_THROW("Sparse texture feedback is not supported on ESSL.");
6859 require_extension_internal("GL_ARB_sparse_texture2");
6860
6861 auto &temps = extra_sub_expressions[id];
6862 if (temps == 0)
6863 temps = ir.increase_bound_by(2);
6864
6865 feedback_id = temps + 0;
6866 texel_id = temps + 1;
6867
6868 auto &return_type = get<SPIRType>(result_type_id);
6869 if (return_type.basetype != SPIRType::Struct || return_type.member_types.size() != 2)
6870 SPIRV_CROSS_THROW("Invalid return type for sparse feedback.");
6871 emit_uninitialized_temporary(return_type.member_types[0], feedback_id);
6872 emit_uninitialized_temporary(return_type.member_types[1], texel_id);
6873}
6874
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006875uint32_t CompilerGLSL::get_sparse_feedback_texel_id(uint32_t id) const
6876{
6877 auto itr = extra_sub_expressions.find(id);
6878 if (itr == extra_sub_expressions.end())
6879 return 0;
6880 else
6881 return itr->second + 1;
6882}
6883
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006884void CompilerGLSL::emit_texture_op(const Instruction &i, bool sparse)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006885{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02006886 auto *ops = stream(i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006887 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006888
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006889 SmallVector<uint32_t> inherited_expressions;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006890
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006891 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006892 uint32_t id = ops[1];
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006893 auto &return_type = get<SPIRType>(result_type_id);
6894
6895 uint32_t sparse_code_id = 0;
6896 uint32_t sparse_texel_id = 0;
6897 if (sparse)
6898 emit_sparse_feedback_temporaries(result_type_id, id, sparse_code_id, sparse_texel_id);
Chip Davis39dce882019-08-02 15:11:19 -05006899
6900 bool forward = false;
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006901 string expr = to_texture_op(i, sparse, &forward, inherited_expressions);
6902
6903 if (sparse)
6904 {
6905 statement(to_expression(sparse_code_id), " = ", expr, ";");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006906 expr = join(type_to_glsl(return_type), "(", to_expression(sparse_code_id), ", ", to_expression(sparse_texel_id),
6907 ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006908 forward = true;
6909 inherited_expressions.clear();
6910 }
6911
Chip Davis39dce882019-08-02 15:11:19 -05006912 emit_op(result_type_id, id, expr, forward);
6913 for (auto &inherit : inherited_expressions)
6914 inherit_expression_dependencies(id, inherit);
6915
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006916 // Do not register sparse ops as control dependent as they are always lowered to a temporary.
Chip Davis39dce882019-08-02 15:11:19 -05006917 switch (op)
6918 {
6919 case OpImageSampleDrefImplicitLod:
6920 case OpImageSampleImplicitLod:
6921 case OpImageSampleProjImplicitLod:
6922 case OpImageSampleProjDrefImplicitLod:
6923 register_control_dependent_expression(id);
6924 break;
6925
6926 default:
6927 break;
6928 }
6929}
6930
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006931std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool *forward,
Chip Davis39dce882019-08-02 15:11:19 -05006932 SmallVector<uint32_t> &inherited_expressions)
6933{
6934 auto *ops = stream(i);
6935 auto op = static_cast<Op>(i.op);
6936 uint32_t length = i.length;
6937
6938 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006939 VariableID img = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006940 uint32_t coord = ops[3];
6941 uint32_t dref = 0;
6942 uint32_t comp = 0;
6943 bool gather = false;
6944 bool proj = false;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006945 bool fetch = false;
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01006946 bool nonuniform_expression = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006947 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006948
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006949 auto &result_type = get<SPIRType>(result_type_id);
6950
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006951 inherited_expressions.push_back(coord);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02006952 if (has_decoration(img, DecorationNonUniform) && !maybe_get_backing_variable(img))
6953 nonuniform_expression = true;
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02006954
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006955 switch (op)
6956 {
6957 case OpImageSampleDrefImplicitLod:
6958 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006959 case OpImageSparseSampleDrefImplicitLod:
6960 case OpImageSparseSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006961 dref = ops[4];
6962 opt = &ops[5];
6963 length -= 5;
6964 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006965
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006966 case OpImageSampleProjDrefImplicitLod:
6967 case OpImageSampleProjDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006968 case OpImageSparseSampleProjDrefImplicitLod:
6969 case OpImageSparseSampleProjDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006970 dref = ops[4];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006971 opt = &ops[5];
6972 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006973 proj = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006974 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006975
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006976 case OpImageDrefGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006977 case OpImageSparseDrefGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006978 dref = ops[4];
6979 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006980 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006981 gather = true;
rdb509908d2020-11-07 00:01:57 +01006982 if (options.es && options.version < 310)
6983 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6984 else if (!options.es && options.version < 400)
6985 SPIRV_CROSS_THROW("textureGather with depth compare requires GLSL 400.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006986 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006987
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006988 case OpImageGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006989 case OpImageSparseGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006990 comp = ops[4];
6991 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006992 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006993 gather = true;
rdb509908d2020-11-07 00:01:57 +01006994 if (options.es && options.version < 310)
6995 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6996 else if (!options.es && options.version < 400)
6997 {
6998 if (!expression_is_constant_null(comp))
6999 SPIRV_CROSS_THROW("textureGather with component requires GLSL 400.");
7000 require_extension_internal("GL_ARB_texture_gather");
7001 }
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007002 break;
7003
7004 case OpImageFetch:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007005 case OpImageSparseFetch:
Bill Hollings8f6df772017-05-19 18:14:08 -04007006 case OpImageRead: // Reads == fetches in Metal (other langs will not get here)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007007 opt = &ops[4];
7008 length -= 4;
7009 fetch = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007010 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007011
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007012 case OpImageSampleProjImplicitLod:
7013 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007014 case OpImageSparseSampleProjImplicitLod:
7015 case OpImageSparseSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007016 opt = &ops[4];
7017 length -= 4;
7018 proj = true;
7019 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007020
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007021 default:
7022 opt = &ops[4];
7023 length -= 4;
7024 break;
7025 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007026
Bill Hollings8f6df772017-05-19 18:14:08 -04007027 // Bypass pointers because we need the real image struct
7028 auto &type = expression_type(img);
7029 auto &imgtype = get<SPIRType>(type.self);
7030
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007031 uint32_t coord_components = 0;
7032 switch (imgtype.image.dim)
7033 {
7034 case spv::Dim1D:
7035 coord_components = 1;
7036 break;
7037 case spv::Dim2D:
7038 coord_components = 2;
7039 break;
7040 case spv::Dim3D:
7041 coord_components = 3;
7042 break;
7043 case spv::DimCube:
7044 coord_components = 3;
7045 break;
7046 case spv::DimBuffer:
7047 coord_components = 1;
7048 break;
7049 default:
7050 coord_components = 2;
7051 break;
7052 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007053
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01007054 if (dref)
7055 inherited_expressions.push_back(dref);
7056
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007057 if (proj)
7058 coord_components++;
7059 if (imgtype.image.arrayed)
7060 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007061
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007062 uint32_t bias = 0;
7063 uint32_t lod = 0;
7064 uint32_t grad_x = 0;
7065 uint32_t grad_y = 0;
7066 uint32_t coffset = 0;
7067 uint32_t offset = 0;
7068 uint32_t coffsets = 0;
7069 uint32_t sample = 0;
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02007070 uint32_t minlod = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007071 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007073 if (length)
7074 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007075 flags = *opt++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007076 length--;
7077 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007078
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02007079 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007080 if (length && (flags & flag))
7081 {
7082 v = *opt++;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01007083 inherited_expressions.push_back(v);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007084 length--;
7085 }
7086 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007087
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007088 test(bias, ImageOperandsBiasMask);
7089 test(lod, ImageOperandsLodMask);
7090 test(grad_x, ImageOperandsGradMask);
7091 test(grad_y, ImageOperandsGradMask);
7092 test(coffset, ImageOperandsConstOffsetMask);
7093 test(offset, ImageOperandsOffsetMask);
7094 test(coffsets, ImageOperandsConstOffsetsMask);
7095 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02007096 test(minlod, ImageOperandsMinLodMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007097
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007098 TextureFunctionBaseArguments base_args = {};
7099 base_args.img = img;
7100 base_args.imgtype = &imgtype;
7101 base_args.is_fetch = fetch != 0;
7102 base_args.is_gather = gather != 0;
7103 base_args.is_proj = proj != 0;
7104
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007105 string expr;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007106 TextureFunctionNameArguments name_args = {};
7107
7108 name_args.base = base_args;
7109 name_args.has_array_offsets = coffsets != 0;
7110 name_args.has_offset = coffset != 0 || offset != 0;
7111 name_args.has_grad = grad_x != 0 || grad_y != 0;
7112 name_args.has_dref = dref != 0;
7113 name_args.is_sparse_feedback = sparse;
7114 name_args.has_min_lod = minlod != 0;
7115 name_args.lod = lod;
7116 expr += to_function_name(name_args);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007117 expr += "(";
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007118
7119 uint32_t sparse_texel_id = 0;
7120 if (sparse)
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007121 sparse_texel_id = get_sparse_feedback_texel_id(ops[1]);
7122
7123 TextureFunctionArguments args = {};
7124 args.base = base_args;
7125 args.coord = coord;
7126 args.coord_components = coord_components;
7127 args.dref = dref;
7128 args.grad_x = grad_x;
7129 args.grad_y = grad_y;
7130 args.lod = lod;
7131 args.coffset = coffset;
7132 args.offset = offset;
7133 args.bias = bias;
7134 args.component = comp;
7135 args.sample = sample;
7136 args.sparse_texel = sparse_texel_id;
7137 args.min_lod = minlod;
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01007138 args.nonuniform_expression = nonuniform_expression;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007139 expr += to_function_args(args, forward);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007140 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007141
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +02007142 // texture(samplerXShadow) returns float. shadowX() returns vec4, but only in desktop GLSL. Swizzle here.
7143 if (is_legacy() && !options.es && is_depth_image(imgtype, img))
Sidney Justf6dad782018-06-22 00:28:40 -07007144 expr += ".r";
7145
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01007146 // Sampling from a texture which was deduced to be a depth image, might actually return 1 component here.
7147 // Remap back to 4 components as sampling opcodes expect.
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02007148 if (backend.comparison_image_samples_scalar && image_opcode_is_sample_no_dref(op))
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01007149 {
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02007150 bool image_is_depth = false;
7151 const auto *combined = maybe_get<SPIRCombinedImageSampler>(img);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02007152 VariableID image_id = combined ? combined->image : img;
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02007153
Bill Hollingsfd252b22021-11-08 15:59:45 -05007154 if (combined && is_depth_image(imgtype, combined->image))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02007155 image_is_depth = true;
Bill Hollingsfd252b22021-11-08 15:59:45 -05007156 else if (is_depth_image(imgtype, img))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02007157 image_is_depth = true;
7158
7159 // We must also check the backing variable for the image.
7160 // We might have loaded an OpImage, and used that handle for two different purposes.
7161 // Once with comparison, once without.
7162 auto *image_variable = maybe_get_backing_variable(image_id);
Bill Hollingsfd252b22021-11-08 15:59:45 -05007163 if (image_variable && is_depth_image(get<SPIRType>(image_variable->basetype), image_variable->self))
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02007164 image_is_depth = true;
7165
7166 if (image_is_depth)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02007167 expr = remap_swizzle(result_type, 1, expr);
7168 }
7169
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007170 if (!sparse && !backend.support_small_type_sampling_result && result_type.width < 32)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02007171 {
7172 // Just value cast (narrowing) to expected type since we cannot rely on narrowing to work automatically.
7173 // Hopefully compiler picks this up and converts the texturing instruction to the appropriate precision.
7174 expr = join(type_to_glsl_constructor(result_type), "(", expr, ")");
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01007175 }
7176
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01007177 // Deals with reads from MSL. We might need to downconvert to fewer components.
7178 if (op == OpImageRead)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02007179 expr = remap_swizzle(result_type, 4, expr);
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01007180
Chip Davis39dce882019-08-02 15:11:19 -05007181 return expr;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007182}
7183
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01007184bool CompilerGLSL::expression_is_constant_null(uint32_t id) const
7185{
7186 auto *c = maybe_get<SPIRConstant>(id);
7187 if (!c)
7188 return false;
7189 return c->constant_is_null();
7190}
7191
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02007192bool CompilerGLSL::expression_is_non_value_type_array(uint32_t ptr)
7193{
7194 auto &type = expression_type(ptr);
7195 if (type.array.empty())
7196 return false;
7197
7198 if (!backend.array_is_value_type)
7199 return true;
7200
7201 auto *var = maybe_get_backing_variable(ptr);
7202 if (!var)
7203 return false;
7204
7205 auto &backed_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzen9b255812022-01-17 17:33:57 +01007206 return !backend.array_is_value_type_in_buffer_blocks && backed_type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02007207 has_member_decoration(backed_type.self, 0, DecorationOffset);
7208}
7209
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007210// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
7211// For some subclasses, the function is a method on the specified image.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007212string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007213{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007214 if (args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007215 {
7216 if (options.es)
7217 SPIRV_CROSS_THROW("Sparse residency is not supported in ESSL.");
7218 require_extension_internal("GL_ARB_sparse_texture_clamp");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007219 }
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02007220
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007221 string fname;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007222 auto &imgtype = *args.base.imgtype;
7223 VariableID tex = args.base.img;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007224
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007225 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007226 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
7227 // 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 +02007228 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007229 bool workaround_lod_array_shadow_as_grad = false;
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007230 if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzena3c41772022-05-13 15:47:22 +02007231 is_depth_image(imgtype, tex) && args.lod && !args.base.is_fetch)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007232 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007233 if (!expression_is_constant_null(args.lod))
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01007234 {
crissdb52e272020-10-08 12:14:52 +02007235 SPIRV_CROSS_THROW("textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be "
7236 "expressed in GLSL.");
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01007237 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007238 workaround_lod_array_shadow_as_grad = true;
7239 }
7240
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007241 if (args.is_sparse_feedback)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007242 fname += "sparse";
7243
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007244 if (args.base.is_fetch)
7245 fname += args.is_sparse_feedback ? "TexelFetch" : "texelFetch";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007246 else
7247 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007248 fname += args.is_sparse_feedback ? "Texture" : "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007249
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007250 if (args.base.is_gather)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007251 fname += "Gather";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007252 if (args.has_array_offsets)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007253 fname += "Offsets";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007254 if (args.base.is_proj)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007255 fname += "Proj";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007256 if (args.has_grad || workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007257 fname += "Grad";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007258 if (args.lod != 0 && !workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007259 fname += "Lod";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007260 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007261
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007262 if (args.has_offset)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007263 fname += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007264
Hans-Kristian Arntzenf383cc92020-06-08 13:39:02 +02007265 if (args.has_min_lod)
7266 fname += "Clamp";
7267
7268 if (args.is_sparse_feedback || args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007269 fname += "ARB";
7270
rdb509908d2020-11-07 00:01:57 +01007271 return (is_legacy() && !args.base.is_gather) ? legacy_tex_op(fname, imgtype, tex) : fname;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007272}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007273
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007274std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id)
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007275{
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007276 auto *var = maybe_get_backing_variable(id);
7277
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007278 // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler in GLSL.
7279 // In Vulkan GLSL, we can make use of the newer GL_EXT_samplerless_texture_functions.
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007280 if (var)
7281 {
7282 auto &type = get<SPIRType>(var->basetype);
7283 if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer)
7284 {
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007285 if (options.vulkan_semantics)
7286 {
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007287 if (dummy_sampler_id)
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02007288 {
7289 // Don't need to consider Shadow state since the dummy sampler is always non-shadow.
7290 auto sampled_type = type;
7291 sampled_type.basetype = SPIRType::SampledImage;
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007292 return join(type_to_glsl(sampled_type), "(", to_non_uniform_aware_expression(id), ", ",
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02007293 to_expression(dummy_sampler_id), ")");
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02007294 }
7295 else
7296 {
7297 // Newer glslang supports this extension to deal with texture2D as argument to texture functions.
7298 require_extension_internal("GL_EXT_samplerless_texture_functions");
7299 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007300 }
7301 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007302 {
7303 if (!dummy_sampler_id)
crissdb52e272020-10-08 12:14:52 +02007304 SPIRV_CROSS_THROW("Cannot find dummy sampler ID. Was "
7305 "build_dummy_sampler_for_combined_images() called?");
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007306
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007307 return to_combined_image_sampler(id, dummy_sampler_id);
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007308 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007309 }
7310 }
7311
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007312 return to_non_uniform_aware_expression(id);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007313}
7314
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007315// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007316string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool *p_forward)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007317{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007318 VariableID img = args.base.img;
7319 auto &imgtype = *args.base.imgtype;
7320
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007321 string farg_str;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007322 if (args.base.is_fetch)
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02007323 farg_str = convert_separate_image_to_expression(img);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02007324 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02007325 farg_str = to_non_uniform_aware_expression(img);
Hans-Kristian Arntzen1a2e4de2018-02-21 13:43:16 +01007326
Hans-Kristian Arntzena11c4782020-12-07 13:00:15 +01007327 if (args.nonuniform_expression && farg_str.find_first_of('[') != string::npos)
7328 {
7329 // Only emit nonuniformEXT() wrapper if the underlying expression is arrayed in some way.
7330 farg_str = join(backend.nonuniform_qualifier, "(", farg_str, ")");
7331 }
7332
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007333 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02007334 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007335 if (comps == in_comps)
7336 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007337
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007338 switch (comps)
7339 {
7340 case 1:
7341 return ".x";
7342 case 2:
7343 return swizz_func ? ".xy()" : ".xy";
7344 case 3:
7345 return swizz_func ? ".xyz()" : ".xyz";
7346 default:
7347 return "";
7348 }
7349 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007350
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007351 bool forward = should_forward(args.coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007352
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007353 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007354 auto swizzle_expr = swizzle(args.coord_components, expression_type(args.coord).vecsize);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01007355 // Only enclose the UV expression if needed.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02007356 auto coord_expr =
7357 (*swizzle_expr == '\0') ? to_expression(args.coord) : (to_enclosed_expression(args.coord) + swizzle_expr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007358
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007359 // texelFetch only takes int, not uint.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007360 auto &coord_type = expression_type(args.coord);
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007361 if (coord_type.basetype == SPIRType::UInt)
7362 {
7363 auto expected_type = coord_type;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007364 expected_type.vecsize = args.coord_components;
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01007365 expected_type.basetype = SPIRType::Int;
7366 coord_expr = bitcast_expression(expected_type, coord_type.basetype, coord_expr);
7367 }
7368
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007369 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007370 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
7371 // 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 +02007372 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02007373 bool workaround_lod_array_shadow_as_grad =
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007374 ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzena3c41772022-05-13 15:47:22 +02007375 is_depth_image(imgtype, img) && args.lod != 0 && !args.base.is_fetch;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007376
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007377 if (args.dref)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007378 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007379 forward = forward && should_forward(args.dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007380
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007381 // SPIR-V splits dref and coordinate.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02007382 if (args.base.is_gather ||
7383 args.coord_components == 4) // GLSL also splits the arguments in two. Same for textureGather.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007384 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007385 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007386 farg_str += to_expression(args.coord);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007387 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007388 farg_str += to_expression(args.dref);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007389 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007390 else if (args.base.is_proj)
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007391 {
7392 // Have to reshuffle so we get vec4(coord, dref, proj), special case.
7393 // Other shading languages splits up the arguments for coord and compare value like SPIR-V.
7394 // The coordinate type for textureProj shadow is always vec4 even for sampler1DShadow.
7395 farg_str += ", vec4(";
7396
7397 if (imgtype.image.dim == Dim1D)
7398 {
7399 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007400 farg_str += to_enclosed_expression(args.coord) + ".x";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007401 farg_str += ", ";
7402 farg_str += "0.0, ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007403 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007404 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007405 farg_str += to_enclosed_expression(args.coord) + ".y)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007406 }
7407 else if (imgtype.image.dim == Dim2D)
7408 {
7409 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007410 farg_str += to_enclosed_expression(args.coord) + (swizz_func ? ".xy()" : ".xy");
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007411 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007412 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007413 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007414 farg_str += to_enclosed_expression(args.coord) + ".z)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02007415 }
7416 else
7417 SPIRV_CROSS_THROW("Invalid type for textureProj with shadow.");
7418 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007419 else
7420 {
7421 // Create a composite which merges coord/dref into a single vector.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007422 auto type = expression_type(args.coord);
7423 type.vecsize = args.coord_components + 1;
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +02007424 if (imgtype.image.dim == Dim1D && options.es)
7425 type.vecsize++;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007426 farg_str += ", ";
7427 farg_str += type_to_glsl_constructor(type);
7428 farg_str += "(";
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +02007429
7430 if (imgtype.image.dim == Dim1D && options.es)
7431 {
7432 if (imgtype.image.arrayed)
7433 {
7434 farg_str += enclose_expression(coord_expr) + ".x";
7435 farg_str += ", 0.0, ";
7436 farg_str += enclose_expression(coord_expr) + ".y";
7437 }
7438 else
7439 {
7440 farg_str += coord_expr;
7441 farg_str += ", 0.0";
7442 }
7443 }
7444 else
7445 farg_str += coord_expr;
7446
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007447 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007448 farg_str += to_expression(args.dref);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007449 farg_str += ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007450 }
7451 }
7452 else
7453 {
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +02007454 if (imgtype.image.dim == Dim1D && options.es)
7455 {
7456 // Have to fake a second coordinate.
7457 if (type_is_floating_point(coord_type))
7458 {
7459 // Cannot mix proj and array.
7460 if (imgtype.image.arrayed || args.base.is_proj)
7461 {
7462 coord_expr = join("vec3(", enclose_expression(coord_expr), ".x, 0.0, ",
7463 enclose_expression(coord_expr), ".y)");
7464 }
7465 else
7466 coord_expr = join("vec2(", coord_expr, ", 0.0)");
7467 }
7468 else
7469 {
7470 if (imgtype.image.arrayed)
7471 {
7472 coord_expr = join("ivec3(", enclose_expression(coord_expr),
7473 ".x, 0, ",
7474 enclose_expression(coord_expr), ".y)");
7475 }
7476 else
7477 coord_expr = join("ivec2(", coord_expr, ", 0)");
7478 }
7479 }
7480
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007481 farg_str += ", ";
7482 farg_str += coord_expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007483 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007484
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007485 if (args.grad_x || args.grad_y)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007486 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007487 forward = forward && should_forward(args.grad_x);
7488 forward = forward && should_forward(args.grad_y);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007489 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007490 farg_str += to_expression(args.grad_x);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007491 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007492 farg_str += to_expression(args.grad_y);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007493 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007494
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007495 if (args.lod)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007496 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007497 if (workaround_lod_array_shadow_as_grad)
Robert Konrad3f745032017-03-23 09:55:32 +01007498 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007499 // Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
7500 // Implementing this as plain texture() is not safe on some implementations.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02007501 if (imgtype.image.dim == Dim2D)
7502 farg_str += ", vec2(0.0), vec2(0.0)";
7503 else if (imgtype.image.dim == DimCube)
7504 farg_str += ", vec3(0.0), vec3(0.0)";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02007505 }
7506 else
7507 {
rdbe8c500c2020-11-05 22:55:44 +01007508 forward = forward && should_forward(args.lod);
7509 farg_str += ", ";
7510
rdbe8c500c2020-11-05 22:55:44 +01007511 // Lod expression for TexelFetch in GLSL must be int, and only int.
Hans-Kristian Arntzen5d9a9532022-02-16 11:13:29 +01007512 if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms)
7513 farg_str += bitcast_expression(SPIRType::Int, args.lod);
rdbe8c500c2020-11-05 22:55:44 +01007514 else
rdbe8c500c2020-11-05 22:55:44 +01007515 farg_str += to_expression(args.lod);
Robert Konrad3f745032017-03-23 09:55:32 +01007516 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007517 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007518 else if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms)
Hans-Kristian Arntzend93807a2018-04-30 10:53:21 +02007519 {
7520 // Lod argument is optional in OpImageFetch, but we require a LOD value, pick 0 as the default.
7521 farg_str += ", 0";
7522 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007523
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007524 if (args.coffset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007525 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007526 forward = forward && should_forward(args.coffset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007527 farg_str += ", ";
Hans-Kristian Arntzen5d9a9532022-02-16 11:13:29 +01007528 farg_str += bitcast_expression(SPIRType::Int, args.coffset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007529 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007530 else if (args.offset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007531 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007532 forward = forward && should_forward(args.offset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007533 farg_str += ", ";
Hans-Kristian Arntzen5d9a9532022-02-16 11:13:29 +01007534 farg_str += bitcast_expression(SPIRType::Int, args.offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007535 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007536
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007537 if (args.sample)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007538 {
7539 farg_str += ", ";
Hans-Kristian Arntzen5d9a9532022-02-16 11:13:29 +01007540 farg_str += bitcast_expression(SPIRType::Int, args.sample);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007541 }
7542
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007543 if (args.min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007544 {
7545 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007546 farg_str += to_expression(args.min_lod);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007547 }
7548
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007549 if (args.sparse_texel)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007550 {
7551 // Sparse texel output parameter comes after everything else, except it's before the optional, component/bias arguments.
7552 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007553 farg_str += to_expression(args.sparse_texel);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02007554 }
7555
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007556 if (args.bias)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007557 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007558 forward = forward && should_forward(args.bias);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007559 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007560 farg_str += to_expression(args.bias);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007561 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007562
rdb509908d2020-11-07 00:01:57 +01007563 if (args.component && !expression_is_constant_null(args.component))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007564 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02007565 forward = forward && should_forward(args.component);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007566 farg_str += ", ";
Hans-Kristian Arntzen5d9a9532022-02-16 11:13:29 +01007567 farg_str += bitcast_expression(SPIRType::Int, args.component);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007568 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007569
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007570 *p_forward = forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007571
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05007572 return farg_str;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007573}
7574
Hans-Kristian Arntzen31be74a2022-03-03 11:04:45 +01007575Op CompilerGLSL::get_remapped_spirv_op(Op op) const
7576{
7577 if (options.relax_nan_checks)
7578 {
7579 switch (op)
7580 {
7581 case OpFUnordLessThan:
7582 op = OpFOrdLessThan;
7583 break;
7584 case OpFUnordLessThanEqual:
7585 op = OpFOrdLessThanEqual;
7586 break;
7587 case OpFUnordGreaterThan:
7588 op = OpFOrdGreaterThan;
7589 break;
7590 case OpFUnordGreaterThanEqual:
7591 op = OpFOrdGreaterThanEqual;
7592 break;
7593 case OpFUnordEqual:
7594 op = OpFOrdEqual;
7595 break;
7596 case OpFOrdNotEqual:
7597 op = OpFUnordNotEqual;
7598 break;
7599
7600 default:
7601 break;
7602 }
7603 }
7604
7605 return op;
7606}
7607
7608GLSLstd450 CompilerGLSL::get_remapped_glsl_op(GLSLstd450 std450_op) const
7609{
7610 // Relax to non-NaN aware opcodes.
7611 if (options.relax_nan_checks)
7612 {
7613 switch (std450_op)
7614 {
7615 case GLSLstd450NClamp:
7616 std450_op = GLSLstd450FClamp;
7617 break;
7618 case GLSLstd450NMin:
7619 std450_op = GLSLstd450FMin;
7620 break;
7621 case GLSLstd450NMax:
7622 std450_op = GLSLstd450FMax;
7623 break;
7624 default:
7625 break;
7626 }
7627 }
7628
7629 return std450_op;
7630}
7631
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007632void 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 +01007633{
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02007634 auto op = static_cast<GLSLstd450>(eop);
7635
7636 if (is_legacy() && is_unsigned_glsl_opcode(op))
7637 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy GLSL targets.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007638
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007639 // If we need to do implicit bitcasts, make sure we do it with the correct type.
7640 uint32_t integer_width = get_integer_width_for_glsl_instruction(op, args, length);
7641 auto int_type = to_signed_basetype(integer_width);
7642 auto uint_type = to_unsigned_basetype(integer_width);
7643
Hans-Kristian Arntzen31be74a2022-03-03 11:04:45 +01007644 op = get_remapped_glsl_op(op);
7645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007646 switch (op)
7647 {
7648 // FP fiddling
7649 case GLSLstd450Round:
rdb9e6e5d22020-11-06 17:34:38 +01007650 if (!is_legacy())
7651 emit_unary_func_op(result_type, id, args[0], "round");
7652 else
7653 {
7654 auto op0 = to_enclosed_expression(args[0]);
7655 auto &op0_type = expression_type(args[0]);
7656 auto expr = join("floor(", op0, " + ", type_to_glsl_constructor(op0_type), "(0.5))");
7657 bool forward = should_forward(args[0]);
7658 emit_op(result_type, id, expr, forward);
7659 inherit_expression_dependencies(id, args[0]);
7660 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007661 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007662
7663 case GLSLstd450RoundEven:
rdb9e6e5d22020-11-06 17:34:38 +01007664 if (!is_legacy())
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007665 emit_unary_func_op(result_type, id, args[0], "roundEven");
rdb9e6e5d22020-11-06 17:34:38 +01007666 else if (!options.es)
7667 {
7668 // This extension provides round() with round-to-even semantics.
7669 require_extension_internal("GL_EXT_gpu_shader4");
7670 emit_unary_func_op(result_type, id, args[0], "round");
7671 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007672 else
rdb9e6e5d22020-11-06 17:34:38 +01007673 SPIRV_CROSS_THROW("roundEven supported only in ESSL 300.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007674 break;
7675
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007676 case GLSLstd450Trunc:
7677 emit_unary_func_op(result_type, id, args[0], "trunc");
7678 break;
7679 case GLSLstd450SAbs:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007680 emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type);
7681 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007682 case GLSLstd450FAbs:
7683 emit_unary_func_op(result_type, id, args[0], "abs");
7684 break;
7685 case GLSLstd450SSign:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007686 emit_unary_func_op_cast(result_type, id, args[0], "sign", int_type, int_type);
7687 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007688 case GLSLstd450FSign:
7689 emit_unary_func_op(result_type, id, args[0], "sign");
7690 break;
7691 case GLSLstd450Floor:
7692 emit_unary_func_op(result_type, id, args[0], "floor");
7693 break;
7694 case GLSLstd450Ceil:
7695 emit_unary_func_op(result_type, id, args[0], "ceil");
7696 break;
7697 case GLSLstd450Fract:
7698 emit_unary_func_op(result_type, id, args[0], "fract");
7699 break;
7700 case GLSLstd450Radians:
7701 emit_unary_func_op(result_type, id, args[0], "radians");
7702 break;
7703 case GLSLstd450Degrees:
7704 emit_unary_func_op(result_type, id, args[0], "degrees");
7705 break;
7706 case GLSLstd450Fma:
Hans-Kristian Arntzen3ca8bc52019-04-08 10:33:34 +02007707 if ((!options.es && options.version < 400) || (options.es && options.version < 320))
7708 {
7709 auto expr = join(to_enclosed_expression(args[0]), " * ", to_enclosed_expression(args[1]), " + ",
7710 to_enclosed_expression(args[2]));
7711
7712 emit_op(result_type, id, expr,
7713 should_forward(args[0]) && should_forward(args[1]) && should_forward(args[2]));
7714 for (uint32_t i = 0; i < 3; i++)
7715 inherit_expression_dependencies(id, args[i]);
7716 }
7717 else
7718 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007719 break;
7720 case GLSLstd450Modf:
7721 register_call_out_argument(args[1]);
7722 forced_temporaries.insert(id);
7723 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
7724 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007725
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007726 case GLSLstd450ModfStruct:
7727 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007728 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02007729 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007730 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
7731 to_expression(id), ".", to_member_name(type, 1), ");");
7732 break;
7733 }
7734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007735 // Minmax
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007736 case GLSLstd450UMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007737 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", uint_type, false);
7738 break;
7739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007740 case GLSLstd450SMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007741 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", int_type, false);
7742 break;
7743
7744 case GLSLstd450FMin:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007745 emit_binary_func_op(result_type, id, args[0], args[1], "min");
7746 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007747
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007748 case GLSLstd450FMax:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007749 emit_binary_func_op(result_type, id, args[0], args[1], "max");
7750 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007751
7752 case GLSLstd450UMax:
7753 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", uint_type, false);
7754 break;
7755
7756 case GLSLstd450SMax:
7757 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", int_type, false);
7758 break;
7759
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007760 case GLSLstd450FClamp:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007761 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
7762 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007763
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007764 case GLSLstd450UClamp:
7765 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", uint_type);
7766 break;
7767
7768 case GLSLstd450SClamp:
7769 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", int_type);
7770 break;
7771
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007772 // Trig
7773 case GLSLstd450Sin:
7774 emit_unary_func_op(result_type, id, args[0], "sin");
7775 break;
7776 case GLSLstd450Cos:
7777 emit_unary_func_op(result_type, id, args[0], "cos");
7778 break;
7779 case GLSLstd450Tan:
7780 emit_unary_func_op(result_type, id, args[0], "tan");
7781 break;
7782 case GLSLstd450Asin:
7783 emit_unary_func_op(result_type, id, args[0], "asin");
7784 break;
7785 case GLSLstd450Acos:
7786 emit_unary_func_op(result_type, id, args[0], "acos");
7787 break;
7788 case GLSLstd450Atan:
7789 emit_unary_func_op(result_type, id, args[0], "atan");
7790 break;
7791 case GLSLstd450Sinh:
7792 emit_unary_func_op(result_type, id, args[0], "sinh");
7793 break;
7794 case GLSLstd450Cosh:
7795 emit_unary_func_op(result_type, id, args[0], "cosh");
7796 break;
7797 case GLSLstd450Tanh:
7798 emit_unary_func_op(result_type, id, args[0], "tanh");
7799 break;
7800 case GLSLstd450Asinh:
7801 emit_unary_func_op(result_type, id, args[0], "asinh");
7802 break;
7803 case GLSLstd450Acosh:
7804 emit_unary_func_op(result_type, id, args[0], "acosh");
7805 break;
7806 case GLSLstd450Atanh:
7807 emit_unary_func_op(result_type, id, args[0], "atanh");
7808 break;
7809 case GLSLstd450Atan2:
7810 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
7811 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007812
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007813 // Exponentials
7814 case GLSLstd450Pow:
7815 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
7816 break;
7817 case GLSLstd450Exp:
7818 emit_unary_func_op(result_type, id, args[0], "exp");
7819 break;
7820 case GLSLstd450Log:
7821 emit_unary_func_op(result_type, id, args[0], "log");
7822 break;
7823 case GLSLstd450Exp2:
7824 emit_unary_func_op(result_type, id, args[0], "exp2");
7825 break;
7826 case GLSLstd450Log2:
7827 emit_unary_func_op(result_type, id, args[0], "log2");
7828 break;
7829 case GLSLstd450Sqrt:
7830 emit_unary_func_op(result_type, id, args[0], "sqrt");
7831 break;
7832 case GLSLstd450InverseSqrt:
7833 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
7834 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007836 // Matrix math
7837 case GLSLstd450Determinant:
7838 emit_unary_func_op(result_type, id, args[0], "determinant");
7839 break;
7840 case GLSLstd450MatrixInverse:
7841 emit_unary_func_op(result_type, id, args[0], "inverse");
7842 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007843
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007844 // Lerping
7845 case GLSLstd450FMix:
7846 case GLSLstd450IMix:
7847 {
7848 emit_mix_op(result_type, id, args[0], args[1], args[2]);
7849 break;
7850 }
7851 case GLSLstd450Step:
7852 emit_binary_func_op(result_type, id, args[0], args[1], "step");
7853 break;
7854 case GLSLstd450SmoothStep:
7855 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
7856 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007858 // Packing
7859 case GLSLstd450Frexp:
7860 register_call_out_argument(args[1]);
7861 forced_temporaries.insert(id);
7862 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
7863 break;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007864
7865 case GLSLstd450FrexpStruct:
7866 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007867 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02007868 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02007869 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
7870 to_expression(id), ".", to_member_name(type, 1), ");");
7871 break;
7872 }
7873
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007874 case GLSLstd450Ldexp:
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007875 {
7876 bool forward = should_forward(args[0]) && should_forward(args[1]);
7877
7878 auto op0 = to_unpacked_expression(args[0]);
7879 auto op1 = to_unpacked_expression(args[1]);
7880 auto &op1_type = expression_type(args[1]);
7881 if (op1_type.basetype != SPIRType::Int)
7882 {
7883 // Need a value cast here.
7884 auto target_type = op1_type;
7885 target_type.basetype = SPIRType::Int;
7886 op1 = join(type_to_glsl_constructor(target_type), "(", op1, ")");
7887 }
7888
7889 auto expr = join("ldexp(", op0, ", ", op1, ")");
7890
7891 emit_op(result_type, id, expr, forward);
7892 inherit_expression_dependencies(id, args[0]);
7893 inherit_expression_dependencies(id, args[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007894 break;
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007895 }
7896
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007897 case GLSLstd450PackSnorm4x8:
7898 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
7899 break;
7900 case GLSLstd450PackUnorm4x8:
7901 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
7902 break;
7903 case GLSLstd450PackSnorm2x16:
7904 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
7905 break;
7906 case GLSLstd450PackUnorm2x16:
7907 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
7908 break;
7909 case GLSLstd450PackHalf2x16:
7910 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
7911 break;
7912 case GLSLstd450UnpackSnorm4x8:
7913 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
7914 break;
7915 case GLSLstd450UnpackUnorm4x8:
7916 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
7917 break;
7918 case GLSLstd450UnpackSnorm2x16:
7919 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
7920 break;
7921 case GLSLstd450UnpackUnorm2x16:
7922 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
7923 break;
7924 case GLSLstd450UnpackHalf2x16:
7925 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
7926 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007927
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007928 case GLSLstd450PackDouble2x32:
7929 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
7930 break;
7931 case GLSLstd450UnpackDouble2x32:
7932 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
7933 break;
7934
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007935 // Vector math
7936 case GLSLstd450Length:
7937 emit_unary_func_op(result_type, id, args[0], "length");
7938 break;
7939 case GLSLstd450Distance:
7940 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
7941 break;
7942 case GLSLstd450Cross:
7943 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
7944 break;
7945 case GLSLstd450Normalize:
7946 emit_unary_func_op(result_type, id, args[0], "normalize");
7947 break;
7948 case GLSLstd450FaceForward:
7949 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
7950 break;
7951 case GLSLstd450Reflect:
7952 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
7953 break;
7954 case GLSLstd450Refract:
7955 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
7956 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007957
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007958 // Bit-fiddling
7959 case GLSLstd450FindILsb:
Hans-Kristian Arntzen932ee0e2019-07-12 10:57:56 +02007960 // findLSB always returns int.
7961 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 +02007962 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007963
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007964 case GLSLstd450FindSMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007965 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", int_type, int_type);
7966 break;
7967
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007968 case GLSLstd450FindUMsb:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02007969 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type,
7970 int_type); // findMSB always returns int.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007971 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007972
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007973 // Multisampled varying
7974 case GLSLstd450InterpolateAtCentroid:
7975 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
7976 break;
7977 case GLSLstd450InterpolateAtSample:
7978 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
7979 break;
7980 case GLSLstd450InterpolateAtOffset:
7981 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
7982 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007983
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007984 case GLSLstd450NMin:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007985 case GLSLstd450NMax:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007986 {
7987 emit_nminmax_op(result_type, id, args[0], args[1], op);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007988 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007989 }
7990
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007991 case GLSLstd450NClamp:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007992 {
7993 // Make sure we have a unique ID here to avoid aliasing the extra sub-expressions between clamp and NMin sub-op.
7994 // 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 +01007995 uint32_t &max_id = extra_sub_expressions[id | EXTRA_SUB_EXPRESSION_TYPE_AUX];
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007996 if (!max_id)
7997 max_id = ir.increase_bound_by(1);
7998
7999 // Inherit precision qualifiers.
8000 ir.meta[max_id] = ir.meta[id];
8001
8002 emit_nminmax_op(result_type, max_id, args[0], args[1], GLSLstd450NMax);
8003 emit_nminmax_op(result_type, id, max_id, args[2], GLSLstd450NMin);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02008004 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01008005 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02008006
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008007 default:
8008 statement("// unimplemented GLSL op ", eop);
8009 break;
8010 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008011}
8012
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01008013void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op)
8014{
8015 // Need to emulate this call.
8016 uint32_t &ids = extra_sub_expressions[id];
8017 if (!ids)
8018 {
8019 ids = ir.increase_bound_by(5);
8020 auto btype = get<SPIRType>(result_type);
8021 btype.basetype = SPIRType::Boolean;
8022 set<SPIRType>(ids, btype);
8023 }
8024
8025 uint32_t btype_id = ids + 0;
8026 uint32_t left_nan_id = ids + 1;
8027 uint32_t right_nan_id = ids + 2;
8028 uint32_t tmp_id = ids + 3;
8029 uint32_t mixed_first_id = ids + 4;
8030
8031 // Inherit precision qualifiers.
8032 ir.meta[tmp_id] = ir.meta[id];
8033 ir.meta[mixed_first_id] = ir.meta[id];
8034
8035 emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
8036 emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
8037 emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max");
8038 emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id);
8039 emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id);
8040}
8041
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008042void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
8043 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01008044{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008045 require_extension_internal("GL_AMD_shader_ballot");
Lou Kramer6671f522017-11-21 14:04:57 +01008046
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008047 enum AMDShaderBallot
8048 {
Lou Kramer6671f522017-11-21 14:04:57 +01008049 SwizzleInvocationsAMD = 1,
8050 SwizzleInvocationsMaskedAMD = 2,
8051 WriteInvocationAMD = 3,
8052 MbcntAMD = 4
8053 };
8054
8055 auto op = static_cast<AMDShaderBallot>(eop);
8056
8057 switch (op)
8058 {
8059 case SwizzleInvocationsAMD:
8060 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008061 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01008062 break;
8063
8064 case SwizzleInvocationsMaskedAMD:
8065 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsMaskedAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008066 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01008067 break;
8068
8069 case WriteInvocationAMD:
8070 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "writeInvocationAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008071 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01008072 break;
8073
8074 case MbcntAMD:
8075 emit_unary_func_op(result_type, id, args[0], "mbcntAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008076 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01008077 break;
8078
8079 default:
8080 statement("// unimplemented SPV AMD shader ballot op ", eop);
8081 break;
8082 }
8083}
8084
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008085void CompilerGLSL::emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t id, uint32_t eop,
8086 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01008087{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008088 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Lou Kramer6671f522017-11-21 14:04:57 +01008089
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008090 enum AMDShaderExplicitVertexParameter
8091 {
Lou Kramer6671f522017-11-21 14:04:57 +01008092 InterpolateAtVertexAMD = 1
8093 };
8094
8095 auto op = static_cast<AMDShaderExplicitVertexParameter>(eop);
8096
8097 switch (op)
8098 {
8099 case InterpolateAtVertexAMD:
8100 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtVertexAMD");
8101 break;
8102
8103 default:
8104 statement("// unimplemented SPV AMD shader explicit vertex parameter op ", eop);
8105 break;
8106 }
8107}
8108
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008109void CompilerGLSL::emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t id, uint32_t eop,
8110 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01008111{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008112 require_extension_internal("GL_AMD_shader_trinary_minmax");
Lou Kramer6671f522017-11-21 14:04:57 +01008113
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008114 enum AMDShaderTrinaryMinMax
8115 {
Lou Kramer6671f522017-11-21 14:04:57 +01008116 FMin3AMD = 1,
8117 UMin3AMD = 2,
8118 SMin3AMD = 3,
8119 FMax3AMD = 4,
8120 UMax3AMD = 5,
8121 SMax3AMD = 6,
8122 FMid3AMD = 7,
8123 UMid3AMD = 8,
8124 SMid3AMD = 9
8125 };
8126
8127 auto op = static_cast<AMDShaderTrinaryMinMax>(eop);
8128
8129 switch (op)
8130 {
8131 case FMin3AMD:
8132 case UMin3AMD:
8133 case SMin3AMD:
8134 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "min3");
8135 break;
8136
8137 case FMax3AMD:
8138 case UMax3AMD:
8139 case SMax3AMD:
8140 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "max3");
8141 break;
8142
8143 case FMid3AMD:
8144 case UMid3AMD:
8145 case SMid3AMD:
8146 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mid3");
8147 break;
8148
8149 default:
8150 statement("// unimplemented SPV AMD shader trinary minmax op ", eop);
8151 break;
8152 }
8153}
8154
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008155void CompilerGLSL::emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
8156 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01008157{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008158 require_extension_internal("GL_AMD_gcn_shader");
Lou Kramer6671f522017-11-21 14:04:57 +01008159
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008160 enum AMDGCNShader
8161 {
Lou Kramer6671f522017-11-21 14:04:57 +01008162 CubeFaceIndexAMD = 1,
8163 CubeFaceCoordAMD = 2,
8164 TimeAMD = 3
8165 };
8166
8167 auto op = static_cast<AMDGCNShader>(eop);
8168
8169 switch (op)
8170 {
8171 case CubeFaceIndexAMD:
8172 emit_unary_func_op(result_type, id, args[0], "cubeFaceIndexAMD");
8173 break;
8174 case CubeFaceCoordAMD:
8175 emit_unary_func_op(result_type, id, args[0], "cubeFaceCoordAMD");
8176 break;
8177 case TimeAMD:
8178 {
8179 string expr = "timeAMD()";
8180 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008181 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01008182 break;
8183 }
8184
8185 default:
8186 statement("// unimplemented SPV AMD gcn shader op ", eop);
8187 break;
8188 }
8189}
8190
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008191void CompilerGLSL::emit_subgroup_op(const Instruction &i)
8192{
8193 const uint32_t *ops = stream(i);
8194 auto op = static_cast<Op>(i.op);
8195
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02008196 if (!options.vulkan_semantics && !is_supported_subgroup_op_in_opengl(op))
crissdb52e272020-10-08 12:14:52 +02008197 SPIRV_CROSS_THROW("This subgroup operation is only supported in Vulkan semantics.");
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008198
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008199 // If we need to do implicit bitcasts, make sure we do it with the correct type.
8200 uint32_t integer_width = get_integer_width_for_instruction(i);
8201 auto int_type = to_signed_basetype(integer_width);
8202 auto uint_type = to_unsigned_basetype(integer_width);
8203
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008204 switch (op)
8205 {
8206 case OpGroupNonUniformElect:
crissdb52e272020-10-08 12:14:52 +02008207 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupElect);
8208 break;
8209
8210 case OpGroupNonUniformBallotBitCount:
8211 {
8212 const GroupOperation operation = static_cast<GroupOperation>(ops[3]);
8213 if (operation == GroupOperationReduce)
8214 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitCount);
8215 else if (operation == GroupOperationInclusiveScan || operation == GroupOperationExclusiveScan)
8216 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
8217 }
8218 break;
8219
8220 case OpGroupNonUniformBallotBitExtract:
8221 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitExtract);
8222 break;
8223
8224 case OpGroupNonUniformInverseBallot:
8225 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
8226 break;
8227
8228 case OpGroupNonUniformBallot:
8229 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallot);
8230 break;
8231
8232 case OpGroupNonUniformBallotFindLSB:
8233 case OpGroupNonUniformBallotFindMSB:
8234 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotFindLSB_MSB);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008235 break;
8236
8237 case OpGroupNonUniformBroadcast:
8238 case OpGroupNonUniformBroadcastFirst:
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +01008239 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBroadcast_First);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008240 break;
8241
8242 case OpGroupNonUniformShuffle:
8243 case OpGroupNonUniformShuffleXor:
8244 require_extension_internal("GL_KHR_shader_subgroup_shuffle");
8245 break;
8246
8247 case OpGroupNonUniformShuffleUp:
8248 case OpGroupNonUniformShuffleDown:
8249 require_extension_internal("GL_KHR_shader_subgroup_shuffle_relative");
8250 break;
8251
8252 case OpGroupNonUniformAll:
8253 case OpGroupNonUniformAny:
8254 case OpGroupNonUniformAllEqual:
crissdb52e272020-10-08 12:14:52 +02008255 {
8256 const SPIRType &type = expression_type(ops[3]);
8257 if (type.basetype == SPIRType::BaseType::Boolean && type.vecsize == 1u)
8258 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAll_Any_AllEqualBool);
8259 else
8260 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAllEqualT);
8261 }
8262 break;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008263
8264 case OpGroupNonUniformFAdd:
8265 case OpGroupNonUniformFMul:
8266 case OpGroupNonUniformFMin:
8267 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008268 case OpGroupNonUniformIAdd:
8269 case OpGroupNonUniformIMul:
8270 case OpGroupNonUniformSMin:
8271 case OpGroupNonUniformSMax:
8272 case OpGroupNonUniformUMin:
8273 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008274 case OpGroupNonUniformBitwiseAnd:
8275 case OpGroupNonUniformBitwiseOr:
8276 case OpGroupNonUniformBitwiseXor:
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +01008277 case OpGroupNonUniformLogicalAnd:
8278 case OpGroupNonUniformLogicalOr:
8279 case OpGroupNonUniformLogicalXor:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008280 {
8281 auto operation = static_cast<GroupOperation>(ops[3]);
8282 if (operation == GroupOperationClusteredReduce)
8283 {
8284 require_extension_internal("GL_KHR_shader_subgroup_clustered");
8285 }
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008286 else if (operation == GroupOperationExclusiveScan || operation == GroupOperationInclusiveScan ||
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008287 operation == GroupOperationReduce)
8288 {
8289 require_extension_internal("GL_KHR_shader_subgroup_arithmetic");
8290 }
8291 else
8292 SPIRV_CROSS_THROW("Invalid group operation.");
8293 break;
8294 }
8295
8296 case OpGroupNonUniformQuadSwap:
8297 case OpGroupNonUniformQuadBroadcast:
8298 require_extension_internal("GL_KHR_shader_subgroup_quad");
8299 break;
8300
8301 default:
8302 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
8303 }
8304
8305 uint32_t result_type = ops[0];
8306 uint32_t id = ops[1];
8307
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008308 auto scope = static_cast<Scope>(evaluate_constant_u32(ops[2]));
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008309 if (scope != ScopeSubgroup)
8310 SPIRV_CROSS_THROW("Only subgroup scope is supported.");
8311
8312 switch (op)
8313 {
8314 case OpGroupNonUniformElect:
8315 emit_op(result_type, id, "subgroupElect()", true);
8316 break;
8317
8318 case OpGroupNonUniformBroadcast:
8319 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBroadcast");
8320 break;
8321
8322 case OpGroupNonUniformBroadcastFirst:
8323 emit_unary_func_op(result_type, id, ops[3], "subgroupBroadcastFirst");
8324 break;
8325
8326 case OpGroupNonUniformBallot:
8327 emit_unary_func_op(result_type, id, ops[3], "subgroupBallot");
8328 break;
8329
8330 case OpGroupNonUniformInverseBallot:
8331 emit_unary_func_op(result_type, id, ops[3], "subgroupInverseBallot");
8332 break;
8333
8334 case OpGroupNonUniformBallotBitExtract:
8335 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBallotBitExtract");
8336 break;
8337
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008338 case OpGroupNonUniformBallotFindLSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008339 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindLSB");
8340 break;
8341
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008342 case OpGroupNonUniformBallotFindMSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008343 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindMSB");
8344 break;
8345
8346 case OpGroupNonUniformBallotBitCount:
8347 {
8348 auto operation = static_cast<GroupOperation>(ops[3]);
8349 if (operation == GroupOperationReduce)
8350 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotBitCount");
8351 else if (operation == GroupOperationInclusiveScan)
8352 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotInclusiveBitCount");
8353 else if (operation == GroupOperationExclusiveScan)
8354 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotExclusiveBitCount");
8355 else
8356 SPIRV_CROSS_THROW("Invalid BitCount operation.");
8357 break;
8358 }
8359
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008360 case OpGroupNonUniformShuffle:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008361 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffle");
8362 break;
8363
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008364 case OpGroupNonUniformShuffleXor:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008365 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleXor");
8366 break;
8367
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008368 case OpGroupNonUniformShuffleUp:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008369 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleUp");
8370 break;
8371
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008372 case OpGroupNonUniformShuffleDown:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008373 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleDown");
8374 break;
8375
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008376 case OpGroupNonUniformAll:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008377 emit_unary_func_op(result_type, id, ops[3], "subgroupAll");
8378 break;
8379
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008380 case OpGroupNonUniformAny:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008381 emit_unary_func_op(result_type, id, ops[3], "subgroupAny");
8382 break;
8383
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008384 case OpGroupNonUniformAllEqual:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008385 emit_unary_func_op(result_type, id, ops[3], "subgroupAllEqual");
8386 break;
8387
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008388 // clang-format off
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008389#define GLSL_GROUP_OP(op, glsl_op) \
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008390case OpGroupNonUniform##op: \
8391 { \
8392 auto operation = static_cast<GroupOperation>(ops[3]); \
8393 if (operation == GroupOperationReduce) \
8394 emit_unary_func_op(result_type, id, ops[4], "subgroup" #glsl_op); \
8395 else if (operation == GroupOperationInclusiveScan) \
8396 emit_unary_func_op(result_type, id, ops[4], "subgroupInclusive" #glsl_op); \
8397 else if (operation == GroupOperationExclusiveScan) \
8398 emit_unary_func_op(result_type, id, ops[4], "subgroupExclusive" #glsl_op); \
8399 else if (operation == GroupOperationClusteredReduce) \
8400 emit_binary_func_op(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op); \
8401 else \
8402 SPIRV_CROSS_THROW("Invalid group operation."); \
8403 break; \
8404 }
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008405
8406#define GLSL_GROUP_OP_CAST(op, glsl_op, type) \
8407case OpGroupNonUniform##op: \
8408 { \
8409 auto operation = static_cast<GroupOperation>(ops[3]); \
8410 if (operation == GroupOperationReduce) \
8411 emit_unary_func_op_cast(result_type, id, ops[4], "subgroup" #glsl_op, type, type); \
8412 else if (operation == GroupOperationInclusiveScan) \
8413 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupInclusive" #glsl_op, type, type); \
8414 else if (operation == GroupOperationExclusiveScan) \
8415 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupExclusive" #glsl_op, type, type); \
8416 else if (operation == GroupOperationClusteredReduce) \
8417 emit_binary_func_op_cast_clustered(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op, type); \
8418 else \
8419 SPIRV_CROSS_THROW("Invalid group operation."); \
8420 break; \
8421 }
8422
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008423 GLSL_GROUP_OP(FAdd, Add)
8424 GLSL_GROUP_OP(FMul, Mul)
8425 GLSL_GROUP_OP(FMin, Min)
8426 GLSL_GROUP_OP(FMax, Max)
8427 GLSL_GROUP_OP(IAdd, Add)
8428 GLSL_GROUP_OP(IMul, Mul)
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008429 GLSL_GROUP_OP_CAST(SMin, Min, int_type)
8430 GLSL_GROUP_OP_CAST(SMax, Max, int_type)
8431 GLSL_GROUP_OP_CAST(UMin, Min, uint_type)
8432 GLSL_GROUP_OP_CAST(UMax, Max, uint_type)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008433 GLSL_GROUP_OP(BitwiseAnd, And)
8434 GLSL_GROUP_OP(BitwiseOr, Or)
8435 GLSL_GROUP_OP(BitwiseXor, Xor)
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +01008436 GLSL_GROUP_OP(LogicalAnd, And)
8437 GLSL_GROUP_OP(LogicalOr, Or)
8438 GLSL_GROUP_OP(LogicalXor, Xor)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008439#undef GLSL_GROUP_OP
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01008440#undef GLSL_GROUP_OP_CAST
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008441 // clang-format on
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008442
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008443 case OpGroupNonUniformQuadSwap:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008444 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008445 uint32_t direction = evaluate_constant_u32(ops[4]);
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008446 if (direction == 0)
8447 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapHorizontal");
8448 else if (direction == 1)
8449 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapVertical");
8450 else if (direction == 2)
8451 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapDiagonal");
8452 else
8453 SPIRV_CROSS_THROW("Invalid quad swap direction.");
8454 break;
8455 }
8456
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008457 case OpGroupNonUniformQuadBroadcast:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02008458 {
8459 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupQuadBroadcast");
8460 break;
8461 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008462
8463 default:
8464 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
8465 }
8466
8467 register_control_dependent_expression(id);
8468}
8469
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008470string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008471{
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008472 // OpBitcast can deal with pointers.
8473 if (out_type.pointer || in_type.pointer)
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +02008474 {
8475 if (out_type.vecsize == 2 || in_type.vecsize == 2)
8476 require_extension_internal("GL_EXT_buffer_reference_uvec2");
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008477 return type_to_glsl(out_type);
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +02008478 }
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02008479
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008480 if (out_type.basetype == in_type.basetype)
8481 return "";
8482
Chip Davisef0b1fc2019-01-30 20:19:05 -06008483 assert(out_type.basetype != SPIRType::Boolean);
8484 assert(in_type.basetype != SPIRType::Boolean);
8485
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008486 bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
8487 bool same_size_cast = out_type.width == in_type.width;
8488
8489 // Trivial bitcast case, casts between integers.
8490 if (integral_cast && same_size_cast)
Chip Davis0d949e12018-11-05 14:55:56 -06008491 return type_to_glsl(out_type);
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008492
8493 // Catch-all 8-bit arithmetic casts (GL_EXT_shader_explicit_arithmetic_types).
8494 if (out_type.width == 8 && in_type.width >= 16 && integral_cast && in_type.vecsize == 1)
8495 return "unpack8";
8496 else if (in_type.width == 8 && out_type.width == 16 && integral_cast && out_type.vecsize == 1)
8497 return "pack16";
8498 else if (in_type.width == 8 && out_type.width == 32 && integral_cast && out_type.vecsize == 1)
8499 return "pack32";
8500
8501 // Floating <-> Integer special casts. Just have to enumerate all cases. :(
8502 // 16-bit, 32-bit and 64-bit floats.
8503 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008504 {
8505 if (is_legacy_es())
8506 SPIRV_CROSS_THROW("Float -> Uint bitcast not supported on legacy ESSL.");
8507 else if (!options.es && options.version < 330)
8508 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008509 return "floatBitsToUint";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008510 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008511 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008512 {
8513 if (is_legacy_es())
8514 SPIRV_CROSS_THROW("Float -> Int bitcast not supported on legacy ESSL.");
8515 else if (!options.es && options.version < 330)
8516 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008517 return "floatBitsToInt";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008518 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008519 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008520 {
8521 if (is_legacy_es())
8522 SPIRV_CROSS_THROW("Uint -> Float bitcast not supported on legacy ESSL.");
8523 else if (!options.es && options.version < 330)
8524 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008525 return "uintBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008526 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008527 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008528 {
8529 if (is_legacy_es())
8530 SPIRV_CROSS_THROW("Int -> Float bitcast not supported on legacy ESSL.");
8531 else if (!options.es && options.version < 330)
8532 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008533 return "intBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02008534 }
8535
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02008536 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
8537 return "doubleBitsToInt64";
8538 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
8539 return "doubleBitsToUint64";
8540 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
8541 return "int64BitsToDouble";
8542 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
8543 return "uint64BitsToDouble";
Chip Davis0d949e12018-11-05 14:55:56 -06008544 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Half)
8545 return "float16BitsToInt16";
8546 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half)
8547 return "float16BitsToUint16";
8548 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Short)
8549 return "int16BitsToFloat16";
8550 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
8551 return "uint16BitsToFloat16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008552
8553 // And finally, some even more special purpose casts.
8554 if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
Lou Kramer6671f522017-11-21 14:04:57 +01008555 return "packUint2x32";
Asuka55dfbea2020-04-17 22:46:06 +08008556 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UInt64 && out_type.vecsize == 2)
8557 return "unpackUint2x32";
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008558 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
8559 return "unpackFloat2x16";
8560 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)
8561 return "packFloat2x16";
Chip Davis0d949e12018-11-05 14:55:56 -06008562 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Short && in_type.vecsize == 2)
8563 return "packInt2x16";
8564 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int && in_type.vecsize == 1)
8565 return "unpackInt2x16";
8566 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UShort && in_type.vecsize == 2)
8567 return "packUint2x16";
8568 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
8569 return "unpackUint2x16";
8570 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Short && in_type.vecsize == 4)
8571 return "packInt4x16";
8572 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int64 && in_type.vecsize == 1)
8573 return "unpackInt4x16";
8574 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UShort && in_type.vecsize == 4)
8575 return "packUint4x16";
8576 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt64 && in_type.vecsize == 1)
8577 return "unpackUint4x16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008578
8579 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008580}
8581
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008582string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008583{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008584 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008585 if (op.empty())
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02008586 return to_enclosed_unpacked_expression(argument);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008587 else
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02008588 return join(op, "(", to_unpacked_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008589}
8590
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008591std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg)
8592{
8593 auto expr = to_expression(arg);
8594 auto &src_type = expression_type(arg);
8595 if (src_type.basetype != target_type)
8596 {
8597 auto target = src_type;
8598 target.basetype = target_type;
8599 expr = join(bitcast_glsl_op(target, src_type), "(", expr, ")");
8600 }
8601
8602 return expr;
8603}
8604
8605std::string CompilerGLSL::bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type,
8606 const std::string &expr)
8607{
8608 if (target_type.basetype == expr_type)
8609 return expr;
8610
8611 auto src_type = target_type;
8612 src_type.basetype = expr_type;
8613 return join(bitcast_glsl_op(target_type, src_type), "(", expr, ")");
8614}
8615
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008616string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008617{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008618 switch (builtin)
8619 {
8620 case BuiltInPosition:
8621 return "gl_Position";
8622 case BuiltInPointSize:
8623 return "gl_PointSize";
Bill Hollingse73e8e42016-12-17 17:07:53 -05008624 case BuiltInClipDistance:
8625 return "gl_ClipDistance";
Hans-Kristian Arntzen7f2e1792017-03-05 12:44:29 +01008626 case BuiltInCullDistance:
8627 return "gl_CullDistance";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008628 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008629 if (options.vulkan_semantics)
crissdb52e272020-10-08 12:14:52 +02008630 SPIRV_CROSS_THROW("Cannot implement gl_VertexID in Vulkan GLSL. This shader was created "
8631 "with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008632 return "gl_VertexID";
8633 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008634 if (options.vulkan_semantics)
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02008635 {
8636 auto model = get_entry_point().model;
8637 switch (model)
8638 {
8639 case spv::ExecutionModelIntersectionKHR:
8640 case spv::ExecutionModelAnyHitKHR:
8641 case spv::ExecutionModelClosestHitKHR:
8642 // gl_InstanceID is allowed in these shaders.
8643 break;
8644
8645 default:
crissdb52e272020-10-08 12:14:52 +02008646 SPIRV_CROSS_THROW("Cannot implement gl_InstanceID in Vulkan GLSL. This shader was "
8647 "created with GL semantics.");
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02008648 }
8649 }
rdb031cbaa2020-06-12 22:42:26 +02008650 if (!options.es && options.version < 140)
8651 {
8652 require_extension_internal("GL_ARB_draw_instanced");
8653 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008654 return "gl_InstanceID";
8655 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008656 if (options.vulkan_semantics)
8657 return "gl_VertexIndex";
8658 else
8659 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008660 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008661 if (options.vulkan_semantics)
8662 return "gl_InstanceIndex";
rdb031cbaa2020-06-12 22:42:26 +02008663
8664 if (!options.es && options.version < 140)
8665 {
8666 require_extension_internal("GL_ARB_draw_instanced");
8667 }
8668
8669 if (options.vertex.support_nonzero_base_instance)
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008670 {
8671 if (!options.vulkan_semantics)
8672 {
8673 // This is a soft-enable. We will opt-in to using gl_BaseInstanceARB if supported.
8674 require_extension_internal("GL_ARB_shader_draw_parameters");
8675 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008676 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008677 }
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02008678 else
8679 return "gl_InstanceID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008680 case BuiltInPrimitiveId:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02008681 if (storage == StorageClassInput && get_entry_point().model == ExecutionModelGeometry)
8682 return "gl_PrimitiveIDIn";
8683 else
8684 return "gl_PrimitiveID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008685 case BuiltInInvocationId:
8686 return "gl_InvocationID";
8687 case BuiltInLayer:
8688 return "gl_Layer";
Hans-Kristian Arntzenf825bd92018-01-04 12:41:25 +01008689 case BuiltInViewportIndex:
8690 return "gl_ViewportIndex";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008691 case BuiltInTessLevelOuter:
8692 return "gl_TessLevelOuter";
8693 case BuiltInTessLevelInner:
8694 return "gl_TessLevelInner";
8695 case BuiltInTessCoord:
8696 return "gl_TessCoord";
8697 case BuiltInFragCoord:
8698 return "gl_FragCoord";
8699 case BuiltInPointCoord:
8700 return "gl_PointCoord";
8701 case BuiltInFrontFacing:
8702 return "gl_FrontFacing";
8703 case BuiltInFragDepth:
8704 return "gl_FragDepth";
8705 case BuiltInNumWorkgroups:
8706 return "gl_NumWorkGroups";
8707 case BuiltInWorkgroupSize:
8708 return "gl_WorkGroupSize";
8709 case BuiltInWorkgroupId:
8710 return "gl_WorkGroupID";
8711 case BuiltInLocalInvocationId:
8712 return "gl_LocalInvocationID";
8713 case BuiltInGlobalInvocationId:
8714 return "gl_GlobalInvocationID";
8715 case BuiltInLocalInvocationIndex:
8716 return "gl_LocalInvocationIndex";
Hans-Kristian Arntzen61f1d8b2018-11-28 15:18:43 +01008717 case BuiltInHelperInvocation:
8718 return "gl_HelperInvocation";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008719
Chip Davisfcad0192018-08-28 13:47:29 -05008720 case BuiltInBaseVertex:
8721 if (options.es)
8722 SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008723
8724 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008725 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008726 if (options.version < 460)
8727 {
8728 require_extension_internal("GL_ARB_shader_draw_parameters");
8729 return "gl_BaseVertexARB";
8730 }
8731 return "gl_BaseVertex";
Chip Davisfcad0192018-08-28 13:47:29 -05008732 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008733 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8734 require_extension_internal("GL_ARB_shader_draw_parameters");
8735 return "SPIRV_Cross_BaseVertex";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008736
Chip Davisfcad0192018-08-28 13:47:29 -05008737 case BuiltInBaseInstance:
8738 if (options.es)
8739 SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008740
8741 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008742 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008743 if (options.version < 460)
8744 {
8745 require_extension_internal("GL_ARB_shader_draw_parameters");
8746 return "gl_BaseInstanceARB";
8747 }
8748 return "gl_BaseInstance";
Chip Davisfcad0192018-08-28 13:47:29 -05008749 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008750 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8751 require_extension_internal("GL_ARB_shader_draw_parameters");
8752 return "SPIRV_Cross_BaseInstance";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008753
Chip Davisfcad0192018-08-28 13:47:29 -05008754 case BuiltInDrawIndex:
8755 if (options.es)
8756 SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008757
8758 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05008759 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02008760 if (options.version < 460)
8761 {
8762 require_extension_internal("GL_ARB_shader_draw_parameters");
8763 return "gl_DrawIDARB";
8764 }
8765 return "gl_DrawID";
8766 }
Peter Kasting7cdab072021-06-30 09:17:59 -07008767 // On regular GL, this is soft-enabled and we emit ifdefs in code.
8768 require_extension_internal("GL_ARB_shader_draw_parameters");
8769 return "gl_DrawIDARB";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008770
8771 case BuiltInSampleId:
8772 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008773 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008774 if (!options.es && options.version < 400)
8775 SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
8776 return "gl_SampleID";
8777
8778 case BuiltInSampleMask:
8779 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008780 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008781 if (!options.es && options.version < 400)
8782 SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
8783
8784 if (storage == StorageClassInput)
8785 return "gl_SampleMaskIn";
8786 else
8787 return "gl_SampleMask";
8788
8789 case BuiltInSamplePosition:
8790 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008791 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008792 if (!options.es && options.version < 400)
8793 SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
8794 return "gl_SamplePosition";
8795
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008796 case BuiltInViewIndex:
8797 if (options.vulkan_semantics)
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008798 return "gl_ViewIndex";
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008799 else
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008800 return "gl_ViewID_OVR";
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02008801
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008802 case BuiltInNumSubgroups:
crissdb52e272020-10-08 12:14:52 +02008803 request_subgroup_feature(ShaderSubgroupSupportHelper::NumSubgroups);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008804 return "gl_NumSubgroups";
8805
8806 case BuiltInSubgroupId:
crissdb52e272020-10-08 12:14:52 +02008807 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008808 return "gl_SubgroupID";
8809
8810 case BuiltInSubgroupSize:
crissdb52e272020-10-08 12:14:52 +02008811 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupSize);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008812 return "gl_SubgroupSize";
8813
8814 case BuiltInSubgroupLocalInvocationId:
crissdb52e272020-10-08 12:14:52 +02008815 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInvocationID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008816 return "gl_SubgroupInvocationID";
8817
8818 case BuiltInSubgroupEqMask:
crissdb52e272020-10-08 12:14:52 +02008819 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008820 return "gl_SubgroupEqMask";
8821
8822 case BuiltInSubgroupGeMask:
crissdb52e272020-10-08 12:14:52 +02008823 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008824 return "gl_SubgroupGeMask";
8825
8826 case BuiltInSubgroupGtMask:
crissdb52e272020-10-08 12:14:52 +02008827 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008828 return "gl_SubgroupGtMask";
8829
8830 case BuiltInSubgroupLeMask:
crissdb52e272020-10-08 12:14:52 +02008831 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008832 return "gl_SubgroupLeMask";
8833
8834 case BuiltInSubgroupLtMask:
crissdb52e272020-10-08 12:14:52 +02008835 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008836 return "gl_SubgroupLtMask";
8837
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008838 case BuiltInLaunchIdKHR:
8839 return ray_tracing_is_khr ? "gl_LaunchIDEXT" : "gl_LaunchIDNV";
8840 case BuiltInLaunchSizeKHR:
8841 return ray_tracing_is_khr ? "gl_LaunchSizeEXT" : "gl_LaunchSizeNV";
8842 case BuiltInWorldRayOriginKHR:
8843 return ray_tracing_is_khr ? "gl_WorldRayOriginEXT" : "gl_WorldRayOriginNV";
8844 case BuiltInWorldRayDirectionKHR:
8845 return ray_tracing_is_khr ? "gl_WorldRayDirectionEXT" : "gl_WorldRayDirectionNV";
8846 case BuiltInObjectRayOriginKHR:
8847 return ray_tracing_is_khr ? "gl_ObjectRayOriginEXT" : "gl_ObjectRayOriginNV";
8848 case BuiltInObjectRayDirectionKHR:
8849 return ray_tracing_is_khr ? "gl_ObjectRayDirectionEXT" : "gl_ObjectRayDirectionNV";
8850 case BuiltInRayTminKHR:
8851 return ray_tracing_is_khr ? "gl_RayTminEXT" : "gl_RayTminNV";
8852 case BuiltInRayTmaxKHR:
8853 return ray_tracing_is_khr ? "gl_RayTmaxEXT" : "gl_RayTmaxNV";
8854 case BuiltInInstanceCustomIndexKHR:
8855 return ray_tracing_is_khr ? "gl_InstanceCustomIndexEXT" : "gl_InstanceCustomIndexNV";
8856 case BuiltInObjectToWorldKHR:
8857 return ray_tracing_is_khr ? "gl_ObjectToWorldEXT" : "gl_ObjectToWorldNV";
8858 case BuiltInWorldToObjectKHR:
8859 return ray_tracing_is_khr ? "gl_WorldToObjectEXT" : "gl_WorldToObjectNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +01008860 case BuiltInHitTNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008861 // gl_HitTEXT is an alias of RayTMax in KHR.
Patrick Moursda39a7b2019-02-26 15:43:03 +01008862 return "gl_HitTNV";
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +01008863 case BuiltInHitKindKHR:
8864 return ray_tracing_is_khr ? "gl_HitKindEXT" : "gl_HitKindNV";
8865 case BuiltInIncomingRayFlagsKHR:
8866 return ray_tracing_is_khr ? "gl_IncomingRayFlagsEXT" : "gl_IncomingRayFlagsNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +01008867
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02008868 case BuiltInBaryCoordKHR:
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008869 {
8870 if (options.es && options.version < 320)
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02008871 SPIRV_CROSS_THROW("gl_BaryCoordEXT requires ESSL 320.");
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008872 else if (!options.es && options.version < 450)
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02008873 SPIRV_CROSS_THROW("gl_BaryCoordEXT requires GLSL 450.");
8874
8875 if (barycentric_is_nv)
8876 {
8877 require_extension_internal("GL_NV_fragment_shader_barycentric");
8878 return "gl_BaryCoordNV";
8879 }
8880 else
8881 {
8882 require_extension_internal("GL_EXT_fragment_shader_barycentric");
8883 return "gl_BaryCoordEXT";
8884 }
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008885 }
8886
8887 case BuiltInBaryCoordNoPerspNV:
8888 {
8889 if (options.es && options.version < 320)
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02008890 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspEXT requires ESSL 320.");
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008891 else if (!options.es && options.version < 450)
Hans-Kristian Arntzene45d01c2022-05-27 13:27:48 +02008892 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspEXT requires GLSL 450.");
8893
8894 if (barycentric_is_nv)
8895 {
8896 require_extension_internal("GL_NV_fragment_shader_barycentric");
8897 return "gl_BaryCoordNoPerspNV";
8898 }
8899 else
8900 {
8901 require_extension_internal("GL_EXT_fragment_shader_barycentric");
8902 return "gl_BaryCoordNoPerspEXT";
8903 }
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008904 }
8905
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +02008906 case BuiltInFragStencilRefEXT:
8907 {
8908 if (!options.es)
8909 {
8910 require_extension_internal("GL_ARB_shader_stencil_export");
8911 return "gl_FragStencilRefARB";
8912 }
8913 else
8914 SPIRV_CROSS_THROW("Stencil export not supported in GLES.");
8915 }
8916
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +02008917 case BuiltInPrimitiveShadingRateKHR:
8918 {
8919 if (!options.vulkan_semantics)
8920 SPIRV_CROSS_THROW("Can only use PrimitiveShadingRateKHR in Vulkan GLSL.");
8921 require_extension_internal("GL_EXT_fragment_shading_rate");
8922 return "gl_PrimitiveShadingRateEXT";
8923 }
8924
8925 case BuiltInShadingRateKHR:
8926 {
8927 if (!options.vulkan_semantics)
8928 SPIRV_CROSS_THROW("Can only use ShadingRateKHR in Vulkan GLSL.");
8929 require_extension_internal("GL_EXT_fragment_shading_rate");
8930 return "gl_ShadingRateEXT";
8931 }
8932
Chip Davis6a585542019-07-12 21:50:50 -05008933 case BuiltInDeviceIndex:
8934 if (!options.vulkan_semantics)
8935 SPIRV_CROSS_THROW("Need Vulkan semantics for device group support.");
8936 require_extension_internal("GL_EXT_device_group");
8937 return "gl_DeviceIndex";
8938
Hans-Kristian Arntzen3fd14842021-04-20 13:44:52 +02008939 case BuiltInFullyCoveredEXT:
8940 if (!options.es)
8941 require_extension_internal("GL_NV_conservative_raster_underestimation");
8942 else
8943 SPIRV_CROSS_THROW("Need desktop GL to use GL_NV_conservative_raster_underestimation.");
8944 return "gl_FragFullyCoveredNV";
8945
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02008946 case BuiltInPrimitiveTriangleIndicesEXT:
8947 return "gl_PrimitiveTriangleIndicesEXT";
8948 case BuiltInPrimitiveLineIndicesEXT:
8949 return "gl_PrimitiveLineIndicesEXT";
8950 case BuiltInPrimitivePointIndicesEXT:
8951 return "gl_PrimitivePointIndicesEXT";
8952 case BuiltInCullPrimitiveEXT:
8953 return "gl_CullPrimitiveEXT";
8954
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008955 default:
Bill Hollingse73e8e42016-12-17 17:07:53 -05008956 return join("gl_BuiltIn_", convert_to_string(builtin));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008957 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008958}
8959
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008960const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008961{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008962 switch (index)
8963 {
8964 case 0:
8965 return "x";
8966 case 1:
8967 return "y";
8968 case 2:
8969 return "z";
8970 case 3:
8971 return "w";
8972 default:
Bill Hollings595eb0c2021-10-20 14:46:30 -04008973 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 +02008974 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008975}
8976
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02008977void CompilerGLSL::access_chain_internal_append_index(std::string &expr, uint32_t /*base*/, const SPIRType * /*type*/,
Bill Hollings5493b302022-09-14 15:19:15 -04008978 AccessChainFlags flags, bool &access_chain_is_arrayed,
Lukas Hermanns6673a672019-10-22 11:06:16 -04008979 uint32_t index)
8980{
8981 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
Bill Hollings5493b302022-09-14 15:19:15 -04008982 bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0;
Lukas Hermanns6673a672019-10-22 11:06:16 -04008983 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
8984
Bill Hollings5493b302022-09-14 15:19:15 -04008985 string idx_expr = index_is_literal ? convert_to_string(index) : to_unpacked_expression(index, register_expression_read);
Lukas Hermanns6673a672019-10-22 11:06:16 -04008986
Bill Hollings5493b302022-09-14 15:19:15 -04008987 // For the case where the base of an OpPtrAccessChain already ends in [n],
8988 // we need to use the index as an offset to the existing index, otherwise,
8989 // we can just use the index directly.
8990 if (ptr_chain && access_chain_is_arrayed)
8991 {
8992 size_t split_pos = expr.find_last_of(']');
8993 string expr_front = expr.substr(0, split_pos);
8994 string expr_back = expr.substr(split_pos);
8995 expr = expr_front + " + " + enclose_expression(idx_expr) + expr_back;
8996 }
Lukas Hermanns6673a672019-10-22 11:06:16 -04008997 else
Bill Hollings5493b302022-09-14 15:19:15 -04008998 {
8999 expr += "[";
9000 expr += idx_expr;
9001 expr += "]";
9002 }
Lukas Hermanns6673a672019-10-22 11:06:16 -04009003}
9004
Hans-Kristian Arntzen75ed7382021-04-14 15:10:02 +02009005bool CompilerGLSL::access_chain_needs_stage_io_builtin_translation(uint32_t)
9006{
9007 return true;
9008}
9009
Hans-Kristian Arntzeneb5e09f2017-02-23 19:33:14 +01009010string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009011 AccessChainFlags flags, AccessChainMeta *meta)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009012{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009013 string expr;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009014
9015 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009016 bool msb_is_id = (flags & ACCESS_CHAIN_LITERAL_MSB_FORCE_ID) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009017 bool chain_only = (flags & ACCESS_CHAIN_CHAIN_ONLY_BIT) != 0;
9018 bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0;
9019 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009020 bool flatten_member_reference = (flags & ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009021
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009022 if (!chain_only)
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009023 {
9024 // We handle transpose explicitly, so don't resolve that here.
9025 auto *e = maybe_get<SPIRExpression>(base);
9026 bool old_transpose = e && e->need_transpose;
9027 if (e)
9028 e->need_transpose = false;
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009029 expr = to_enclosed_expression(base, register_expression_read);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009030 if (e)
9031 e->need_transpose = old_transpose;
9032 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009033
Bill Hollings1e84a372017-08-12 00:21:13 -04009034 // Start traversing type hierarchy at the proper non-pointer types,
9035 // but keep type_id referencing the original pointer for use below.
Bill Hollingse0910312018-06-24 15:06:12 -04009036 uint32_t type_id = expression_type_id(base);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02009037
9038 if (!backend.native_pointers)
9039 {
9040 if (ptr_chain)
9041 SPIRV_CROSS_THROW("Backend does not support native pointers and does not support OpPtrAccessChain.");
9042
9043 // Wrapped buffer reference pointer types will need to poke into the internal "value" member before
9044 // continuing the access chain.
9045 if (should_dereference(base))
9046 {
9047 auto &type = get<SPIRType>(type_id);
9048 expr = dereference_expression(type, expr);
9049 }
9050 }
9051
Chip Davisfc02b3d2019-01-08 12:54:40 -06009052 const auto *type = &get_pointee_type(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009053
Hans-Kristian Arntzenb71f5df2018-05-08 15:33:51 +02009054 bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos;
Bill Hollings13583622016-12-14 02:12:52 -05009055 bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009056 bool is_packed = has_extended_decoration(base, SPIRVCrossDecorationPhysicalTypePacked);
9057 uint32_t physical_type = get_extended_decoration(base, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009058 bool is_invariant = has_decoration(base, DecorationInvariant);
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02009059 bool relaxed_precision = has_decoration(base, DecorationRelaxedPrecision);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009060 bool pending_array_enclose = false;
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02009061 bool dimension_flatten = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009062
Bill Hollings5493b302022-09-14 15:19:15 -04009063 const auto append_index = [&](uint32_t index, bool is_literal, bool is_ptr_chain = false) {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009064 AccessChainFlags mod_flags = flags;
9065 if (!is_literal)
9066 mod_flags &= ~ACCESS_CHAIN_INDEX_IS_LITERAL_BIT;
Bill Hollings5493b302022-09-14 15:19:15 -04009067 if (!is_ptr_chain)
9068 mod_flags &= ~ACCESS_CHAIN_PTR_CHAIN_BIT;
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009069 access_chain_internal_append_index(expr, base, type, mod_flags, access_chain_is_arrayed, index);
Bill Hollings4185acc2022-07-01 16:10:41 -04009070 check_physical_type_cast(expr, type, physical_type);
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02009071 };
9072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009073 for (uint32_t i = 0; i < count; i++)
9074 {
9075 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009076
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009077 bool is_literal = index_is_literal;
9078 if (is_literal && msb_is_id && (index >> 31u) != 0u)
9079 {
9080 is_literal = false;
9081 index &= 0x7fffffffu;
9082 }
9083
Chip Davis3bfb2f92018-12-03 02:06:33 -06009084 // Pointer chains
9085 if (ptr_chain && i == 0)
9086 {
9087 // If we are flattening multidimensional arrays, only create opening bracket on first
9088 // array index.
9089 if (options.flatten_multidimensional_arrays)
9090 {
9091 dimension_flatten = type->array.size() >= 1;
9092 pending_array_enclose = dimension_flatten;
9093 if (pending_array_enclose)
9094 expr += "[";
9095 }
9096
9097 if (options.flatten_multidimensional_arrays && dimension_flatten)
9098 {
9099 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009100 if (is_literal)
Chip Davis3bfb2f92018-12-03 02:06:33 -06009101 expr += convert_to_string(index);
9102 else
9103 expr += to_enclosed_expression(index, register_expression_read);
9104
9105 for (auto j = uint32_t(type->array.size()); j; j--)
9106 {
9107 expr += " * ";
9108 expr += enclose_expression(to_array_size(*type, j - 1));
9109 }
9110
9111 if (type->array.empty())
9112 pending_array_enclose = false;
9113 else
9114 expr += " + ";
9115
9116 if (!pending_array_enclose)
9117 expr += "]";
9118 }
9119 else
9120 {
Bill Hollings5493b302022-09-14 15:19:15 -04009121 append_index(index, is_literal, true);
Chip Davis3bfb2f92018-12-03 02:06:33 -06009122 }
9123
Chip Davise75add42019-02-05 18:13:26 -06009124 if (type->basetype == SPIRType::ControlPointArray)
9125 {
9126 type_id = type->parent_type;
9127 type = &get<SPIRType>(type_id);
9128 }
9129
Chip Davis3bfb2f92018-12-03 02:06:33 -06009130 access_chain_is_arrayed = true;
9131 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009132 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06009133 else if (!type->array.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009134 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009135 // If we are flattening multidimensional arrays, only create opening bracket on first
9136 // array index.
9137 if (options.flatten_multidimensional_arrays && !pending_array_enclose)
9138 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02009139 dimension_flatten = type->array.size() > 1;
9140 pending_array_enclose = dimension_flatten;
9141 if (pending_array_enclose)
9142 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009143 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009144
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01009145 assert(type->parent_type);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009146
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009147 auto *var = maybe_get<SPIRVariable>(base);
Bill Hollings27d4af72018-01-08 16:18:34 -05009148 if (backend.force_gl_in_out_block && i == 0 && var && is_builtin_variable(*var) &&
9149 !has_decoration(type->self, DecorationBlock))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009150 {
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009151 // This deals with scenarios for tesc/geom where arrays of gl_Position[] are declared.
9152 // Normally, these variables live in blocks when compiled from GLSL,
9153 // but HLSL seems to just emit straight arrays here.
9154 // We must pretend this access goes through gl_in/gl_out arrays
9155 // to be able to access certain builtins as arrays.
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02009156 // Similar concerns apply for mesh shaders where we have to redirect to gl_MeshVerticesEXT or MeshPrimitivesEXT.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009157 auto builtin = ir.meta[base].decoration.builtin_type;
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02009158 bool mesh_shader = get_execution_model() == ExecutionModelMeshEXT;
9159
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009160 switch (builtin)
9161 {
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01009162 // case BuiltInCullDistance: // These are already arrays, need to figure out rules for these in tess/geom.
9163 // case BuiltInClipDistance:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009164 case BuiltInPosition:
9165 case BuiltInPointSize:
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02009166 if (mesh_shader)
9167 expr = join("gl_MeshVerticesEXT[", to_expression(index, register_expression_read), "].", expr);
9168 else if (var->storage == StorageClassInput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009169 expr = join("gl_in[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009170 else if (var->storage == StorageClassOutput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009171 expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009172 else
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009173 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009174 break;
9175
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +02009176 case BuiltInPrimitiveId:
9177 case BuiltInLayer:
9178 case BuiltInViewportIndex:
9179 case BuiltInCullPrimitiveEXT:
9180 case BuiltInPrimitiveShadingRateKHR:
9181 if (mesh_shader)
9182 expr = join("gl_MeshPrimitivesEXT[", to_expression(index, register_expression_read), "].", expr);
9183 else
9184 append_index(index, is_literal);
9185 break;
9186
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009187 default:
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009188 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009189 break;
9190 }
9191 }
9192 else if (options.flatten_multidimensional_arrays && dimension_flatten)
9193 {
9194 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009195 auto &parent_type = get<SPIRType>(type->parent_type);
9196
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009197 if (is_literal)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009198 expr += convert_to_string(index);
9199 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009200 expr += to_enclosed_expression(index, register_expression_read);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009201
9202 for (auto j = uint32_t(parent_type.array.size()); j; j--)
9203 {
9204 expr += " * ";
9205 expr += enclose_expression(to_array_size(parent_type, j - 1));
9206 }
9207
9208 if (parent_type.array.empty())
9209 pending_array_enclose = false;
9210 else
9211 expr += " + ";
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009212
9213 if (!pending_array_enclose)
9214 expr += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009215 }
Hans-Kristian Arntzen9d18c822019-10-24 17:10:22 +02009216 // 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.
9217 // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask.
9218 else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn))))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009219 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009220 append_index(index, is_literal);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009221 }
9222
Bill Hollings1e84a372017-08-12 00:21:13 -04009223 type_id = type->parent_type;
9224 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009225
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009226 access_chain_is_arrayed = true;
9227 }
Bill Hollings76cb8072021-10-28 10:16:34 -04009228 // 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 +02009229 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
9230 else if (type->basetype == SPIRType::Struct)
9231 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009232 if (!is_literal)
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009233 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009234
Bill Hollings76cb8072021-10-28 10:16:34 -04009235 if (index < uint32_t(type->member_type_index_redirection.size()))
9236 index = type->member_type_index_redirection[index];
9237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009238 if (index >= type->member_types.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01009239 SPIRV_CROSS_THROW("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009240
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009241 BuiltIn builtin;
Hans-Kristian Arntzen75ed7382021-04-14 15:10:02 +02009242 if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009243 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009244 if (access_chain_is_arrayed)
9245 {
9246 expr += ".";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02009247 expr += builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009248 }
9249 else
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02009250 expr = builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009251 }
9252 else
9253 {
Bill Hollingsc1b81542017-05-22 21:41:19 -04009254 // If the member has a qualified name, use it as the entire chain
Bill Hollings1e84a372017-08-12 00:21:13 -04009255 string qual_mbr_name = get_member_qualified_name(type_id, index);
Bill Hollingsc1b81542017-05-22 21:41:19 -04009256 if (!qual_mbr_name.empty())
9257 expr = qual_mbr_name;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009258 else if (flatten_member_reference)
9259 expr += join("_", to_member_name(*type, index));
Bill Hollingsc1b81542017-05-22 21:41:19 -04009260 else
Chip Davis3bfb2f92018-12-03 02:06:33 -06009261 expr += to_member_reference(base, *type, index, ptr_chain);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009262 }
Bill Hollingsb332bae2017-03-01 13:07:40 -05009263
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009264 if (has_member_decoration(type->self, index, DecorationInvariant))
9265 is_invariant = true;
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02009266 if (has_member_decoration(type->self, index, DecorationRelaxedPrecision))
9267 relaxed_precision = true;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009268
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009269 is_packed = member_is_packed_physical_type(*type, index);
Hans-Kristian Arntzenf6251e42019-07-19 11:21:02 +02009270 if (member_is_remapped_physical_type(*type, index))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009271 physical_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01009272 else
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009273 physical_type = 0;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01009274
Bill Hollings13583622016-12-14 02:12:52 -05009275 row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009276 type = &get<SPIRType>(type->member_types[index]);
9277 }
9278 // Matrix -> Vector
9279 else if (type->columns > 1)
9280 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02009281 // If we have a row-major matrix here, we need to defer any transpose in case this access chain
9282 // is used to store a column. We can resolve it right here and now if we access a scalar directly,
9283 // by flipping indexing order of the matrix.
Bill Hollings343677e2016-12-11 11:01:08 -05009284
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009285 expr += "[";
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01009286 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009287 expr += convert_to_string(index);
9288 else
Bill Hollings974a0812021-10-21 16:11:33 -04009289 expr += to_unpacked_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009290 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009291
Bill Hollings1e84a372017-08-12 00:21:13 -04009292 type_id = type->parent_type;
9293 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009294 }
9295 // Vector -> Scalar
9296 else if (type->vecsize > 1)
9297 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02009298 string deferred_index;
9299 if (row_major_matrix_needs_conversion)
9300 {
9301 // Flip indexing order.
9302 auto column_index = expr.find_last_of('[');
9303 if (column_index != string::npos)
9304 {
9305 deferred_index = expr.substr(column_index);
9306 expr.resize(column_index);
9307 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02009308 }
9309
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02009310 // Internally, access chain implementation can also be used on composites,
9311 // ignore scalar access workarounds in this case.
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02009312 StorageClass effective_storage = StorageClassGeneric;
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02009313 bool ignore_potential_sliced_writes = false;
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02009314 if ((flags & ACCESS_CHAIN_FORCE_COMPOSITE_BIT) == 0)
9315 {
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +02009316 if (expression_type(base).pointer)
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +02009317 effective_storage = get_expression_effective_storage_class(base);
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02009318
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02009319 // Special consideration for control points.
9320 // Control points can only be written by InvocationID, so there is no need
9321 // to consider scalar access chains here.
9322 // Cleans up some cases where it's very painful to determine the accurate storage class
9323 // since blocks can be partially masked ...
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +02009324 auto *var = maybe_get_backing_variable(base);
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02009325 if (var && var->storage == StorageClassOutput &&
9326 get_execution_model() == ExecutionModelTessellationControl &&
9327 !has_decoration(var->self, DecorationPatch))
9328 {
9329 ignore_potential_sliced_writes = true;
9330 }
9331 }
9332 else
9333 ignore_potential_sliced_writes = true;
9334
9335 if (!row_major_matrix_needs_conversion && !ignore_potential_sliced_writes)
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02009336 {
9337 // On some backends, we might not be able to safely access individual scalars in a vector.
9338 // To work around this, we might have to cast the access chain reference to something which can,
9339 // like a pointer to scalar, which we can then index into.
9340 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
9341 is_packed);
9342 }
9343
Sebastián Aedo905b8242021-11-11 12:57:57 -03009344 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009345 {
Sebastián Aedo905b8242021-11-11 12:57:57 -03009346 bool out_of_bounds = (index >= type->vecsize);
9347
9348 if (!is_packed && !row_major_matrix_needs_conversion)
9349 {
9350 expr += ".";
9351 expr += index_to_swizzle(out_of_bounds ? 0 : index);
9352 }
9353 else
9354 {
9355 // For packed vectors, we can only access them as an array, not by swizzle.
9356 expr += join("[", out_of_bounds ? 0 : index, "]");
9357 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009358 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02009359 else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009360 {
9361 auto &c = get<SPIRConstant>(index);
Sebastián Aedo905b8242021-11-11 12:57:57 -03009362 bool out_of_bounds = (c.scalar() >= type->vecsize);
9363
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02009364 if (c.specialization)
9365 {
9366 // If the index is a spec constant, we cannot turn extract into a swizzle.
Sebastián Aedo905b8242021-11-11 12:57:57 -03009367 expr += join("[", out_of_bounds ? "0" : to_expression(index), "]");
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02009368 }
9369 else
9370 {
9371 expr += ".";
Sebastián Aedo905b8242021-11-11 12:57:57 -03009372 expr += index_to_swizzle(out_of_bounds ? 0 : c.scalar());
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02009373 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009374 }
9375 else
9376 {
9377 expr += "[";
Bill Hollings974a0812021-10-21 16:11:33 -04009378 expr += to_unpacked_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009379 expr += "]";
9380 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009381
Hans-Kristian Arntzen436b1252021-04-07 13:33:26 +02009382 if (row_major_matrix_needs_conversion && !ignore_potential_sliced_writes)
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02009383 {
9384 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
9385 is_packed);
9386 }
9387
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02009388 expr += deferred_index;
9389 row_major_matrix_needs_conversion = false;
9390
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01009391 is_packed = false;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009392 physical_type = 0;
Bill Hollings1e84a372017-08-12 00:21:13 -04009393 type_id = type->parent_type;
9394 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009395 }
Bill Hollings2964e322018-02-13 14:44:40 -05009396 else if (!backend.allow_truncated_access_chain)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01009397 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009398 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009399
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009400 if (pending_array_enclose)
9401 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02009402 SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
9403 "but the access chain was terminated in the middle of a multidimensional array. "
9404 "This is not supported.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009405 }
9406
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009407 if (meta)
9408 {
9409 meta->need_transpose = row_major_matrix_needs_conversion;
9410 meta->storage_is_packed = is_packed;
9411 meta->storage_is_invariant = is_invariant;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009412 meta->storage_physical_type = physical_type;
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +02009413 meta->relaxed_precision = relaxed_precision;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009414 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009415
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009416 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009417}
9418
Bill Hollings4185acc2022-07-01 16:10:41 -04009419void CompilerGLSL::check_physical_type_cast(std::string &, const SPIRType *, uint32_t)
9420{
9421}
9422
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02009423void CompilerGLSL::prepare_access_chain_for_scalar_access(std::string &, const SPIRType &, spv::StorageClass, bool &)
9424{
9425}
9426
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009427string CompilerGLSL::to_flattened_struct_member(const string &basename, const SPIRType &type, uint32_t index)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009428{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009429 auto ret = join(basename, "_", to_member_name(type, index));
9430 ParsedIR::sanitize_underscores(ret);
9431 return ret;
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009432}
9433
Bill Hollings2d0d3282017-01-20 11:33:59 -05009434string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
Chip Davis3bfb2f92018-12-03 02:06:33 -06009435 AccessChainMeta *meta, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009436{
Arseny Kapoulkine24c66252017-01-16 14:19:49 -08009437 if (flattened_buffer_blocks.count(base))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009438 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009439 uint32_t matrix_stride = 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009440 uint32_t array_stride = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009441 bool need_transpose = false;
Chip Davis3bfb2f92018-12-03 02:06:33 -06009442 flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009443 &array_stride, ptr_chain);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009444
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009445 if (meta)
9446 {
9447 meta->need_transpose = target_type.columns > 1 && need_transpose;
9448 meta->storage_is_packed = false;
9449 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009450
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01009451 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, array_stride,
9452 need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009453 }
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009454 else if (flattened_structs.count(base) && count > 0)
9455 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009456 AccessChainFlags flags = ACCESS_CHAIN_CHAIN_ONLY_BIT | ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
9457 if (ptr_chain)
9458 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
9459
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009460 if (flattened_structs[base])
9461 {
9462 flags |= ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT;
9463 if (meta)
9464 meta->flattened_struct = target_type.basetype == SPIRType::Struct;
9465 }
9466
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009467 auto chain = access_chain_internal(base, indices, count, flags, nullptr).substr(1);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009468 if (meta)
9469 {
9470 meta->need_transpose = false;
9471 meta->storage_is_packed = false;
9472 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009473
9474 auto basename = to_flattened_access_chain_expression(base);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009475 auto ret = join(basename, "_", chain);
9476 ParsedIR::sanitize_underscores(ret);
9477 return ret;
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009478 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009479 else
9480 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009481 AccessChainFlags flags = ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
9482 if (ptr_chain)
9483 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
9484 return access_chain_internal(base, indices, count, flags, meta);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009485 }
9486}
9487
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009488string CompilerGLSL::load_flattened_struct(const string &basename, const SPIRType &type)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009489{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009490 auto expr = type_to_glsl_constructor(type);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009491 expr += '(';
9492
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009493 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
9494 {
9495 if (i)
9496 expr += ", ";
9497
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009498 auto &member_type = get<SPIRType>(type.member_types[i]);
9499 if (member_type.basetype == SPIRType::Struct)
9500 expr += load_flattened_struct(to_flattened_struct_member(basename, type, i), member_type);
9501 else
9502 expr += to_flattened_struct_member(basename, type, i);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01009503 }
9504 expr += ')';
9505 return expr;
9506}
9507
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009508std::string CompilerGLSL::to_flattened_access_chain_expression(uint32_t id)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009509{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009510 // Do not use to_expression as that will unflatten access chains.
9511 string basename;
9512 if (const auto *var = maybe_get<SPIRVariable>(id))
9513 basename = to_name(var->self);
9514 else if (const auto *expr = maybe_get<SPIRExpression>(id))
9515 basename = expr->expression;
9516 else
9517 basename = to_expression(id);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009518
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009519 return basename;
9520}
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009521
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009522void CompilerGLSL::store_flattened_struct(const string &basename, uint32_t rhs_id, const SPIRType &type,
9523 const SmallVector<uint32_t> &indices)
9524{
9525 SmallVector<uint32_t> sub_indices = indices;
9526 sub_indices.push_back(0);
9527
9528 auto *member_type = &type;
9529 for (auto &index : indices)
9530 member_type = &get<SPIRType>(member_type->member_types[index]);
9531
9532 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009533 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009534 sub_indices.back() = i;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02009535 auto lhs = join(basename, "_", to_member_name(*member_type, i));
9536 ParsedIR::sanitize_underscores(lhs);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009537
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009538 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
9539 {
9540 store_flattened_struct(lhs, rhs_id, type, sub_indices);
9541 }
9542 else
9543 {
9544 auto rhs = to_expression(rhs_id) + to_multi_member_reference(type, sub_indices);
9545 statement(lhs, " = ", rhs, ";");
9546 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009547 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009548}
9549
9550void CompilerGLSL::store_flattened_struct(uint32_t lhs_id, uint32_t value)
9551{
9552 auto &type = expression_type(lhs_id);
9553 auto basename = to_flattened_access_chain_expression(lhs_id);
9554 store_flattened_struct(basename, value, type, {});
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01009555}
9556
Bill Hollings2d0d3282017-01-20 11:33:59 -05009557std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009558 const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009559 uint32_t /* array_stride */, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009560{
9561 if (!target_type.array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009562 SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009563 else if (target_type.basetype == SPIRType::Struct)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009564 return flattened_access_chain_struct(base, indices, count, target_type, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009565 else if (target_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009566 return flattened_access_chain_matrix(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009567 else
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009568 return flattened_access_chain_vector(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009569}
9570
Bill Hollings2d0d3282017-01-20 11:33:59 -05009571std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
9572 const SPIRType &target_type, uint32_t offset)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009573{
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009574 std::string expr;
9575
Shintaro Sakaharaed4ded02022-02-16 21:53:24 +09009576 if (backend.can_declare_struct_inline)
9577 {
9578 expr += type_to_glsl_constructor(target_type);
9579 expr += "(";
9580 }
9581 else
9582 expr += "{";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009583
Henrik Rydgårdbfae0412017-03-07 09:59:26 +01009584 for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009585 {
9586 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08009587 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009588
9589 const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009590 uint32_t member_offset = type_struct_member_offset(target_type, i);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009591
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009592 // The access chain terminates at the struct, so we need to find matrix strides and row-major information
9593 // ahead of time.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009594 bool need_transpose = false;
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009595 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009596 if (member_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009597 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009598 need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009599 matrix_stride = type_struct_member_matrix_stride(target_type, i);
9600 }
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009601
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009602 auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009603 0 /* array_stride */, need_transpose);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009604
9605 // Cannot forward transpositions, so resolve them here.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009606 if (need_transpose)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009607 expr += convert_row_major_matrix(tmp, member_type, 0, false);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009608 else
9609 expr += tmp;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009610 }
9611
Shintaro Sakaharaed4ded02022-02-16 21:53:24 +09009612 expr += backend.can_declare_struct_inline ? ")" : "}";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009613
9614 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009615}
9616
Bill Hollings2d0d3282017-01-20 11:33:59 -05009617std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01009618 const SPIRType &target_type, uint32_t offset,
9619 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009620{
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009621 assert(matrix_stride);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009622 SPIRType tmp_type = target_type;
9623 if (need_transpose)
9624 swap(tmp_type.vecsize, tmp_type.columns);
9625
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009626 std::string expr;
9627
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009628 expr += type_to_glsl_constructor(tmp_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009629 expr += "(";
9630
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009631 for (uint32_t i = 0; i < tmp_type.columns; i++)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009632 {
9633 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08009634 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009635
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009636 expr += flattened_access_chain_vector(base, indices, count, tmp_type, offset + i * matrix_stride, matrix_stride,
9637 /* need_transpose= */ false);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009638 }
9639
9640 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009641
9642 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009643}
9644
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009645std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
9646 const SPIRType &target_type, uint32_t offset,
9647 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009648{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02009649 auto result = flattened_access_chain_offset(expression_type(base), indices, count, offset, 16);
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009650
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009651 auto buffer_name = to_name(expression_type(base).self);
9652
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009653 if (need_transpose)
9654 {
9655 std::string expr;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009656
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08009657 if (target_type.vecsize > 1)
9658 {
9659 expr += type_to_glsl_constructor(target_type);
9660 expr += "(";
9661 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009662
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009663 for (uint32_t i = 0; i < target_type.vecsize; ++i)
9664 {
9665 if (i != 0)
9666 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009667
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009668 uint32_t component_offset = result.second + i * matrix_stride;
9669
9670 assert(component_offset % (target_type.width / 8) == 0);
9671 uint32_t index = component_offset / (target_type.width / 8);
9672
9673 expr += buffer_name;
9674 expr += "[";
9675 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
9676 expr += convert_to_string(index / 4);
9677 expr += "]";
9678
9679 expr += vector_swizzle(1, index % 4);
9680 }
9681
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08009682 if (target_type.vecsize > 1)
9683 {
9684 expr += ")";
9685 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08009686
9687 return expr;
9688 }
9689 else
9690 {
9691 assert(result.second % (target_type.width / 8) == 0);
9692 uint32_t index = result.second / (target_type.width / 8);
9693
9694 std::string expr;
9695
9696 expr += buffer_name;
9697 expr += "[";
9698 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
9699 expr += convert_to_string(index / 4);
9700 expr += "]";
9701
9702 expr += vector_swizzle(target_type.vecsize, index % 4);
9703
9704 return expr;
9705 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009706}
9707
Chip Davis3bfb2f92018-12-03 02:06:33 -06009708std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(
9709 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 +01009710 bool *need_transpose, uint32_t *out_matrix_stride, uint32_t *out_array_stride, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009711{
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01009712 // Start traversing type hierarchy at the proper non-pointer types.
Chip Davisfc02b3d2019-01-08 12:54:40 -06009713 const auto *type = &get_pointee_type(basetype);
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01009714
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009715 std::string expr;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009716
9717 // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout.
9718 bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false;
9719 uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009720 uint32_t array_stride = out_array_stride ? *out_array_stride : 0;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009721
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009722 for (uint32_t i = 0; i < count; i++)
9723 {
9724 uint32_t index = indices[i];
9725
Chip Davis3bfb2f92018-12-03 02:06:33 -06009726 // Pointers
9727 if (ptr_chain && i == 0)
9728 {
9729 // Here, the pointer type will be decorated with an array stride.
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009730 array_stride = get_decoration(basetype.self, DecorationArrayStride);
Chip Davis3bfb2f92018-12-03 02:06:33 -06009731 if (!array_stride)
9732 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
9733
9734 auto *constant = maybe_get<SPIRConstant>(index);
9735 if (constant)
9736 {
9737 // Constant array access.
9738 offset += constant->scalar() * array_stride;
9739 }
9740 else
9741 {
9742 // Dynamic array access.
9743 if (array_stride % word_stride)
9744 {
crissdb52e272020-10-08 12:14:52 +02009745 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
9746 "of a 4-component vector. "
9747 "Likely culprit here is a float or vec2 array inside a push "
9748 "constant block which is std430. "
9749 "This cannot be flattened. Try using std140 layout instead.");
Chip Davis3bfb2f92018-12-03 02:06:33 -06009750 }
9751
9752 expr += to_enclosed_expression(index);
9753 expr += " * ";
9754 expr += convert_to_string(array_stride / word_stride);
9755 expr += " + ";
9756 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06009757 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009758 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06009759 else if (!type->array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009760 {
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009761 auto *constant = maybe_get<SPIRConstant>(index);
9762 if (constant)
9763 {
9764 // Constant array access.
9765 offset += constant->scalar() * array_stride;
9766 }
9767 else
9768 {
9769 // Dynamic array access.
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009770 if (array_stride % word_stride)
9771 {
crissdb52e272020-10-08 12:14:52 +02009772 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
9773 "of a 4-component vector. "
9774 "Likely culprit here is a float or vec2 array inside a push "
9775 "constant block which is std430. "
9776 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009777 }
9778
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009779 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009780 expr += " * ";
9781 expr += convert_to_string(array_stride / word_stride);
9782 expr += " + ";
9783 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009784
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009785 uint32_t parent_type = type->parent_type;
9786 type = &get<SPIRType>(parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01009787
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009788 if (!type->array.empty())
9789 array_stride = get_decoration(parent_type, DecorationArrayStride);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009790 }
9791 // For structs, the index refers to a constant, which indexes into the members.
9792 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
9793 else if (type->basetype == SPIRType::Struct)
9794 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009795 index = evaluate_constant_u32(index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009796
9797 if (index >= type->member_types.size())
9798 SPIRV_CROSS_THROW("Member index is out of bounds!");
9799
9800 offset += type_struct_member_offset(*type, index);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009801
9802 auto &struct_type = *type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009803 type = &get<SPIRType>(type->member_types[index]);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009804
9805 if (type->columns > 1)
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009806 {
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009807 matrix_stride = type_struct_member_matrix_stride(struct_type, index);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009808 row_major_matrix_needs_conversion =
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009809 combined_decoration_for_member(struct_type, index).get(DecorationRowMajor);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01009810 }
9811 else
9812 row_major_matrix_needs_conversion = false;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009813
9814 if (!type->array.empty())
9815 array_stride = type_struct_member_array_stride(struct_type, index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009816 }
9817 // Matrix -> Vector
9818 else if (type->columns > 1)
9819 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009820 auto *constant = maybe_get<SPIRConstant>(index);
9821 if (constant)
9822 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009823 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009824 offset += index * (row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride);
9825 }
9826 else
9827 {
9828 uint32_t indexing_stride = row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride;
9829 // Dynamic array access.
9830 if (indexing_stride % word_stride)
9831 {
crissdb52e272020-10-08 12:14:52 +02009832 SPIRV_CROSS_THROW("Matrix stride for dynamic indexing must be divisible by the size of a "
9833 "4-component vector. "
9834 "Likely culprit here is a row-major matrix being accessed dynamically. "
9835 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009836 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009837
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009838 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009839 expr += " * ";
9840 expr += convert_to_string(indexing_stride / word_stride);
9841 expr += " + ";
9842 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009843
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009844 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009845 }
9846 // Vector -> Scalar
9847 else if (type->vecsize > 1)
9848 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009849 auto *constant = maybe_get<SPIRConstant>(index);
9850 if (constant)
9851 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02009852 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009853 offset += index * (row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8));
9854 }
9855 else
9856 {
9857 uint32_t indexing_stride = row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009858
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009859 // Dynamic array access.
9860 if (indexing_stride % word_stride)
9861 {
crissdb52e272020-10-08 12:14:52 +02009862 SPIRV_CROSS_THROW("Stride for dynamic vector indexing must be divisible by the "
9863 "size of a 4-component vector. "
9864 "This cannot be flattened in legacy targets.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009865 }
9866
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009867 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02009868 expr += " * ";
9869 expr += convert_to_string(indexing_stride / word_stride);
9870 expr += " + ";
9871 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009872
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01009873 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009874 }
9875 else
9876 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
9877 }
9878
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08009879 if (need_transpose)
9880 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01009881 if (out_matrix_stride)
9882 *out_matrix_stride = matrix_stride;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01009883 if (out_array_stride)
9884 *out_array_stride = array_stride;
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08009885
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08009886 return std::make_pair(expr, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009887}
9888
Chip Davis3bfb2f92018-12-03 02:06:33 -06009889bool CompilerGLSL::should_dereference(uint32_t id)
9890{
9891 const auto &type = expression_type(id);
9892 // Non-pointer expressions don't need to be dereferenced.
9893 if (!type.pointer)
9894 return false;
9895
9896 // Handles shouldn't be dereferenced either.
9897 if (!expression_is_lvalue(id))
9898 return false;
9899
9900 // If id is a variable but not a phi variable, we should not dereference it.
9901 if (auto *var = maybe_get<SPIRVariable>(id))
9902 return var->phi_variable;
9903
9904 // If id is an access chain, we should not dereference it.
9905 if (auto *expr = maybe_get<SPIRExpression>(id))
9906 return !expr->access_chain;
9907
9908 // Otherwise, we should dereference this pointer expression.
9909 return true;
9910}
9911
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009912bool CompilerGLSL::should_forward(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009913{
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07009914 // If id is a variable we will try to forward it regardless of force_temporary check below
9915 // This is important because otherwise we'll get local sampler copies (highp sampler2D foo = bar) that are invalid in OpenGL GLSL
Hans-Kristian Arntzenef6bde62022-01-17 12:49:02 +01009916
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02009917 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen476b6542022-03-04 11:05:21 +01009918 if (var)
Hans-Kristian Arntzen93b0dc72022-03-04 11:08:55 +01009919 {
Bill Hollings85f98eb2022-03-23 14:48:22 -04009920 // Never forward volatile builtin variables, e.g. SPIR-V 1.6 HelperInvocation.
9921 return !(has_decoration(id, DecorationBuiltIn) && has_decoration(id, DecorationVolatile));
Hans-Kristian Arntzen93b0dc72022-03-04 11:08:55 +01009922 }
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07009923
9924 // For debugging emit temporary variables for all expressions
9925 if (options.force_temporary)
9926 return false;
9927
Hans-Kristian Arntzenef6bde62022-01-17 12:49:02 +01009928 // If an expression carries enough dependencies we need to stop forwarding at some point,
9929 // or we explode compilers. There are usually limits to how much we can nest expressions.
9930 auto *expr = maybe_get<SPIRExpression>(id);
9931 const uint32_t max_expression_dependencies = 64;
9932 if (expr && expr->expression_dependencies.size() >= max_expression_dependencies)
9933 return false;
9934
Bill Hollings85f98eb2022-03-23 14:48:22 -04009935 if (expr && expr->loaded_from
9936 && has_decoration(expr->loaded_from, DecorationBuiltIn)
9937 && has_decoration(expr->loaded_from, DecorationVolatile))
Hans-Kristian Arntzen93b0dc72022-03-04 11:08:55 +01009938 {
Bill Hollings85f98eb2022-03-23 14:48:22 -04009939 // Never forward volatile builtin variables, e.g. SPIR-V 1.6 HelperInvocation.
Hans-Kristian Arntzen93b0dc72022-03-04 11:08:55 +01009940 return false;
9941 }
9942
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07009943 // Immutable expression can always be forwarded.
9944 if (is_immutable(id))
9945 return true;
9946
9947 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009948}
9949
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009950bool CompilerGLSL::should_suppress_usage_tracking(uint32_t id) const
9951{
9952 // Used only by opcodes which don't do any real "work", they just swizzle data in some fashion.
9953 return !expression_is_forwarded(id) || expression_suppresses_usage_tracking(id);
9954}
9955
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009956void CompilerGLSL::track_expression_read(uint32_t id)
9957{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009958 switch (ir.ids[id].get_type())
9959 {
9960 case TypeExpression:
9961 {
9962 auto &e = get<SPIRExpression>(id);
9963 for (auto implied_read : e.implied_read_expressions)
9964 track_expression_read(implied_read);
9965 break;
9966 }
9967
9968 case TypeAccessChain:
9969 {
9970 auto &e = get<SPIRAccessChain>(id);
9971 for (auto implied_read : e.implied_read_expressions)
9972 track_expression_read(implied_read);
9973 break;
9974 }
9975
9976 default:
9977 break;
9978 }
9979
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009980 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
9981 // 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 +02009982 if (expression_is_forwarded(id) && !expression_suppresses_usage_tracking(id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009983 {
9984 auto &v = expression_usage_counts[id];
9985 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009986
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02009987 // If we create an expression outside a loop,
9988 // but access it inside a loop, we're implicitly reading it multiple times.
9989 // If the expression in question is expensive, we should hoist it out to avoid relying on loop-invariant code motion
9990 // working inside the backend compiler.
9991 if (expression_read_implies_multiple_reads(id))
9992 v++;
9993
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009994 if (v >= 2)
9995 {
9996 //if (v == 2)
9997 // 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 +01009998
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009999 // Force a recompile after this pass to avoid forwarding this variable.
Hans-Kristian Arntzena56b22b2022-02-16 12:12:58 +010010000 force_temporary_and_recompile(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010001 }
10002 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010003}
10004
10005bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
10006{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010007 if (forced_temporaries.find(id) != end(forced_temporaries))
10008 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010009
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010010 for (uint32_t i = 0; i < num_args; i++)
10011 if (!should_forward(args[i]))
10012 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010013
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010014 // We need to forward globals as well.
10015 if (!pure)
10016 {
10017 for (auto global : global_variables)
10018 if (!should_forward(global))
10019 return false;
10020 for (auto aliased : aliased_variables)
10021 if (!should_forward(aliased))
10022 return false;
10023 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010025 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010026}
10027
10028void CompilerGLSL::register_impure_function_call()
10029{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010030 // Impure functions can modify globals and aliased variables, so invalidate them as well.
10031 for (auto global : global_variables)
10032 flush_dependees(get<SPIRVariable>(global));
10033 for (auto aliased : aliased_variables)
10034 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010035}
10036
10037void CompilerGLSL::register_call_out_argument(uint32_t id)
10038{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010039 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010040
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010041 auto *var = maybe_get<SPIRVariable>(id);
10042 if (var)
10043 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010044}
10045
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +010010046string CompilerGLSL::variable_decl_function_local(SPIRVariable &var)
10047{
10048 // These variables are always function local,
10049 // so make sure we emit the variable without storage qualifiers.
10050 // Some backends will inject custom variables locally in a function
10051 // with a storage qualifier which is not function-local.
10052 auto old_storage = var.storage;
10053 var.storage = StorageClassFunction;
10054 auto expr = variable_decl(var);
10055 var.storage = old_storage;
10056 return expr;
10057}
10058
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020010059void CompilerGLSL::emit_variable_temporary_copies(const SPIRVariable &var)
10060{
Lukas Hermanns50ac6862019-09-18 14:03:54 -040010061 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen3f569ed2019-10-24 17:12:23 +020010062 if (var.allocate_temporary_copy && !flushed_phi_variables.count(var.self))
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020010063 {
10064 auto &type = get<SPIRType>(var.basetype);
10065 auto &flags = get_decoration_bitset(var.self);
10066 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, join("_", var.self, "_copy")), ";");
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -040010067 flushed_phi_variables.insert(var.self);
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020010068 }
10069}
10070
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010071void CompilerGLSL::flush_variable_declaration(uint32_t id)
10072{
Lukas Hermanns50ac6862019-09-18 14:03:54 -040010073 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010074 auto *var = maybe_get<SPIRVariable>(id);
10075 if (var && var->deferred_declaration)
10076 {
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010010077 string initializer;
10078 if (options.force_zero_initialized_variables &&
10079 (var->storage == StorageClassFunction || var->storage == StorageClassGeneric ||
10080 var->storage == StorageClassPrivate) &&
10081 !var->initializer && type_can_zero_initialize(get_variable_data_type(*var)))
10082 {
10083 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(*var)));
10084 }
10085
10086 statement(variable_decl_function_local(*var), initializer, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010087 var->deferred_declaration = false;
10088 }
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -040010089 if (var)
10090 {
10091 emit_variable_temporary_copies(*var);
10092 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010093}
10094
10095bool CompilerGLSL::remove_duplicate_swizzle(string &op)
10096{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010097 auto pos = op.find_last_of('.');
10098 if (pos == string::npos || pos == 0)
10099 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010100
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010101 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010102
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010103 if (backend.swizzle_is_function)
10104 {
10105 if (final_swiz.size() < 2)
10106 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010107
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010108 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
10109 final_swiz.erase(final_swiz.size() - 2, string::npos);
10110 else
10111 return false;
10112 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010113
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010114 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
10115 // If so, and previous swizzle is of same length,
10116 // we can drop the final swizzle altogether.
10117 for (uint32_t i = 0; i < final_swiz.size(); i++)
10118 {
10119 static const char expected[] = { 'x', 'y', 'z', 'w' };
10120 if (i >= 4 || final_swiz[i] != expected[i])
10121 return false;
10122 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010123
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010124 auto prevpos = op.find_last_of('.', pos - 1);
10125 if (prevpos == string::npos)
10126 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010128 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010129
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010130 // Make sure there are only swizzles here ...
10131 for (auto i = prevpos; i < pos; i++)
10132 {
10133 if (op[i] < 'w' || op[i] > 'z')
10134 {
10135 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
10136 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
10137 break;
10138 return false;
10139 }
10140 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010141
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010142 // If original swizzle is large enough, just carve out the components we need.
10143 // E.g. foobar.wyx.xy will turn into foobar.wy.
10144 if (pos - prevpos >= final_swiz.size())
10145 {
10146 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010147
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010148 // Add back the function call ...
10149 if (backend.swizzle_is_function)
10150 op += "()";
10151 }
10152 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010153}
10154
10155// Optimizes away vector swizzles where we have something like
10156// vec3 foo;
10157// foo.xyz <-- swizzle expression does nothing.
10158// This is a very common pattern after OpCompositeCombine.
10159bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
10160{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010161 auto pos = op.find_last_of('.');
10162 if (pos == string::npos || pos == 0)
10163 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010164
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010165 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010166
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010167 if (backend.swizzle_is_function)
10168 {
10169 if (final_swiz.size() < 2)
10170 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010171
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010172 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
10173 final_swiz.erase(final_swiz.size() - 2, string::npos);
10174 else
10175 return false;
10176 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010178 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
10179 // If so, and previous swizzle is of same length,
10180 // we can drop the final swizzle altogether.
10181 for (uint32_t i = 0; i < final_swiz.size(); i++)
10182 {
10183 static const char expected[] = { 'x', 'y', 'z', 'w' };
10184 if (i >= 4 || final_swiz[i] != expected[i])
10185 return false;
10186 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010187
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010188 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010189
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010190 // Sanity checking ...
Lukas Hermanns7ad0a842019-09-23 18:05:04 -040010191 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010193 if (type.vecsize == final_swiz.size())
10194 op.erase(pos, string::npos);
10195 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010196}
10197
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010010198string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010199{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010200 ID base = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010201 string op;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010202 string subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010203
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010010204 // Can only merge swizzles for vectors.
10205 auto &type = get<SPIRType>(return_type);
10206 bool can_apply_swizzle_opt = type.basetype != SPIRType::Struct && type.array.empty() && type.columns == 1;
10207 bool swizzle_optimization = false;
10208
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010209 for (uint32_t i = 0; i < length; i++)
10210 {
10211 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010212
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010213 // If we're merging another scalar which belongs to the same base
10214 // 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 +010010215 if (can_apply_swizzle_opt && e && e->base_expression && e->base_expression == base)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010216 {
10217 // Only supposed to be used for vector swizzle -> scalar.
10218 assert(!e->expression.empty() && e->expression.front() == '.');
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010219 subop += e->expression.substr(1, string::npos);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010220 swizzle_optimization = true;
10221 }
10222 else
10223 {
10224 // We'll likely end up with duplicated swizzles, e.g.
10225 // foobar.xyz.xyz from patterns like
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010226 // OpVectorShuffle
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010227 // OpCompositeExtract x 3
10228 // OpCompositeConstruct 3x + other scalar.
10229 // Just modify op in-place.
10230 if (swizzle_optimization)
10231 {
10232 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010233 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010234
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010235 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
10236 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
10237 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
10238 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
10239 // Case 1:
10240 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
10241 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
10242 // Case 2:
10243 // foo.xyz: Duplicate swizzle won't kick in.
10244 // If foo is vec3, we can remove xyz, giving just foo.
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010245 if (!remove_duplicate_swizzle(subop))
10246 remove_unity_swizzle(base, subop);
10247
10248 // Strips away redundant parens if we created them during component extraction.
10249 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010250 swizzle_optimization = false;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010251 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010252 }
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010253 else
10254 op += subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010255
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010256 if (i)
10257 op += ", ";
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +020010258
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020010259 bool uses_buffer_offset =
10260 type.basetype == SPIRType::Struct && has_member_decoration(type.self, i, DecorationOffset);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +020010261 subop = to_composite_constructor_expression(elems[i], uses_buffer_offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010262 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010263
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010264 base = e ? e->base_expression : ID(0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010265 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010266
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010267 if (swizzle_optimization)
10268 {
10269 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010270 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010271
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010272 if (!remove_duplicate_swizzle(subop))
10273 remove_unity_swizzle(base, subop);
10274 // Strips away redundant parens if we created them during component extraction.
10275 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010276 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010277
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +010010278 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010279 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010280}
10281
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010282bool CompilerGLSL::skip_argument(uint32_t id) const
10283{
10284 if (!combined_image_samplers.empty() || !options.vulkan_semantics)
10285 {
10286 auto &type = expression_type(id);
10287 if (type.basetype == SPIRType::Sampler || (type.basetype == SPIRType::Image && type.image.sampled == 1))
10288 return true;
10289 }
10290 return false;
10291}
10292
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020010293bool CompilerGLSL::optimize_read_modify_write(const SPIRType &type, const string &lhs, const string &rhs)
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +010010294{
10295 // Do this with strings because we have a very clear pattern we can check for and it avoids
10296 // adding lots of special cases to the code emission.
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +010010297 if (rhs.size() < lhs.size() + 3)
10298 return false;
10299
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020010300 // Do not optimize matrices. They are a bit awkward to reason about in general
10301 // (in which order does operation happen?), and it does not work on MSL anyways.
10302 if (type.vecsize > 1 && type.columns > 1)
10303 return false;
10304
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +010010305 auto index = rhs.find(lhs);
10306 if (index != 0)
10307 return false;
10308
10309 // TODO: Shift operators, but it's not important for now.
10310 auto op = rhs.find_first_of("+-/*%|&^", lhs.size() + 1);
10311 if (op != lhs.size() + 1)
10312 return false;
10313
David Srbeckye596d402017-09-05 16:05:53 +010010314 // Check that the op is followed by space. This excludes && and ||.
Hans-Kristian Arntzen03db5c42017-09-06 09:15:27 +020010315 if (rhs[op + 1] != ' ')
David Srbeckye596d402017-09-05 16:05:53 +010010316 return false;
10317
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +010010318 char bop = rhs[op];
10319 auto expr = rhs.substr(lhs.size() + 3);
10320 // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code.
10321 // Find some common patterns which are equivalent.
10322 if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)"))
10323 statement(lhs, bop, bop, ";");
10324 else
10325 statement(lhs, " ", bop, "= ", expr, ";");
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +010010326 return true;
10327}
10328
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010329void CompilerGLSL::register_control_dependent_expression(uint32_t expr)
10330{
10331 if (forwarded_temporaries.find(expr) == end(forwarded_temporaries))
10332 return;
10333
10334 assert(current_emitting_block);
10335 current_emitting_block->invalidate_expressions.push_back(expr);
10336}
10337
10338void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010339{
10340 current_emitting_block = &block;
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020010341
10342 if (backend.requires_relaxed_precision_analysis)
10343 {
10344 // If PHI variables are consumed in unexpected precision contexts, copy them here.
10345 for (auto &phi : block.phi_variables)
10346 {
10347 auto itr = temporary_to_mirror_precision_alias.find(phi.function_variable);
10348 if (itr != temporary_to_mirror_precision_alias.end())
10349 {
10350 // Explicitly, we don't want to inherit RelaxedPrecision state in this CopyObject,
10351 // so it helps to have handle_instruction_precision() on the outside of emit_instruction().
10352 EmbeddedInstruction inst;
10353 inst.op = OpCopyObject;
10354 inst.length = 3;
10355 inst.ops.push_back(expression_type_id(itr->first));
10356 inst.ops.push_back(itr->second);
10357 inst.ops.push_back(itr->first);
10358 emit_instruction(inst);
10359 }
10360 }
10361 }
10362
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010363 for (auto &op : block.ops)
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020010364 {
10365 auto temporary_copy = handle_instruction_precision(op);
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010366 emit_instruction(op);
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020010367 if (temporary_copy.dst_id)
10368 {
10369 // Explicitly, we don't want to inherit RelaxedPrecision state in this CopyObject,
10370 // so it helps to have handle_instruction_precision() on the outside of emit_instruction().
10371 EmbeddedInstruction inst;
10372 inst.op = OpCopyObject;
10373 inst.length = 3;
10374 inst.ops.push_back(expression_type_id(temporary_copy.src_id));
10375 inst.ops.push_back(temporary_copy.dst_id);
10376 inst.ops.push_back(temporary_copy.src_id);
10377
10378 // Never attempt to hoist mirrored temporaries.
10379 // They are hoisted in lock-step with their parents.
10380 block_temporary_hoisting = true;
10381 emit_instruction(inst);
10382 block_temporary_hoisting = false;
10383 }
10384 }
10385
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010386 current_emitting_block = nullptr;
10387}
10388
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010389void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression &expr)
10390{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010391 // Allow trivially forwarded expressions like OpLoad or trivial shuffles,
10392 // these will be marked as having suppressed usage tracking.
10393 // Our only concern is to make sure arithmetic operations are done in similar ways.
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +020010394 if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) &&
10395 forced_invariant_temporaries.count(expr.self) == 0)
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010396 {
Hans-Kristian Arntzena56b22b2022-02-16 12:12:58 +010010397 force_temporary_and_recompile(expr.self);
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +020010398 forced_invariant_temporaries.insert(expr.self);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010399
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +020010400 for (auto &dependent : expr.expression_dependencies)
10401 disallow_forwarding_in_expression_chain(get<SPIRExpression>(dependent));
10402 }
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010403}
10404
10405void CompilerGLSL::handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id)
10406{
10407 // Variables or access chains marked invariant are complicated. We will need to make sure the code-gen leading up to
10408 // this variable is consistent. The failure case for SPIRV-Cross is when an expression is forced to a temporary
10409 // in one translation unit, but not another, e.g. due to multiple use of an expression.
10410 // This causes variance despite the output variable being marked invariant, so the solution here is to force all dependent
10411 // expressions to be temporaries.
10412 // It is uncertain if this is enough to support invariant in all possible cases, but it should be good enough
10413 // for all reasonable uses of invariant.
10414 if (!has_decoration(store_id, DecorationInvariant))
10415 return;
10416
10417 auto *expr = maybe_get<SPIRExpression>(value_id);
10418 if (!expr)
10419 return;
10420
10421 disallow_forwarding_in_expression_chain(*expr);
10422}
10423
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +010010424void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +010010425{
10426 auto rhs = to_pointer_expression(rhs_expression);
10427
10428 // Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
10429 if (!rhs.empty())
10430 {
10431 handle_store_to_invariant_variable(lhs_expression, rhs_expression);
10432
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010010433 if (!unroll_array_to_complex_store(lhs_expression, rhs_expression))
10434 {
10435 auto lhs = to_dereferenced_expression(lhs_expression);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010436 if (has_decoration(lhs_expression, DecorationNonUniform))
10437 convert_non_uniform_expression(lhs, lhs_expression);
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +010010438
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010010439 // We might need to cast in order to store to a builtin.
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020010440 cast_to_variable_store(lhs_expression, rhs, expression_type(rhs_expression));
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +010010441
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010010442 // Tries to optimize assignments like "<lhs> = <lhs> op expr".
10443 // While this is purely cosmetic, this is important for legacy ESSL where loop
10444 // variable increments must be in either i++ or i += const-expr.
10445 // Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
10446 if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
10447 statement(lhs, " = ", rhs, ";");
10448 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +010010449 register_write(lhs_expression);
10450 }
10451}
10452
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010453uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &instr) const
10454{
10455 if (instr.length < 3)
10456 return 32;
10457
10458 auto *ops = stream(instr);
10459
10460 switch (instr.op)
10461 {
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020010462 case OpSConvert:
10463 case OpConvertSToF:
10464 case OpUConvert:
10465 case OpConvertUToF:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010466 case OpIEqual:
10467 case OpINotEqual:
10468 case OpSLessThan:
10469 case OpSLessThanEqual:
10470 case OpSGreaterThan:
10471 case OpSGreaterThanEqual:
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020010472 case OpULessThan:
10473 case OpULessThanEqual:
10474 case OpUGreaterThan:
10475 case OpUGreaterThanEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010476 return expression_type(ops[2]).width;
10477
10478 default:
10479 {
10480 // We can look at result type which is more robust.
10481 auto *type = maybe_get<SPIRType>(ops[0]);
10482 if (type && type_is_integral(*type))
10483 return type->width;
10484 else
10485 return 32;
10486 }
10487 }
10488}
10489
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +010010490uint32_t CompilerGLSL::get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *ops, uint32_t length) const
10491{
10492 if (length < 1)
10493 return 32;
10494
10495 switch (op)
10496 {
10497 case GLSLstd450SAbs:
10498 case GLSLstd450SSign:
10499 case GLSLstd450UMin:
10500 case GLSLstd450SMin:
10501 case GLSLstd450UMax:
10502 case GLSLstd450SMax:
10503 case GLSLstd450UClamp:
10504 case GLSLstd450SClamp:
10505 case GLSLstd450FindSMsb:
10506 case GLSLstd450FindUMsb:
10507 return expression_type(ops[0]).width;
10508
10509 default:
10510 {
10511 // We don't need to care about other opcodes, just return 32.
10512 return 32;
10513 }
10514 }
10515}
10516
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020010517void CompilerGLSL::forward_relaxed_precision(uint32_t dst_id, const uint32_t *args, uint32_t length)
10518{
10519 // Only GLSL supports RelaxedPrecision directly.
10520 // We cannot implement this in HLSL or MSL because it is tied to the type system.
10521 // In SPIR-V, everything must masquerade as 32-bit.
10522 if (!backend.requires_relaxed_precision_analysis)
10523 return;
10524
10525 auto input_precision = analyze_expression_precision(args, length);
10526
10527 // For expressions which are loaded or directly forwarded, we inherit mediump implicitly.
10528 // For dst_id to be analyzed properly, it must inherit any relaxed precision decoration from src_id.
10529 if (input_precision == Options::Mediump)
10530 set_decoration(dst_id, DecorationRelaxedPrecision);
10531}
10532
10533CompilerGLSL::Options::Precision CompilerGLSL::analyze_expression_precision(const uint32_t *args, uint32_t length) const
10534{
10535 // Now, analyze the precision at which the arguments would run.
10536 // GLSL rules are such that the precision used to evaluate an expression is equal to the highest precision
10537 // for the inputs. Constants do not have inherent precision and do not contribute to this decision.
10538 // If all inputs are constants, they inherit precision from outer expressions, including an l-value.
10539 // In this case, we'll have to force a temporary for dst_id so that we can bind the constant expression with
10540 // correct precision.
10541 bool expression_has_highp = false;
10542 bool expression_has_mediump = false;
10543
10544 for (uint32_t i = 0; i < length; i++)
10545 {
10546 uint32_t arg = args[i];
Hans-Kristian Arntzen92164d32022-05-13 12:14:56 +020010547
10548 auto handle_type = ir.ids[arg].get_type();
10549 if (handle_type == TypeConstant || handle_type == TypeConstantOp || handle_type == TypeUndef)
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020010550 continue;
10551
10552 if (has_decoration(arg, DecorationRelaxedPrecision))
10553 expression_has_mediump = true;
10554 else
10555 expression_has_highp = true;
10556 }
10557
10558 if (expression_has_highp)
10559 return Options::Highp;
10560 else if (expression_has_mediump)
10561 return Options::Mediump;
10562 else
10563 return Options::DontCare;
10564}
10565
10566void CompilerGLSL::analyze_precision_requirements(uint32_t type_id, uint32_t dst_id, uint32_t *args, uint32_t length)
10567{
10568 if (!backend.requires_relaxed_precision_analysis)
10569 return;
10570
10571 auto &type = get<SPIRType>(type_id);
10572
10573 // RelaxedPrecision only applies to 32-bit values.
10574 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt)
10575 return;
10576
10577 bool operation_is_highp = !has_decoration(dst_id, DecorationRelaxedPrecision);
10578
10579 auto input_precision = analyze_expression_precision(args, length);
10580 if (input_precision == Options::DontCare)
10581 {
10582 consume_temporary_in_precision_context(type_id, dst_id, input_precision);
10583 return;
10584 }
10585
10586 // In SPIR-V and GLSL, the semantics are flipped for how relaxed precision is determined.
10587 // In SPIR-V, the operation itself marks RelaxedPrecision, meaning that inputs can be truncated to 16-bit.
10588 // However, if the expression is not, inputs must be expanded to 32-bit first,
10589 // since the operation must run at high precision.
10590 // This is the awkward part, because if we have mediump inputs, or expressions which derived from mediump,
10591 // we might have to forcefully bind the source IDs to highp temporaries. This is done by clearing decorations
10592 // and forcing temporaries. Similarly for mediump operations. We bind highp expressions to mediump variables.
10593 if ((operation_is_highp && input_precision == Options::Mediump) ||
10594 (!operation_is_highp && input_precision == Options::Highp))
10595 {
10596 auto precision = operation_is_highp ? Options::Highp : Options::Mediump;
10597 for (uint32_t i = 0; i < length; i++)
10598 {
10599 // Rewrites the opcode so that we consume an ID in correct precision context.
10600 // This is pretty hacky, but it's the most straight forward way of implementing this without adding
10601 // lots of extra passes to rewrite all code blocks.
10602 args[i] = consume_temporary_in_precision_context(expression_type_id(args[i]), args[i], precision);
10603 }
10604 }
10605}
10606
10607// This is probably not exhaustive ...
10608static bool opcode_is_precision_sensitive_operation(Op op)
10609{
10610 switch (op)
10611 {
10612 case OpFAdd:
10613 case OpFSub:
10614 case OpFMul:
10615 case OpFNegate:
10616 case OpIAdd:
10617 case OpISub:
10618 case OpIMul:
10619 case OpSNegate:
10620 case OpFMod:
10621 case OpFDiv:
10622 case OpFRem:
10623 case OpSMod:
10624 case OpSDiv:
10625 case OpSRem:
10626 case OpUMod:
10627 case OpUDiv:
10628 case OpVectorTimesMatrix:
10629 case OpMatrixTimesVector:
10630 case OpMatrixTimesMatrix:
10631 case OpDPdx:
10632 case OpDPdy:
10633 case OpDPdxCoarse:
10634 case OpDPdyCoarse:
10635 case OpDPdxFine:
10636 case OpDPdyFine:
10637 case OpFwidth:
10638 case OpFwidthCoarse:
10639 case OpFwidthFine:
10640 case OpVectorTimesScalar:
10641 case OpMatrixTimesScalar:
10642 case OpOuterProduct:
10643 case OpFConvert:
10644 case OpSConvert:
10645 case OpUConvert:
10646 case OpConvertSToF:
10647 case OpConvertUToF:
10648 case OpConvertFToU:
10649 case OpConvertFToS:
10650 return true;
10651
10652 default:
10653 return false;
10654 }
10655}
10656
10657// Instructions which just load data but don't do any arithmetic operation should just inherit the decoration.
10658// SPIR-V doesn't require this, but it's somewhat implied it has to work this way, relaxed precision is only
10659// relevant when operating on the IDs, not when shuffling things around.
10660static bool opcode_is_precision_forwarding_instruction(Op op, uint32_t &arg_count)
10661{
10662 switch (op)
10663 {
10664 case OpLoad:
10665 case OpAccessChain:
10666 case OpInBoundsAccessChain:
10667 case OpCompositeExtract:
10668 case OpVectorExtractDynamic:
10669 case OpSampledImage:
10670 case OpImage:
10671 case OpCopyObject:
10672
10673 case OpImageRead:
10674 case OpImageFetch:
10675 case OpImageSampleImplicitLod:
10676 case OpImageSampleProjImplicitLod:
10677 case OpImageSampleDrefImplicitLod:
10678 case OpImageSampleProjDrefImplicitLod:
10679 case OpImageSampleExplicitLod:
10680 case OpImageSampleProjExplicitLod:
10681 case OpImageSampleDrefExplicitLod:
10682 case OpImageSampleProjDrefExplicitLod:
10683 case OpImageGather:
10684 case OpImageDrefGather:
10685 case OpImageSparseRead:
10686 case OpImageSparseFetch:
10687 case OpImageSparseSampleImplicitLod:
10688 case OpImageSparseSampleProjImplicitLod:
10689 case OpImageSparseSampleDrefImplicitLod:
10690 case OpImageSparseSampleProjDrefImplicitLod:
10691 case OpImageSparseSampleExplicitLod:
10692 case OpImageSparseSampleProjExplicitLod:
10693 case OpImageSparseSampleDrefExplicitLod:
10694 case OpImageSparseSampleProjDrefExplicitLod:
10695 case OpImageSparseGather:
10696 case OpImageSparseDrefGather:
10697 arg_count = 1;
10698 return true;
10699
10700 case OpVectorShuffle:
10701 arg_count = 2;
10702 return true;
10703
10704 case OpCompositeConstruct:
10705 return true;
10706
10707 default:
10708 break;
10709 }
10710
10711 return false;
10712}
10713
10714CompilerGLSL::TemporaryCopy CompilerGLSL::handle_instruction_precision(const Instruction &instruction)
10715{
10716 auto ops = stream_mutable(instruction);
10717 auto opcode = static_cast<Op>(instruction.op);
10718 uint32_t length = instruction.length;
10719
10720 if (backend.requires_relaxed_precision_analysis)
10721 {
10722 if (length > 2)
10723 {
10724 uint32_t forwarding_length = length - 2;
10725
10726 if (opcode_is_precision_sensitive_operation(opcode))
10727 analyze_precision_requirements(ops[0], ops[1], &ops[2], forwarding_length);
10728 else if (opcode == OpExtInst && length >= 5 && get<SPIRExtension>(ops[2]).ext == SPIRExtension::GLSL)
10729 analyze_precision_requirements(ops[0], ops[1], &ops[4], forwarding_length - 2);
10730 else if (opcode_is_precision_forwarding_instruction(opcode, forwarding_length))
10731 forward_relaxed_precision(ops[1], &ops[2], forwarding_length);
10732 }
10733
Hans-Kristian Arntzen7eb5ced2022-05-02 15:27:09 +020010734 uint32_t result_type = 0, result_id = 0;
10735 if (instruction_to_result_type(result_type, result_id, opcode, ops, length))
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020010736 {
10737 auto itr = temporary_to_mirror_precision_alias.find(ops[1]);
10738 if (itr != temporary_to_mirror_precision_alias.end())
10739 return { itr->second, itr->first };
10740 }
10741 }
10742
10743 return {};
10744}
10745
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +020010746void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010747{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010748 auto ops = stream(instruction);
10749 auto opcode = static_cast<Op>(instruction.op);
10750 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010751
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010752#define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
10753#define GLSL_BOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010754 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 +020010755#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
10756#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
10757#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
10758#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
10759#define GLSL_BFOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010760 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 +020010761#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
10762#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010763
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010764 // If we need to do implicit bitcasts, make sure we do it with the correct type.
10765 uint32_t integer_width = get_integer_width_for_instruction(instruction);
10766 auto int_type = to_signed_basetype(integer_width);
10767 auto uint_type = to_unsigned_basetype(integer_width);
10768
Hans-Kristian Arntzen31be74a2022-03-03 11:04:45 +010010769 opcode = get_remapped_spirv_op(opcode);
10770
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010771 switch (opcode)
10772 {
10773 // Dealing with memory
10774 case OpLoad:
10775 {
10776 uint32_t result_type = ops[0];
10777 uint32_t id = ops[1];
10778 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010780 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010781
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010782 // If we're loading from memory that cannot be changed by the shader,
10783 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010784 // If an expression is mutable and forwardable, we speculate that it is immutable.
10785 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
10786
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010787 // If loading a non-native row-major matrix, mark the expression as need_transpose.
10788 bool need_transpose = false;
10789 bool old_need_transpose = false;
10790
10791 auto *ptr_expression = maybe_get<SPIRExpression>(ptr);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010792
10793 if (forward)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010794 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010795 // If we're forwarding the load, we're also going to forward transpose state, so don't transpose while
10796 // taking the expression.
10797 if (ptr_expression && ptr_expression->need_transpose)
10798 {
10799 old_need_transpose = true;
10800 ptr_expression->need_transpose = false;
10801 need_transpose = true;
10802 }
10803 else if (is_non_native_row_major_matrix(ptr))
10804 need_transpose = true;
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010805 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010806
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010807 // If we are forwarding this load,
10808 // don't register the read to access chain here, defer that to when we actually use the expression,
10809 // using the add_implied_read_expression mechanism.
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010810 string expr;
10811
10812 bool is_packed = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked);
10813 bool is_remapped = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID);
10814 if (forward || (!is_packed && !is_remapped))
10815 {
10816 // For the simple case, we do not need to deal with repacking.
10817 expr = to_dereferenced_expression(ptr, false);
10818 }
10819 else
10820 {
10821 // If we are not forwarding the expression, we need to unpack and resolve any physical type remapping here before
10822 // storing the expression to a temporary.
10823 expr = to_unpacked_expression(ptr);
10824 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010825
Chip Davis5281d992020-06-13 23:03:30 -050010826 auto &type = get<SPIRType>(result_type);
10827 auto &expr_type = expression_type(ptr);
10828
10829 // If the expression has more vector components than the result type, insert
10830 // a swizzle. This shouldn't happen normally on valid SPIR-V, but it might
10831 // happen with e.g. the MSL backend replacing the type of an input variable.
10832 if (expr_type.vecsize > type.vecsize)
10833 expr = enclose_expression(expr + vector_swizzle(type.vecsize, 0));
10834
Chip Davisfc4a12f2022-08-05 01:16:45 -070010835 if (forward && ptr_expression)
10836 ptr_expression->need_transpose = old_need_transpose;
10837
Chip Davis3e6010d2020-10-14 15:04:03 -050010838 // We might need to cast in order to load from a builtin.
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020010839 cast_from_variable_load(ptr, expr, type);
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020010840
Chip Davisfc4a12f2022-08-05 01:16:45 -070010841 if (forward && ptr_expression)
10842 ptr_expression->need_transpose = false;
10843
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010010844 // We might be trying to load a gl_Position[N], where we should be
10845 // doing float4[](gl_in[i].gl_Position, ...) instead.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010010846 // Similar workarounds are required for input arrays in tessellation.
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010010847 // Also, loading from gl_SampleMask array needs special unroll.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010010848 unroll_array_from_complex_load(id, ptr, expr);
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010010849
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010850 if (!type_is_opaque_value(type) && has_decoration(ptr, DecorationNonUniform))
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010851 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020010852 // If we're loading something non-opaque, we need to handle non-uniform descriptor access.
10853 convert_non_uniform_expression(expr, ptr);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010854 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020010855
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010856 if (forward && ptr_expression)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010857 ptr_expression->need_transpose = old_need_transpose;
Bill Hollings13583622016-12-14 02:12:52 -050010858
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020010859 bool flattened = ptr_expression && flattened_buffer_blocks.count(ptr_expression->loaded_from) != 0;
10860
10861 if (backend.needs_row_major_load_workaround && !is_non_native_row_major_matrix(ptr) && !flattened)
10862 rewrite_load_for_wrapped_row_major(expr, result_type, ptr);
10863
Hans-Kristian Arntzen18b82ca2018-07-09 14:02:50 +020010864 // 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 +020010865 // However, if we try to load a complex, composite object from a flattened buffer,
10866 // 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 +020010867 bool usage_tracking = flattened && (type.basetype == SPIRType::Struct || (type.columns > 1));
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +020010868
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010869 SPIRExpression *e = nullptr;
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +020010870 if (!forward && expression_is_non_value_type_array(ptr))
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010871 {
10872 // Complicated load case where we need to make a copy of ptr, but we cannot, because
10873 // it is an array, and our backend does not support arrays as value types.
10874 // Emit the temporary, and copy it explicitly.
10875 e = &emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020010876 emit_array_copy(to_expression(id), id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010877 }
10878 else
10879 e = &emit_op(result_type, id, expr, forward, !usage_tracking);
10880
10881 e->need_transpose = need_transpose;
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010882 register_read(id, ptr, forward);
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010883
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010884 if (forward)
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +010010885 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +020010886 // Pass through whether the result is of a packed type and the physical type ID.
10887 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked))
10888 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10889 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID))
10890 {
10891 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID,
10892 get_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID));
10893 }
10894 }
10895 else
10896 {
10897 // This might have been set on an earlier compilation iteration, force it to be unset.
10898 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10899 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +010010900 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010901
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010902 inherit_expression_dependencies(id, ptr);
10903 if (forward)
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010904 add_implied_read_expression(*e, ptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010905 break;
10906 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010907
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010908 case OpInBoundsAccessChain:
10909 case OpAccessChain:
Chip Davis3bfb2f92018-12-03 02:06:33 -060010910 case OpPtrAccessChain:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010911 {
10912 auto *var = maybe_get<SPIRVariable>(ops[2]);
10913 if (var)
10914 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010915
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010916 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +020010917 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010918 AccessChainMeta meta;
Chip Davis3bfb2f92018-12-03 02:06:33 -060010919 bool ptr_chain = opcode == OpPtrAccessChain;
Shintaro Sakaharaed4ded02022-02-16 21:53:24 +090010920 auto &target_type = get<SPIRType>(ops[0]);
10921 auto e = access_chain(ops[2], &ops[3], length - 3, target_type, &meta, ptr_chain);
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +020010922
Shintaro Sakaharaed4ded02022-02-16 21:53:24 +090010923 // If the base is flattened UBO of struct type, the expression has to be a composite.
10924 // In that case, backends which do not support inline syntax need it to be bound to a temporary.
10925 // Otherwise, invalid expressions like ({UBO[0].xyz, UBO[0].w, UBO[1]}).member are emitted.
10926 bool requires_temporary = false;
10927 if (flattened_buffer_blocks.count(ops[2]) && target_type.basetype == SPIRType::Struct)
10928 requires_temporary = !backend.can_declare_struct_inline;
10929
10930 auto &expr = requires_temporary ?
Daniel Thornburgh44c33332022-03-02 23:02:38 +000010931 emit_op(ops[0], ops[1], std::move(e), false) :
10932 set<SPIRExpression>(ops[1], std::move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +020010933
10934 auto *backing_variable = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010935 expr.loaded_from = backing_variable ? backing_variable->self : ID(ops[2]);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010936 expr.need_transpose = meta.need_transpose;
Chip Davis3bfb2f92018-12-03 02:06:33 -060010937 expr.access_chain = true;
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010938
10939 // Mark the result as being packed. Some platforms handled packed vectors differently than non-packed.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010940 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010941 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypePacked);
10942 if (meta.storage_physical_type != 0)
10943 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010944 if (meta.storage_is_invariant)
10945 set_decoration(ops[1], DecorationInvariant);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010946 if (meta.flattened_struct)
10947 flattened_structs[ops[1]] = true;
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020010948 if (meta.relaxed_precision && backend.requires_relaxed_precision_analysis)
10949 set_decoration(ops[1], DecorationRelaxedPrecision);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +010010950
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010951 // If we have some expression dependencies in our access chain, this access chain is technically a forwarded
10952 // temporary which could be subject to invalidation.
10953 // Need to assume we're forwarded while calling inherit_expression_depdendencies.
10954 forwarded_temporaries.insert(ops[1]);
10955 // The access chain itself is never forced to a temporary, but its dependencies might.
10956 suppressed_usage_tracking.insert(ops[1]);
10957
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +010010958 for (uint32_t i = 2; i < length; i++)
10959 {
10960 inherit_expression_dependencies(ops[1], ops[i]);
10961 add_implied_read_expression(expr, ops[i]);
10962 }
10963
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010964 // If we have no dependencies after all, i.e., all indices in the access chain are immutable temporaries,
10965 // we're not forwarded after all.
10966 if (expr.expression_dependencies.empty())
10967 forwarded_temporaries.erase(ops[1]);
10968
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010969 break;
10970 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010971
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010972 case OpStore:
10973 {
10974 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010975
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010976 if (var && var->statically_assigned)
10977 var->static_expression = ops[1];
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010978 else if (var && var->loop_variable && !var->loop_variable_enable)
10979 var->static_expression = ops[1];
Hans-Kristian Arntzend31bc022020-05-28 11:49:28 +020010980 else if (var && var->remapped_variable && var->static_expression)
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020010981 {
10982 // Skip the write.
10983 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010984 else if (flattened_structs.count(ops[0]))
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +010010985 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020010986 store_flattened_struct(ops[0], ops[1]);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +010010987 register_write(ops[0]);
10988 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010989 else
10990 {
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +010010991 emit_store_statement(ops[0], ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010992 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +010010993
Chip Davis3bfb2f92018-12-03 02:06:33 -060010994 // Storing a pointer results in a variable pointer, so we must conservatively assume
10995 // we can write through it.
10996 if (expression_type(ops[1]).pointer)
10997 register_write(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010998 break;
10999 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011000
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011001 case OpArrayLength:
11002 {
11003 uint32_t result_type = ops[0];
11004 uint32_t id = ops[1];
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +010011005 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 +020011006 if (has_decoration(ops[2], DecorationNonUniform))
11007 convert_non_uniform_expression(e, ops[2]);
Hans-Kristian Arntzenb6f8a202019-05-07 19:02:32 +020011008 set<SPIRExpression>(id, join(type_to_glsl(get<SPIRType>(result_type)), "(", e, ".length())"), result_type,
11009 true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011010 break;
11011 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011012
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011013 // Function calls
11014 case OpFunctionCall:
11015 {
11016 uint32_t result_type = ops[0];
11017 uint32_t id = ops[1];
11018 uint32_t func = ops[2];
11019 const auto *arg = &ops[3];
11020 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011021
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011022 auto &callee = get<SPIRFunction>(func);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011023 auto &return_type = get<SPIRType>(callee.return_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011024 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011025
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011026 bool callee_has_out_variables = false;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011027 bool emit_return_value_as_argument = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011028
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011029 // Invalidate out variables passed to functions since they can be OpStore'd to.
11030 for (uint32_t i = 0; i < length; i++)
11031 {
11032 if (callee.arguments[i].write_count)
11033 {
11034 register_call_out_argument(arg[i]);
11035 callee_has_out_variables = true;
11036 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011037
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011038 flush_variable_declaration(arg[i]);
11039 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011040
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011041 if (!return_type.array.empty() && !backend.can_return_array)
11042 {
11043 callee_has_out_variables = true;
11044 emit_return_value_as_argument = true;
11045 }
11046
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011047 if (!pure)
11048 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011049
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011050 string funexpr;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020011051 SmallVector<string> arglist;
Bill Hollings1c180782017-11-05 21:34:42 -050011052 funexpr += to_name(func) + "(";
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011053
11054 if (emit_return_value_as_argument)
11055 {
11056 statement(type_to_glsl(return_type), " ", to_name(id), type_to_array_glsl(return_type), ";");
11057 arglist.push_back(to_name(id));
11058 }
11059
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011060 for (uint32_t i = 0; i < length; i++)
11061 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020011062 // Do not pass in separate images or samplers if we're remapping
11063 // to combined image samplers.
11064 if (skip_argument(arg[i]))
11065 continue;
11066
Chip Davis39dce882019-08-02 15:11:19 -050011067 arglist.push_back(to_func_call_arg(callee.arguments[i], arg[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011068 }
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +020011069
11070 for (auto &combined : callee.combined_parameters)
11071 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020011072 auto image_id = combined.global_image ? combined.image_id : VariableID(arg[combined.image_id]);
11073 auto sampler_id = combined.global_sampler ? combined.sampler_id : VariableID(arg[combined.sampler_id]);
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +020011074 arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +020011075 }
Bill Hollingsa759e2c2016-10-19 14:09:51 -070011076
Bill Hollingsac00c602016-10-24 09:24:24 -040011077 append_global_func_args(callee, length, arglist);
Bill Hollingsa759e2c2016-10-19 14:09:51 -070011078
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020011079 funexpr += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011080 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011081
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011082 // Check for function call constraints.
11083 check_function_call_constraints(arg, length);
11084
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011085 if (return_type.basetype != SPIRType::Void)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011086 {
11087 // If the function actually writes to an out variable,
11088 // take the conservative route and do not forward.
11089 // The problem is that we might not read the function
11090 // result (and emit the function) before an out variable
11091 // is read (common case when return value is ignored!
11092 // In order to avoid start tracking invalid variables,
11093 // just avoid the forwarding problem altogether.
11094 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
11095 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011096
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011097 if (emit_return_value_as_argument)
11098 {
11099 statement(funexpr, ";");
11100 set<SPIRExpression>(id, to_name(id), result_type, true);
11101 }
11102 else
11103 emit_op(result_type, id, funexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011104
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011105 // Function calls are implicit loads from all variables in question.
11106 // Set dependencies for them.
11107 for (uint32_t i = 0; i < length; i++)
11108 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011109
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011110 // If we're going to forward the temporary result,
11111 // put dependencies on every variable that must not change.
11112 if (forward)
11113 register_global_read_dependencies(callee, id);
11114 }
11115 else
11116 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011118 break;
11119 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011120
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011121 // Composite munging
11122 case OpCompositeConstruct:
11123 {
11124 uint32_t result_type = ops[0];
11125 uint32_t id = ops[1];
Hans-Kristian Arntzen9a527132018-03-09 15:26:36 +010011126 const auto *const elems = &ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011127 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011128
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011129 bool forward = true;
11130 for (uint32_t i = 0; i < length; i++)
11131 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011132
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011133 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020011134 auto *in_type = length > 0 ? &expression_type(elems[0]) : nullptr;
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020011135
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011136 // Only splat if we have vector constructors.
11137 // Arrays and structs must be initialized properly in full.
11138 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011139
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020011140 bool splat = false;
11141 bool swizzle_splat = false;
11142
11143 if (in_type)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +010011144 {
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020011145 splat = in_type->vecsize == 1 && in_type->columns == 1 && !composite && backend.use_constructor_splatting;
11146 swizzle_splat = in_type->vecsize == 1 && in_type->columns == 1 && backend.can_swizzle_scalar;
11147
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020011148 if (ir.ids[elems[0]].get_type() == TypeConstant && !type_is_floating_point(*in_type))
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020011149 {
11150 // Cannot swizzle literal integers as a special case.
11151 swizzle_splat = false;
11152 }
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +010011153 }
11154
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010011155 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011156 {
11157 uint32_t input = elems[0];
11158 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010011159 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011160 if (input != elems[i])
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010011161 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011162 splat = false;
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010011163 swizzle_splat = false;
11164 }
11165 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011166 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011167
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010011168 if (out_type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
11169 forward = false;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +010011170 if (!out_type.array.empty() && !backend.can_declare_arrays_inline)
11171 forward = false;
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020011172 if (type_is_empty(out_type) && !backend.supports_empty_struct)
11173 forward = false;
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010011174
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011175 string constructor_op;
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +020011176 if (backend.use_initializer_list && composite)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011177 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020011178 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011179 // Only use this path if we are building composites.
11180 // This path cannot be used for arithmetic.
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +020011181 if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +010011182 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
Hans-Kristian Arntzenc9d4f9c2020-02-24 12:47:14 +010011183 else if (backend.use_typed_initializer_list && backend.array_is_value_type && !out_type.array.empty())
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020011184 {
11185 // MSL path. Array constructor is baked into type here, do not use _constructor variant.
11186 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
11187 needs_trailing_tracket = true;
11188 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011189 constructor_op += "{ ";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020011190
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020011191 if (type_is_empty(out_type) && !backend.supports_empty_struct)
11192 constructor_op += "0";
11193 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020011194 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011195 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010011196 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011197 constructor_op += " }";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020011198 if (needs_trailing_tracket)
11199 constructor_op += ")";
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011200 }
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +010011201 else if (swizzle_splat && !composite)
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +010011202 {
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020011203 constructor_op = remap_swizzle(get<SPIRType>(result_type), 1, to_unpacked_expression(elems[0]));
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +010011204 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011205 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011206 {
11207 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020011208 if (type_is_empty(out_type) && !backend.supports_empty_struct)
11209 constructor_op += "0";
11210 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +020011211 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011212 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +010011213 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020011214 constructor_op += ")";
11215 }
11216
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +020011217 if (!constructor_op.empty())
11218 {
11219 emit_op(result_type, id, constructor_op, forward);
11220 for (uint32_t i = 0; i < length; i++)
11221 inherit_expression_dependencies(id, elems[i]);
11222 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011223 break;
11224 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011225
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011226 case OpVectorInsertDynamic:
11227 {
11228 uint32_t result_type = ops[0];
11229 uint32_t id = ops[1];
11230 uint32_t vec = ops[2];
11231 uint32_t comp = ops[3];
11232 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011233
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011234 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011235
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011236 // Make a copy, then use access chain to store the variable.
11237 statement(declare_temporary(result_type, id), to_expression(vec), ";");
11238 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010011239 auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +020011240 statement(chain, " = ", to_unpacked_expression(comp), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011241 break;
11242 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011243
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011244 case OpVectorExtractDynamic:
11245 {
11246 uint32_t result_type = ops[0];
11247 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011248
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010011249 auto expr = access_chain_internal(ops[2], &ops[3], 1, 0, nullptr);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011250 emit_op(result_type, id, expr, should_forward(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010011251 inherit_expression_dependencies(id, ops[2]);
11252 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011253 break;
11254 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011255
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011256 case OpCompositeExtract:
11257 {
11258 uint32_t result_type = ops[0];
11259 uint32_t id = ops[1];
11260 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011261
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011262 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011263
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +020011264 // We can only split the expression here if our expression is forwarded as a temporary.
11265 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
11266
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +010011267 // Do not allow base expression for struct members. We risk doing "swizzle" optimizations in this case.
11268 auto &composite_type = expression_type(ops[2]);
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010011269 bool composite_type_is_complex = composite_type.basetype == SPIRType::Struct || !composite_type.array.empty();
11270 if (composite_type_is_complex)
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +010011271 allow_base_expression = false;
11272
Hans-Kristian Arntzenc7b75a82020-04-07 18:22:14 +020011273 // Packed expressions or physical ID mapped expressions cannot be split up.
11274 if (has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypePacked) ||
11275 has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypeID))
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +010011276 allow_base_expression = false;
11277
Hans-Kristian Arntzen7ff2db42019-08-27 11:41:54 +020011278 // Cannot use base expression for row-major matrix row-extraction since we need to interleave access pattern
11279 // into the base expression.
11280 if (is_non_native_row_major_matrix(ops[2]))
11281 allow_base_expression = false;
11282
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010011283 AccessChainMeta meta;
11284 SPIRExpression *e = nullptr;
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010011285 auto *c = maybe_get<SPIRConstant>(ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010011286
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010011287 if (c && !c->specialization && !composite_type_is_complex)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011288 {
Hans-Kristian Arntzen7ab3f3f2021-01-22 12:17:05 +010011289 auto expr = to_extract_constant_composite_expression(result_type, *c, ops + 3, length);
11290 e = &emit_op(result_type, id, expr, true, true);
11291 }
11292 else if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
11293 {
11294 // Only apply this optimization if result is scalar.
11295
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011296 // We want to split the access chain from the base.
11297 // This is so we can later combine different CompositeExtract results
11298 // with CompositeConstruct without emitting code like
11299 //
11300 // vec3 temp = texture(...).xyz
11301 // vec4(temp.x, temp.y, temp.z, 1.0).
11302 //
11303 // when we actually wanted to emit this
11304 // vec4(texture(...).xyz, 1.0).
11305 //
11306 // Including the base will prevent this and would trigger multiple reads
11307 // from expression causing it to be forced to an actual temporary in GLSL.
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010011308 auto expr = access_chain_internal(ops[2], &ops[3], length,
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +020011309 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_CHAIN_ONLY_BIT |
11310 ACCESS_CHAIN_FORCE_COMPOSITE_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020011311 e = &emit_op(result_type, id, expr, true, should_suppress_usage_tracking(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010011312 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010011313 e->base_expression = ops[2];
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020011314
11315 if (meta.relaxed_precision && backend.requires_relaxed_precision_analysis)
11316 set_decoration(ops[1], DecorationRelaxedPrecision);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011317 }
11318 else
11319 {
Hans-Kristian Arntzen394c0382021-04-06 11:35:04 +020011320 auto expr = access_chain_internal(ops[2], &ops[3], length,
11321 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_FORCE_COMPOSITE_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020011322 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 +010011323 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011324 }
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010011325
11326 // Pass through some meta information to the loaded expression.
11327 // We can still end up loading a buffer type to a variable, then CompositeExtract from it
11328 // instead of loading everything through an access chain.
11329 e->need_transpose = meta.need_transpose;
11330 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020011331 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
11332 if (meta.storage_physical_type != 0)
11333 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010011334 if (meta.storage_is_invariant)
11335 set_decoration(id, DecorationInvariant);
11336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011337 break;
11338 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011339
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011340 case OpCompositeInsert:
11341 {
11342 uint32_t result_type = ops[0];
11343 uint32_t id = ops[1];
11344 uint32_t obj = ops[2];
11345 uint32_t composite = ops[3];
11346 const auto *elems = &ops[4];
11347 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011349 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011350
Hans-Kristian Arntzen23662662022-05-18 12:26:20 +020011351 // CompositeInsert requires a copy + modification, but this is very awkward code in HLL.
11352 // Speculate that the input composite is no longer used, and we can modify it in-place.
11353 // There are various scenarios where this is not possible to satisfy.
11354 bool can_modify_in_place = true;
11355 forced_temporaries.insert(id);
11356
11357 // Cannot safely RMW PHI variables since they have no way to be invalidated,
11358 // forcing temporaries is not going to help.
11359 // This is similar for Constant and Undef inputs.
11360 // The only safe thing to RMW is SPIRExpression.
Hans-Kristian Arntzen05bbcc22022-08-09 12:44:57 +020011361 // If the expression has already been used (i.e. used in a continue block), we have to keep using
11362 // that loop variable, since we won't be able to override the expression after the fact.
11363 // If the composite is hoisted, we might never be able to properly invalidate any usage
11364 // of that composite in a subsequent loop iteration.
Hans-Kristian Arntzen23662662022-05-18 12:26:20 +020011365 if (invalid_expressions.count(composite) ||
11366 block_composite_insert_overwrite.count(composite) ||
Hans-Kristian Arntzen05bbcc22022-08-09 12:44:57 +020011367 hoisted_temporaries.count(id) || hoisted_temporaries.count(composite) ||
Hans-Kristian Arntzen23662662022-05-18 12:26:20 +020011368 maybe_get<SPIRExpression>(composite) == nullptr)
11369 {
11370 can_modify_in_place = false;
11371 }
11372 else if (backend.requires_relaxed_precision_analysis &&
11373 has_decoration(composite, DecorationRelaxedPrecision) !=
11374 has_decoration(id, DecorationRelaxedPrecision) &&
11375 get<SPIRType>(result_type).basetype != SPIRType::Struct)
11376 {
11377 // Similarly, if precision does not match for input and output,
11378 // we cannot alias them. If we write a composite into a relaxed precision
11379 // ID, we might get a false truncation.
11380 can_modify_in_place = false;
11381 }
11382
11383 if (can_modify_in_place)
11384 {
11385 // Have to make sure the modified SSA value is bound to a temporary so we can modify it in-place.
11386 if (!forced_temporaries.count(composite))
11387 force_temporary_and_recompile(composite);
11388
11389 auto chain = access_chain_internal(composite, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
11390 statement(chain, " = ", to_unpacked_expression(obj), ";");
11391 set<SPIRExpression>(id, to_expression(composite), result_type, true);
11392 invalid_expressions.insert(composite);
11393 composite_insert_overwritten.insert(composite);
11394 }
11395 else
11396 {
11397 if (maybe_get<SPIRUndef>(composite) != nullptr)
11398 {
11399 emit_uninitialized_temporary_expression(result_type, id);
11400 }
11401 else
11402 {
11403 // Make a copy, then use access chain to store the variable.
11404 statement(declare_temporary(result_type, id), to_expression(composite), ";");
11405 set<SPIRExpression>(id, to_name(id), result_type, true);
11406 }
11407
11408 auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
11409 statement(chain, " = ", to_unpacked_expression(obj), ";");
11410 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011411
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011412 break;
11413 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011414
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010011415 case OpCopyMemory:
11416 {
11417 uint32_t lhs = ops[0];
11418 uint32_t rhs = ops[1];
11419 if (lhs != rhs)
11420 {
Hans-Kristian Arntzen4ca06c72021-03-08 14:09:32 +010011421 uint32_t &tmp_id = extra_sub_expressions[instruction.offset | EXTRA_SUB_EXPRESSION_TYPE_STREAM_OFFSET];
11422 if (!tmp_id)
11423 tmp_id = ir.increase_bound_by(1);
11424 uint32_t tmp_type_id = expression_type(rhs).parent_type;
11425
11426 EmbeddedInstruction fake_load, fake_store;
11427 fake_load.op = OpLoad;
11428 fake_load.length = 3;
11429 fake_load.ops.push_back(tmp_type_id);
11430 fake_load.ops.push_back(tmp_id);
11431 fake_load.ops.push_back(rhs);
11432
11433 fake_store.op = OpStore;
11434 fake_store.length = 2;
11435 fake_store.ops.push_back(lhs);
11436 fake_store.ops.push_back(tmp_id);
11437
11438 // Load and Store do a *lot* of workarounds, and we'd like to reuse them as much as possible.
11439 // Synthesize a fake Load and Store pair for CopyMemory.
11440 emit_instruction(fake_load);
11441 emit_instruction(fake_store);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010011442 }
11443 break;
11444 }
11445
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010011446 case OpCopyLogical:
11447 {
11448 // This is used for copying object of different types, arrays and structs.
11449 // We need to unroll the copy, element-by-element.
11450 uint32_t result_type = ops[0];
11451 uint32_t id = ops[1];
11452 uint32_t rhs = ops[2];
11453
11454 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010011455 emit_copy_logical_type(id, result_type, rhs, expression_type_id(rhs), {});
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010011456 break;
11457 }
11458
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011459 case OpCopyObject:
11460 {
11461 uint32_t result_type = ops[0];
11462 uint32_t id = ops[1];
11463 uint32_t rhs = ops[2];
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010011464 bool pointer = get<SPIRType>(result_type).pointer;
11465
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011466 auto *chain = maybe_get<SPIRAccessChain>(rhs);
Bill Hollingsb7b0e802020-10-29 18:50:42 -040011467 auto *imgsamp = maybe_get<SPIRCombinedImageSampler>(rhs);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011468 if (chain)
11469 {
11470 // Cannot lower to a SPIRExpression, just copy the object.
11471 auto &e = set<SPIRAccessChain>(id, *chain);
11472 e.self = id;
11473 }
Bill Hollingsb7b0e802020-10-29 18:50:42 -040011474 else if (imgsamp)
11475 {
11476 // Cannot lower to a SPIRExpression, just copy the object.
11477 // GLSL does not currently use this type and will never get here, but MSL does.
Bill Hollings7f67abe2020-10-30 16:05:44 -040011478 // Handled here instead of CompilerMSL for better integration and general handling,
Bill Hollingsb7b0e802020-10-29 18:50:42 -040011479 // and in case GLSL or other subclasses require it in the future.
11480 auto &e = set<SPIRCombinedImageSampler>(id, *imgsamp);
11481 e.self = id;
11482 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011483 else if (expression_is_lvalue(rhs) && !pointer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011484 {
11485 // Need a copy.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010011486 // For pointer types, we copy the pointer itself.
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020011487 emit_op(result_type, id, to_unpacked_expression(rhs), false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011488 }
11489 else
11490 {
11491 // RHS expression is immutable, so just forward it.
11492 // Copying these things really make no sense, but
11493 // seems to be allowed anyways.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010011494 auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
11495 if (pointer)
11496 {
11497 auto *var = maybe_get_backing_variable(rhs);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020011498 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010011499 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011500
11501 // If we're copying an access chain, need to inherit the read expressions.
11502 auto *rhs_expr = maybe_get<SPIRExpression>(rhs);
11503 if (rhs_expr)
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020011504 {
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011505 e.implied_read_expressions = rhs_expr->implied_read_expressions;
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020011506 e.expression_dependencies = rhs_expr->expression_dependencies;
11507 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011508 }
11509 break;
11510 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011512 case OpVectorShuffle:
11513 {
11514 uint32_t result_type = ops[0];
11515 uint32_t id = ops[1];
11516 uint32_t vec0 = ops[2];
11517 uint32_t vec1 = ops[3];
11518 const auto *elems = &ops[4];
11519 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011520
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011521 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011522
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010011523 // If we have the undefined swizzle index -1, we need to swizzle in undefined data,
11524 // or in our case, T(0).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011525 bool shuffle = false;
11526 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010011527 if (elems[i] >= type0.vecsize || elems[i] == 0xffffffffu)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011528 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011529
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020011530 // Cannot use swizzles with packed expressions, force shuffle path.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020011531 if (!shuffle && has_extended_decoration(vec0, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020011532 shuffle = true;
11533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011534 string expr;
Bill Hollings1845f312017-12-31 18:55:04 -050011535 bool should_fwd, trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011536
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011537 if (shuffle)
11538 {
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +010011539 should_fwd = should_forward(vec0) && should_forward(vec1);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020011540 trivial_forward = should_suppress_usage_tracking(vec0) && should_suppress_usage_tracking(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011542 // Constructor style and shuffling from two different vectors.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020011543 SmallVector<string> args;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011544 for (uint32_t i = 0; i < length; i++)
11545 {
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010011546 if (elems[i] == 0xffffffffu)
11547 {
11548 // Use a constant 0 here.
11549 // We could use the first component or similar, but then we risk propagating
11550 // a value we might not need, and bog down codegen.
11551 SPIRConstant c;
11552 c.constant_type = type0.parent_type;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020011553 assert(type0.parent_type != ID(0));
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010011554 args.push_back(constant_expression(c));
11555 }
11556 else if (elems[i] >= type0.vecsize)
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020011557 args.push_back(to_extract_component_expression(vec1, elems[i] - type0.vecsize));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011558 else
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020011559 args.push_back(to_extract_component_expression(vec0, elems[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011560 }
11561 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
11562 }
11563 else
11564 {
Bill Hollings1845f312017-12-31 18:55:04 -050011565 should_fwd = should_forward(vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020011566 trivial_forward = should_suppress_usage_tracking(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011567
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011568 // We only source from first vector, so can use swizzle.
Bill Hollingsd8d2da92018-01-05 17:46:56 -050011569 // If the vector is packed, unpack it before applying a swizzle (needed for MSL)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +020011570 expr += to_enclosed_unpacked_expression(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011571 expr += ".";
11572 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010011573 {
11574 assert(elems[i] != 0xffffffffu);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011575 expr += index_to_swizzle(elems[i]);
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010011576 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -050011577
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011578 if (backend.swizzle_is_function && length > 1)
11579 expr += "()";
11580 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011581
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011582 // A shuffle is trivial in that it doesn't actually *do* anything.
11583 // 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 +010011584
Bill Hollings1845f312017-12-31 18:55:04 -050011585 emit_op(result_type, id, expr, should_fwd, trivial_forward);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020011586
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010011587 inherit_expression_dependencies(id, vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020011588 if (vec0 != vec1)
11589 inherit_expression_dependencies(id, vec1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011590 break;
11591 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011592
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011593 // ALU
11594 case OpIsNan:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011595 GLSL_UFOP(isnan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011596 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011597
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011598 case OpIsInf:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011599 GLSL_UFOP(isinf);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011600 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011601
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011602 case OpSNegate:
11603 case OpFNegate:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011604 GLSL_UOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011605 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011606
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011607 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011608 {
11609 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
11610 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011611 GLSL_BOP_CAST(+, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011612 break;
11613 }
11614
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011615 case OpFAdd:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011616 GLSL_BOP(+);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011617 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011618
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011619 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011620 {
11621 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011622 GLSL_BOP_CAST(-, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011623 break;
11624 }
11625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011626 case OpFSub:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011627 GLSL_BOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011628 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011629
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011630 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011631 {
11632 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011633 GLSL_BOP_CAST(*, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011634 break;
11635 }
11636
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010011637 case OpVectorTimesMatrix:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011638 case OpMatrixTimesVector:
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010011639 {
11640 // If the matrix needs transpose, just flip the multiply order.
11641 auto *e = maybe_get<SPIRExpression>(ops[opcode == OpMatrixTimesVector ? 2 : 3]);
11642 if (e && e->need_transpose)
11643 {
11644 e->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020011645 string expr;
11646
11647 if (opcode == OpMatrixTimesVector)
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020011648 expr = join(to_enclosed_unpacked_expression(ops[3]), " * ",
11649 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020011650 else
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020011651 expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
11652 to_enclosed_unpacked_expression(ops[2]));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020011653
11654 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
11655 emit_op(ops[0], ops[1], expr, forward);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010011656 e->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020011657 inherit_expression_dependencies(ops[1], ops[2]);
11658 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010011659 }
11660 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011661 GLSL_BOP(*);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011662 break;
11663 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011664
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020011665 case OpMatrixTimesMatrix:
11666 {
11667 auto *a = maybe_get<SPIRExpression>(ops[2]);
11668 auto *b = maybe_get<SPIRExpression>(ops[3]);
11669
11670 // If both matrices need transpose, we can multiply in flipped order and tag the expression as transposed.
11671 // a^T * b^T = (b * a)^T.
11672 if (a && b && a->need_transpose && b->need_transpose)
11673 {
11674 a->need_transpose = false;
11675 b->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020011676 auto expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
11677 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
11678 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
11679 auto &e = emit_op(ops[0], ops[1], expr, forward);
11680 e.need_transpose = true;
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020011681 a->need_transpose = true;
11682 b->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020011683 inherit_expression_dependencies(ops[1], ops[2]);
11684 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020011685 }
11686 else
11687 GLSL_BOP(*);
11688
11689 break;
11690 }
11691
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011692 case OpFMul:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011693 case OpMatrixTimesScalar:
11694 case OpVectorTimesScalar:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011695 GLSL_BOP(*);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011696 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011697
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011698 case OpOuterProduct:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011699 GLSL_BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011700 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011701
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011702 case OpDot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011703 GLSL_BFOP(dot);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011704 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011705
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011706 case OpTranspose:
rdbbf719942020-11-05 17:09:33 +010011707 if (options.version < 120) // Matches GLSL 1.10 / ESSL 1.00
11708 {
11709 // transpose() is not available, so instead, flip need_transpose,
11710 // which can later be turned into an emulated transpose op by
11711 // convert_row_major_matrix(), if necessary.
11712 uint32_t result_type = ops[0];
11713 uint32_t result_id = ops[1];
11714 uint32_t input = ops[2];
11715
11716 // Force need_transpose to false temporarily to prevent
11717 // to_expression() from doing the transpose.
11718 bool need_transpose = false;
11719 auto *input_e = maybe_get<SPIRExpression>(input);
11720 if (input_e)
11721 swap(need_transpose, input_e->need_transpose);
11722
11723 bool forward = should_forward(input);
11724 auto &e = emit_op(result_type, result_id, to_expression(input), forward);
11725 e.need_transpose = !need_transpose;
11726
11727 // Restore the old need_transpose flag.
11728 if (input_e)
11729 input_e->need_transpose = need_transpose;
11730 }
11731 else
11732 GLSL_UFOP(transpose);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011733 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011734
Jin Zhoue792cd62018-05-22 00:44:34 -040011735 case OpSRem:
Jin Zhou6b144cc2018-05-24 01:17:47 -040011736 {
11737 uint32_t result_type = ops[0];
11738 uint32_t result_id = ops[1];
11739 uint32_t op0 = ops[2];
11740 uint32_t op1 = ops[3];
11741
11742 // Needs special handling.
11743 bool forward = should_forward(op0) && should_forward(op1);
11744 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
11745 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
11746
11747 emit_op(result_type, result_id, expr, forward);
11748 inherit_expression_dependencies(result_id, op0);
11749 inherit_expression_dependencies(result_id, op1);
Jin Zhoue792cd62018-05-22 00:44:34 -040011750 break;
Jin Zhou6b144cc2018-05-24 01:17:47 -040011751 }
Jin Zhoue792cd62018-05-22 00:44:34 -040011752
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011753 case OpSDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011754 GLSL_BOP_CAST(/, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011755 break;
11756
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011757 case OpUDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011758 GLSL_BOP_CAST(/, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011759 break;
11760
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011761 case OpIAddCarry:
11762 case OpISubBorrow:
11763 {
11764 if (options.es && options.version < 310)
11765 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
11766 else if (!options.es && options.version < 400)
11767 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 400.");
11768
11769 uint32_t result_type = ops[0];
11770 uint32_t result_id = ops[1];
11771 uint32_t op0 = ops[2];
11772 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011773 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020011774 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011775 const char *op = opcode == OpIAddCarry ? "uaddCarry" : "usubBorrow";
11776
11777 statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", op, "(", to_expression(op0), ", ",
11778 to_expression(op1), ", ", to_expression(result_id), ".", to_member_name(type, 1), ");");
11779 break;
11780 }
11781
11782 case OpUMulExtended:
11783 case OpSMulExtended:
11784 {
11785 if (options.es && options.version < 310)
11786 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
11787 else if (!options.es && options.version < 400)
11788 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 4000.");
11789
11790 uint32_t result_type = ops[0];
11791 uint32_t result_id = ops[1];
11792 uint32_t op0 = ops[2];
11793 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011794 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020011795 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010011796 const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended";
11797
11798 statement(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(result_id), ".",
11799 to_member_name(type, 1), ", ", to_expression(result_id), ".", to_member_name(type, 0), ");");
11800 break;
11801 }
11802
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011803 case OpFDiv:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011804 GLSL_BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011805 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011806
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011807 case OpShiftRightLogical:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011808 GLSL_BOP_CAST(>>, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011809 break;
11810
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011811 case OpShiftRightArithmetic:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011812 GLSL_BOP_CAST(>>, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011813 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011814
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011815 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020011816 {
11817 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011818 GLSL_BOP_CAST(<<, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011819 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020011820 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011821
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011822 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011823 {
11824 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011825 GLSL_BOP_CAST(|, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011826 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011827 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011828
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011829 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011830 {
11831 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +010011832 GLSL_BOP_CAST(^, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011833 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011834 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011836 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011837 {
11838 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011839 GLSL_BOP_CAST(&, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011840 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011841 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011842
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011843 case OpNot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011844 GLSL_UOP(~);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011845 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011846
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011847 case OpUMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011848 GLSL_BOP_CAST(%, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011849 break;
11850
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011851 case OpSMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011852 GLSL_BOP_CAST(%, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011853 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011854
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011855 case OpFMod:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011856 GLSL_BFOP(mod);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011857 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +020011858
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011859 case OpFRem:
11860 {
11861 if (is_legacy())
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010011862 SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is "
11863 "needed for legacy.");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011864
11865 uint32_t result_type = ops[0];
11866 uint32_t result_id = ops[1];
11867 uint32_t op0 = ops[2];
11868 uint32_t op1 = ops[3];
11869
11870 // Needs special handling.
11871 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010011872 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
11873 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010011874
11875 emit_op(result_type, result_id, expr, forward);
11876 inherit_expression_dependencies(result_id, op0);
11877 inherit_expression_dependencies(result_id, op1);
11878 break;
11879 }
11880
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011881 // Relational
11882 case OpAny:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011883 GLSL_UFOP(any);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011884 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011885
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011886 case OpAll:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011887 GLSL_UFOP(all);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011888 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011889
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011890 case OpSelect:
11891 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
11892 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011893
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011894 case OpLogicalOr:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011895 {
11896 // No vector variant in GLSL for logical OR.
11897 auto result_type = ops[0];
11898 auto id = ops[1];
11899 auto &type = get<SPIRType>(result_type);
11900
11901 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020011902 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011903 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011904 GLSL_BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011905 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011906 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011907
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011908 case OpLogicalAnd:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011909 {
11910 // No vector variant in GLSL for logical AND.
11911 auto result_type = ops[0];
11912 auto id = ops[1];
11913 auto &type = get<SPIRType>(result_type);
11914
11915 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020011916 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011917 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011918 GLSL_BOP(&&);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011919 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011920 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011921
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011922 case OpLogicalNot:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011923 {
11924 auto &type = get<SPIRType>(ops[0]);
11925 if (type.vecsize > 1)
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010011926 GLSL_UFOP(not );
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011927 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011928 GLSL_UOP(!);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011929 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010011930 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011931
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011932 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011933 {
11934 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011935 GLSL_BFOP_CAST(equal, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011936 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011937 GLSL_BOP_CAST(==, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011938 break;
11939 }
11940
11941 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011942 case OpFOrdEqual:
11943 {
11944 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011945 GLSL_BFOP(equal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011946 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011947 GLSL_BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011948 break;
11949 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011950
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011951 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011952 {
11953 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011954 GLSL_BFOP_CAST(notEqual, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011955 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010011956 GLSL_BOP_CAST(!=, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011957 break;
11958 }
11959
11960 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011961 case OpFOrdNotEqual:
Hans-Kristian Arntzen31be74a2022-03-03 11:04:45 +010011962 case OpFUnordNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011963 {
Hans-Kristian Arntzen31be74a2022-03-03 11:04:45 +010011964 // GLSL is fuzzy on what to do with ordered vs unordered not equal.
11965 // glslang started emitting UnorderedNotEqual some time ago to harmonize with IEEE,
11966 // but this means we have no easy way of implementing ordered not equal.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011967 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011968 GLSL_BFOP(notEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011969 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011970 GLSL_BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011971 break;
11972 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011973
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011974 case OpUGreaterThan:
11975 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011976 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011977 auto type = opcode == OpUGreaterThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011978 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011979 GLSL_BFOP_CAST(greaterThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011980 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011981 GLSL_BOP_CAST(>, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011982 break;
11983 }
11984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011985 case OpFOrdGreaterThan:
11986 {
11987 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011988 GLSL_BFOP(greaterThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011989 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011990 GLSL_BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011991 break;
11992 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011993
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011994 case OpUGreaterThanEqual:
11995 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011996 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020011997 auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020011998 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011999 GLSL_BFOP_CAST(greaterThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012000 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012001 GLSL_BOP_CAST(>=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012002 break;
12003 }
12004
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012005 case OpFOrdGreaterThanEqual:
12006 {
12007 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012008 GLSL_BFOP(greaterThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012009 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012010 GLSL_BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012011 break;
12012 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012013
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012014 case OpULessThan:
12015 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012016 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020012017 auto type = opcode == OpULessThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012018 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012019 GLSL_BFOP_CAST(lessThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012020 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012021 GLSL_BOP_CAST(<, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012022 break;
12023 }
12024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012025 case OpFOrdLessThan:
12026 {
12027 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012028 GLSL_BFOP(lessThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012029 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012030 GLSL_BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012031 break;
12032 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012033
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012034 case OpULessThanEqual:
12035 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012036 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020012037 auto type = opcode == OpULessThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012038 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012039 GLSL_BFOP_CAST(lessThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012040 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012041 GLSL_BOP_CAST(<=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020012042 break;
12043 }
12044
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012045 case OpFOrdLessThanEqual:
12046 {
12047 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012048 GLSL_BFOP(lessThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012049 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012050 GLSL_BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012051 break;
12052 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012053
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012054 // Conversion
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020012055 case OpSConvert:
12056 case OpConvertSToF:
12057 case OpUConvert:
12058 case OpConvertUToF:
12059 {
12060 auto input_type = opcode == OpSConvert || opcode == OpConvertSToF ? int_type : uint_type;
12061 uint32_t result_type = ops[0];
12062 uint32_t id = ops[1];
12063
12064 auto &type = get<SPIRType>(result_type);
12065 auto &arg_type = expression_type(ops[2]);
12066 auto func = type_to_glsl_constructor(type);
12067
Hans-Kristian Arntzen4edb99d2019-11-28 13:49:53 +010012068 if (arg_type.width < type.width || type_is_floating_point(type))
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020012069 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), input_type, type.basetype);
12070 else
12071 emit_unary_func_op(result_type, id, ops[2], func.c_str());
12072 break;
12073 }
12074
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012075 case OpConvertFToU:
12076 case OpConvertFToS:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020012077 {
12078 // Cast to expected arithmetic type, then potentially bitcast away to desired signedness.
12079 uint32_t result_type = ops[0];
12080 uint32_t id = ops[1];
12081 auto &type = get<SPIRType>(result_type);
12082 auto expected_type = type;
12083 auto &float_type = expression_type(ops[2]);
12084 expected_type.basetype =
12085 opcode == OpConvertFToS ? to_signed_basetype(type.width) : to_unsigned_basetype(type.width);
12086
12087 auto func = type_to_glsl_constructor(expected_type);
12088 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), float_type.basetype, expected_type.basetype);
12089 break;
12090 }
12091
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012092 case OpFConvert:
12093 {
12094 uint32_t result_type = ops[0];
12095 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012096
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012097 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
12098 emit_unary_func_op(result_type, id, ops[2], func.c_str());
12099 break;
12100 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012102 case OpBitcast:
12103 {
12104 uint32_t result_type = ops[0];
12105 uint32_t id = ops[1];
12106 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012107
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +020012108 if (!emit_complex_bitcast(result_type, id, arg))
12109 {
12110 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
12111 emit_unary_func_op(result_type, id, arg, op.c_str());
12112 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012113 break;
12114 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012115
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020012116 case OpQuantizeToF16:
12117 {
12118 uint32_t result_type = ops[0];
12119 uint32_t id = ops[1];
12120 uint32_t arg = ops[2];
12121
12122 string op;
12123 auto &type = get<SPIRType>(result_type);
12124
12125 switch (type.vecsize)
12126 {
12127 case 1:
12128 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
12129 break;
12130 case 2:
12131 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
12132 break;
12133 case 3:
12134 {
12135 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
12136 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
12137 op = join("vec3(", op0, ", ", op1, ")");
12138 break;
12139 }
12140 case 4:
12141 {
12142 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
12143 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
12144 op = join("vec4(", op0, ", ", op1, ")");
12145 break;
12146 }
12147 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012148 SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020012149 }
12150
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010012151 emit_op(result_type, id, op, should_forward(arg));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010012152 inherit_expression_dependencies(id, arg);
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020012153 break;
12154 }
12155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012156 // Derivatives
12157 case OpDPdx:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012158 GLSL_UFOP(dFdx);
Lubos Lenco80c39412016-09-17 14:33:16 +020012159 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012160 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012161 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012162 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012163
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012164 case OpDPdy:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012165 GLSL_UFOP(dFdy);
Lubos Lenco80c39412016-09-17 14:33:16 +020012166 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012167 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012168 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012169 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012170
Robert Konrad9ec9dd02017-03-24 13:59:19 +010012171 case OpDPdxFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012172 GLSL_UFOP(dFdxFine);
Robert Konradcb637db2017-03-24 15:58:54 +010012173 if (options.es)
12174 {
12175 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
12176 }
12177 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012178 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012179 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010012180 break;
12181
12182 case OpDPdyFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012183 GLSL_UFOP(dFdyFine);
Robert Konradcb637db2017-03-24 15:58:54 +010012184 if (options.es)
12185 {
12186 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
12187 }
12188 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012189 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012190 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010012191 break;
12192
12193 case OpDPdxCoarse:
Robert Konradcb637db2017-03-24 15:58:54 +010012194 if (options.es)
12195 {
12196 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
12197 }
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012198 GLSL_UFOP(dFdxCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010012199 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012200 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012201 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010012202 break;
12203
12204 case OpDPdyCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012205 GLSL_UFOP(dFdyCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010012206 if (options.es)
12207 {
12208 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
12209 }
12210 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012211 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012212 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010012213 break;
12214
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012215 case OpFwidth:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012216 GLSL_UFOP(fwidth);
Lubos Lenco80c39412016-09-17 14:33:16 +020012217 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012218 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012219 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012220 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012221
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010012222 case OpFwidthCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012223 GLSL_UFOP(fwidthCoarse);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010012224 if (options.es)
12225 {
12226 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
12227 }
12228 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012229 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012230 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010012231 break;
12232
12233 case OpFwidthFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012234 GLSL_UFOP(fwidthFine);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010012235 if (options.es)
12236 {
12237 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
12238 }
12239 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012240 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012241 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010012242 break;
12243
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012244 // Bitfield
12245 case OpBitFieldInsert:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020012246 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020012247 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 +020012248 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020012249 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012250
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012251 case OpBitFieldSExtract:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020012252 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020012253 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 +020012254 SPIRType::Int, SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012255 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020012256 }
12257
12258 case OpBitFieldUExtract:
12259 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020012260 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 +020012261 SPIRType::Int, SPIRType::Int);
12262 break;
12263 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012264
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012265 case OpBitReverse:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020012266 // BitReverse does not have issues with sign since result type must match input type.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020012267 GLSL_UFOP(bitfieldReverse);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012268 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012269
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012270 case OpBitCount:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020012271 {
12272 auto basetype = expression_type(ops[2]).basetype;
12273 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "bitCount", basetype, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012274 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020012275 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012276
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012277 // Atomics
12278 case OpAtomicExchange:
12279 {
12280 uint32_t result_type = ops[0];
12281 uint32_t id = ops[1];
12282 uint32_t ptr = ops[2];
12283 // Ignore semantics for now, probably only relevant to CL.
12284 uint32_t val = ops[5];
12285 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012286
12287 emit_atomic_func_op(result_type, id, ptr, val, op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012288 break;
12289 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012290
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012291 case OpAtomicCompareExchange:
12292 {
12293 uint32_t result_type = ops[0];
12294 uint32_t id = ops[1];
12295 uint32_t ptr = ops[2];
12296 uint32_t val = ops[6];
12297 uint32_t comp = ops[7];
12298 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012299
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012300 emit_atomic_func_op(result_type, id, ptr, comp, val, op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012301 break;
12302 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012303
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012304 case OpAtomicLoad:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020012305 {
12306 // In plain GLSL, we have no atomic loads, so emulate this by fetch adding by 0 and hope compiler figures it out.
12307 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
12308 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen8b236f22019-04-24 09:31:44 +020012309 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020012310 bool atomic_image = check_atomic_image(ops[2]);
12311 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
12312 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
12313 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
12314 const char *increment = unsigned_type ? "0u" : "0";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012315 emit_op(ops[0], ops[1],
12316 join(op, "(",
12317 to_non_uniform_aware_expression(ops[2]), ", ", increment, ")"), false);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020012318 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012319 break;
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020012320 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012321
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010012322 case OpAtomicStore:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020012323 {
12324 // In plain GLSL, we have no atomic stores, so emulate this with an atomic exchange where we don't consume the result.
12325 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
12326 uint32_t ptr = ops[0];
12327 // Ignore semantics for now, probably only relevant to CL.
12328 uint32_t val = ops[3];
12329 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012330 statement(op, "(", to_non_uniform_aware_expression(ptr), ", ", to_expression(val), ");");
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020012331 flush_all_atomic_capable_variables();
12332 break;
12333 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012335 case OpAtomicIIncrement:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012336 case OpAtomicIDecrement:
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020012337 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012338 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020012339 auto &type = expression_type(ops[2]);
12340 if (type.storage == StorageClassAtomicCounter)
12341 {
12342 // Legacy GLSL stuff, not sure if this is relevant to support.
12343 if (opcode == OpAtomicIIncrement)
12344 GLSL_UFOP(atomicCounterIncrement);
12345 else
12346 GLSL_UFOP(atomicCounterDecrement);
12347 }
12348 else
12349 {
12350 bool atomic_image = check_atomic_image(ops[2]);
12351 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
12352 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
12353 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
12354
12355 const char *increment = nullptr;
12356 if (opcode == OpAtomicIIncrement && unsigned_type)
12357 increment = "1u";
12358 else if (opcode == OpAtomicIIncrement)
12359 increment = "1";
12360 else if (unsigned_type)
12361 increment = "uint(-1)";
12362 else
12363 increment = "-1";
12364
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012365 emit_op(ops[0], ops[1],
12366 join(op, "(", to_non_uniform_aware_expression(ops[2]), ", ", increment, ")"), false);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020012367 }
12368
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012369 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012370 break;
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020012371 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012372
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012373 case OpAtomicIAdd:
Hans-Kristian Arntzen88e583d2022-05-27 12:12:50 +020012374 case OpAtomicFAddEXT:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012375 {
12376 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012377 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012378 break;
12379 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012380
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012381 case OpAtomicISub:
12382 {
12383 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
12384 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012385 auto expr = join(op, "(", to_non_uniform_aware_expression(ops[2]), ", -", to_enclosed_expression(ops[5]), ")");
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010012386 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012387 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012388 break;
12389 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012390
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012391 case OpAtomicSMin:
12392 case OpAtomicUMin:
12393 {
12394 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012395 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012396 break;
12397 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012398
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012399 case OpAtomicSMax:
12400 case OpAtomicUMax:
12401 {
12402 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012403 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012404 break;
12405 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012406
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012407 case OpAtomicAnd:
12408 {
12409 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012410 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012411 break;
12412 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012413
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012414 case OpAtomicOr:
12415 {
12416 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012417 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012418 break;
12419 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012420
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012421 case OpAtomicXor:
12422 {
12423 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012424 emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012425 break;
12426 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012428 // Geometry shaders
12429 case OpEmitVertex:
12430 statement("EmitVertex();");
12431 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012432
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012433 case OpEndPrimitive:
12434 statement("EndPrimitive();");
12435 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012436
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012437 case OpEmitStreamVertex:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010012438 {
12439 if (options.es)
12440 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
12441 else if (!options.es && options.version < 400)
12442 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
12443
12444 auto stream_expr = to_expression(ops[0]);
12445 if (expression_type(ops[0]).basetype != SPIRType::Int)
12446 stream_expr = join("int(", stream_expr, ")");
12447 statement("EmitStreamVertex(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012448 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010012449 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012450
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012451 case OpEndStreamPrimitive:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010012452 {
12453 if (options.es)
12454 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
12455 else if (!options.es && options.version < 400)
12456 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
12457
12458 auto stream_expr = to_expression(ops[0]);
12459 if (expression_type(ops[0]).basetype != SPIRType::Int)
12460 stream_expr = join("int(", stream_expr, ")");
12461 statement("EndStreamPrimitive(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012462 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010012463 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012464
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012465 // Textures
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012466 case OpImageSampleExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012467 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012468 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012469 case OpImageSampleProjDrefExplicitLod:
Lubos Lenco80c39412016-09-17 14:33:16 +020012470 case OpImageSampleImplicitLod:
12471 case OpImageSampleProjImplicitLod:
12472 case OpImageSampleDrefImplicitLod:
12473 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012474 case OpImageFetch:
12475 case OpImageGather:
12476 case OpImageDrefGather:
12477 // Gets a bit hairy, so move this to a separate instruction.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012478 emit_texture_op(instruction, false);
12479 break;
12480
12481 case OpImageSparseSampleExplicitLod:
12482 case OpImageSparseSampleProjExplicitLod:
12483 case OpImageSparseSampleDrefExplicitLod:
12484 case OpImageSparseSampleProjDrefExplicitLod:
12485 case OpImageSparseSampleImplicitLod:
12486 case OpImageSparseSampleProjImplicitLod:
12487 case OpImageSparseSampleDrefImplicitLod:
12488 case OpImageSparseSampleProjDrefImplicitLod:
12489 case OpImageSparseFetch:
12490 case OpImageSparseGather:
12491 case OpImageSparseDrefGather:
12492 // Gets a bit hairy, so move this to a separate instruction.
12493 emit_texture_op(instruction, true);
12494 break;
12495
12496 case OpImageSparseTexelsResident:
12497 if (options.es)
12498 SPIRV_CROSS_THROW("Sparse feedback is not supported in GLSL.");
12499 require_extension_internal("GL_ARB_sparse_texture2");
Hans-Kristian Arntzen857e1c42020-06-08 11:40:02 +020012500 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "sparseTexelsResidentARB", int_type, SPIRType::Boolean);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012501 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012503 case OpImage:
12504 {
12505 uint32_t result_type = ops[0];
12506 uint32_t id = ops[1];
Hans-Kristian Arntzenaaf397c2018-04-27 11:10:10 +020012507
12508 // Suppress usage tracking.
12509 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012510
12511 // When using the image, we need to know which variable it is actually loaded from.
12512 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012513 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012514 break;
12515 }
12516
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020012517 case OpImageQueryLod:
12518 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012519 const char *op = nullptr;
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020012520 if (!options.es && options.version < 400)
12521 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012522 require_extension_internal("GL_ARB_texture_query_lod");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020012523 // For some reason, the ARB spec is all-caps.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012524 op = "textureQueryLOD";
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020012525 }
12526 else if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012527 SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020012528 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012529 op = "textureQueryLod";
12530
12531 auto sampler_expr = to_expression(ops[2]);
12532 if (has_decoration(ops[2], DecorationNonUniform))
12533 {
12534 if (maybe_get_backing_variable(ops[2]))
12535 convert_non_uniform_expression(sampler_expr, ops[2]);
12536 else if (*backend.nonuniform_qualifier != '\0')
12537 sampler_expr = join(backend.nonuniform_qualifier, "(", sampler_expr, ")");
12538 }
12539
12540 bool forward = should_forward(ops[3]);
12541 emit_op(ops[0], ops[1],
12542 join(op, "(", sampler_expr, ", ", to_unpacked_expression(ops[3]), ")"),
12543 forward);
12544 inherit_expression_dependencies(ops[1], ops[2]);
12545 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012546 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020012547 break;
12548 }
12549
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020012550 case OpImageQueryLevels:
12551 {
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020012552 uint32_t result_type = ops[0];
12553 uint32_t id = ops[1];
12554
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020012555 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012556 require_extension_internal("GL_ARB_texture_query_levels");
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020012557 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012558 SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020012559
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020012560 auto expr = join("textureQueryLevels(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020012561 auto &restype = get<SPIRType>(ops[0]);
12562 expr = bitcast_expression(restype, SPIRType::Int, expr);
12563 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020012564 break;
12565 }
12566
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012567 case OpImageQuerySamples:
12568 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012569 auto &type = expression_type(ops[2]);
12570 uint32_t result_type = ops[0];
12571 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012572
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012573 string expr;
12574 if (type.image.sampled == 2)
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012575 expr = join("imageSamples(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012576 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020012577 expr = join("textureSamples(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012578
12579 auto &restype = get<SPIRType>(ops[0]);
12580 expr = bitcast_expression(restype, SPIRType::Int, expr);
12581 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012582 break;
12583 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012584
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012585 case OpSampledImage:
12586 {
12587 uint32_t result_type = ops[0];
12588 uint32_t id = ops[1];
12589 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020012590 inherit_expression_dependencies(id, ops[2]);
12591 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012592 break;
12593 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +020012594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012595 case OpImageQuerySizeLod:
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012596 {
12597 uint32_t result_type = ops[0];
12598 uint32_t id = ops[1];
rdb10fa5f62020-11-09 15:26:46 +010012599 uint32_t img = ops[2];
Aaron Siegel7b4c4702022-09-15 11:33:09 -070012600 auto &type = expression_type(img);
12601 auto &imgtype = get<SPIRType>(type.self);
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012602
rdb10fa5f62020-11-09 15:26:46 +010012603 std::string fname = "textureSize";
12604 if (is_legacy_desktop())
12605 {
rdb10fa5f62020-11-09 15:26:46 +010012606 fname = legacy_tex_op(fname, imgtype, img);
12607 }
12608 else if (is_legacy_es())
12609 SPIRV_CROSS_THROW("textureSize is not supported in ESSL 100.");
12610
12611 auto expr = join(fname, "(", convert_separate_image_to_expression(img), ", ",
Hans-Kristian Arntzen7e23e692018-04-30 12:46:21 +020012612 bitcast_expression(SPIRType::Int, ops[3]), ")");
Aaron Siegel7b4c4702022-09-15 11:33:09 -070012613
12614 // ES needs to emulate 1D images as 2D.
12615 if (type.image.dim == Dim1D && options.es)
12616 expr = join(expr, ".x");
12617
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012618 auto &restype = get<SPIRType>(ops[0]);
12619 expr = bitcast_expression(restype, SPIRType::Int, expr);
12620 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012621 break;
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012622 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012623
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012624 // Image load/store
12625 case OpImageRead:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012626 case OpImageSparseRead:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012627 {
12628 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
12629 // not adding the proper qualifiers.
12630 // If it turns out we need to read the image after all, remove the qualifier and recompile.
12631 auto *var = maybe_get_backing_variable(ops[2]);
12632 if (var)
12633 {
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020012634 auto &flags = get_decoration_bitset(var->self);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012635 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012636 {
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020012637 unset_decoration(var->self, DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012638 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012639 }
12640 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012641
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012642 uint32_t result_type = ops[0];
12643 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012644
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012645 bool pure;
12646 string imgexpr;
12647 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012648
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020012649 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012650 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012651 if (type.image.ms)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012652 SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012653
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +020012654 auto itr =
12655 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 +010012656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012657 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020012658 {
12659 // For non-PLS inputs, we rely on subpass type remapping information to get it right
12660 // since ImageRead always returns 4-component vectors and the backing type is opaque.
12661 if (!var->remapped_components)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012662 SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012663 imgexpr = remap_swizzle(get<SPIRType>(result_type), var->remapped_components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020012664 }
12665 else
12666 {
12667 // PLS input could have different number of components than what the SPIR expects, swizzle to
12668 // the appropriate vector size.
12669 uint32_t components = pls_format_to_components(itr->format);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012670 imgexpr = remap_swizzle(get<SPIRType>(result_type), components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020012671 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012672 pure = true;
12673 }
12674 else if (type.image.dim == DimSubpassData)
12675 {
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010012676 if (var && subpass_input_is_framebuffer_fetch(var->self))
12677 {
12678 imgexpr = to_expression(var->self);
12679 }
12680 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020012681 {
12682 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012683 if (type.image.ms)
12684 {
12685 uint32_t operands = ops[4];
12686 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020012687 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
12688 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012689
12690 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012691 imgexpr = join("subpassLoad(", to_non_uniform_aware_expression(ops[2]), ", ", to_expression(samples), ")");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012692 }
12693 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012694 imgexpr = join("subpassLoad(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020012695 }
12696 else
12697 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012698 if (type.image.ms)
12699 {
12700 uint32_t operands = ops[4];
12701 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020012702 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
12703 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012704
12705 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012706 imgexpr = join("texelFetch(", to_non_uniform_aware_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012707 to_expression(samples), ")");
12708 }
12709 else
12710 {
12711 // Implement subpass loads via texture barrier style sampling.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012712 imgexpr = join("texelFetch(", to_non_uniform_aware_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012713 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020012714 }
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012715 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012716 pure = true;
12717 }
12718 else
12719 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012720 bool sparse = opcode == OpImageSparseRead;
12721 uint32_t sparse_code_id = 0;
12722 uint32_t sparse_texel_id = 0;
12723 if (sparse)
12724 emit_sparse_feedback_temporaries(ops[0], ops[1], sparse_code_id, sparse_texel_id);
12725
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010012726 // imageLoad only accepts int coords, not uint.
12727 auto coord_expr = to_expression(ops[3]);
12728 auto target_coord_type = expression_type(ops[3]);
12729 target_coord_type.basetype = SPIRType::Int;
12730 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
12731
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +020012732 // ES needs to emulate 1D images as 2D.
12733 if (type.image.dim == Dim1D && options.es)
12734 coord_expr = join("ivec2(", coord_expr, ", 0)");
12735
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012736 // Plain image load/store.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012737 if (sparse)
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012738 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012739 if (type.image.ms)
12740 {
12741 uint32_t operands = ops[4];
12742 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020012743 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
12744 "operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012745
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012746 uint32_t samples = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012747 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_non_uniform_aware_expression(ops[2]), ", ",
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012748 coord_expr, ", ", to_expression(samples), ", ", to_expression(sparse_texel_id), ");");
12749 }
12750 else
12751 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012752 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_non_uniform_aware_expression(ops[2]), ", ",
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012753 coord_expr, ", ", to_expression(sparse_texel_id), ");");
12754 }
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020012755 imgexpr = join(type_to_glsl(get<SPIRType>(result_type)), "(", to_expression(sparse_code_id), ", ",
12756 to_expression(sparse_texel_id), ")");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012757 }
12758 else
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012759 {
12760 if (type.image.ms)
12761 {
12762 uint32_t operands = ops[4];
12763 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020012764 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
12765 "operand mask was used.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012766
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012767 uint32_t samples = ops[5];
12768 imgexpr =
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012769 join("imageLoad(", to_non_uniform_aware_expression(ops[2]), ", ", coord_expr, ", ", to_expression(samples), ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012770 }
12771 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012772 imgexpr = join("imageLoad(", to_non_uniform_aware_expression(ops[2]), ", ", coord_expr, ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020012773 }
12774
12775 if (!sparse)
12776 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012777 pure = false;
12778 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012779
Hans-Kristian Arntzen476b6542022-03-04 11:05:21 +010012780 if (var)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012781 {
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010012782 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
12783 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012784
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012785 // We only need to track dependencies if we're reading from image load/store.
12786 if (!pure)
12787 {
12788 e.loaded_from = var->self;
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010012789 if (forward)
12790 var->dependees.push_back(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012791 }
12792 }
12793 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010012794 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010012795
12796 inherit_expression_dependencies(id, ops[2]);
12797 if (type.image.ms)
12798 inherit_expression_dependencies(id, ops[5]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012799 break;
12800 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012801
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012802 case OpImageTexelPointer:
12803 {
12804 uint32_t result_type = ops[0];
12805 uint32_t id = ops[1];
Mark Satterthwaitec4f97042019-08-26 11:28:13 -040012806
12807 auto coord_expr = to_expression(ops[3]);
12808 auto target_coord_type = expression_type(ops[3]);
12809 target_coord_type.basetype = SPIRType::Int;
12810 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
12811
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010012812 auto expr = join(to_expression(ops[2]), ", ", coord_expr);
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010012813 auto &e = set<SPIRExpression>(id, expr, result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012814
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012815 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012816 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012817 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen6edbf0c2019-10-24 11:30:20 +020012818 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012819 break;
12820 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012821
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012822 case OpImageWrite:
12823 {
12824 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
12825 // not adding the proper qualifiers.
12826 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
12827 auto *var = maybe_get_backing_variable(ops[0]);
12828 if (var)
12829 {
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020012830 if (has_decoration(var->self, DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012831 {
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020012832 unset_decoration(var->self, DecorationNonWritable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012833 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012834 }
12835 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012836
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012837 auto &type = expression_type(ops[0]);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012838 auto &value_type = expression_type(ops[2]);
12839 auto store_type = value_type;
12840 store_type.vecsize = 4;
12841
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010012842 // imageStore only accepts int coords, not uint.
12843 auto coord_expr = to_expression(ops[1]);
12844 auto target_coord_type = expression_type(ops[1]);
12845 target_coord_type.basetype = SPIRType::Int;
12846 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
12847
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +020012848 // ES needs to emulate 1D images as 2D.
12849 if (type.image.dim == Dim1D && options.es)
12850 coord_expr = join("ivec2(", coord_expr, ", 0)");
12851
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012852 if (type.image.ms)
12853 {
12854 uint32_t operands = ops[3];
12855 if (operands != ImageOperandsSampleMask || length != 5)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012856 SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012857 uint32_t samples = ops[4];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012858 statement("imageStore(", to_non_uniform_aware_expression(ops[0]), ", ", coord_expr, ", ", to_expression(samples), ", ",
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010012859 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020012860 }
12861 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012862 statement("imageStore(", to_non_uniform_aware_expression(ops[0]), ", ", coord_expr, ", ",
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020012863 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012864
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012865 if (var && variable_storage_is_aliased(*var))
12866 flush_all_aliased_variables();
12867 break;
12868 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012869
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012870 case OpImageQuerySize:
12871 {
12872 auto &type = expression_type(ops[2]);
12873 uint32_t result_type = ops[0];
12874 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012875
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012876 if (type.basetype == SPIRType::Image)
12877 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012878 string expr;
12879 if (type.image.sampled == 2)
12880 {
rdb10fa5f62020-11-09 15:26:46 +010012881 if (!options.es && options.version < 430)
12882 require_extension_internal("GL_ARB_shader_image_size");
12883 else if (options.es && options.version < 310)
12884 SPIRV_CROSS_THROW("At least ESSL 3.10 required for imageSize.");
12885
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012886 // The size of an image is always constant.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020012887 expr = join("imageSize(", to_non_uniform_aware_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012888 }
12889 else
12890 {
12891 // This path is hit for samplerBuffers and multisampled images which do not have LOD.
rdb10fa5f62020-11-09 15:26:46 +010012892 std::string fname = "textureSize";
12893 if (is_legacy())
12894 {
12895 auto &imgtype = get<SPIRType>(type.self);
12896 fname = legacy_tex_op(fname, imgtype, ops[2]);
12897 }
12898 expr = join(fname, "(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020012899 }
12900
12901 auto &restype = get<SPIRType>(ops[0]);
12902 expr = bitcast_expression(restype, SPIRType::Int, expr);
12903 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012904 }
12905 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010012906 SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012907 break;
12908 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012909
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012910 // Compute
12911 case OpControlBarrier:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012912 case OpMemoryBarrier:
12913 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012914 uint32_t execution_scope = 0;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012915 uint32_t memory;
12916 uint32_t semantics;
12917
12918 if (opcode == OpMemoryBarrier)
12919 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012920 memory = evaluate_constant_u32(ops[0]);
12921 semantics = evaluate_constant_u32(ops[1]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012922 }
12923 else
12924 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012925 execution_scope = evaluate_constant_u32(ops[0]);
12926 memory = evaluate_constant_u32(ops[1]);
12927 semantics = evaluate_constant_u32(ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012928 }
12929
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012930 if (execution_scope == ScopeSubgroup || memory == ScopeSubgroup)
12931 {
crissdb52e272020-10-08 12:14:52 +020012932 // OpControlBarrier with ScopeSubgroup is subgroupBarrier()
12933 if (opcode != OpControlBarrier)
12934 {
12935 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMemBarrier);
12936 }
12937 else
12938 {
12939 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBarrier);
12940 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020012941 }
12942
12943 if (execution_scope != ScopeSubgroup && get_entry_point().model == ExecutionModelTessellationControl)
12944 {
12945 // Control shaders only have barriers, and it implies memory barriers.
12946 if (opcode == OpControlBarrier)
12947 statement("barrier();");
12948 break;
12949 }
12950
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012951 // We only care about these flags, acquire/release and friends are not relevant to GLSL.
12952 semantics = mask_relevant_memory_semantics(semantics);
12953
12954 if (opcode == OpMemoryBarrier)
12955 {
12956 // If we are a memory barrier, and the next instruction is a control barrier, check if that memory barrier
12957 // does what we need, so we avoid redundant barriers.
12958 const Instruction *next = get_next_instruction_in_block(instruction);
12959 if (next && next->op == OpControlBarrier)
12960 {
12961 auto *next_ops = stream(*next);
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012962 uint32_t next_memory = evaluate_constant_u32(next_ops[1]);
12963 uint32_t next_semantics = evaluate_constant_u32(next_ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012964 next_semantics = mask_relevant_memory_semantics(next_semantics);
12965
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010012966 bool memory_scope_covered = false;
12967 if (next_memory == memory)
12968 memory_scope_covered = true;
12969 else if (next_semantics == MemorySemanticsWorkgroupMemoryMask)
12970 {
12971 // If we only care about workgroup memory, either Device or Workgroup scope is fine,
12972 // scope does not have to match.
12973 if ((next_memory == ScopeDevice || next_memory == ScopeWorkgroup) &&
12974 (memory == ScopeDevice || memory == ScopeWorkgroup))
12975 {
12976 memory_scope_covered = true;
12977 }
12978 }
12979 else if (memory == ScopeWorkgroup && next_memory == ScopeDevice)
12980 {
12981 // The control barrier has device scope, but the memory barrier just has workgroup scope.
12982 memory_scope_covered = true;
12983 }
12984
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012985 // If we have the same memory scope, and all memory types are covered, we're good.
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010012986 if (memory_scope_covered && (semantics & next_semantics) == semantics)
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010012987 break;
12988 }
12989 }
12990
12991 // We are synchronizing some memory or syncing execution,
12992 // so we cannot forward any loads beyond the memory barrier.
12993 if (semantics || opcode == OpControlBarrier)
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012994 {
12995 assert(current_emitting_block);
12996 flush_control_dependent_expressions(current_emitting_block->self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012997 flush_all_active_variables();
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010012998 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012999
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010013000 if (memory == ScopeWorkgroup) // Only need to consider memory within a group
13001 {
13002 if (semantics == MemorySemanticsWorkgroupMemoryMask)
Hans-Kristian Arntzen67b29912019-12-04 15:06:19 +010013003 {
13004 // OpControlBarrier implies a memory barrier for shared memory as well.
13005 bool implies_shared_barrier = opcode == OpControlBarrier && execution_scope == ScopeWorkgroup;
13006 if (!implies_shared_barrier)
13007 statement("memoryBarrierShared();");
13008 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010013009 else if (semantics != 0)
13010 statement("groupMemoryBarrier();");
13011 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013012 else if (memory == ScopeSubgroup)
13013 {
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +020013014 const uint32_t all_barriers =
13015 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013016
13017 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
13018 {
13019 // These are not relevant for GLSL, but assume it means memoryBarrier().
13020 // memoryBarrier() does everything, so no need to test anything else.
13021 statement("subgroupMemoryBarrier();");
13022 }
13023 else if ((semantics & all_barriers) == all_barriers)
13024 {
13025 // Short-hand instead of emitting 3 barriers.
13026 statement("subgroupMemoryBarrier();");
13027 }
13028 else
13029 {
13030 // Pick out individual barriers.
13031 if (semantics & MemorySemanticsWorkgroupMemoryMask)
13032 statement("subgroupMemoryBarrierShared();");
13033 if (semantics & MemorySemanticsUniformMemoryMask)
13034 statement("subgroupMemoryBarrierBuffer();");
13035 if (semantics & MemorySemanticsImageMemoryMask)
13036 statement("subgroupMemoryBarrierImage();");
13037 }
13038 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010013039 else
13040 {
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010013041 const uint32_t all_barriers =
13042 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010013043
13044 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
13045 {
13046 // These are not relevant for GLSL, but assume it means memoryBarrier().
13047 // memoryBarrier() does everything, so no need to test anything else.
13048 statement("memoryBarrier();");
13049 }
13050 else if ((semantics & all_barriers) == all_barriers)
13051 {
13052 // Short-hand instead of emitting 4 barriers.
13053 statement("memoryBarrier();");
13054 }
13055 else
13056 {
13057 // Pick out individual barriers.
13058 if (semantics & MemorySemanticsWorkgroupMemoryMask)
13059 statement("memoryBarrierShared();");
13060 if (semantics & MemorySemanticsUniformMemoryMask)
13061 statement("memoryBarrierBuffer();");
13062 if (semantics & MemorySemanticsImageMemoryMask)
13063 statement("memoryBarrierImage();");
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010013064 }
13065 }
13066
13067 if (opcode == OpControlBarrier)
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013068 {
13069 if (execution_scope == ScopeSubgroup)
13070 statement("subgroupBarrier();");
13071 else
13072 statement("barrier();");
13073 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013074 break;
13075 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013076
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013077 case OpExtInst:
13078 {
13079 uint32_t extension_set = ops[2];
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013080 auto ext = get<SPIRExtension>(extension_set).ext;
Lou Kramer6671f522017-11-21 14:04:57 +010013081
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013082 if (ext == SPIRExtension::GLSL)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013083 {
Lou Kramer6671f522017-11-21 14:04:57 +010013084 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
13085 }
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013086 else if (ext == SPIRExtension::SPV_AMD_shader_ballot)
Lou Kramer6671f522017-11-21 14:04:57 +010013087 {
13088 emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
13089 }
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013090 else if (ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
Lou Kramer6671f522017-11-21 14:04:57 +010013091 {
13092 emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
13093 }
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013094 else if (ext == SPIRExtension::SPV_AMD_shader_trinary_minmax)
Lou Kramer6671f522017-11-21 14:04:57 +010013095 {
13096 emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
13097 }
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013098 else if (ext == SPIRExtension::SPV_AMD_gcn_shader)
Lou Kramer6671f522017-11-21 14:04:57 +010013099 {
13100 emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
13101 }
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013102 else if (ext == SPIRExtension::SPV_debug_info)
Lifeng Pan5ca87792019-07-04 16:03:06 +080013103 {
13104 break; // Ignore SPIR-V debug information extended instructions.
13105 }
Hans-Kristian Arntzend2a4f982022-04-19 12:07:54 +020013106 else if (ext == SPIRExtension::NonSemanticDebugPrintf)
13107 {
13108 // Operation 1 is printf.
13109 if (ops[3] == 1)
13110 {
13111 if (!options.vulkan_semantics)
13112 SPIRV_CROSS_THROW("Debug printf is only supported in Vulkan GLSL.\n");
13113 require_extension_internal("GL_EXT_debug_printf");
13114 auto &format_string = get<SPIRString>(ops[4]).str;
13115 string expr = join("debugPrintfEXT(\"", format_string, "\"");
13116 for (uint32_t i = 5; i < length; i++)
13117 {
13118 expr += ", ";
13119 expr += to_expression(ops[i]);
13120 }
13121 statement(expr, ");");
13122 }
13123 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010013124 else
13125 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013126 statement("// unimplemented ext op ", instruction.op);
13127 break;
13128 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013129
Lou Kramer6671f522017-11-21 14:04:57 +010013130 break;
13131 }
13132
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013133 // Legacy sub-group stuff ...
Lou Kramer6671f522017-11-21 14:04:57 +010013134 case OpSubgroupBallotKHR:
13135 {
Lou Kramer6671f522017-11-21 14:04:57 +010013136 uint32_t result_type = ops[0];
13137 uint32_t id = ops[1];
13138 string expr;
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013139 expr = join("uvec4(unpackUint2x32(ballotARB(" + to_expression(ops[2]) + ")), 0u, 0u)");
Hans-Kristian Arntzen4979d102018-03-12 17:51:14 +010013140 emit_op(result_type, id, expr, should_forward(ops[2]));
Lou Kramer6671f522017-11-21 14:04:57 +010013141
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013142 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzenae2680c2018-03-12 17:42:48 +010013143 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013144 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013145 break;
13146 }
13147
13148 case OpSubgroupFirstInvocationKHR:
13149 {
Lou Kramer6671f522017-11-21 14:04:57 +010013150 uint32_t result_type = ops[0];
13151 uint32_t id = ops[1];
13152 emit_unary_func_op(result_type, id, ops[2], "readFirstInvocationARB");
13153
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013154 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013155 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013156 break;
13157 }
13158
13159 case OpSubgroupReadInvocationKHR:
13160 {
Lou Kramer6671f522017-11-21 14:04:57 +010013161 uint32_t result_type = ops[0];
13162 uint32_t id = ops[1];
13163 emit_binary_func_op(result_type, id, ops[2], ops[3], "readInvocationARB");
13164
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013165 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013166 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013167 break;
13168 }
13169
13170 case OpSubgroupAllKHR:
13171 {
Lou Kramer6671f522017-11-21 14:04:57 +010013172 uint32_t result_type = ops[0];
13173 uint32_t id = ops[1];
13174 emit_unary_func_op(result_type, id, ops[2], "allInvocationsARB");
13175
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013176 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013177 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013178 break;
13179 }
13180
13181 case OpSubgroupAnyKHR:
13182 {
Lou Kramer6671f522017-11-21 14:04:57 +010013183 uint32_t result_type = ops[0];
13184 uint32_t id = ops[1];
13185 emit_unary_func_op(result_type, id, ops[2], "anyInvocationARB");
13186
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013187 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013188 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013189 break;
13190 }
13191
13192 case OpSubgroupAllEqualKHR:
13193 {
Lou Kramer6671f522017-11-21 14:04:57 +010013194 uint32_t result_type = ops[0];
13195 uint32_t id = ops[1];
13196 emit_unary_func_op(result_type, id, ops[2], "allInvocationsEqualARB");
13197
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013198 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013199 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013200 break;
13201 }
13202
13203 case OpGroupIAddNonUniformAMD:
13204 case OpGroupFAddNonUniformAMD:
13205 {
Lou Kramer6671f522017-11-21 14:04:57 +010013206 uint32_t result_type = ops[0];
13207 uint32_t id = ops[1];
13208 emit_unary_func_op(result_type, id, ops[4], "addInvocationsNonUniformAMD");
13209
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013210 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013211 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013212 break;
13213 }
13214
13215 case OpGroupFMinNonUniformAMD:
13216 case OpGroupUMinNonUniformAMD:
13217 case OpGroupSMinNonUniformAMD:
13218 {
Lou Kramer6671f522017-11-21 14:04:57 +010013219 uint32_t result_type = ops[0];
13220 uint32_t id = ops[1];
13221 emit_unary_func_op(result_type, id, ops[4], "minInvocationsNonUniformAMD");
13222
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013223 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013224 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013225 break;
13226 }
13227
13228 case OpGroupFMaxNonUniformAMD:
13229 case OpGroupUMaxNonUniformAMD:
13230 case OpGroupSMaxNonUniformAMD:
13231 {
Lou Kramer6671f522017-11-21 14:04:57 +010013232 uint32_t result_type = ops[0];
13233 uint32_t id = ops[1];
13234 emit_unary_func_op(result_type, id, ops[4], "maxInvocationsNonUniformAMD");
13235
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013236 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013237 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010013238 break;
13239 }
13240
13241 case OpFragmentMaskFetchAMD:
13242 {
13243 auto &type = expression_type(ops[2]);
13244 uint32_t result_type = ops[0];
13245 uint32_t id = ops[1];
13246
13247 if (type.image.dim == spv::DimSubpassData)
13248 {
13249 emit_unary_func_op(result_type, id, ops[2], "fragmentMaskFetchAMD");
13250 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010013251 else
Lou Kramer6671f522017-11-21 14:04:57 +010013252 {
13253 emit_binary_func_op(result_type, id, ops[2], ops[3], "fragmentMaskFetchAMD");
13254 }
13255
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013256 require_extension_internal("GL_AMD_shader_fragment_mask");
Lou Kramer6671f522017-11-21 14:04:57 +010013257 break;
13258 }
13259
13260 case OpFragmentFetchAMD:
13261 {
13262 auto &type = expression_type(ops[2]);
13263 uint32_t result_type = ops[0];
13264 uint32_t id = ops[1];
13265
13266 if (type.image.dim == spv::DimSubpassData)
13267 {
13268 emit_binary_func_op(result_type, id, ops[2], ops[4], "fragmentFetchAMD");
13269 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010013270 else
Lou Kramer6671f522017-11-21 14:04:57 +010013271 {
13272 emit_trinary_func_op(result_type, id, ops[2], ops[3], ops[4], "fragmentFetchAMD");
13273 }
13274
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020013275 require_extension_internal("GL_AMD_shader_fragment_mask");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013276 break;
13277 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013278
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013279 // Vulkan 1.1 sub-group stuff ...
13280 case OpGroupNonUniformElect:
13281 case OpGroupNonUniformBroadcast:
13282 case OpGroupNonUniformBroadcastFirst:
13283 case OpGroupNonUniformBallot:
13284 case OpGroupNonUniformInverseBallot:
13285 case OpGroupNonUniformBallotBitExtract:
13286 case OpGroupNonUniformBallotBitCount:
13287 case OpGroupNonUniformBallotFindLSB:
13288 case OpGroupNonUniformBallotFindMSB:
13289 case OpGroupNonUniformShuffle:
13290 case OpGroupNonUniformShuffleXor:
13291 case OpGroupNonUniformShuffleUp:
13292 case OpGroupNonUniformShuffleDown:
13293 case OpGroupNonUniformAll:
13294 case OpGroupNonUniformAny:
13295 case OpGroupNonUniformAllEqual:
13296 case OpGroupNonUniformFAdd:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020013297 case OpGroupNonUniformIAdd:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013298 case OpGroupNonUniformFMul:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020013299 case OpGroupNonUniformIMul:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013300 case OpGroupNonUniformFMin:
13301 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020013302 case OpGroupNonUniformSMin:
13303 case OpGroupNonUniformSMax:
13304 case OpGroupNonUniformUMin:
13305 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013306 case OpGroupNonUniformBitwiseAnd:
13307 case OpGroupNonUniformBitwiseOr:
13308 case OpGroupNonUniformBitwiseXor:
Hans-Kristian Arntzen55700432021-03-08 12:06:46 +010013309 case OpGroupNonUniformLogicalAnd:
13310 case OpGroupNonUniformLogicalOr:
13311 case OpGroupNonUniformLogicalXor:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020013312 case OpGroupNonUniformQuadSwap:
13313 case OpGroupNonUniformQuadBroadcast:
13314 emit_subgroup_op(instruction);
13315 break;
13316
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020013317 case OpFUnordEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020013318 case OpFUnordLessThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020013319 case OpFUnordGreaterThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020013320 case OpFUnordLessThanEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020013321 case OpFUnordGreaterThanEqual:
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020013322 {
13323 // GLSL doesn't specify if floating point comparisons are ordered or unordered,
13324 // but glslang always emits ordered floating point compares for GLSL.
13325 // To get unordered compares, we can test the opposite thing and invert the result.
13326 // This way, we force true when there is any NaN present.
13327 uint32_t op0 = ops[2];
13328 uint32_t op1 = ops[3];
13329
13330 string expr;
13331 if (expression_type(op0).vecsize > 1)
13332 {
13333 const char *comp_op = nullptr;
13334 switch (opcode)
13335 {
13336 case OpFUnordEqual:
13337 comp_op = "notEqual";
13338 break;
13339
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020013340 case OpFUnordLessThan:
13341 comp_op = "greaterThanEqual";
13342 break;
13343
13344 case OpFUnordLessThanEqual:
13345 comp_op = "greaterThan";
13346 break;
13347
13348 case OpFUnordGreaterThan:
13349 comp_op = "lessThanEqual";
13350 break;
13351
13352 case OpFUnordGreaterThanEqual:
13353 comp_op = "lessThan";
13354 break;
13355
13356 default:
13357 assert(0);
13358 break;
13359 }
13360
13361 expr = join("not(", comp_op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), "))");
13362 }
13363 else
13364 {
13365 const char *comp_op = nullptr;
13366 switch (opcode)
13367 {
13368 case OpFUnordEqual:
13369 comp_op = " != ";
13370 break;
13371
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020013372 case OpFUnordLessThan:
13373 comp_op = " >= ";
13374 break;
13375
13376 case OpFUnordLessThanEqual:
13377 comp_op = " > ";
13378 break;
13379
13380 case OpFUnordGreaterThan:
13381 comp_op = " <= ";
13382 break;
13383
13384 case OpFUnordGreaterThanEqual:
13385 comp_op = " < ";
13386 break;
13387
13388 default:
13389 assert(0);
13390 break;
13391 }
13392
13393 expr = join("!(", to_enclosed_unpacked_expression(op0), comp_op, to_enclosed_unpacked_expression(op1), ")");
13394 }
13395
13396 emit_op(ops[0], ops[1], expr, should_forward(op0) && should_forward(op1));
13397 inherit_expression_dependencies(ops[1], op0);
13398 inherit_expression_dependencies(ops[1], op1);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020013399 break;
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020013400 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020013401
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013402 case OpReportIntersectionKHR:
13403 // NV is same opcode.
13404 forced_temporaries.insert(ops[1]);
13405 if (ray_tracing_is_khr)
13406 GLSL_BFOP(reportIntersectionEXT);
13407 else
13408 GLSL_BFOP(reportIntersectionNV);
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020013409 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010013410 break;
13411 case OpIgnoreIntersectionNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013412 // KHR variant is a terminator.
Patrick Moursda39a7b2019-02-26 15:43:03 +010013413 statement("ignoreIntersectionNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020013414 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010013415 break;
13416 case OpTerminateRayNV:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013417 // KHR variant is a terminator.
Patrick Moursda39a7b2019-02-26 15:43:03 +010013418 statement("terminateRayNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020013419 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010013420 break;
13421 case OpTraceNV:
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020013422 statement("traceNV(", to_non_uniform_aware_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
Patrick Moursc96bab02019-03-26 14:04:39 +010013423 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
13424 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
13425 to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020013426 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010013427 break;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013428 case OpTraceRayKHR:
13429 if (!has_decoration(ops[10], DecorationLocation))
13430 SPIRV_CROSS_THROW("A memory declaration object must be used in TraceRayKHR.");
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020013431 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 +010013432 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
13433 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
13434 to_expression(ops[9]), ", ", get_decoration(ops[10], DecorationLocation), ");");
13435 flush_control_dependent_expressions(current_emitting_block->self);
13436 break;
Patrick Moursda39a7b2019-02-26 15:43:03 +010013437 case OpExecuteCallableNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010013438 statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020013439 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010013440 break;
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013441 case OpExecuteCallableKHR:
13442 if (!has_decoration(ops[1], DecorationLocation))
13443 SPIRV_CROSS_THROW("A memory declaration object must be used in ExecuteCallableKHR.");
13444 statement("executeCallableEXT(", to_expression(ops[0]), ", ", get_decoration(ops[1], DecorationLocation), ");");
13445 flush_control_dependent_expressions(current_emitting_block->self);
13446 break;
13447
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013448 // Don't bother forwarding temporaries. Avoids having to test expression invalidation with ray query objects.
13449 case OpRayQueryInitializeKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020013450 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013451 statement("rayQueryInitializeEXT(",
13452 to_expression(ops[0]), ", ", to_expression(ops[1]), ", ",
13453 to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
13454 to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
13455 to_expression(ops[6]), ", ", to_expression(ops[7]), ");");
13456 break;
13457 case OpRayQueryProceedKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020013458 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013459 emit_op(ops[0], ops[1], join("rayQueryProceedEXT(", to_expression(ops[2]), ")"), false);
13460 break;
13461 case OpRayQueryTerminateKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020013462 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013463 statement("rayQueryTerminateEXT(", to_expression(ops[0]), ");");
13464 break;
13465 case OpRayQueryGenerateIntersectionKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020013466 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013467 statement("rayQueryGenerateIntersectionEXT(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
13468 break;
13469 case OpRayQueryConfirmIntersectionKHR:
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020013470 flush_variable_declaration(ops[0]);
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013471 statement("rayQueryConfirmIntersectionEXT(", to_expression(ops[0]), ");");
13472 break;
13473#define GLSL_RAY_QUERY_GET_OP(op) \
13474 case OpRayQueryGet##op##KHR: \
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020013475 flush_variable_declaration(ops[2]); \
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013476 emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ")"), false); \
13477 break
13478#define GLSL_RAY_QUERY_GET_OP2(op) \
13479 case OpRayQueryGet##op##KHR: \
Hans-Kristian Arntzen18f3cd62021-07-20 12:03:07 +020013480 flush_variable_declaration(ops[2]); \
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013481 emit_op(ops[0], ops[1], join("rayQueryGet" #op "EXT(", to_expression(ops[2]), ", ", "bool(", to_expression(ops[3]), "))"), false); \
13482 break
13483 GLSL_RAY_QUERY_GET_OP(RayTMin);
13484 GLSL_RAY_QUERY_GET_OP(RayFlags);
13485 GLSL_RAY_QUERY_GET_OP(WorldRayOrigin);
13486 GLSL_RAY_QUERY_GET_OP(WorldRayDirection);
13487 GLSL_RAY_QUERY_GET_OP(IntersectionCandidateAABBOpaque);
13488 GLSL_RAY_QUERY_GET_OP2(IntersectionType);
13489 GLSL_RAY_QUERY_GET_OP2(IntersectionT);
13490 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceCustomIndex);
13491 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceId);
13492 GLSL_RAY_QUERY_GET_OP2(IntersectionInstanceShaderBindingTableRecordOffset);
13493 GLSL_RAY_QUERY_GET_OP2(IntersectionGeometryIndex);
13494 GLSL_RAY_QUERY_GET_OP2(IntersectionPrimitiveIndex);
13495 GLSL_RAY_QUERY_GET_OP2(IntersectionBarycentrics);
13496 GLSL_RAY_QUERY_GET_OP2(IntersectionFrontFace);
13497 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayDirection);
13498 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectRayOrigin);
13499 GLSL_RAY_QUERY_GET_OP2(IntersectionObjectToWorld);
13500 GLSL_RAY_QUERY_GET_OP2(IntersectionWorldToObject);
13501#undef GLSL_RAY_QUERY_GET_OP
13502#undef GLSL_RAY_QUERY_GET_OP2
13503
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013504 case OpConvertUToAccelerationStructureKHR:
Hans-Kristian Arntzene08e0cf2022-06-17 13:05:08 +020013505 {
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020013506 require_extension_internal("GL_EXT_ray_tracing");
Hans-Kristian Arntzene08e0cf2022-06-17 13:05:08 +020013507
13508 bool elide_temporary = should_forward(ops[2]) && forced_temporaries.count(ops[1]) == 0 &&
13509 !hoisted_temporaries.count(ops[1]);
13510
13511 if (elide_temporary)
13512 {
13513 GLSL_UFOP(accelerationStructureEXT);
13514 }
13515 else
13516 {
13517 // Force this path in subsequent iterations.
13518 forced_temporaries.insert(ops[1]);
13519
13520 // We cannot declare a temporary acceleration structure in GLSL.
13521 // If we get to this point, we'll have to emit a temporary uvec2,
13522 // and cast to RTAS on demand.
13523 statement(declare_temporary(expression_type_id(ops[2]), ops[1]), to_unpacked_expression(ops[2]), ";");
13524 // Use raw SPIRExpression interface to block all usage tracking.
13525 set<SPIRExpression>(ops[1], join("accelerationStructureEXT(", to_name(ops[1]), ")"), ops[0], true);
13526 }
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010013527 break;
Hans-Kristian Arntzene08e0cf2022-06-17 13:05:08 +020013528 }
Patrick Moursda39a7b2019-02-26 15:43:03 +010013529
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013530 case OpConvertUToPtr:
13531 {
13532 auto &type = get<SPIRType>(ops[0]);
13533 if (type.storage != StorageClassPhysicalStorageBufferEXT)
13534 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertUToPtr.");
13535
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +020013536 auto &in_type = expression_type(ops[2]);
13537 if (in_type.vecsize == 2)
13538 require_extension_internal("GL_EXT_buffer_reference_uvec2");
13539
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013540 auto op = type_to_glsl(type);
13541 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
13542 break;
13543 }
13544
13545 case OpConvertPtrToU:
13546 {
13547 auto &type = get<SPIRType>(ops[0]);
13548 auto &ptr_type = expression_type(ops[2]);
13549 if (ptr_type.storage != StorageClassPhysicalStorageBufferEXT)
13550 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertPtrToU.");
13551
Hans-Kristian Arntzenb8f1e712021-09-02 13:11:36 +020013552 if (type.vecsize == 2)
13553 require_extension_internal("GL_EXT_buffer_reference_uvec2");
13554
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013555 auto op = type_to_glsl(type);
13556 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
13557 break;
13558 }
13559
lifpan876627d2019-04-08 19:45:31 +080013560 case OpUndef:
13561 // Undefined value has been declared.
13562 break;
13563
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020013564 case OpLine:
13565 {
13566 emit_line_directive(ops[0], ops[1]);
13567 break;
13568 }
13569
Lifeng Pan5ca87792019-07-04 16:03:06 +080013570 case OpNoLine:
13571 break;
13572
Chip Davis50dce102019-07-13 15:57:33 -050013573 case OpDemoteToHelperInvocationEXT:
13574 if (!options.vulkan_semantics)
13575 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
13576 require_extension_internal("GL_EXT_demote_to_helper_invocation");
13577 statement(backend.demote_literal, ";");
13578 break;
13579
13580 case OpIsHelperInvocationEXT:
13581 if (!options.vulkan_semantics)
13582 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
13583 require_extension_internal("GL_EXT_demote_to_helper_invocation");
Hans-Kristian Arntzen005c14a2022-03-04 10:54:31 +010013584 // Helper lane state with demote is volatile by nature.
13585 // Do not forward this.
Chip Davis12a86542019-07-18 17:32:35 -050013586 emit_op(ops[0], ops[1], "helperInvocationEXT()", false);
Chip Davis50dce102019-07-13 15:57:33 -050013587 break;
13588
Chip Davis2eff4202019-08-04 00:07:20 -050013589 case OpBeginInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020013590 // If the interlock is complex, we emit this elsewhere.
13591 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050013592 {
Erfan Ahmadi43eecb22021-10-19 09:39:55 +033013593 statement("SPIRV_Cross_beginInvocationInterlock();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020013594 flush_all_active_variables();
13595 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050013596 }
13597 break;
13598
13599 case OpEndInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020013600 // If the interlock is complex, we emit this elsewhere.
13601 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050013602 {
Erfan Ahmadi43eecb22021-10-19 09:39:55 +033013603 statement("SPIRV_Cross_endInvocationInterlock();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020013604 flush_all_active_variables();
13605 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050013606 }
13607 break;
13608
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013609 case OpSetMeshOutputsEXT:
13610 statement("SetMeshOutputsEXT(", to_unpacked_expression(ops[0]), ", ", to_unpacked_expression(ops[1]), ");");
13611 break;
13612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013613 default:
13614 statement("// unimplemented op ", instruction.op);
13615 break;
13616 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013617}
13618
Bill Hollingsa759e2c2016-10-19 14:09:51 -070013619// Appends function arguments, mapped from global variables, beyond the specified arg index.
Bill Hollingsfe8b8602016-07-06 16:55:45 -040013620// This is used when a function call uses fewer arguments than the function defines.
Bill Hollingsa759e2c2016-10-19 14:09:51 -070013621// This situation may occur if the function signature has been dynamically modified to
13622// extract global variables referenced from within the function, and convert them to
13623// function arguments. This is necessary for shader languages that do not support global
13624// access to shader input content from within a function (eg. Metal). Each additional
13625// function args uses the name of the global variable. Function nesting will modify the
Bill Hollingsfe3683e2018-01-24 15:38:17 -050013626// functions and function calls all the way up the nesting chain.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020013627void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<string> &arglist)
Bill Hollingsfe8b8602016-07-06 16:55:45 -040013628{
Bill Hollingsac00c602016-10-24 09:24:24 -040013629 auto &args = func.arguments;
Bill Hollings943191a2016-10-27 10:20:01 -040013630 uint32_t arg_cnt = uint32_t(args.size());
Bill Hollingsac00c602016-10-24 09:24:24 -040013631 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010013632 {
Bill Hollingsfe3683e2018-01-24 15:38:17 -050013633 auto &arg = args[arg_idx];
13634 assert(arg.alias_global_variable);
Bill Hollingsfe3683e2018-01-24 15:38:17 -050013635
13636 // If the underlying variable needs to be declared
13637 // (ie. a local variable with deferred declaration), do so now.
13638 uint32_t var_id = get<SPIRVariable>(arg.id).basevariable;
13639 if (var_id)
13640 flush_variable_declaration(var_id);
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +020013641
Chip Davis39dce882019-08-02 15:11:19 -050013642 arglist.push_back(to_func_call_arg(arg, arg.id));
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010013643 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -040013644}
13645
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013646string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
13647{
Hans-Kristian Arntzena0c13e42019-10-07 10:31:42 +020013648 if (type.type_alias != TypeID(0) &&
13649 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
13650 {
13651 return to_member_name(get<SPIRType>(type.type_alias), index);
13652 }
13653
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013654 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013655 if (index < memb.size() && !memb[index].alias.empty())
13656 return memb[index].alias;
13657 else
Hans-Kristian Arntzen1c6df1b2017-07-29 21:44:20 +020013658 return join("_m", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013659}
13660
Chip Davis3bfb2f92018-12-03 02:06:33 -060013661string CompilerGLSL::to_member_reference(uint32_t, const SPIRType &type, uint32_t index, bool)
Chip Davis3a9af962018-09-26 20:06:05 -050013662{
13663 return join(".", to_member_name(type, index));
13664}
13665
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020013666string CompilerGLSL::to_multi_member_reference(const SPIRType &type, const SmallVector<uint32_t> &indices)
13667{
13668 string ret;
13669 auto *member_type = &type;
13670 for (auto &index : indices)
13671 {
13672 ret += join(".", to_member_name(*member_type, index));
13673 member_type = &get<SPIRType>(member_type->member_types[index]);
13674 }
13675 return ret;
13676}
13677
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013678void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
13679{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013680 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013681 if (index < memb.size() && !memb[index].alias.empty())
13682 {
13683 auto &name = memb[index].alias;
13684 if (name.empty())
13685 return;
13686
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020013687 ParsedIR::sanitize_identifier(name, true, true);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013688 update_name_cache(type.member_name_cache, name);
13689 }
13690}
13691
Bill Hollingsb332bae2017-03-01 13:07:40 -050013692// Checks whether the ID is a row_major matrix that requires conversion before use
Bill Hollings13583622016-12-14 02:12:52 -050013693bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020013694{
Bill Hollings13583622016-12-14 02:12:52 -050013695 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010013696 // Legacy targets do not support row major.
13697 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050013698 return false;
13699
Hans-Kristian Arntzen120af422020-10-14 16:07:10 +020013700 auto *e = maybe_get<SPIRExpression>(id);
13701 if (e)
13702 return e->need_transpose;
13703 else
13704 return has_decoration(id, DecorationRowMajor);
Bill Hollings343677e2016-12-11 11:01:08 -050013705}
13706
Bill Hollings13583622016-12-14 02:12:52 -050013707// Checks whether the member is a row_major matrix that requires conversion before use
13708bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index)
Bill Hollings343677e2016-12-11 11:01:08 -050013709{
Bill Hollings13583622016-12-14 02:12:52 -050013710 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010013711 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050013712 return false;
13713
13714 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +010013715 if (!has_member_decoration(type.self, index, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -050013716 return false;
13717
13718 // Only square row-major matrices can be converted at this time.
13719 // Converting non-square matrices will require defining custom GLSL function that
13720 // swaps matrix elements while retaining the original dimensional form of the matrix.
13721 const auto mbr_type = get<SPIRType>(type.member_types[index]);
13722 if (mbr_type.columns != mbr_type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +010013723 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -050013724
13725 return true;
Bill Hollings343677e2016-12-11 11:01:08 -050013726}
13727
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020013728// Checks if we need to remap physical type IDs when declaring the type in a buffer.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020013729bool CompilerGLSL::member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const
Bill Hollingsb332bae2017-03-01 13:07:40 -050013730{
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020013731 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID);
13732}
13733
13734// Checks whether the member is in packed data type, that might need to be unpacked.
13735bool CompilerGLSL::member_is_packed_physical_type(const SPIRType &type, uint32_t index) const
13736{
13737 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
Bill Hollingsb332bae2017-03-01 13:07:40 -050013738}
13739
Bill Hollings13583622016-12-14 02:12:52 -050013740// Wraps the expression string in a function call that converts the
13741// row_major matrix result of the expression to a column_major matrix.
13742// Base implementation uses the standard library transpose() function.
13743// Subclasses may override to use a different function.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020013744string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t /* physical_type_id */,
13745 bool /*is_packed*/)
Bill Hollings343677e2016-12-11 11:01:08 -050013746{
13747 strip_enclosed_expression(exp_str);
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020013748 if (!is_matrix(exp_type))
13749 {
13750 auto column_index = exp_str.find_last_of('[');
13751 if (column_index == string::npos)
13752 return exp_str;
13753
13754 auto column_expr = exp_str.substr(column_index);
13755 exp_str.resize(column_index);
13756
13757 auto transposed_expr = type_to_glsl_constructor(exp_type) + "(";
13758
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020013759 // Loading a column from a row-major matrix. Unroll the load.
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020013760 for (uint32_t c = 0; c < exp_type.vecsize; c++)
13761 {
13762 transposed_expr += join(exp_str, '[', c, ']', column_expr);
13763 if (c + 1 < exp_type.vecsize)
13764 transposed_expr += ", ";
13765 }
13766
13767 transposed_expr += ")";
13768 return transposed_expr;
13769 }
rdbbf719942020-11-05 17:09:33 +010013770 else if (options.version < 120)
13771 {
13772 // GLSL 110, ES 100 do not have transpose(), so emulate it. Note that
13773 // these GLSL versions do not support non-square matrices.
13774 if (exp_type.vecsize == 2 && exp_type.columns == 2)
13775 {
13776 if (!requires_transpose_2x2)
13777 {
13778 requires_transpose_2x2 = true;
13779 force_recompile();
13780 }
13781 }
13782 else if (exp_type.vecsize == 3 && exp_type.columns == 3)
13783 {
13784 if (!requires_transpose_3x3)
13785 {
13786 requires_transpose_3x3 = true;
13787 force_recompile();
13788 }
13789 }
13790 else if (exp_type.vecsize == 4 && exp_type.columns == 4)
13791 {
13792 if (!requires_transpose_4x4)
13793 {
13794 requires_transpose_4x4 = true;
13795 force_recompile();
13796 }
13797 }
13798 else
13799 SPIRV_CROSS_THROW("Non-square matrices are not supported in legacy GLSL, cannot transpose.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010013800 return join("spvTranspose(", exp_str, ")");
rdbbf719942020-11-05 17:09:33 +010013801 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020013802 else
13803 return join("transpose(", exp_str, ")");
Bill Hollings343677e2016-12-11 11:01:08 -050013804}
13805
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020013806string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020013807{
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020013808 string type_name = type_to_glsl(type, id);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +020013809 remap_variable_type_name(type, name, type_name);
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +020013810 return join(type_name, " ", name, type_to_array_glsl(type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020013811}
13812
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020013813bool CompilerGLSL::variable_decl_is_remapped_storage(const SPIRVariable &var, StorageClass storage) const
Hans-Kristian Arntzenf2b5fb32021-03-26 17:23:44 +010013814{
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020013815 return var.storage == storage;
Hans-Kristian Arntzenf2b5fb32021-03-26 17:23:44 +010013816}
13817
Bill Hollings484931d2017-02-28 21:44:36 -050013818// Emit a structure member. Subclasses may override to modify output,
13819// or to dynamically add a padding member if needed.
Bill Hollingsdc694272017-03-11 12:17:22 -050013820void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
msiglreithd096f5c2017-11-27 16:00:56 +010013821 const string &qualifier, uint32_t)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013822{
Bill Hollings484931d2017-02-28 21:44:36 -050013823 auto &membertype = get<SPIRType>(member_type_id);
13824
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013825 Bitset memberflags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013826 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013827 if (index < memb.size())
13828 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013829
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020013830 string qualifiers;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013831 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
13832 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013833
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020013834 if (is_block)
13835 qualifiers = to_interpolation_qualifiers(memberflags);
13836
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013837 statement(layout_for_member(type, index), qualifiers, qualifier, flags_to_qualifiers_glsl(membertype, memberflags),
Bill Hollings484931d2017-02-28 21:44:36 -050013838 variable_decl(membertype, to_member_name(type, index)), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013839}
13840
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +020013841void CompilerGLSL::emit_struct_padding_target(const SPIRType &)
13842{
13843}
13844
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013845string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013846{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013847 // GL_EXT_buffer_reference variables can be marked as restrict.
13848 if (flags.get(DecorationRestrictPointerEXT))
13849 return "restrict ";
13850
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013851 string qual;
13852
Hans-Kristian Arntzenac11a912021-07-26 22:05:55 +020013853 if (type_is_floating_point(type) && flags.get(DecorationNoContraction) && backend.support_precise_qualifier)
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013854 qual = "precise ";
13855
Hans-Kristian Arntzenac11a912021-07-26 22:05:55 +020013856 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
13857 bool type_supports_precision =
13858 type.basetype == SPIRType::Float || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
13859 type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
13860 type.basetype == SPIRType::Sampler;
13861
13862 if (!type_supports_precision)
13863 return qual;
13864
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013865 if (options.es)
13866 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +020013867 auto &execution = get_entry_point();
13868
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013869 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013870 {
13871 bool implied_fmediump = type.basetype == SPIRType::Float &&
13872 options.fragment.default_float_precision == Options::Mediump &&
13873 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013874
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013875 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
13876 options.fragment.default_int_precision == Options::Mediump &&
13877 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013878
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013879 qual += (implied_fmediump || implied_imediump) ? "" : "mediump ";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013880 }
13881 else
13882 {
13883 bool implied_fhighp =
13884 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
13885 execution.model == ExecutionModelFragment) ||
13886 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013887
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013888 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
13889 ((options.fragment.default_int_precision == Options::Highp &&
13890 execution.model == ExecutionModelFragment) ||
13891 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013892
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013893 qual += (implied_fhighp || implied_ihighp) ? "" : "highp ";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013894 }
13895 }
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010013896 else if (backend.allow_precision_qualifiers)
13897 {
13898 // Vulkan GLSL supports precision qualifiers, even in desktop profiles, which is convenient.
13899 // 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 +010013900 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013901 qual += "mediump ";
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010013902 }
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013903
13904 return qual;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013905}
13906
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013907string CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013908{
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013909 auto &type = expression_type(id);
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +020013910 bool use_precision_qualifiers = backend.allow_precision_qualifiers;
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020013911 if (use_precision_qualifiers && (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage))
13912 {
13913 // Force mediump for the sampler type. We cannot declare 16-bit or smaller image types.
13914 auto &result_type = get<SPIRType>(type.image.type);
13915 if (result_type.width < 32)
13916 return "mediump ";
13917 }
13918 return flags_to_qualifiers_glsl(type, ir.meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013919}
13920
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013921void CompilerGLSL::fixup_io_block_patch_primitive_qualifiers(const SPIRVariable &var)
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013922{
13923 // Works around weird behavior in glslangValidator where
13924 // a patch out block is translated to just block members getting the decoration.
13925 // To make glslang not complain when we compile again, we have to transform this back to a case where
13926 // the variable itself has Patch decoration, and not members.
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013927 // Same for perprimitiveEXT.
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013928 auto &type = get<SPIRType>(var.basetype);
13929 if (has_decoration(type.self, DecorationBlock))
13930 {
13931 uint32_t member_count = uint32_t(type.member_types.size());
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013932 Decoration promoted_decoration = {};
13933 bool do_promote_decoration = false;
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013934 for (uint32_t i = 0; i < member_count; i++)
13935 {
13936 if (has_member_decoration(type.self, i, DecorationPatch))
13937 {
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013938 promoted_decoration = DecorationPatch;
13939 do_promote_decoration = true;
13940 break;
13941 }
13942 else if (has_member_decoration(type.self, i, DecorationPerPrimitiveEXT))
13943 {
13944 promoted_decoration = DecorationPerPrimitiveEXT;
13945 do_promote_decoration = true;
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013946 break;
13947 }
13948 }
13949
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013950 if (do_promote_decoration)
13951 {
13952 set_decoration(var.self, promoted_decoration);
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013953 for (uint32_t i = 0; i < member_count; i++)
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013954 unset_member_decoration(type.self, i, promoted_decoration);
13955 }
Hans-Kristian Arntzen175381f2021-01-04 16:48:35 +010013956 }
13957}
13958
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013959string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
13960{
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020013961 auto &flags = get_decoration_bitset(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013962 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013963
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013964 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013965
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013966 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
13967 res += "shared ";
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020013968 else if (var && var->storage == StorageClassTaskPayloadWorkgroupEXT)
13969 res += "taskPayloadSharedEXT ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013970
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020013971 res += to_interpolation_qualifiers(flags);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010013972 if (var)
13973 res += to_storage_qualifiers_glsl(*var);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010013974
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013975 auto &type = expression_type(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013976 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
13977 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013978 if (flags.get(DecorationCoherent))
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020013979 res += "coherent ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013980 if (flags.get(DecorationRestrict))
Hans-Kristian Arntzen11dfcb62017-08-29 15:54:22 +020013981 res += "restrict ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013982
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013983 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013984 res += "readonly ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013985
13986 bool formatted_load = type.image.format == ImageFormatUnknown;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013987 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013988 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013989 res += "writeonly ";
Hans-Kristian Arntzenf93a8fb2021-04-20 13:32:41 +020013990 formatted_load = false;
13991 }
13992
13993 if (formatted_load)
13994 {
13995 if (!options.es)
13996 require_extension_internal("GL_EXT_shader_image_load_formatted");
13997 else
13998 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_image_load_formatted in ESSL.");
13999 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014000 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014001
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020014002 res += to_precision_qualifiers_glsl(id);
14003
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014004 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014005}
14006
14007string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
14008{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014009 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014010 auto &type = expression_type(arg.id);
14011 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014012
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014013 if (type.pointer)
14014 {
14015 if (arg.write_count && arg.read_count)
14016 direction = "inout ";
14017 else if (arg.write_count)
14018 direction = "out ";
14019 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014020
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020014021 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 +010014022}
14023
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020014024string CompilerGLSL::to_initializer_expression(const SPIRVariable &var)
14025{
Bill Hollings974a0812021-10-21 16:11:33 -040014026 return to_unpacked_expression(var.initializer);
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020014027}
14028
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010014029string CompilerGLSL::to_zero_initialized_expression(uint32_t type_id)
14030{
14031#ifndef NDEBUG
14032 auto &type = get<SPIRType>(type_id);
14033 assert(type.storage == StorageClassPrivate || type.storage == StorageClassFunction ||
14034 type.storage == StorageClassGeneric);
14035#endif
14036 uint32_t id = ir.increase_bound_by(1);
14037 ir.make_constant_null(id, type_id, false);
14038 return constant_expression(get<SPIRConstant>(id));
14039}
14040
14041bool CompilerGLSL::type_can_zero_initialize(const SPIRType &type) const
14042{
14043 if (type.pointer)
14044 return false;
14045
14046 if (!type.array.empty() && options.flatten_multidimensional_arrays)
14047 return false;
14048
14049 for (auto &literal : type.array_size_literal)
14050 if (!literal)
14051 return false;
14052
14053 for (auto &memb : type.member_types)
14054 if (!type_can_zero_initialize(get<SPIRType>(memb)))
14055 return false;
14056
14057 return true;
14058}
14059
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014060string CompilerGLSL::variable_decl(const SPIRVariable &variable)
14061{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014062 // Ignore the pointer type since GLSL doesn't have pointers.
Chip Davis3bfb2f92018-12-03 02:06:33 -060014063 auto &type = get_variable_data_type(variable);
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +020014064
Hans-Kristian Arntzen97796e02021-02-26 12:50:24 +010014065 if (type.pointer_depth > 1 && !backend.support_pointer_to_pointer)
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +010014066 SPIRV_CROSS_THROW("Cannot declare pointer-to-pointer types.");
14067
Hans-Kristian Arntzenb0f7dee2017-06-17 10:56:24 +020014068 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 +020014069
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010014070 if (variable.loop_variable && variable.static_expression)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014071 {
14072 uint32_t expr = variable.static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014073 if (ir.ids[expr].get_type() != TypeUndef)
Bill Hollings974a0812021-10-21 16:11:33 -040014074 res += join(" = ", to_unpacked_expression(variable.static_expression));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010014075 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
14076 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014077 }
Hans-Kristian Arntzenc9946292021-04-14 11:27:05 +020014078 else if (variable.initializer && !variable_decl_is_remapped_storage(variable, StorageClassWorkgroup))
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014079 {
14080 uint32_t expr = variable.initializer;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014081 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020014082 res += join(" = ", to_initializer_expression(variable));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010014083 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
14084 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010014085 }
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010014086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014087 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014088}
14089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014090const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014091{
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020014092 auto &flags = get_decoration_bitset(variable.self);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014093 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014094 return "mediump ";
14095 else
14096 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014097}
14098
14099string CompilerGLSL::pls_decl(const PlsRemap &var)
14100{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014101 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014102
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014103 SPIRType type;
14104 type.vecsize = pls_format_to_components(var.format);
14105 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014106
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014107 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
14108 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014109}
14110
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +010014111uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type) const
14112{
14113 return to_array_size_literal(type, uint32_t(type.array.size() - 1));
14114}
14115
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020014116uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t index) const
14117{
14118 assert(type.array.size() == type.array_size_literal.size());
14119
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010014120 if (type.array_size_literal[index])
14121 {
14122 return type.array[index];
14123 }
14124 else
14125 {
14126 // Use the default spec constant value.
14127 // This is the best we can do.
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020014128 return evaluate_constant_u32(type.array[index]);
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010014129 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020014130}
14131
14132string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index)
14133{
14134 assert(type.array.size() == type.array_size_literal.size());
14135
14136 auto &size = type.array[index];
14137 if (!type.array_size_literal[index])
14138 return to_expression(size);
14139 else if (size)
14140 return convert_to_string(size);
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020014141 else if (!backend.unsized_array_supported)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020014142 {
14143 // For runtime-sized arrays, we can work around
14144 // lack of standard support for this by simply having
14145 // a single element array.
14146 //
14147 // Runtime length arrays must always be the last element
14148 // in an interface block.
14149 return "1";
14150 }
14151 else
14152 return "";
14153}
14154
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014155string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
14156{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020014157 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
14158 {
14159 // We are using a wrapped pointer type, and we should not emit any array declarations here.
14160 return "";
14161 }
14162
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020014163 if (type.array.empty())
14164 return "";
14165
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020014166 if (options.flatten_multidimensional_arrays)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014167 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020014168 string res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014169 res += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020014170 for (auto i = uint32_t(type.array.size()); i; i--)
14171 {
14172 res += enclose_expression(to_array_size(type, i - 1));
14173 if (i > 1)
14174 res += " * ";
14175 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014176 res += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020014177 return res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014178 }
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020014179 else
14180 {
14181 if (type.array.size() > 1)
14182 {
14183 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020014184 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020014185 else if (options.es && options.version < 310)
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020014186 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
14187 "Try using --flatten-multidimensional-arrays or set "
14188 "options.flatten_multidimensional_arrays to true.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020014189 }
14190
14191 string res;
14192 for (auto i = uint32_t(type.array.size()); i; i--)
14193 {
14194 res += "[";
14195 res += to_array_size(type, i - 1);
14196 res += "]";
14197 }
14198 return res;
14199 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014200}
14201
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020014202string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014203{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014204 auto &imagetype = get<SPIRType>(type.image.type);
14205 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014207 switch (imagetype.basetype)
14208 {
14209 case SPIRType::Int:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020014210 case SPIRType::Short:
14211 case SPIRType::SByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014212 res = "i";
14213 break;
14214 case SPIRType::UInt:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020014215 case SPIRType::UShort:
14216 case SPIRType::UByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014217 res = "u";
14218 break;
14219 default:
14220 break;
14221 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014222
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020014223 // For half image types, we will force mediump for the sampler, and cast to f16 after any sampling operation.
14224 // We cannot express a true half texture type in GLSL. Neither for short integer formats for that matter.
14225
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020014226 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020014227 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010014228 else if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
14229 subpass_input_is_framebuffer_fetch(id))
14230 {
14231 SPIRType sampled_type = get<SPIRType>(type.image.type);
14232 sampled_type.vecsize = 4;
14233 return type_to_glsl(sampled_type);
14234 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020014235
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014236 // If we're emulating subpassInput with samplers, force sampler2D
14237 // so we don't have to specify format.
14238 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +020014239 {
14240 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
14241 if (type.image.dim == DimBuffer && type.image.sampled == 1)
14242 res += "sampler";
14243 else
14244 res += type.image.sampled == 2 ? "image" : "texture";
14245 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014246 else
14247 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014248
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014249 switch (type.image.dim)
14250 {
14251 case Dim1D:
Hans-Kristian Arntzen1c887302022-05-27 11:51:34 +020014252 // ES doesn't support 1D. Fake it with 2D.
14253 res += options.es ? "2D" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014254 break;
14255 case Dim2D:
14256 res += "2D";
14257 break;
14258 case Dim3D:
14259 res += "3D";
14260 break;
14261 case DimCube:
14262 res += "Cube";
14263 break;
Sidney Justfbb4df32019-01-06 12:21:59 -080014264 case DimRect:
14265 if (options.es)
14266 SPIRV_CROSS_THROW("Rectangle textures are not supported on OpenGL ES.");
14267
14268 if (is_legacy_desktop())
14269 require_extension_internal("GL_ARB_texture_rectangle");
14270
14271 res += "2DRect";
14272 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014273
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014274 case DimBuffer:
14275 if (options.es && options.version < 320)
miomioreimu4407c0d2022-01-10 16:49:45 +080014276 require_extension_internal("GL_EXT_texture_buffer");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014277 else if (!options.es && options.version < 300)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020014278 require_extension_internal("GL_EXT_texture_buffer_object");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014279 res += "Buffer";
14280 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014281
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014282 case DimSubpassData:
14283 res += "2D";
14284 break;
14285 default:
Sidney Justfbb4df32019-01-06 12:21:59 -080014286 SPIRV_CROSS_THROW("Only 1D, 2D, 2DRect, 3D, Buffer, InputTarget and Cube textures supported.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014287 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014288
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020014289 if (type.image.ms)
14290 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014291 if (type.image.arrayed)
Rob Fischer21990632016-09-17 17:01:50 +090014292 {
Lubos Lenco52158642016-09-17 15:56:23 +020014293 if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020014294 require_extension_internal("GL_EXT_texture_array");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014295 res += "Array";
Rob Fischer21990632016-09-17 17:01:50 +090014296 }
Hans-Kristian Arntzena3ae8612018-02-09 12:37:17 +010014297
14298 // "Shadow" state in GLSL only exists for samplers and combined image samplers.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020014299 if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) &&
Bill Hollingsfd252b22021-11-08 15:59:45 -050014300 is_depth_image(type, id))
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020014301 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014302 res += "Shadow";
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020014303 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014304
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014305 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014306}
14307
14308string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
14309{
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020014310 if (backend.use_array_constructor && type.array.size() > 1)
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020014311 {
14312 if (options.flatten_multidimensional_arrays)
crissdb52e272020-10-08 12:14:52 +020014313 SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, "
14314 "e.g. float[][]().");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020014315 else if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020014316 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020014317 else if (options.es && options.version < 310)
14318 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
14319 }
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020014320
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014321 auto e = type_to_glsl(type);
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020014322 if (backend.use_array_constructor)
14323 {
14324 for (uint32_t i = 0; i < type.array.size(); i++)
14325 e += "[]";
14326 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014327 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014328}
14329
Bill Hollingsb41e1482017-05-29 20:45:05 -040014330// The optional id parameter indicates the object whose type we are trying
14331// to find the description for. It is optional. Most type descriptions do not
14332// depend on a specific object's use of that type.
14333string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014334{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020014335 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
14336 {
14337 // Need to create a magic type name which compacts the entire type information.
14338 string name = type_to_glsl(get_pointee_type(type));
14339 for (size_t i = 0; i < type.array.size(); i++)
14340 {
14341 if (type.array_size_literal[i])
14342 name += join(type.array[i], "_");
14343 else
14344 name += join("id", type.array[i], "_");
14345 }
14346 name += "Pointer";
14347 return name;
14348 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014349
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014350 switch (type.basetype)
14351 {
14352 case SPIRType::Struct:
14353 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020014354 if (backend.explicit_struct_type)
14355 return join("struct ", to_name(type.self));
14356 else
14357 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014358
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014359 case SPIRType::Image:
14360 case SPIRType::SampledImage:
Bill Hollingsb41e1482017-05-29 20:45:05 -040014361 return image_type_glsl(type, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014362
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014363 case SPIRType::Sampler:
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +020014364 // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
14365 // this distinction into the type system.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020014366 return comparison_ids.count(id) ? "samplerShadow" : "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014367
Hans-Kristian Arntzen6b0e5582020-04-21 14:25:18 +020014368 case SPIRType::AccelerationStructure:
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010014369 return ray_tracing_is_khr ? "accelerationStructureEXT" : "accelerationStructureNV";
Patrick Moursda39a7b2019-02-26 15:43:03 +010014370
Hans-Kristian Arntzen5b227cc2021-07-19 13:36:37 +020014371 case SPIRType::RayQuery:
14372 return "rayQueryEXT";
14373
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014374 case SPIRType::Void:
14375 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014376
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014377 default:
14378 break;
14379 }
14380
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020014381 if (type.basetype == SPIRType::UInt && is_legacy())
14382 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
14383
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014384 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
14385 {
14386 switch (type.basetype)
14387 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020014388 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014389 return "bool";
Chip Davis117ccf42018-11-01 17:20:07 -050014390 case SPIRType::SByte:
14391 return backend.basic_int8_type;
14392 case SPIRType::UByte:
14393 return backend.basic_uint8_type;
14394 case SPIRType::Short:
14395 return backend.basic_int16_type;
14396 case SPIRType::UShort:
14397 return backend.basic_uint16_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014398 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050014399 return backend.basic_int_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014400 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050014401 return backend.basic_uint_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014402 case SPIRType::AtomicCounter:
14403 return "atomic_uint";
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010014404 case SPIRType::Half:
14405 return "float16_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014406 case SPIRType::Float:
14407 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020014408 case SPIRType::Double:
14409 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020014410 case SPIRType::Int64:
14411 return "int64_t";
14412 case SPIRType::UInt64:
14413 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014414 default:
14415 return "???";
14416 }
14417 }
14418 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
14419 {
14420 switch (type.basetype)
14421 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020014422 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014423 return join("bvec", type.vecsize);
Chip Davis117ccf42018-11-01 17:20:07 -050014424 case SPIRType::SByte:
14425 return join("i8vec", type.vecsize);
14426 case SPIRType::UByte:
14427 return join("u8vec", type.vecsize);
14428 case SPIRType::Short:
14429 return join("i16vec", type.vecsize);
14430 case SPIRType::UShort:
14431 return join("u16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014432 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050014433 return join("ivec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014434 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050014435 return join("uvec", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010014436 case SPIRType::Half:
14437 return join("f16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014438 case SPIRType::Float:
14439 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020014440 case SPIRType::Double:
14441 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020014442 case SPIRType::Int64:
14443 return join("i64vec", type.vecsize);
14444 case SPIRType::UInt64:
14445 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014446 default:
14447 return "???";
14448 }
14449 }
14450 else if (type.vecsize == type.columns) // Simple Matrix builtin
14451 {
14452 switch (type.basetype)
14453 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020014454 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014455 return join("bmat", type.vecsize);
14456 case SPIRType::Int:
14457 return join("imat", type.vecsize);
14458 case SPIRType::UInt:
14459 return join("umat", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010014460 case SPIRType::Half:
14461 return join("f16mat", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014462 case SPIRType::Float:
14463 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020014464 case SPIRType::Double:
14465 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020014466 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014467 default:
14468 return "???";
14469 }
14470 }
14471 else
14472 {
14473 switch (type.basetype)
14474 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020014475 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014476 return join("bmat", type.columns, "x", type.vecsize);
14477 case SPIRType::Int:
14478 return join("imat", type.columns, "x", type.vecsize);
14479 case SPIRType::UInt:
14480 return join("umat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010014481 case SPIRType::Half:
14482 return join("f16mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014483 case SPIRType::Float:
14484 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020014485 case SPIRType::Double:
14486 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020014487 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014488 default:
14489 return "???";
14490 }
14491 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014492}
14493
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010014494void CompilerGLSL::add_variable(unordered_set<string> &variables_primary,
14495 const unordered_set<string> &variables_secondary, string &name)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014496{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014497 if (name.empty())
14498 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014499
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020014500 ParsedIR::sanitize_underscores(name);
14501 if (ParsedIR::is_globally_reserved_identifier(name, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014502 {
14503 name.clear();
14504 return;
14505 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014506
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010014507 update_name_cache(variables_primary, variables_secondary, name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +010014508}
14509
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020014510void CompilerGLSL::add_local_variable_name(uint32_t id)
14511{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010014512 add_variable(local_variable_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020014513}
14514
14515void CompilerGLSL::add_resource_name(uint32_t id)
14516{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010014517 add_variable(resource_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014518}
14519
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +020014520void CompilerGLSL::add_header_line(const std::string &line)
14521{
14522 header_lines.push_back(line);
14523}
14524
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010014525bool CompilerGLSL::has_extension(const std::string &ext) const
14526{
14527 auto itr = find(begin(forced_extensions), end(forced_extensions), ext);
14528 return itr != end(forced_extensions);
14529}
14530
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020014531void CompilerGLSL::require_extension(const std::string &ext)
14532{
14533 if (!has_extension(ext))
14534 forced_extensions.push_back(ext);
14535}
14536
14537void CompilerGLSL::require_extension_internal(const string &ext)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014538{
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010014539 if (backend.supports_extensions && !has_extension(ext))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014540 {
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010014541 forced_extensions.push_back(ext);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014542 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014543 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014544}
14545
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014546void CompilerGLSL::flatten_buffer_block(VariableID id)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080014547{
14548 auto &var = get<SPIRVariable>(id);
14549 auto &type = get<SPIRType>(var.basetype);
14550 auto name = to_name(type.self, false);
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020014551 auto &flags = get_decoration_bitset(type.self);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080014552
14553 if (!type.array.empty())
14554 SPIRV_CROSS_THROW(name + " is an array of UBOs.");
14555 if (type.basetype != SPIRType::Struct)
14556 SPIRV_CROSS_THROW(name + " is not a struct.");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014557 if (!flags.get(DecorationBlock))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080014558 SPIRV_CROSS_THROW(name + " is not a block.");
14559 if (type.member_types.empty())
14560 SPIRV_CROSS_THROW(name + " is an empty struct.");
14561
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080014562 flattened_buffer_blocks.insert(id);
14563}
14564
Lukas Hermanns6673a672019-10-22 11:06:16 -040014565bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) const
14566{
14567 return false; // GLSL itself does not need to translate array builtin types to non-array builtin types
14568}
14569
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014570bool CompilerGLSL::check_atomic_image(uint32_t id)
14571{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014572 auto &type = expression_type(id);
14573 if (type.storage == StorageClassImage)
14574 {
14575 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020014576 require_extension_internal("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014577
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014578 auto *var = maybe_get_backing_variable(id);
14579 if (var)
14580 {
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020014581 if (has_decoration(var->self, DecorationNonWritable) || has_decoration(var->self, DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014582 {
Hans-Kristian Arntzend28136c2022-04-29 13:47:49 +020014583 unset_decoration(var->self, DecorationNonWritable);
14584 unset_decoration(var->self, DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014585 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014586 }
14587 }
14588 return true;
14589 }
14590 else
14591 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014592}
14593
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010014594void CompilerGLSL::add_function_overload(const SPIRFunction &func)
14595{
14596 Hasher hasher;
14597 for (auto &arg : func.arguments)
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010014598 {
14599 // Parameters can vary with pointer type or not,
14600 // but that will not change the signature in GLSL/HLSL,
14601 // so strip the pointer type before hashing.
Chip Davisfc02b3d2019-01-08 12:54:40 -060014602 uint32_t type_id = get_pointee_type_id(arg.type);
Bill Hollingse0910312018-06-24 15:06:12 -040014603 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020014604
14605 if (!combined_image_samplers.empty())
14606 {
14607 // If we have combined image samplers, we cannot really trust the image and sampler arguments
14608 // we pass down to callees, because they may be shuffled around.
14609 // Ignore these arguments, to make sure that functions need to differ in some other way
14610 // to be considered different overloads.
Bill Hollingse0910312018-06-24 15:06:12 -040014611 if (type.basetype == SPIRType::SampledImage ||
14612 (type.basetype == SPIRType::Image && type.image.sampled == 1) || type.basetype == SPIRType::Sampler)
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020014613 {
14614 continue;
14615 }
14616 }
14617
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010014618 hasher.u32(type_id);
14619 }
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010014620 uint64_t types_hash = hasher.get();
14621
14622 auto function_name = to_name(func.self);
14623 auto itr = function_overloads.find(function_name);
14624 if (itr != end(function_overloads))
14625 {
14626 // There exists a function with this name already.
14627 auto &overloads = itr->second;
14628 if (overloads.count(types_hash) != 0)
14629 {
14630 // Overload conflict, assign a new name.
14631 add_resource_name(func.self);
14632 function_overloads[to_name(func.self)].insert(types_hash);
14633 }
14634 else
14635 {
14636 // Can reuse the name.
14637 overloads.insert(types_hash);
14638 }
14639 }
14640 else
14641 {
14642 // First time we see this function name.
14643 add_resource_name(func.self);
14644 function_overloads[to_name(func.self)].insert(types_hash);
14645 }
14646}
14647
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014648void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014649{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014650 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010014651 add_function_overload(func);
14652
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020014653 // Avoid shadow declarations.
14654 local_variable_names = resource_names;
14655
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014656 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014657
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014658 auto &type = get<SPIRType>(func.return_type);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020014659 decl += flags_to_qualifiers_glsl(type, return_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014660 decl += type_to_glsl(type);
Hans-Kristian Arntzen9fa91f72018-02-05 09:34:54 +010014661 decl += type_to_array_glsl(type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014662 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014663
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014664 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014665 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020014666 // If we need complex fallback in GLSL, we just wrap main() in a function
14667 // and interlock the entire shader ...
14668 if (interlocked_is_complex)
14669 decl += "spvMainInterlockedBody";
14670 else
14671 decl += "main";
14672
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014673 processing_entry_point = true;
14674 }
14675 else
Bill Hollings1c180782017-11-05 21:34:42 -050014676 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014677
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014678 decl += "(";
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020014679 SmallVector<string> arglist;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014680 for (auto &arg : func.arguments)
14681 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020014682 // Do not pass in separate images or samplers if we're remapping
14683 // to combined image samplers.
14684 if (skip_argument(arg.id))
14685 continue;
14686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014687 // Might change the variable name if it already exists in this function.
14688 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
14689 // to use same name for variables.
14690 // 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 +020014691 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014692
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020014693 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014694
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014695 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
14696 auto *var = maybe_get<SPIRVariable>(arg.id);
14697 if (var)
14698 var->parameter = &arg;
14699 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014700
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +020014701 for (auto &arg : func.shadow_arguments)
14702 {
14703 // Might change the variable name if it already exists in this function.
14704 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
14705 // to use same name for variables.
14706 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
14707 add_local_variable_name(arg.id);
14708
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020014709 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014710
14711 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
14712 auto *var = maybe_get<SPIRVariable>(arg.id);
14713 if (var)
14714 var->parameter = &arg;
14715 }
14716
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020014717 decl += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014718 decl += ")";
14719 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014720}
14721
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010014722void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014723{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014724 // Avoid potential cycles.
14725 if (func.active)
14726 return;
14727 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014728
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014729 // If we depend on a function, emit that function before we emit our own function.
14730 for (auto block : func.blocks)
14731 {
14732 auto &b = get<SPIRBlock>(block);
14733 for (auto &i : b.ops)
14734 {
14735 auto ops = stream(i);
14736 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014738 if (op == OpFunctionCall)
14739 {
14740 // Recursively emit functions which are called.
14741 uint32_t id = ops[2];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014742 emit_function(get<SPIRFunction>(id), ir.meta[ops[1]].decoration.decoration_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014743 }
14744 }
14745 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014746
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020014747 if (func.entry_line.file_id != 0)
14748 emit_line_directive(func.entry_line.file_id, func.entry_line.line_literal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014749 emit_function_prototype(func, return_flags);
14750 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014751
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020014752 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +020014753 emit_entry_point_declarations();
14754
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014755 current_function = &func;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014756 auto &entry_block = get<SPIRBlock>(func.entry_block);
14757
Hans-Kristian Arntzen30343f32020-02-24 13:22:52 +010014758 sort(begin(func.constant_arrays_needed_on_stack), end(func.constant_arrays_needed_on_stack));
14759 for (auto &array : func.constant_arrays_needed_on_stack)
14760 {
14761 auto &c = get<SPIRConstant>(array);
14762 auto &type = get<SPIRType>(c.constant_type);
14763 statement(variable_decl(type, join("_", array, "_array_copy")), " = ", constant_expression(c), ";");
14764 }
14765
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014766 for (auto &v : func.local_variables)
14767 {
14768 auto &var = get<SPIRVariable>(v);
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020014769 var.deferred_declaration = false;
14770
Hans-Kristian Arntzenae7bb412021-04-06 15:50:02 +020014771 if (variable_decl_is_remapped_storage(var, StorageClassWorkgroup))
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020014772 {
14773 // Special variable type which cannot have initializer,
14774 // need to be declared as standalone variables.
14775 // Comes from MSL which can push global variables as local variables in main function.
14776 add_local_variable_name(var.self);
14777 statement(variable_decl(var), ";");
14778 var.deferred_declaration = false;
14779 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020014780 else if (var.storage == StorageClassPrivate)
14781 {
14782 // These variables will not have had their CFG usage analyzed, so move it to the entry block.
14783 // Comes from MSL which can push global variables as local variables in main function.
14784 // We could just declare them right now, but we would miss out on an important initialization case which is
14785 // LUT declaration in MSL.
14786 // If we don't declare the variable when it is assigned we're forced to go through a helper function
14787 // which copies elements one by one.
14788 add_local_variable_name(var.self);
Hans-Kristian Arntzenf8592ec2020-04-21 11:20:49 +020014789
14790 if (var.initializer)
14791 {
14792 statement(variable_decl(var), ";");
14793 var.deferred_declaration = false;
14794 }
14795 else
14796 {
14797 auto &dominated = entry_block.dominated_variables;
14798 if (find(begin(dominated), end(dominated), var.self) == end(dominated))
14799 entry_block.dominated_variables.push_back(var.self);
14800 var.deferred_declaration = true;
14801 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020014802 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020014803 else if (var.storage == StorageClassFunction && var.remapped_variable && var.static_expression)
14804 {
14805 // No need to declare this variable, it has a static expression.
14806 var.deferred_declaration = false;
14807 }
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020014808 else if (expression_is_lvalue(v))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014809 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020014810 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014811
Hans-Kristian Arntzenf1415212020-06-19 10:51:00 +020014812 // Loop variables should never be declared early, they are explicitly emitted in a loop.
14813 if (var.initializer && !var.loop_variable)
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +010014814 statement(variable_decl_function_local(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014815 else
14816 {
14817 // Don't declare variable until first use to declutter the GLSL output quite a lot.
14818 // If we don't touch the variable before first branch,
14819 // declare it then since we need variable declaration to be in top scope.
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020014820 var.deferred_declaration = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014821 }
14822 }
14823 else
14824 {
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020014825 // 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 +010014826 // For these types (non-lvalue), we enforce forwarding through a shadowed variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014827 // This means that when we OpStore to these variables, we just write in the expression ID directly.
14828 // This breaks any kind of branching, since the variable must be statically assigned.
14829 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
14830 var.statically_assigned = true;
14831 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014832
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014833 var.loop_variable_enable = false;
Hans-Kristian Arntzenb847c882016-11-18 17:06:49 +010014834
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014835 // Loop variables are never declared outside their for-loop, so block any implicit declaration.
14836 if (var.loop_variable)
Hans-Kristian Arntzen40b30532022-04-28 14:36:53 +020014837 {
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014838 var.deferred_declaration = false;
Hans-Kristian Arntzen40b30532022-04-28 14:36:53 +020014839 // Need to reset the static expression so we can fallback to initializer if need be.
14840 var.static_expression = 0;
14841 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014842 }
14843
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020014844 // Enforce declaration order for regression testing purposes.
14845 for (auto &block_id : func.blocks)
14846 {
14847 auto &block = get<SPIRBlock>(block_id);
14848 sort(begin(block.dominated_variables), end(block.dominated_variables));
14849 }
14850
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020014851 for (auto &line : current_function->fixup_hooks_in)
14852 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040014853
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014854 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014855
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014856 end_scope();
14857 processing_entry_point = false;
14858 statement("");
Hans-Kristian Arntzend81bfc52019-06-13 10:31:37 +020014859
14860 // Make sure deferred declaration state for local variables is cleared when we are done with function.
14861 // We risk declaring Private/Workgroup variables in places we are not supposed to otherwise.
14862 for (auto &v : func.local_variables)
14863 {
14864 auto &var = get<SPIRVariable>(v);
14865 var.deferred_declaration = false;
14866 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014867}
14868
14869void CompilerGLSL::emit_fixup()
14870{
Hans-Kristian Arntzen5ea576e2020-09-28 14:09:39 +020014871 if (is_vertex_like_shader())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014872 {
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020014873 if (options.vertex.fixup_clipspace)
14874 {
14875 const char *suffix = backend.float_literal_suffix ? "f" : "";
14876 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
14877 }
14878
14879 if (options.vertex.flip_vert_y)
14880 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014881 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014882}
14883
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014884void CompilerGLSL::flush_phi(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014885{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014886 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014887 if (child.ignore_phi_from_block == from)
14888 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014889
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014890 unordered_set<uint32_t> temporary_phi_variables;
14891
14892 for (auto itr = begin(child.phi_variables); itr != end(child.phi_variables); ++itr)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014893 {
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014894 auto &phi = *itr;
14895
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014896 if (phi.parent == from)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014897 {
14898 auto &var = get<SPIRVariable>(phi.function_variable);
14899
14900 // A Phi variable might be a loop variable, so flush to static expression.
14901 if (var.loop_variable && !var.loop_variable_enable)
14902 var.static_expression = phi.local_variable;
14903 else
14904 {
14905 flush_variable_declaration(phi.function_variable);
14906
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014907 // Check if we are going to write to a Phi variable that another statement will read from
14908 // as part of another Phi node in our target block.
14909 // For this case, we will need to copy phi.function_variable to a temporary, and use that for future reads.
14910 // This is judged to be extremely rare, so deal with it here using a simple, but suboptimal algorithm.
14911 bool need_saved_temporary =
14912 find_if(itr + 1, end(child.phi_variables), [&](const SPIRBlock::Phi &future_phi) -> bool {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014913 return future_phi.local_variable == ID(phi.function_variable) && future_phi.parent == from;
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014914 }) != end(child.phi_variables);
14915
14916 if (need_saved_temporary)
14917 {
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014918 // Need to make sure we declare the phi variable with a copy at the right scope.
14919 // We cannot safely declare a temporary here since we might be inside a continue block.
14920 if (!var.allocate_temporary_copy)
14921 {
14922 var.allocate_temporary_copy = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014923 force_recompile();
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010014924 }
14925 statement("_", phi.function_variable, "_copy", " = ", to_name(phi.function_variable), ";");
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014926 temporary_phi_variables.insert(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014927 }
14928
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014929 // This might be called in continue block, so make sure we
Hans-Kristian Arntzen91753632017-09-25 10:16:45 +020014930 // use this to emit ESSL 1.0 compliant increments/decrements.
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014931 auto lhs = to_expression(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014932
14933 string rhs;
14934 if (temporary_phi_variables.count(phi.local_variable))
14935 rhs = join("_", phi.local_variable, "_copy");
14936 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060014937 rhs = to_pointer_expression(phi.local_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010014938
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020014939 if (!optimize_read_modify_write(get<SPIRType>(var.basetype), lhs, rhs))
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014940 statement(lhs, " = ", rhs, ";");
14941 }
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010014942
14943 register_write(phi.function_variable);
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020014944 }
14945 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014946}
14947
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014948void CompilerGLSL::branch_to_continue(BlockID from, BlockID to)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014949{
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014950 auto &to_block = get<SPIRBlock>(to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010014951 if (from == to)
14952 return;
14953
14954 assert(is_continue(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014955 if (to_block.complex_continue)
14956 {
14957 // Just emit the whole block chain as is.
14958 auto usage_counts = expression_usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014959
14960 emit_block_chain(to_block);
14961
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020014962 // Expression usage counts are moot after returning from the continue block.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014963 expression_usage_counts = usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014964 }
14965 else
14966 {
14967 auto &from_block = get<SPIRBlock>(from);
14968 bool outside_control_flow = false;
14969 uint32_t loop_dominator = 0;
14970
14971 // FIXME: Refactor this to not use the old loop_dominator tracking.
14972 if (from_block.merge_block)
14973 {
14974 // If we are a loop header, we don't set the loop dominator,
14975 // so just use "self" here.
14976 loop_dominator = from;
14977 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014978 else if (from_block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014979 {
14980 loop_dominator = from_block.loop_dominator;
14981 }
14982
14983 if (loop_dominator != 0)
14984 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014985 auto &cfg = get_cfg_for_current_function();
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014986
14987 // For non-complex continue blocks, we implicitly branch to the continue block
14988 // by having the continue block be part of the loop header in for (; ; continue-block).
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014989 outside_control_flow = cfg.node_terminates_control_flow_in_sub_graph(loop_dominator, from);
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014990 }
14991
14992 // Some simplification for for-loops. We always end up with a useless continue;
14993 // statement since we branch to a loop block.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020014994 // 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 +010014995 // we can avoid writing out an explicit continue statement.
14996 // Similar optimization to return statements if we know we're outside flow control.
14997 if (!outside_control_flow)
14998 statement("continue;");
14999 }
15000}
15001
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015002void CompilerGLSL::branch(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015003{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015004 flush_phi(from, to);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010015005 flush_control_dependent_expressions(from);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015006
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020015007 bool to_is_continue = is_continue(to);
15008
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015009 // This is only a continue if we branch to our loop dominator.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020015010 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 +020015011 {
15012 // This can happen if we had a complex continue block which was emitted.
15013 // Once the continue block tries to branch to the loop header, just emit continue;
15014 // and end the chain here.
15015 statement("continue;");
15016 }
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010015017 else if (from != to && is_break(to))
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015018 {
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010015019 // We cannot break to ourselves, so check explicitly for from != to.
15020 // This case can trigger if a loop header is all three of these things:
15021 // - Continue block
15022 // - Loop header
15023 // - Break merge target all at once ...
15024
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015025 // Very dirty workaround.
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +020015026 // Switch constructs are able to break, but they cannot break out of a loop at the same time,
15027 // yet SPIR-V allows it.
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015028 // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block,
15029 // write to the ladder here, and defer the break.
15030 // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case.
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +020015031 if (is_loop_break(to))
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015032 {
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +020015033 for (size_t n = current_emitting_switch_stack.size(); n; n--)
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015034 {
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +020015035 auto *current_emitting_switch = current_emitting_switch_stack[n - 1];
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015036
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +020015037 if (current_emitting_switch &&
15038 current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) &&
15039 get<SPIRBlock>(current_emitting_switch->loop_dominator).merge_block == to)
15040 {
15041 if (!current_emitting_switch->need_ladder_break)
15042 {
15043 force_recompile();
15044 current_emitting_switch->need_ladder_break = true;
15045 }
15046
15047 statement("_", current_emitting_switch->self, "_ladder_break = true;");
15048 }
15049 else
15050 break;
15051 }
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015052 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015053 statement("break;");
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015054 }
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020015055 else if (to_is_continue || from == to)
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010015056 {
15057 // For from == to case can happen for a do-while loop which branches into itself.
15058 // We don't mark these cases as continue blocks, but the only possible way to branch into
15059 // ourselves is through means of continue blocks.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020015060
15061 // If we are merging to a continue block, there is no need to emit the block chain for continue here.
15062 // We can branch to the continue block after we merge execution.
15063
15064 // Here we make use of structured control flow rules from spec:
15065 // 2.11: - the merge block declared by a header block cannot be a merge block declared by any other header block
15066 // - each header block must strictly dominate its merge block, unless the merge block is unreachable in the CFG
15067 // If we are branching to a merge block, we must be inside a construct which dominates the merge block.
15068 auto &block_meta = ir.block_meta[to];
15069 bool branching_to_merge =
15070 (block_meta & (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT |
15071 ParsedIR::BLOCK_META_LOOP_MERGE_BIT)) != 0;
15072 if (!to_is_continue || !branching_to_merge)
15073 branch_to_continue(from, to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010015074 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015075 else if (!is_conditional(to))
15076 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015077
15078 // It is important that we check for break before continue.
15079 // A block might serve two purposes, a break block for the inner scope, and
15080 // a continue block in the outer scope.
15081 // Inner scope always takes precedence.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015082}
15083
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015084void CompilerGLSL::branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015085{
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020015086 auto &from_block = get<SPIRBlock>(from);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015087 BlockID merge_block = from_block.merge == SPIRBlock::MergeSelection ? from_block.next_block : BlockID(0);
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020015088
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020015089 // If we branch directly to our selection merge target, we don't need a code path.
15090 bool true_block_needs_code = true_block != merge_block || flush_phi_required(from, true_block);
15091 bool false_block_needs_code = false_block != merge_block || flush_phi_required(from, false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015092
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020015093 if (!true_block_needs_code && !false_block_needs_code)
15094 return;
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020015095
Hans-Kristian Arntzen449f68e2021-06-03 12:19:10 +020015096 // We might have a loop merge here. Only consider selection flattening constructs.
15097 // Loop hints are handled explicitly elsewhere.
15098 if (from_block.hint == SPIRBlock::HintFlatten || from_block.hint == SPIRBlock::HintDontFlatten)
15099 emit_block_hints(from_block);
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020015100
15101 if (true_block_needs_code)
Hans-Kristian Arntzen54cc0b02020-09-17 12:02:43 +020015102 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015103 statement("if (", to_expression(cond), ")");
15104 begin_scope();
15105 branch(from, true_block);
15106 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015107
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020015108 if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015109 {
15110 statement("else");
15111 begin_scope();
15112 branch(from, false_block);
15113 end_scope();
15114 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015115 }
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020015116 else if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015117 {
15118 // Only need false path, use negative conditional.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010015119 statement("if (!", to_enclosed_expression(cond), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015120 begin_scope();
15121 branch(from, false_block);
15122 end_scope();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015123 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015124}
15125
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015126// FIXME: This currently cannot handle complex continue blocks
15127// as in do-while.
15128// This should be seen as a "trivial" continue block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015129string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015130{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015131 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015132
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015133 // While emitting the continue block, declare_temporary will check this
15134 // if we have to emit temporaries.
15135 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015136
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020015137 SmallVector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015138
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015139 // Capture all statements into our list.
15140 auto *old = redirect_statement;
15141 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015142
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015143 // Stamp out all blocks one after each other.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020015144 while ((ir.block_meta[block->self] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) == 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015145 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015146 // Write out all instructions we have in this block.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020015147 emit_block_instructions(*block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015149 // For plain branchless for/while continue blocks.
15150 if (block->next_block)
15151 {
15152 flush_phi(continue_block, block->next_block);
15153 block = &get<SPIRBlock>(block->next_block);
15154 }
15155 // For do while blocks. The last block will be a select block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015156 else if (block->true_block && follow_true_block)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015157 {
15158 flush_phi(continue_block, block->true_block);
15159 block = &get<SPIRBlock>(block->true_block);
15160 }
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015161 else if (block->false_block && follow_false_block)
15162 {
15163 flush_phi(continue_block, block->false_block);
15164 block = &get<SPIRBlock>(block->false_block);
15165 }
15166 else
15167 {
15168 SPIRV_CROSS_THROW("Invalid continue block detected!");
15169 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015170 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015171
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015172 // Restore old pointer.
15173 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015174
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015175 // Somewhat ugly, strip off the last ';' since we use ',' instead.
15176 // Ideally, we should select this behavior in statement().
15177 for (auto &s : statements)
15178 {
15179 if (!s.empty() && s.back() == ';')
Corentin Wallezef9ee492016-10-05 13:01:31 -040015180 s.erase(s.size() - 1, 1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015181 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015182
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015183 current_continue_block = nullptr;
15184 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015185}
15186
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020015187void CompilerGLSL::emit_while_loop_initializers(const SPIRBlock &block)
15188{
15189 // While loops do not take initializers, so declare all of them outside.
15190 for (auto &loop_var : block.loop_variables)
15191 {
15192 auto &var = get<SPIRVariable>(loop_var);
15193 statement(variable_decl(var), ";");
15194 }
15195}
15196
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015197string CompilerGLSL::emit_for_loop_initializers(const SPIRBlock &block)
15198{
15199 if (block.loop_variables.empty())
15200 return "";
15201
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010015202 bool same_types = for_loop_initializers_are_same_type(block);
15203 // We can only declare for loop initializers if all variables are of same type.
15204 // If we cannot do this, declare individual variables before the loop header.
15205
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010015206 // We might have a loop variable candidate which was not assigned to for some reason.
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015207 uint32_t missing_initializers = 0;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010015208 for (auto &variable : block.loop_variables)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015209 {
15210 uint32_t expr = get<SPIRVariable>(variable).static_expression;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010015211
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015212 // Sometimes loop variables are initialized with OpUndef, but we can just declare
15213 // a plain variable without initializer in this case.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020015214 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015215 missing_initializers++;
15216 }
15217
15218 if (block.loop_variables.size() == 1 && missing_initializers == 0)
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015219 {
15220 return variable_decl(get<SPIRVariable>(block.loop_variables.front()));
15221 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015222 else if (!same_types || missing_initializers == uint32_t(block.loop_variables.size()))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010015223 {
15224 for (auto &loop_var : block.loop_variables)
15225 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
15226 return "";
15227 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015228 else
15229 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015230 // We have a mix of loop variables, either ones with a clear initializer, or ones without.
15231 // Separate the two streams.
15232 string expr;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015233
15234 for (auto &loop_var : block.loop_variables)
15235 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015236 uint32_t static_expr = get<SPIRVariable>(loop_var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020015237 if (static_expr == 0 || ir.ids[static_expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015238 {
15239 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
15240 }
15241 else
15242 {
Chip Davis3bfb2f92018-12-03 02:06:33 -060015243 auto &var = get<SPIRVariable>(loop_var);
15244 auto &type = get_variable_data_type(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015245 if (expr.empty())
15246 {
15247 // For loop initializers are of the form <type id = value, id = value, id = value, etc ...
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015248 expr = join(to_qualifiers_glsl(var.self), type_to_glsl(type), " ");
15249 }
15250 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060015251 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015252 expr += ", ";
Chip Davis3bfb2f92018-12-03 02:06:33 -060015253 // In MSL, being based on C++, the asterisk marking a pointer
15254 // binds to the identifier, not the type.
15255 if (type.pointer)
15256 expr += "* ";
15257 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015258
Chip Davis3bfb2f92018-12-03 02:06:33 -060015259 expr += join(to_name(loop_var), " = ", to_pointer_expression(var.static_expression));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015260 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015261 }
15262 return expr;
15263 }
15264}
15265
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010015266bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
15267{
15268 if (block.loop_variables.size() <= 1)
15269 return true;
15270
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015271 uint32_t expected = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010015272 Bitset expected_flags;
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010015273 for (auto &var : block.loop_variables)
15274 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015275 // Don't care about uninitialized variables as they will not be part of the initializers.
15276 uint32_t expr = get<SPIRVariable>(var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020015277 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015278 continue;
15279
15280 if (expected == 0)
15281 {
15282 expected = get<SPIRVariable>(var).basetype;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010015283 expected_flags = get_decoration_bitset(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010015284 }
15285 else if (expected != get<SPIRVariable>(var).basetype)
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010015286 return false;
15287
15288 // Precision flags and things like that must also match.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010015289 if (expected_flags != get_decoration_bitset(var))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010015290 return false;
15291 }
15292
15293 return true;
15294}
15295
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015296bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
15297{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015298 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015299
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015300 if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015301 {
15302 uint32_t current_count = statement_count;
15303 // If we're trying to create a true for loop,
15304 // we need to make sure that all opcodes before branch statement do not actually emit any code.
15305 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020015306 emit_block_instructions(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015307
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015308 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015309
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015310 // This can work! We only did trivial things which could be forwarded in block body!
15311 if (current_count == statement_count && condition_is_temporary)
15312 {
15313 switch (continue_type)
15314 {
15315 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010015316 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010015317 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
15318 flush_undeclared_variables(block);
15319
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010015320 // Important that we do this in this order because
15321 // emitting the continue block can invalidate the condition expression.
15322 auto initializer = emit_for_loop_initializers(block);
15323 auto condition = to_expression(block.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015324
15325 // Condition might have to be inverted.
15326 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
15327 condition = join("!", enclose_expression(condition));
15328
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020015329 emit_block_hints(block);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015330 if (method != SPIRBlock::MergeToSelectContinueForLoop)
15331 {
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015332 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015333 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
15334 }
15335 else
15336 statement("for (", initializer, "; ", condition, "; )");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015337 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010015338 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015339
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015340 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015341 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010015342 // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
15343 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020015344 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015345 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015346
15347 auto condition = to_expression(block.condition);
15348 // Condition might have to be inverted.
15349 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
15350 condition = join("!", enclose_expression(condition));
15351
15352 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015353 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015354 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015355
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015356 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020015357 block.disable_block_optimization = true;
15358 force_recompile();
15359 begin_scope(); // We'll see an end_scope() later.
15360 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015361 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015362
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015363 begin_scope();
15364 return true;
15365 }
15366 else
15367 {
15368 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015369 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015370 begin_scope(); // We'll see an end_scope() later.
15371 return false;
15372 }
15373 }
15374 else if (method == SPIRBlock::MergeToDirectForLoop)
15375 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015376 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015377
Hans-Kristian Arntzen5ff11cc2016-11-18 16:45:11 +010015378 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
15379 flush_undeclared_variables(child);
15380
15381 uint32_t current_count = statement_count;
15382
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015383 // If we're trying to create a true for loop,
15384 // we need to make sure that all opcodes before branch statement do not actually emit any code.
15385 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020015386 emit_block_instructions(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015387
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015388 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015390 if (current_count == statement_count && condition_is_temporary)
15391 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015392 uint32_t target_block = child.true_block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015393
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015394 switch (continue_type)
15395 {
15396 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010015397 {
15398 // Important that we do this in this order because
15399 // emitting the continue block can invalidate the condition expression.
15400 auto initializer = emit_for_loop_initializers(block);
15401 auto condition = to_expression(child.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015402
15403 // Condition might have to be inverted.
15404 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
15405 {
15406 condition = join("!", enclose_expression(condition));
15407 target_block = child.false_block;
15408 }
15409
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010015410 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015411 emit_block_hints(block);
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010015412 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015413 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010015414 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015415
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015416 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015417 {
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020015418 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020015419 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015420
15421 auto condition = to_expression(child.condition);
15422 // Condition might have to be inverted.
15423 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
15424 {
15425 condition = join("!", enclose_expression(condition));
15426 target_block = child.false_block;
15427 }
15428
15429 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015430 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015431 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015432
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015433 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020015434 block.disable_block_optimization = true;
15435 force_recompile();
15436 begin_scope(); // We'll see an end_scope() later.
15437 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015438 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015440 begin_scope();
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015441 branch(child.self, target_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015442 return true;
15443 }
15444 else
15445 {
15446 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020015447 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015448 begin_scope(); // We'll see an end_scope() later.
15449 return false;
15450 }
15451 }
15452 else
15453 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015454}
15455
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010015456void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015457{
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010015458 for (auto &v : block.dominated_variables)
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010015459 flush_variable_declaration(v);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015460}
15461
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015462void CompilerGLSL::emit_hoisted_temporaries(SmallVector<pair<TypeID, ID>> &temporaries)
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015463{
15464 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
15465 // Need to sort these to ensure that reference output is stable.
15466 sort(begin(temporaries), end(temporaries),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020015467 [](const pair<TypeID, ID> &a, const pair<TypeID, ID> &b) { return a.second < b.second; });
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015468
15469 for (auto &tmp : temporaries)
15470 {
Hans-Kristian Arntzen339e61a2022-02-16 11:36:38 +010015471 auto &type = get<SPIRType>(tmp.first);
15472
15473 // There are some rare scenarios where we are asked to declare pointer types as hoisted temporaries.
15474 // This should be ignored unless we're doing actual variable pointers and backend supports it.
15475 // Access chains cannot normally be lowered to temporaries in GLSL and HLSL.
15476 if (type.pointer && !backend.native_pointers)
15477 continue;
15478
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015479 add_local_variable_name(tmp.second);
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020015480 auto &flags = get_decoration_bitset(tmp.second);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010015481
15482 // Not all targets support pointer literals, so don't bother with that case.
15483 string initializer;
15484 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
15485 initializer = join(" = ", to_zero_initialized_expression(tmp.first));
15486
15487 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), initializer, ";");
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015488
15489 hoisted_temporaries.insert(tmp.second);
15490 forced_temporaries.insert(tmp.second);
15491
15492 // The temporary might be read from before it's assigned, set up the expression now.
15493 set<SPIRExpression>(tmp.second, to_name(tmp.second), tmp.first, true);
Hans-Kristian Arntzen7a6c2da2022-04-29 13:49:02 +020015494
15495 // If we have hoisted temporaries in multi-precision contexts, emit that here too ...
15496 // We will not be able to analyze hoisted-ness for dependent temporaries that we hallucinate here.
15497 auto mirrored_precision_itr = temporary_to_mirror_precision_alias.find(tmp.second);
15498 if (mirrored_precision_itr != temporary_to_mirror_precision_alias.end())
15499 {
15500 uint32_t mirror_id = mirrored_precision_itr->second;
15501 auto &mirror_flags = get_decoration_bitset(mirror_id);
15502 statement(flags_to_qualifiers_glsl(type, mirror_flags),
15503 variable_decl(type, to_name(mirror_id)),
15504 initializer, ";");
15505 // The temporary might be read from before it's assigned, set up the expression now.
15506 set<SPIRExpression>(mirror_id, to_name(mirror_id), tmp.first, true);
15507 hoisted_temporaries.insert(mirror_id);
15508 }
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015509 }
15510}
15511
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015512void CompilerGLSL::emit_block_chain(SPIRBlock &block)
15513{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015514 bool select_branch_to_true_block = false;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015515 bool select_branch_to_false_block = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015516 bool skip_direct_branch = false;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010015517 bool emitted_loop_header_variables = false;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015518 bool force_complex_continue_block = false;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020015519 ValueSaver<uint32_t> loop_level_saver(current_loop_level);
15520
15521 if (block.merge == SPIRBlock::MergeLoop)
15522 add_loop_level();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015523
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015524 emit_hoisted_temporaries(block.declare_temporary);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015525
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015526 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
15527 if (block.continue_block)
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010015528 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015529 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010015530 // If we know we cannot emit a loop, mark the block early as a complex loop so we don't force unnecessary recompiles.
15531 if (continue_type == SPIRBlock::ComplexLoop)
15532 block.complex_continue = true;
15533 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015534
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010015535 // If we have loop variables, stop masking out access to the variable now.
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020015536 for (auto var_id : block.loop_variables)
15537 {
15538 auto &var = get<SPIRVariable>(var_id);
15539 var.loop_variable_enable = true;
15540 // We're not going to declare the variable directly, so emit a copy here.
15541 emit_variable_temporary_copies(var);
15542 }
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010015543
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020015544 // Remember deferred declaration state. We will restore it before returning.
15545 SmallVector<bool, 64> rearm_dominated_variables(block.dominated_variables.size());
15546 for (size_t i = 0; i < block.dominated_variables.size(); i++)
15547 {
15548 uint32_t var_id = block.dominated_variables[i];
15549 auto &var = get<SPIRVariable>(var_id);
15550 rearm_dominated_variables[i] = var.deferred_declaration;
15551 }
15552
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015553 // This is the method often used by spirv-opt to implement loops.
15554 // The loop header goes straight into the continue block.
15555 // However, don't attempt this on ESSL 1.0, because if a loop variable is used in a continue block,
15556 // it *MUST* be used in the continue block. This loop method will not work.
15557 if (!is_legacy_es() && block_is_loop_candidate(block, SPIRBlock::MergeToSelectContinueForLoop))
15558 {
15559 flush_undeclared_variables(block);
15560 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
15561 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015562 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
15563 select_branch_to_false_block = true;
15564 else
15565 select_branch_to_true_block = true;
15566
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010015567 emitted_loop_header_variables = true;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015568 force_complex_continue_block = true;
15569 }
15570 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015571 // 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 +010015572 else if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015573 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010015574 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015575 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
15576 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015577 // The body of while, is actually just the true (or false) block, so always branch there unconditionally.
15578 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
15579 select_branch_to_false_block = true;
15580 else
15581 select_branch_to_true_block = true;
15582
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010015583 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015584 }
15585 }
15586 // This is the newer loop behavior in glslang which branches from Loop header directly to
15587 // a new block, which in turn has a OpBranchSelection without a selection merge.
15588 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
15589 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010015590 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015591 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015592 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015593 skip_direct_branch = true;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010015594 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015595 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015596 }
15597 else if (continue_type == SPIRBlock::DoWhileLoop)
15598 {
Hans-Kristian Arntzenb3f6e3d2018-01-24 19:46:53 +010015599 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020015600 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010015601 emitted_loop_header_variables = true;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015602 // We have some temporaries where the loop header is the dominator.
15603 // We risk a case where we have code like:
15604 // for (;;) { create-temporary; break; } consume-temporary;
15605 // so force-declare temporaries here.
15606 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015607 statement("do");
15608 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020015609
15610 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015611 }
15612 else if (block.merge == SPIRBlock::MergeLoop)
15613 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010015614 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020015615 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010015616 emitted_loop_header_variables = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015617
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015618 // We have a generic loop without any distinguishable pattern like for, while or do while.
15619 get<SPIRBlock>(block.continue_block).complex_continue = true;
15620 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015621
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010015622 // We have some temporaries where the loop header is the dominator.
15623 // We risk a case where we have code like:
15624 // for (;;) { create-temporary; break; } consume-temporary;
15625 // so force-declare temporaries here.
15626 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen449f68e2021-06-03 12:19:10 +020015627 emit_block_hints(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015628 statement("for (;;)");
15629 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020015630
15631 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015632 }
15633 else
15634 {
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020015635 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015636 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015637
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015638 // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
15639 // as writes to said loop variables might have been masked out, we need a recompile.
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010015640 if (!emitted_loop_header_variables && !block.loop_variables.empty())
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015641 {
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +010015642 force_recompile_guarantee_forward_progress();
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010015643 for (auto var : block.loop_variables)
15644 get<SPIRVariable>(var).loop_variable = false;
15645 block.loop_variables.clear();
15646 }
15647
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010015648 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015649 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015650
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015651 // Handle end of block.
15652 switch (block.terminator)
15653 {
15654 case SPIRBlock::Direct:
15655 // True when emitting complex continue block.
15656 if (block.loop_dominator == block.next_block)
15657 {
15658 branch(block.self, block.next_block);
15659 emit_next_block = false;
15660 }
15661 // True if MergeToDirectForLoop succeeded.
15662 else if (skip_direct_branch)
15663 emit_next_block = false;
15664 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
15665 {
15666 branch(block.self, block.next_block);
15667 emit_next_block = false;
15668 }
15669 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015671 case SPIRBlock::Select:
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015672 // True if MergeToSelectForLoop or MergeToSelectContinueForLoop succeeded.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015673 if (select_branch_to_true_block)
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010015674 {
15675 if (force_complex_continue_block)
15676 {
15677 assert(block.true_block == block.continue_block);
15678
15679 // We're going to emit a continue block directly here, so make sure it's marked as complex.
15680 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
15681 bool old_complex = complex_continue;
15682 complex_continue = true;
15683 branch(block.self, block.true_block);
15684 complex_continue = old_complex;
15685 }
15686 else
15687 branch(block.self, block.true_block);
15688 }
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010015689 else if (select_branch_to_false_block)
15690 {
15691 if (force_complex_continue_block)
15692 {
15693 assert(block.false_block == block.continue_block);
15694
15695 // We're going to emit a continue block directly here, so make sure it's marked as complex.
15696 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
15697 bool old_complex = complex_continue;
15698 complex_continue = true;
15699 branch(block.self, block.false_block);
15700 complex_continue = old_complex;
15701 }
15702 else
15703 branch(block.self, block.false_block);
15704 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015705 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015706 branch(block.self, block.condition, block.true_block, block.false_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015707 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015709 case SPIRBlock::MultiSelect:
15710 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015711 auto &type = expression_type(block.condition);
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015712 bool unsigned_case = type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort ||
15713 type.basetype == SPIRType::UByte || type.basetype == SPIRType::UInt64;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015714
Hans-Kristian Arntzen45baf242019-03-20 10:42:38 +010015715 if (block.merge == SPIRBlock::MergeNone)
15716 SPIRV_CROSS_THROW("Switch statement is not structured");
15717
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015718 if (!backend.support_64bit_switch && (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64))
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010015719 {
15720 // SPIR-V spec suggests this is allowed, but we cannot support it in higher level languages.
15721 SPIRV_CROSS_THROW("Cannot use 64-bit switch selectors.");
15722 }
15723
15724 const char *label_suffix = "";
15725 if (type.basetype == SPIRType::UInt && backend.uint32_t_literal_suffix)
15726 label_suffix = "u";
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015727 else if (type.basetype == SPIRType::Int64 && backend.support_64bit_switch)
15728 label_suffix = "l";
15729 else if (type.basetype == SPIRType::UInt64 && backend.support_64bit_switch)
15730 label_suffix = "ul";
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010015731 else if (type.basetype == SPIRType::UShort)
15732 label_suffix = backend.uint16_t_literal_suffix;
15733 else if (type.basetype == SPIRType::Short)
15734 label_suffix = backend.int16_t_literal_suffix;
15735
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +020015736 current_emitting_switch_stack.push_back(&block);
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020015737
15738 if (block.need_ladder_break)
15739 statement("bool _", block.self, "_ladder_break = false;");
15740
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015741 // Find all unique case constructs.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015742 unordered_map<uint32_t, SmallVector<uint64_t>> case_constructs;
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015743 SmallVector<uint32_t> block_declaration_order;
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015744 SmallVector<uint64_t> literals_to_merge;
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015745
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015746 // If a switch case branches to the default block for some reason, we can just remove that literal from consideration
15747 // and let the default: block handle it.
15748 // 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.
15749 // We only need to consider possible fallthrough if order[i] branches to order[i + 1].
Sebastián Aedo75e37522021-11-12 10:17:38 -030015750 auto &cases = get_case_list(block);
15751 for (auto &c : cases)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015752 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015753 if (c.block != block.next_block && c.block != block.default_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015754 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015755 if (!case_constructs.count(c.block))
15756 block_declaration_order.push_back(c.block);
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015757 case_constructs[c.block].push_back(c.value);
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015758 }
15759 else if (c.block == block.next_block && block.default_block != block.next_block)
15760 {
15761 // We might have to flush phi inside specific case labels.
15762 // If we can piggyback on default:, do so instead.
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015763 literals_to_merge.push_back(c.value);
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015764 }
15765 }
15766
15767 // Empty literal array -> default.
15768 if (block.default_block != block.next_block)
15769 {
15770 auto &default_block = get<SPIRBlock>(block.default_block);
15771
15772 // We need to slide in the default block somewhere in this chain
15773 // if there are fall-through scenarios since the default is declared separately in OpSwitch.
15774 // Only consider trivial fall-through cases here.
15775 size_t num_blocks = block_declaration_order.size();
15776 bool injected_block = false;
15777
15778 for (size_t i = 0; i < num_blocks; i++)
15779 {
15780 auto &case_block = get<SPIRBlock>(block_declaration_order[i]);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015781 if (execution_is_direct_branch(case_block, default_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015782 {
15783 // Fallthrough to default block, we must inject the default block here.
15784 block_declaration_order.insert(begin(block_declaration_order) + i + 1, block.default_block);
15785 injected_block = true;
15786 break;
15787 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015788 else if (execution_is_direct_branch(default_block, case_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015789 {
15790 // Default case is falling through to another case label, we must inject the default block here.
15791 block_declaration_order.insert(begin(block_declaration_order) + i, block.default_block);
15792 injected_block = true;
15793 break;
15794 }
15795 }
15796
15797 // Order does not matter.
15798 if (!injected_block)
15799 block_declaration_order.push_back(block.default_block);
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015800 else if (is_legacy_es())
15801 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 +020015802
15803 case_constructs[block.default_block] = {};
15804 }
15805
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015806 size_t num_blocks = block_declaration_order.size();
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015807
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015808 const auto to_case_label = [](uint64_t literal, uint32_t width, bool is_unsigned_case) -> string
15809 {
15810 if (is_unsigned_case)
15811 return convert_to_string(literal);
15812
15813 // For smaller cases, the literals are compiled as 32 bit wide
15814 // literals so we don't need to care for all sizes specifically.
15815 if (width <= 32)
15816 {
15817 return convert_to_string(int64_t(int32_t(literal)));
15818 }
15819
15820 return convert_to_string(int64_t(literal));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015821 };
15822
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015823 const auto to_legacy_case_label = [&](uint32_t condition, const SmallVector<uint64_t> &labels,
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020015824 const char *suffix) -> string {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015825 string ret;
15826 size_t count = labels.size();
15827 for (size_t i = 0; i < count; i++)
15828 {
15829 if (i)
15830 ret += " || ";
15831 ret += join(count > 1 ? "(" : "", to_enclosed_expression(condition), " == ", labels[i], suffix,
15832 count > 1 ? ")" : "");
15833 }
15834 return ret;
15835 };
15836
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015837 // We need to deal with a complex scenario for OpPhi. If we have case-fallthrough and Phi in the picture,
15838 // we need to flush phi nodes outside the switch block in a branch,
15839 // and skip any Phi handling inside the case label to make fall-through work as expected.
15840 // This kind of code-gen is super awkward and it's a last resort. Normally we would want to handle this
15841 // inside the case label if at all possible.
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015842 for (size_t i = 1; backend.support_case_fallthrough && i < num_blocks; i++)
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015843 {
15844 if (flush_phi_required(block.self, block_declaration_order[i]) &&
15845 flush_phi_required(block_declaration_order[i - 1], block_declaration_order[i]))
15846 {
15847 uint32_t target_block = block_declaration_order[i];
15848
15849 // Make sure we flush Phi, it might have been marked to be ignored earlier.
15850 get<SPIRBlock>(target_block).ignore_phi_from_block = 0;
15851
15852 auto &literals = case_constructs[target_block];
15853
15854 if (literals.empty())
15855 {
15856 // Oh boy, gotta make a complete negative test instead! o.o
15857 // Find all possible literals that would *not* make us enter the default block.
15858 // If none of those literals match, we flush Phi ...
15859 SmallVector<string> conditions;
15860 for (size_t j = 0; j < num_blocks; j++)
15861 {
15862 auto &negative_literals = case_constructs[block_declaration_order[j]];
15863 for (auto &case_label : negative_literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020015864 conditions.push_back(join(to_enclosed_expression(block.condition),
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015865 " != ", to_case_label(case_label, type.width, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015866 }
15867
15868 statement("if (", merge(conditions, " && "), ")");
15869 begin_scope();
15870 flush_phi(block.self, target_block);
15871 end_scope();
15872 }
15873 else
15874 {
15875 SmallVector<string> conditions;
15876 conditions.reserve(literals.size());
15877 for (auto &case_label : literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020015878 conditions.push_back(join(to_enclosed_expression(block.condition),
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015879 " == ", to_case_label(case_label, type.width, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015880 statement("if (", merge(conditions, " || "), ")");
15881 begin_scope();
15882 flush_phi(block.self, target_block);
15883 end_scope();
15884 }
15885
15886 // Mark the block so that we don't flush Phi from header to case label.
15887 get<SPIRBlock>(target_block).ignore_phi_from_block = block.self;
15888 }
15889 }
15890
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015891 // If there is only one default block, and no cases, this is a case where SPIRV-opt decided to emulate
15892 // non-structured exits with the help of a switch block.
15893 // This is buggy on FXC, so just emit the logical equivalent of a do { } while(false), which is more idiomatic.
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015894 bool block_like_switch = cases.empty();
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015895
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015896 // If this is true, the switch is completely meaningless, and we should just avoid it.
15897 bool collapsed_switch = block_like_switch && block.default_block == block.next_block;
15898
15899 if (!collapsed_switch)
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015900 {
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015901 if (block_like_switch || is_legacy_es())
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020015902 {
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015903 // ESSL 1.0 is not guaranteed to support do/while.
15904 if (is_legacy_es())
15905 {
15906 uint32_t counter = statement_count;
15907 statement("for (int spvDummy", counter, " = 0; spvDummy", counter, " < 1; spvDummy", counter,
15908 "++)");
15909 }
15910 else
15911 statement("do");
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020015912 }
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015913 else
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015914 {
15915 emit_block_hints(block);
15916 statement("switch (", to_unpacked_expression(block.condition), ")");
15917 }
15918 begin_scope();
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020015919 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020015920
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015921 for (size_t i = 0; i < num_blocks; i++)
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015922 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015923 uint32_t target_block = block_declaration_order[i];
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015924 auto &literals = case_constructs[target_block];
15925
15926 if (literals.empty())
15927 {
15928 // Default case.
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015929 if (!block_like_switch)
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015930 {
15931 if (is_legacy_es())
15932 statement("else");
15933 else
15934 statement("default:");
15935 }
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015936 }
15937 else
15938 {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015939 if (is_legacy_es())
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015940 {
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020015941 statement((i ? "else " : ""), "if (", to_legacy_case_label(block.condition, literals, label_suffix),
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015942 ")");
15943 }
15944 else
15945 {
15946 for (auto &case_literal : literals)
15947 {
15948 // 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 -030015949 statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020015950 }
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015951 }
15952 }
15953
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015954 auto &case_block = get<SPIRBlock>(target_block);
Hans-Kristian Arntzen581ed0f2019-06-27 15:10:17 +020015955 if (backend.support_case_fallthrough && i + 1 < num_blocks &&
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020015956 execution_is_direct_branch(case_block, get<SPIRBlock>(block_declaration_order[i + 1])))
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015957 {
15958 // We will fall through here, so just terminate the block chain early.
15959 // We still need to deal with Phi potentially.
15960 // No need for a stack-like thing here since we only do fall-through when there is a
15961 // single trivial branch to fall-through target..
15962 current_emitting_switch_fallthrough = true;
15963 }
15964 else
15965 current_emitting_switch_fallthrough = false;
15966
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015967 if (!block_like_switch)
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015968 begin_scope();
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015969 branch(block.self, target_block);
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015970 if (!block_like_switch)
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020015971 end_scope();
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020015972
15973 current_emitting_switch_fallthrough = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015974 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010015975
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020015976 // 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 +020015977 // This is supposed to emit all cases where we branch from header to merge block directly.
15978 // There are two main scenarios where cannot rely on default fallthrough.
15979 // - There is an explicit default: label already.
15980 // In this case, literals_to_merge need to form their own "default" case, so that we avoid executing that block.
15981 // - Header -> Merge requires flushing PHI. In this case, we need to collect all cases and flush PHI there.
15982 bool header_merge_requires_phi = flush_phi_required(block.self, block.next_block);
15983 bool need_fallthrough_block = block.default_block == block.next_block || !literals_to_merge.empty();
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020015984 if (!collapsed_switch && ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty()))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020015985 {
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015986 for (auto &case_literal : literals_to_merge)
Sebastián Aedo6d8302e2021-11-18 16:08:59 -030015987 statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015988
15989 if (block.default_block == block.next_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015990 {
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015991 if (is_legacy_es())
15992 statement("else");
15993 else
15994 statement("default:");
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020015995 }
Hans-Kristian Arntzen23c44802021-08-31 17:24:09 +020015996
15997 begin_scope();
15998 flush_phi(block.self, block.next_block);
15999 statement("break;");
16000 end_scope();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016001 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016002
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020016003 if (!collapsed_switch)
16004 {
16005 if (block_like_switch && !is_legacy_es())
16006 end_scope_decl("while(false)");
16007 else
16008 end_scope();
16009 }
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020016010 else
Hans-Kristian Arntzen963fdfd2022-07-04 13:55:00 +020016011 flush_phi(block.self, block.next_block);
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020016012
16013 if (block.need_ladder_break)
16014 {
16015 statement("if (_", block.self, "_ladder_break)");
16016 begin_scope();
16017 statement("break;");
16018 end_scope();
16019 }
16020
Hans-Kristian Arntzen4dfac512022-07-22 15:29:48 +020016021 current_emitting_switch_stack.pop_back();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016022 break;
16023 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016025 case SPIRBlock::Return:
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020016026 {
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020016027 for (auto &line : current_function->fixup_hooks_out)
16028 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040016029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016030 if (processing_entry_point)
16031 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016032
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020016033 auto &cfg = get_cfg_for_current_function();
16034
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016035 if (block.return_value)
16036 {
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016037 auto &type = expression_type(block.return_value);
16038 if (!type.array.empty() && !backend.can_return_array)
16039 {
16040 // If we cannot return arrays, we will have a special out argument we can write to instead.
16041 // The backend is responsible for setting this up, and redirection the return values as appropriate.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010016042 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020016043 {
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020016044 emit_array_copy("spvReturnValue", 0, block.return_value, StorageClassFunction,
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +020016045 get_expression_effective_storage_class(block.return_value));
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020016046 }
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016047
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020016048 if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020016049 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016050 {
16051 statement("return;");
16052 }
16053 }
16054 else
16055 {
16056 // OpReturnValue can return Undef, so don't emit anything for this case.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010016057 if (ir.ids[block.return_value].get_type() != TypeUndef)
Bill Hollings974a0812021-10-21 16:11:33 -040016058 statement("return ", to_unpacked_expression(block.return_value), ";");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016059 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016060 }
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020016061 else if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020016062 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016063 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020016064 // If this block is the very final block and not called from control flow,
16065 // we do not need an explicit return which looks out of place. Just end the function here.
16066 // In the very weird case of for(;;) { return; } executing return is unconditional,
16067 // but we actually need a return here ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016068 statement("return;");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016069 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016070 break;
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020016071 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016072
Bill Hollings35e92e62021-09-12 16:28:21 -040016073 // 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 +020016074 case SPIRBlock::Kill:
Bill Hollings943191a2016-10-27 10:20:01 -040016075 statement(backend.discard_literal, ";");
Bill Hollings35e92e62021-09-12 16:28:21 -040016076 if (block.return_value)
Bill Hollings974a0812021-10-21 16:11:33 -040016077 statement("return ", to_unpacked_expression(block.return_value), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016078 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016079
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010016080 case SPIRBlock::Unreachable:
Hans-Kristian Arntzend08ce822022-05-18 17:49:23 +020016081 {
16082 // Avoid emitting false fallthrough, which can happen for
16083 // if (cond) break; else discard; inside a case label.
16084 // Discard is not always implementable as a terminator.
16085
16086 auto &cfg = get_cfg_for_current_function();
16087 bool inner_dominator_is_switch = false;
16088 ID id = block.self;
16089
16090 while (id)
16091 {
16092 auto &iter_block = get<SPIRBlock>(id);
16093 if (iter_block.terminator == SPIRBlock::MultiSelect ||
16094 iter_block.merge == SPIRBlock::MergeLoop)
16095 {
16096 ID next_block = iter_block.merge == SPIRBlock::MergeLoop ?
16097 iter_block.merge_block : iter_block.next_block;
16098 bool outside_construct = next_block && cfg.find_common_dominator(next_block, block.self) == next_block;
16099 if (!outside_construct)
16100 {
16101 inner_dominator_is_switch = iter_block.terminator == SPIRBlock::MultiSelect;
16102 break;
16103 }
16104 }
16105
16106 if (cfg.get_preceding_edges(id).empty())
16107 break;
16108
16109 id = cfg.get_immediate_dominator(id);
16110 }
16111
16112 if (inner_dominator_is_switch)
16113 statement("break; // unreachable workaround");
16114
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010016115 emit_next_block = false;
16116 break;
Hans-Kristian Arntzend08ce822022-05-18 17:49:23 +020016117 }
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010016118
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +010016119 case SPIRBlock::IgnoreIntersection:
16120 statement("ignoreIntersectionEXT;");
16121 break;
16122
16123 case SPIRBlock::TerminateRay:
16124 statement("terminateRayEXT;");
16125 break;
16126
Hans-Kristian Arntzen4c345162022-09-05 12:31:22 +020016127 case SPIRBlock::EmitMeshTasks:
16128 statement("EmitMeshTasksEXT(",
16129 to_unpacked_expression(block.mesh.groups[0]), ", ",
16130 to_unpacked_expression(block.mesh.groups[1]), ", ",
16131 to_unpacked_expression(block.mesh.groups[2]), ");");
16132 break;
16133
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016134 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010016135 SPIRV_CROSS_THROW("Unimplemented block terminator.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016136 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016137
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016138 if (block.next_block && emit_next_block)
16139 {
16140 // If we hit this case, we're dealing with an unconditional branch, which means we will output
16141 // that block after this. If we had selection merge, we already flushed phi variables.
16142 if (block.merge != SPIRBlock::MergeSelection)
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020016143 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016144 flush_phi(block.self, block.next_block);
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020016145 // For a direct branch, need to remember to invalidate expressions in the next linear block instead.
16146 get<SPIRBlock>(block.next_block).invalidate_expressions = block.invalidate_expressions;
16147 }
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010016148
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020016149 // For switch fallthrough cases, we terminate the chain here, but we still need to handle Phi.
16150 if (!current_emitting_switch_fallthrough)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010016151 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020016152 // For merge selects we might have ignored the fact that a merge target
16153 // could have been a break; or continue;
16154 // We will need to deal with it here.
16155 if (is_loop_break(block.next_block))
16156 {
16157 // Cannot check for just break, because switch statements will also use break.
16158 assert(block.merge == SPIRBlock::MergeSelection);
16159 statement("break;");
16160 }
16161 else if (is_continue(block.next_block))
16162 {
16163 assert(block.merge == SPIRBlock::MergeSelection);
16164 branch_to_continue(block.self, block.next_block);
16165 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020016166 else if (BlockID(block.self) != block.next_block)
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020016167 emit_block_chain(get<SPIRBlock>(block.next_block));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010016168 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016169 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016170
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016171 if (block.merge == SPIRBlock::MergeLoop)
16172 {
16173 if (continue_type == SPIRBlock::DoWhileLoop)
16174 {
16175 // Make sure that we run the continue block to get the expressions set, but this
16176 // should become an empty string.
16177 // We have no fallbacks if we cannot forward everything to temporaries ...
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010016178 const auto &continue_block = get<SPIRBlock>(block.continue_block);
Hans-Kristian Arntzen8bfb04d2019-03-06 12:20:13 +010016179 bool positive_test = execution_is_noop(get<SPIRBlock>(continue_block.true_block),
16180 get<SPIRBlock>(continue_block.loop_dominator));
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010016181
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020016182 uint32_t current_count = statement_count;
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010016183 auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020016184 if (statement_count != current_count)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016185 {
16186 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
16187 get<SPIRBlock>(block.continue_block).complex_continue = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020016188 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016189 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016190
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010016191 // Might have to invert the do-while test here.
16192 auto condition = to_expression(continue_block.condition);
16193 if (!positive_test)
16194 condition = join("!", enclose_expression(condition));
16195
16196 end_scope_decl(join("while (", condition, ")"));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016197 }
16198 else
16199 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016200
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020016201 loop_level_saver.release();
16202
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010016203 // We cannot break out of two loops at once, so don't check for break; here.
16204 // Using block.self as the "from" block isn't quite right, but it has the same scope
16205 // and dominance structure, so it's fine.
16206 if (is_continue(block.merge_block))
16207 branch_to_continue(block.self, block.merge_block);
16208 else
16209 emit_block_chain(get<SPIRBlock>(block.merge_block));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016210 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020016211
16212 // Forget about control dependent expressions now.
16213 block.invalidate_expressions.clear();
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020016214
16215 // After we return, we must be out of scope, so if we somehow have to re-emit this function,
16216 // re-declare variables if necessary.
16217 assert(rearm_dominated_variables.size() == block.dominated_variables.size());
16218 for (size_t i = 0; i < block.dominated_variables.size(); i++)
16219 {
16220 uint32_t var = block.dominated_variables[i];
16221 get<SPIRVariable>(var).deferred_declaration = rearm_dominated_variables[i];
16222 }
Hans-Kristian Arntzen25c74b32019-07-10 12:57:12 +020016223
16224 // Just like for deferred declaration, we need to forget about loop variable enable
16225 // if our block chain is reinstantiated later.
16226 for (auto &var_id : block.loop_variables)
16227 get<SPIRVariable>(var_id).loop_variable_enable = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016228}
16229
16230void CompilerGLSL::begin_scope()
16231{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016232 statement("{");
16233 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016234}
16235
16236void CompilerGLSL::end_scope()
16237{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016238 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010016239 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016240 indent--;
16241 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016242}
16243
Chip Daviscb359342019-09-05 23:14:12 -050016244void CompilerGLSL::end_scope(const string &trailer)
16245{
16246 if (!indent)
16247 SPIRV_CROSS_THROW("Popping empty indent stack.");
16248 indent--;
16249 statement("}", trailer);
16250}
16251
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016252void CompilerGLSL::end_scope_decl()
16253{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016254 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010016255 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016256 indent--;
16257 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016258}
16259
16260void CompilerGLSL::end_scope_decl(const string &decl)
16261{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016262 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010016263 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020016264 indent--;
16265 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010016266}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020016267
16268void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
16269{
16270 // If our variable is remapped, and we rely on type-remapping information as
16271 // well, then we cannot pass the variable as a function parameter.
16272 // Fixing this is non-trivial without stamping out variants of the same function,
16273 // so for now warn about this and suggest workarounds instead.
16274 for (uint32_t i = 0; i < length; i++)
16275 {
16276 auto *var = maybe_get<SPIRVariable>(args[i]);
16277 if (!var || !var->remapped_variable)
16278 continue;
16279
16280 auto &type = get<SPIRType>(var->basetype);
16281 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
16282 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010016283 SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
16284 "This will not work correctly because type-remapping information is lost. "
16285 "To workaround, please consider not passing the subpass input as a function parameter, "
16286 "or use in/out variables instead which do not need type remapping information.");
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020016287 }
16288 }
16289}
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010016290
16291const Instruction *CompilerGLSL::get_next_instruction_in_block(const Instruction &instr)
16292{
16293 // FIXME: This is kind of hacky. There should be a cleaner way.
16294 auto offset = uint32_t(&instr - current_emitting_block->ops.data());
16295 if ((offset + 1) < current_emitting_block->ops.size())
16296 return &current_emitting_block->ops[offset + 1];
16297 else
16298 return nullptr;
16299}
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010016300
16301uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
16302{
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010016303 return semantics & (MemorySemanticsAtomicCounterMemoryMask | MemorySemanticsImageMemoryMask |
16304 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask |
16305 MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010016306}
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016307
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020016308void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t, uint32_t rhs_id, StorageClass, StorageClass)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010016309{
16310 statement(lhs, " = ", to_expression(rhs_id), ";");
16311}
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016312
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016313bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id)
16314{
16315 if (!backend.force_gl_in_out_block)
16316 return false;
16317 // This path is only relevant for GL backends.
16318
16319 auto *var = maybe_get<SPIRVariable>(target_id);
16320 if (!var || var->storage != StorageClassOutput)
16321 return false;
16322
16323 if (!is_builtin_variable(*var) || BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInSampleMask)
16324 return false;
16325
16326 auto &type = expression_type(source_id);
16327 string array_expr;
16328 if (type.array_size_literal.back())
16329 {
16330 array_expr = convert_to_string(type.array.back());
16331 if (type.array.back() == 0)
16332 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
16333 }
16334 else
16335 array_expr = to_expression(type.array.back());
16336
16337 SPIRType target_type;
16338 target_type.basetype = SPIRType::Int;
16339
16340 statement("for (int i = 0; i < int(", array_expr, "); i++)");
16341 begin_scope();
16342 statement(to_expression(target_id), "[i] = ",
16343 bitcast_expression(target_type, type.basetype, join(to_expression(source_id), "[i]")),
16344 ";");
16345 end_scope();
16346
16347 return true;
16348}
16349
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016350void 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 +010016351{
16352 if (!backend.force_gl_in_out_block)
16353 return;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016354 // This path is only relevant for GL backends.
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016355
16356 auto *var = maybe_get<SPIRVariable>(source_id);
16357 if (!var)
16358 return;
16359
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016360 if (var->storage != StorageClassInput && var->storage != StorageClassOutput)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016361 return;
16362
16363 auto &type = get_variable_data_type(*var);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016364 if (type.array.empty())
16365 return;
16366
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016367 auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016368 bool is_builtin = is_builtin_variable(*var) &&
16369 (builtin == BuiltInPointSize ||
16370 builtin == BuiltInPosition ||
16371 builtin == BuiltInSampleMask);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016372 bool is_tess = is_tessellation_shader();
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010016373 bool is_patch = has_decoration(var->self, DecorationPatch);
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016374 bool is_sample_mask = is_builtin && builtin == BuiltInSampleMask;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016375
16376 // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
16377 // We must unroll the array load.
16378 // For builtins, we couldn't catch this case normally,
16379 // because this is resolved in the OpAccessChain in most cases.
16380 // If we load the entire array, we have no choice but to unroll here.
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010016381 if (!is_patch && (is_builtin || is_tess))
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016382 {
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016383 auto new_expr = join("_", target_id, "_unrolled");
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016384 statement(variable_decl(type, new_expr, target_id), ";");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016385 string array_expr;
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010016386 if (type.array_size_literal.back())
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016387 {
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010016388 array_expr = convert_to_string(type.array.back());
16389 if (type.array.back() == 0)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016390 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
16391 }
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016392 else
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010016393 array_expr = to_expression(type.array.back());
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016394
16395 // The array size might be a specialization constant, so use a for-loop instead.
16396 statement("for (int i = 0; i < int(", array_expr, "); i++)");
16397 begin_scope();
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016398 if (is_builtin && !is_sample_mask)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016399 statement(new_expr, "[i] = gl_in[i].", expr, ";");
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016400 else if (is_sample_mask)
16401 {
16402 SPIRType target_type;
16403 target_type.basetype = SPIRType::Int;
16404 statement(new_expr, "[i] = ", bitcast_expression(target_type, type.basetype, join(expr, "[i]")), ";");
16405 }
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010016406 else
16407 statement(new_expr, "[i] = ", expr, "[i];");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016408 end_scope();
16409
Daniel Thornburgh44c33332022-03-02 23:02:38 +000016410 expr = std::move(new_expr);
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010016411 }
16412}
16413
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020016414void CompilerGLSL::cast_from_variable_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016415{
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016416 // We will handle array cases elsewhere.
16417 if (!expr_type.array.empty())
16418 return;
16419
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020016420 auto *var = maybe_get_backing_variable(source_id);
16421 if (var)
16422 source_id = var->self;
16423
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016424 // Only interested in standalone builtin variables.
16425 if (!has_decoration(source_id, DecorationBuiltIn))
16426 return;
16427
16428 auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
16429 auto expected_type = expr_type.basetype;
16430
16431 // TODO: Fill in for more builtins.
16432 switch (builtin)
16433 {
16434 case BuiltInLayer:
16435 case BuiltInPrimitiveId:
16436 case BuiltInViewportIndex:
16437 case BuiltInInstanceId:
16438 case BuiltInInstanceIndex:
16439 case BuiltInVertexId:
16440 case BuiltInVertexIndex:
16441 case BuiltInSampleId:
Chip Davisfcad0192018-08-28 13:47:29 -050016442 case BuiltInBaseVertex:
16443 case BuiltInBaseInstance:
16444 case BuiltInDrawIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020016445 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020016446 case BuiltInInstanceCustomIndexNV:
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016447 case BuiltInSampleMask:
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +020016448 case BuiltInPrimitiveShadingRateKHR:
16449 case BuiltInShadingRateKHR:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016450 expected_type = SPIRType::Int;
16451 break;
16452
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020016453 case BuiltInGlobalInvocationId:
16454 case BuiltInLocalInvocationId:
16455 case BuiltInWorkgroupId:
16456 case BuiltInLocalInvocationIndex:
16457 case BuiltInWorkgroupSize:
16458 case BuiltInNumWorkgroups:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020016459 case BuiltInIncomingRayFlagsNV:
16460 case BuiltInLaunchIdNV:
16461 case BuiltInLaunchSizeNV:
Hans-Kristian Arntzen57626172022-09-02 16:31:04 +020016462 case BuiltInPrimitiveTriangleIndicesEXT:
16463 case BuiltInPrimitiveLineIndicesEXT:
16464 case BuiltInPrimitivePointIndicesEXT:
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020016465 expected_type = SPIRType::UInt;
16466 break;
16467
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016468 default:
16469 break;
16470 }
16471
16472 if (expected_type != expr_type.basetype)
16473 expr = bitcast_expression(expr_type, expected_type, expr);
16474}
16475
Hans-Kristian Arntzenedf247f2021-10-25 10:55:11 +020016476void CompilerGLSL::cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016477{
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016478 auto *var = maybe_get_backing_variable(target_id);
16479 if (var)
16480 target_id = var->self;
16481
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016482 // Only interested in standalone builtin variables.
16483 if (!has_decoration(target_id, DecorationBuiltIn))
16484 return;
16485
16486 auto builtin = static_cast<BuiltIn>(get_decoration(target_id, DecorationBuiltIn));
16487 auto expected_type = expr_type.basetype;
16488
16489 // TODO: Fill in for more builtins.
16490 switch (builtin)
16491 {
16492 case BuiltInLayer:
16493 case BuiltInPrimitiveId:
16494 case BuiltInViewportIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020016495 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzenee31e842021-03-08 11:51:51 +010016496 case BuiltInSampleMask:
Hans-Kristian Arntzenc89b5a12021-04-20 13:58:07 +020016497 case BuiltInPrimitiveShadingRateKHR:
16498 case BuiltInShadingRateKHR:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020016499 expected_type = SPIRType::Int;
16500 break;
16501
16502 default:
16503 break;
16504 }
16505
16506 if (expected_type != expr_type.basetype)
16507 {
16508 auto type = expr_type;
16509 type.basetype = expected_type;
16510 expr = bitcast_expression(type, expr_type.basetype, expr);
16511 }
16512}
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020016513
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020016514void CompilerGLSL::convert_non_uniform_expression(string &expr, uint32_t ptr_id)
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020016515{
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020016516 if (*backend.nonuniform_qualifier == '\0')
16517 return;
16518
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020016519 auto *var = maybe_get_backing_variable(ptr_id);
16520 if (!var)
16521 return;
16522
16523 if (var->storage != StorageClassUniformConstant &&
16524 var->storage != StorageClassStorageBuffer &&
16525 var->storage != StorageClassUniform)
16526 return;
16527
16528 auto &backing_type = get<SPIRType>(var->basetype);
16529 if (backing_type.array.empty())
16530 return;
16531
16532 // If we get here, we know we're accessing an arrayed resource which
16533 // might require nonuniform qualifier.
16534
16535 auto start_array_index = expr.find_first_of('[');
16536
16537 if (start_array_index == string::npos)
16538 return;
16539
16540 // We've opened a bracket, track expressions until we can close the bracket.
16541 // This must be our resource index.
16542 size_t end_array_index = string::npos;
16543 unsigned bracket_count = 1;
16544 for (size_t index = start_array_index + 1; index < expr.size(); index++)
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020016545 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020016546 if (expr[index] == ']')
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010016547 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020016548 if (--bracket_count == 0)
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010016549 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020016550 end_array_index = index;
16551 break;
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010016552 }
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010016553 }
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020016554 else if (expr[index] == '[')
16555 bracket_count++;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020016556 }
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +020016557
16558 assert(bracket_count == 0);
16559
16560 // Doesn't really make sense to declare a non-arrayed image with nonuniformEXT, but there's
16561 // nothing we can do here to express that.
16562 if (start_array_index == string::npos || end_array_index == string::npos || end_array_index < start_array_index)
16563 return;
16564
16565 start_array_index++;
16566
16567 expr = join(expr.substr(0, start_array_index), backend.nonuniform_qualifier, "(",
16568 expr.substr(start_array_index, end_array_index - start_array_index), ")",
16569 expr.substr(end_array_index, string::npos));
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020016570}
16571
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +020016572void CompilerGLSL::emit_block_hints(const SPIRBlock &block)
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020016573{
Hans-Kristian Arntzend62b3c22021-06-03 12:00:29 +020016574 if ((options.es && options.version < 310) || (!options.es && options.version < 140))
16575 return;
16576
16577 switch (block.hint)
16578 {
16579 case SPIRBlock::HintFlatten:
16580 require_extension_internal("GL_EXT_control_flow_attributes");
16581 statement("SPIRV_CROSS_FLATTEN");
16582 break;
16583 case SPIRBlock::HintDontFlatten:
16584 require_extension_internal("GL_EXT_control_flow_attributes");
16585 statement("SPIRV_CROSS_BRANCH");
16586 break;
16587 case SPIRBlock::HintUnroll:
16588 require_extension_internal("GL_EXT_control_flow_attributes");
16589 statement("SPIRV_CROSS_UNROLL");
16590 break;
16591 case SPIRBlock::HintDontUnroll:
16592 require_extension_internal("GL_EXT_control_flow_attributes");
16593 statement("SPIRV_CROSS_LOOP");
16594 break;
16595 default:
16596 break;
16597 }
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020016598}
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +010016599
16600void CompilerGLSL::preserve_alias_on_reset(uint32_t id)
16601{
16602 preserved_aliases[id] = get_name(id);
16603}
16604
16605void CompilerGLSL::reset_name_caches()
16606{
16607 for (auto &preserved : preserved_aliases)
16608 set_name(preserved.first, preserved.second);
16609
16610 preserved_aliases.clear();
16611 resource_names.clear();
16612 block_input_names.clear();
16613 block_output_names.clear();
16614 block_ubo_names.clear();
16615 block_ssbo_names.clear();
16616 block_names.clear();
16617 function_overloads.clear();
16618}
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016619
Hans-Kristian Arntzen4ab5bbb2022-03-10 15:38:57 +010016620void CompilerGLSL::fixup_anonymous_struct_names(std::unordered_set<uint32_t> &visited, const SPIRType &type)
16621{
16622 if (visited.count(type.self))
16623 return;
16624 visited.insert(type.self);
16625
16626 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
16627 {
16628 auto &mbr_type = get<SPIRType>(type.member_types[i]);
16629
16630 if (mbr_type.basetype == SPIRType::Struct)
16631 {
16632 // If there are multiple aliases, the output might be somewhat unpredictable,
16633 // but the only real alternative in that case is to do nothing, which isn't any better.
16634 // This check should be fine in practice.
16635 if (get_name(mbr_type.self).empty() && !get_member_name(type.self, i).empty())
16636 {
16637 auto anon_name = join("anon_", get_member_name(type.self, i));
16638 ParsedIR::sanitize_underscores(anon_name);
16639 set_name(mbr_type.self, anon_name);
16640 }
16641
16642 fixup_anonymous_struct_names(visited, mbr_type);
16643 }
16644 }
16645}
16646
16647void CompilerGLSL::fixup_anonymous_struct_names()
16648{
16649 // HLSL codegen can often end up emitting anonymous structs inside blocks, which
16650 // breaks GL linking since all names must match ...
16651 // Try to emit sensible code, so attempt to find such structs and emit anon_$member.
16652
16653 // Breaks exponential explosion with weird type trees.
16654 std::unordered_set<uint32_t> visited;
16655
16656 ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
16657 if (type.basetype == SPIRType::Struct &&
16658 (has_decoration(type.self, DecorationBlock) ||
16659 has_decoration(type.self, DecorationBufferBlock)))
16660 {
16661 fixup_anonymous_struct_names(visited, type);
16662 }
16663 });
16664}
16665
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016666void CompilerGLSL::fixup_type_alias()
16667{
16668 // 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 +020016669 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020016670 if (!type.type_alias)
16671 return;
16672
16673 if (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016674 {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020016675 // Top-level block types should never alias anything else.
16676 type.type_alias = 0;
16677 }
16678 else if (type_is_block_like(type) && type.self == ID(self))
16679 {
16680 // A block-like type is any type which contains Offset decoration, but not top-level blocks,
16681 // i.e. blocks which are placed inside buffers.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016682 // Become the master.
16683 ir.for_each_typed_id<SPIRType>([&](uint32_t other_id, SPIRType &other_type) {
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020016684 if (other_id == self)
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016685 return;
16686
16687 if (other_type.type_alias == type.type_alias)
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020016688 other_type.type_alias = self;
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016689 });
16690
16691 this->get<SPIRType>(type.type_alias).type_alias = self;
16692 type.type_alias = 0;
16693 }
16694 });
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016695}
16696
16697void CompilerGLSL::reorder_type_alias()
16698{
16699 // Reorder declaration of types so that the master of the type alias is always emitted first.
16700 // 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
16701 // 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 +020016702 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020016703
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016704 auto &type_ids = ir.ids_for_type[TypeType];
16705 for (auto alias_itr = begin(type_ids); alias_itr != end(type_ids); ++alias_itr)
16706 {
16707 auto &type = get<SPIRType>(*alias_itr);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020016708 if (type.type_alias != TypeID(0) &&
16709 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016710 {
16711 // We will skip declaring this type, so make sure the type_alias type comes before.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020016712 auto master_itr = find(begin(type_ids), end(type_ids), ID(type.type_alias));
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020016713 assert(master_itr != end(type_ids));
16714
16715 if (alias_itr < master_itr)
16716 {
16717 // Must also swap the type order for the constant-type joined array.
16718 auto &joined_types = ir.ids_for_constant_or_type;
16719 auto alt_alias_itr = find(begin(joined_types), end(joined_types), *alias_itr);
16720 auto alt_master_itr = find(begin(joined_types), end(joined_types), *master_itr);
16721 assert(alt_alias_itr != end(joined_types));
16722 assert(alt_master_itr != end(joined_types));
16723
16724 swap(*alias_itr, *master_itr);
16725 swap(*alt_alias_itr, *alt_master_itr);
16726 }
16727 }
16728 }
16729}
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020016730
16731void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
16732{
16733 // If we are redirecting statements, ignore the line directive.
16734 // Common case here is continue blocks.
16735 if (redirect_statement)
16736 return;
16737
16738 if (options.emit_line_directives)
16739 {
16740 require_extension_internal("GL_GOOGLE_cpp_style_line_directive");
16741 statement_no_indent("#line ", line_literal, " \"", get<SPIRString>(file_id).str, "\"");
16742 }
16743}
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020016744
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010016745void 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 +010016746 SmallVector<uint32_t> chain)
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010016747{
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016748 // Fully unroll all member/array indices one by one.
16749
16750 auto &lhs_type = get<SPIRType>(lhs_type_id);
16751 auto &rhs_type = get<SPIRType>(rhs_type_id);
16752
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010016753 if (!lhs_type.array.empty())
16754 {
16755 // Could use a loop here to support specialization constants, but it gets rather complicated with nested array types,
16756 // and this is a rather obscure opcode anyways, keep it simple unless we are forced to.
16757 uint32_t array_size = to_array_size_literal(lhs_type);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016758 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010016759
16760 for (uint32_t i = 0; i < array_size; i++)
16761 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016762 chain.back() = i;
16763 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 +010016764 }
16765 }
16766 else if (lhs_type.basetype == SPIRType::Struct)
16767 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016768 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010016769 uint32_t member_count = uint32_t(lhs_type.member_types.size());
16770 for (uint32_t i = 0; i < member_count; i++)
16771 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016772 chain.back() = i;
16773 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 +010016774 }
16775 }
16776 else
16777 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016778 // Need to handle unpack/packing fixups since this can differ wildly between the logical types,
16779 // particularly in MSL.
16780 // To deal with this, we emit access chains and go through emit_store_statement
16781 // to deal with all the special cases we can encounter.
16782
16783 AccessChainMeta lhs_meta, rhs_meta;
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010016784 auto lhs = access_chain_internal(lhs_id, chain.data(), uint32_t(chain.size()),
16785 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &lhs_meta);
16786 auto rhs = access_chain_internal(rhs_id, chain.data(), uint32_t(chain.size()),
16787 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &rhs_meta);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016788
16789 uint32_t id = ir.increase_bound_by(2);
16790 lhs_id = id;
16791 rhs_id = id + 1;
16792
16793 {
Daniel Thornburgh44c33332022-03-02 23:02:38 +000016794 auto &lhs_expr = set<SPIRExpression>(lhs_id, std::move(lhs), lhs_type_id, true);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016795 lhs_expr.need_transpose = lhs_meta.need_transpose;
16796
16797 if (lhs_meta.storage_is_packed)
16798 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypePacked);
16799 if (lhs_meta.storage_physical_type != 0)
16800 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID, lhs_meta.storage_physical_type);
16801
16802 forwarded_temporaries.insert(lhs_id);
16803 suppressed_usage_tracking.insert(lhs_id);
16804 }
16805
16806 {
Daniel Thornburgh44c33332022-03-02 23:02:38 +000016807 auto &rhs_expr = set<SPIRExpression>(rhs_id, std::move(rhs), rhs_type_id, true);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010016808 rhs_expr.need_transpose = rhs_meta.need_transpose;
16809
16810 if (rhs_meta.storage_is_packed)
16811 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypePacked);
16812 if (rhs_meta.storage_physical_type != 0)
16813 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID, rhs_meta.storage_physical_type);
16814
16815 forwarded_temporaries.insert(rhs_id);
16816 suppressed_usage_tracking.insert(rhs_id);
16817 }
16818
16819 emit_store_statement(lhs_id, rhs_id);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010016820 }
16821}
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010016822
16823bool CompilerGLSL::subpass_input_is_framebuffer_fetch(uint32_t id) const
16824{
16825 if (!has_decoration(id, DecorationInputAttachmentIndex))
16826 return false;
16827
16828 uint32_t input_attachment_index = get_decoration(id, DecorationInputAttachmentIndex);
16829 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
16830 if (remap.first == input_attachment_index)
16831 return true;
16832
16833 return false;
16834}
16835
16836const SPIRVariable *CompilerGLSL::find_subpass_input_by_attachment_index(uint32_t index) const
16837{
16838 const SPIRVariable *ret = nullptr;
16839 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
16840 if (has_decoration(var.self, DecorationInputAttachmentIndex) &&
16841 get_decoration(var.self, DecorationInputAttachmentIndex) == index)
16842 {
16843 ret = &var;
16844 }
16845 });
16846 return ret;
16847}
16848
16849const SPIRVariable *CompilerGLSL::find_color_output_by_location(uint32_t location) const
16850{
16851 const SPIRVariable *ret = nullptr;
16852 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
16853 if (var.storage == StorageClassOutput && get_decoration(var.self, DecorationLocation) == location)
16854 ret = &var;
16855 });
16856 return ret;
16857}
16858
16859void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs()
16860{
16861 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
16862 {
16863 auto *subpass_var = find_subpass_input_by_attachment_index(remap.first);
16864 auto *output_var = find_color_output_by_location(remap.second);
16865 if (!subpass_var)
16866 continue;
16867 if (!output_var)
crissdb52e272020-10-08 12:14:52 +020016868 SPIRV_CROSS_THROW("Need to declare the corresponding fragment output variable to be able "
16869 "to read from it.");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010016870 if (is_array(get<SPIRType>(output_var->basetype)))
16871 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs.");
16872
16873 auto &func = get<SPIRFunction>(get_entry_point().self);
16874 func.fixup_hooks_in.push_back([=]() {
16875 if (is_legacy())
16876 {
16877 statement(to_expression(subpass_var->self), " = ", "gl_LastFragData[",
16878 get_decoration(output_var->self, DecorationLocation), "];");
16879 }
16880 else
16881 {
16882 uint32_t num_rt_components = this->get<SPIRType>(output_var->basetype).vecsize;
16883 statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ",
16884 to_expression(output_var->self), ";");
16885 }
16886 });
16887 }
16888}
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020016889
16890bool CompilerGLSL::variable_is_depth_or_compare(VariableID id) const
16891{
Bill Hollingsfd252b22021-11-08 15:59:45 -050016892 return is_depth_image(get<SPIRType>(get<SPIRVariable>(id).basetype), id);
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020016893}
crissdb52e272020-10-08 12:14:52 +020016894
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016895const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extension_name(Candidate c)
crissdb52e272020-10-08 12:14:52 +020016896{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016897 static const char *const retval[CandidateCount] = { "GL_KHR_shader_subgroup_ballot",
16898 "GL_KHR_shader_subgroup_basic",
16899 "GL_KHR_shader_subgroup_vote",
16900 "GL_NV_gpu_shader_5",
16901 "GL_NV_shader_thread_group",
16902 "GL_NV_shader_thread_shuffle",
16903 "GL_ARB_shader_ballot",
16904 "GL_ARB_shader_group_vote",
16905 "GL_AMD_gcn_shader" };
crissdb52e272020-10-08 12:14:52 +020016906 return retval[c];
16907}
16908
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016909SmallVector<std::string> CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_names(Candidate c)
crissdb52e272020-10-08 12:14:52 +020016910{
16911 switch (c)
16912 {
16913 case ARB_shader_ballot:
16914 return { "GL_ARB_shader_int64" };
16915 case AMD_gcn_shader:
16916 return { "GL_AMD_gpu_shader_int64", "GL_NV_gpu_shader5" };
16917 default:
16918 return {};
16919 }
16920}
16921
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016922const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_predicate(Candidate c)
crissdb52e272020-10-08 12:14:52 +020016923{
16924 switch (c)
16925 {
16926 case ARB_shader_ballot:
16927 return "defined(GL_ARB_shader_int64)";
16928 case AMD_gcn_shader:
16929 return "(defined(GL_AMD_gpu_shader_int64) || defined(GL_NV_gpu_shader5))";
16930 default:
16931 return "";
16932 }
16933}
16934
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016935CompilerGLSL::ShaderSubgroupSupportHelper::FeatureVector CompilerGLSL::ShaderSubgroupSupportHelper::
16936 get_feature_dependencies(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016937{
16938 switch (feature)
16939 {
16940 case SubgroupAllEqualT:
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010016941 return { SubgroupBroadcast_First, SubgroupAll_Any_AllEqualBool };
crissdb52e272020-10-08 12:14:52 +020016942 case SubgroupElect:
16943 return { SubgroupBallotFindLSB_MSB, SubgroupBallot, SubgroupInvocationID };
16944 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
16945 return { SubgroupMask };
16946 case SubgroupBallotBitCount:
16947 return { SubgroupBallot };
16948 default:
16949 return {};
16950 }
16951}
16952
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016953CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::
16954 get_feature_dependency_mask(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016955{
16956 return build_mask(get_feature_dependencies(feature));
16957}
16958
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016959bool CompilerGLSL::ShaderSubgroupSupportHelper::can_feature_be_implemented_without_extensions(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016960{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016961 static const bool retval[FeatureCount] = { false, false, false, false, false, false,
16962 true, // SubgroupBalloFindLSB_MSB
16963 false, false, false, false,
16964 true, // SubgroupMemBarrier - replaced with workgroup memory barriers
16965 false, false, true, false };
crissdb52e272020-10-08 12:14:52 +020016966
16967 return retval[feature];
16968}
16969
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016970CompilerGLSL::ShaderSubgroupSupportHelper::Candidate CompilerGLSL::ShaderSubgroupSupportHelper::
16971 get_KHR_extension_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016972{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016973 static const Candidate extensions[FeatureCount] = {
crissdb52e272020-10-08 12:14:52 +020016974 KHR_shader_subgroup_ballot, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic,
16975 KHR_shader_subgroup_basic, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_vote,
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010016976 KHR_shader_subgroup_vote, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic,
16977 KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot
crissdb52e272020-10-08 12:14:52 +020016978 };
16979
16980 return extensions[feature];
16981}
16982
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016983void CompilerGLSL::ShaderSubgroupSupportHelper::request_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020016984{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016985 feature_mask |= (FeatureMask(1) << feature) | get_feature_dependency_mask(feature);
crissdb52e272020-10-08 12:14:52 +020016986}
16987
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016988bool CompilerGLSL::ShaderSubgroupSupportHelper::is_feature_requested(Feature feature) const
crissdb52e272020-10-08 12:14:52 +020016989{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016990 return (feature_mask & (1u << feature)) != 0;
crissdb52e272020-10-08 12:14:52 +020016991}
16992
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010016993CompilerGLSL::ShaderSubgroupSupportHelper::Result CompilerGLSL::ShaderSubgroupSupportHelper::resolve() const
crissdb52e272020-10-08 12:14:52 +020016994{
16995 Result res;
16996
16997 for (uint32_t i = 0u; i < FeatureCount; ++i)
16998 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020016999 if (feature_mask & (1u << i))
crissdb52e272020-10-08 12:14:52 +020017000 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017001 auto feature = static_cast<Feature>(i);
17002 std::unordered_set<uint32_t> unique_candidates;
crissdb52e272020-10-08 12:14:52 +020017003
17004 auto candidates = get_candidates_for_feature(feature);
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017005 unique_candidates.insert(candidates.begin(), candidates.end());
crissdb52e272020-10-08 12:14:52 +020017006
17007 auto deps = get_feature_dependencies(feature);
17008 for (Feature d : deps)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017009 {
17010 candidates = get_candidates_for_feature(d);
17011 if (!candidates.empty())
17012 unique_candidates.insert(candidates.begin(), candidates.end());
17013 }
crissdb52e272020-10-08 12:14:52 +020017014
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017015 for (uint32_t c : unique_candidates)
17016 ++res.weights[static_cast<Candidate>(c)];
crissdb52e272020-10-08 12:14:52 +020017017 }
17018 }
17019
17020 return res;
17021}
17022
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010017023CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
17024 get_candidates_for_feature(Feature ft, const Result &r)
crissdb52e272020-10-08 12:14:52 +020017025{
17026 auto c = get_candidates_for_feature(ft);
17027 auto cmp = [&r](Candidate a, Candidate b) {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017028 if (r.weights[a] == r.weights[b])
17029 return a < b; // Prefer candidates with lower enum value
17030 return r.weights[a] > r.weights[b];
crissdb52e272020-10-08 12:14:52 +020017031 };
17032 std::sort(c.begin(), c.end(), cmp);
crissdb52e272020-10-08 12:14:52 +020017033 return c;
17034}
17035
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010017036CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
17037 get_candidates_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020017038{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017039 switch (feature)
crissdb52e272020-10-08 12:14:52 +020017040 {
17041 case SubgroupMask:
17042 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
17043 case SubgroupSize:
17044 return { KHR_shader_subgroup_basic, NV_shader_thread_group, AMD_gcn_shader, ARB_shader_ballot };
17045 case SubgroupInvocationID:
17046 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot };
17047 case SubgroupID:
17048 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
17049 case NumSubgroups:
17050 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
Hans-Kristian Arntzenc8765a72020-12-11 12:24:34 +010017051 case SubgroupBroadcast_First:
crissdb52e272020-10-08 12:14:52 +020017052 return { KHR_shader_subgroup_ballot, NV_shader_thread_shuffle, ARB_shader_ballot };
17053 case SubgroupBallotFindLSB_MSB:
17054 return { KHR_shader_subgroup_ballot, NV_shader_thread_group };
17055 case SubgroupAll_Any_AllEqualBool:
17056 return { KHR_shader_subgroup_vote, NV_gpu_shader_5, ARB_shader_group_vote, AMD_gcn_shader };
17057 case SubgroupAllEqualT:
17058 return {}; // depends on other features only
17059 case SubgroupElect:
17060 return {}; // depends on other features only
17061 case SubgroupBallot:
17062 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
17063 case SubgroupBarrier:
17064 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot, AMD_gcn_shader };
17065 case SubgroupMemBarrier:
17066 return { KHR_shader_subgroup_basic };
17067 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
17068 return {};
17069 case SubgroupBallotBitExtract:
17070 return { NV_shader_thread_group };
17071 case SubgroupBallotBitCount:
17072 return {};
17073 default:
17074 return {};
17075 }
17076}
17077
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010017078CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::build_mask(
17079 const SmallVector<Feature> &features)
crissdb52e272020-10-08 12:14:52 +020017080{
17081 FeatureMask mask = 0;
crissdb52e272020-10-08 12:14:52 +020017082 for (Feature f : features)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017083 mask |= FeatureMask(1) << f;
crissdb52e272020-10-08 12:14:52 +020017084 return mask;
17085}
17086
17087CompilerGLSL::ShaderSubgroupSupportHelper::Result::Result()
17088{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017089 for (auto &weight : weights)
17090 weight = 0;
crissdb52e272020-10-08 12:14:52 +020017091
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020017092 // Make sure KHR_shader_subgroup extensions are always prefered.
17093 const uint32_t big_num = FeatureCount;
17094 weights[KHR_shader_subgroup_ballot] = big_num;
17095 weights[KHR_shader_subgroup_basic] = big_num;
17096 weights[KHR_shader_subgroup_vote] = big_num;
crissdb52e272020-10-08 12:14:52 +020017097}
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020017098
17099void CompilerGLSL::request_workaround_wrapper_overload(TypeID id)
17100{
17101 // Must be ordered to maintain deterministic output, so vector is appropriate.
17102 if (find(begin(workaround_ubo_load_overload_types), end(workaround_ubo_load_overload_types), id) ==
17103 end(workaround_ubo_load_overload_types))
17104 {
17105 force_recompile();
17106 workaround_ubo_load_overload_types.push_back(id);
17107 }
17108}
17109
17110void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID loaded_type, ID ptr)
17111{
17112 // Loading row-major matrices from UBOs on older AMD Windows OpenGL drivers is problematic.
17113 // To load these types correctly, we must first wrap them in a dummy function which only purpose is to
17114 // ensure row_major decoration is actually respected.
17115 auto *var = maybe_get_backing_variable(ptr);
17116 if (!var)
17117 return;
17118
17119 auto &backing_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010017120 bool is_ubo = backing_type.basetype == SPIRType::Struct && backing_type.storage == StorageClassUniform &&
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020017121 has_decoration(backing_type.self, DecorationBlock);
17122 if (!is_ubo)
17123 return;
17124
17125 auto *type = &get<SPIRType>(loaded_type);
17126 bool rewrite = false;
17127
17128 if (is_matrix(*type))
17129 {
17130 // To avoid adding a lot of unnecessary meta tracking to forward the row_major state,
17131 // we will simply look at the base struct itself. It is exceptionally rare to mix and match row-major/col-major state.
17132 // If there is any row-major action going on, we apply the workaround.
17133 // It is harmless to apply the workaround to column-major matrices, so this is still a valid solution.
17134 // If an access chain occurred, the workaround is not required, so loading vectors or scalars don't need workaround.
17135 type = &backing_type;
17136 }
17137
17138 if (type->basetype == SPIRType::Struct)
17139 {
17140 // If we're loading a struct where any member is a row-major matrix, apply the workaround.
17141 for (uint32_t i = 0; i < uint32_t(type->member_types.size()); i++)
17142 {
17143 if (combined_decoration_for_member(*type, i).get(DecorationRowMajor))
17144 {
17145 rewrite = true;
17146 break;
17147 }
17148 }
17149 }
17150
17151 if (rewrite)
17152 {
17153 request_workaround_wrapper_overload(loaded_type);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010017154 expr = join("spvWorkaroundRowMajor(", expr, ")");
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020017155 }
17156}
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +010017157
17158void CompilerGLSL::mask_stage_output_by_location(uint32_t location, uint32_t component)
17159{
17160 masked_output_locations.insert({ location, component });
17161}
17162
17163void CompilerGLSL::mask_stage_output_by_builtin(BuiltIn builtin)
17164{
17165 masked_output_builtins.insert(builtin);
17166}
17167
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020017168bool CompilerGLSL::is_stage_output_variable_masked(const SPIRVariable &var) const
17169{
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020017170 auto &type = get<SPIRType>(var.basetype);
17171 bool is_block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020017172 // Blocks by themselves are never masked. Must be masked per-member.
17173 if (is_block)
17174 return false;
17175
17176 bool is_builtin = has_decoration(var.self, DecorationBuiltIn);
17177
17178 if (is_builtin)
17179 {
17180 return is_stage_output_builtin_masked(BuiltIn(get_decoration(var.self, DecorationBuiltIn)));
17181 }
17182 else
17183 {
17184 if (!has_decoration(var.self, DecorationLocation))
17185 return false;
17186
17187 return is_stage_output_location_masked(
17188 get_decoration(var.self, DecorationLocation),
17189 get_decoration(var.self, DecorationComponent));
17190 }
17191}
17192
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020017193bool 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 +020017194{
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020017195 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020017196 bool is_block = has_decoration(type.self, DecorationBlock);
17197 if (!is_block)
17198 return false;
17199
17200 BuiltIn builtin = BuiltInMax;
17201 if (is_member_builtin(type, index, &builtin))
17202 {
17203 return is_stage_output_builtin_masked(builtin);
17204 }
17205 else
17206 {
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020017207 uint32_t location = get_declared_member_location(var, index, strip_array);
17208 uint32_t component = get_member_decoration(type.self, index, DecorationComponent);
17209 return is_stage_output_location_masked(location, component);
Hans-Kristian Arntzena393de32021-04-06 14:12:24 +020017210 }
17211}
17212
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +010017213bool CompilerGLSL::is_stage_output_location_masked(uint32_t location, uint32_t component) const
17214{
17215 return masked_output_locations.count({ location, component }) != 0;
17216}
17217
17218bool CompilerGLSL::is_stage_output_builtin_masked(spv::BuiltIn builtin) const
17219{
17220 return masked_output_builtins.count(builtin) != 0;
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020017221}
17222
17223uint32_t CompilerGLSL::get_declared_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const
17224{
17225 auto &block_type = get<SPIRType>(var.basetype);
17226 if (has_member_decoration(block_type.self, mbr_idx, DecorationLocation))
17227 return get_member_decoration(block_type.self, mbr_idx, DecorationLocation);
17228 else
17229 return get_accumulated_member_location(var, mbr_idx, strip_array);
17230}
17231
17232uint32_t CompilerGLSL::get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const
17233{
17234 auto &type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
17235 uint32_t location = get_decoration(var.self, DecorationLocation);
17236
17237 for (uint32_t i = 0; i < mbr_idx; i++)
17238 {
17239 auto &mbr_type = get<SPIRType>(type.member_types[i]);
17240
17241 // Start counting from any place we have a new location decoration.
17242 if (has_member_decoration(type.self, mbr_idx, DecorationLocation))
17243 location = get_member_decoration(type.self, mbr_idx, DecorationLocation);
17244
Hans-Kristian Arntzen96ba0442021-04-20 13:03:58 +020017245 uint32_t location_count = type_to_location_count(mbr_type);
Hans-Kristian Arntzenba93b652021-04-06 14:43:34 +020017246 location += location_count;
17247 }
17248
17249 return location;
17250}
Hans-Kristian Arntzenae9ca7d2021-04-19 11:46:30 +020017251
17252StorageClass CompilerGLSL::get_expression_effective_storage_class(uint32_t ptr)
17253{
17254 auto *var = maybe_get_backing_variable(ptr);
17255
17256 // If the expression has been lowered to a temporary, we need to use the Generic storage class.
17257 // We're looking for the effective storage class of a given expression.
17258 // An access chain or forwarded OpLoads from such access chains
17259 // will generally have the storage class of the underlying variable, but if the load was not forwarded
17260 // we have lost any address space qualifiers.
17261 bool forced_temporary = ir.ids[ptr].get_type() == TypeExpression && !get<SPIRExpression>(ptr).access_chain &&
17262 (forced_temporaries.count(ptr) != 0 || forwarded_temporaries.count(ptr) == 0);
17263
17264 if (var && !forced_temporary)
17265 {
17266 if (variable_decl_is_remapped_storage(*var, StorageClassWorkgroup))
17267 return StorageClassWorkgroup;
17268 if (variable_decl_is_remapped_storage(*var, StorageClassStorageBuffer))
17269 return StorageClassStorageBuffer;
17270
17271 // Normalize SSBOs to StorageBuffer here.
17272 if (var->storage == StorageClassUniform &&
17273 has_decoration(get<SPIRType>(var->basetype).self, DecorationBufferBlock))
17274 return StorageClassStorageBuffer;
17275 else
17276 return var->storage;
17277 }
17278 else
17279 return expression_type(ptr).storage;
17280}
Hans-Kristian Arntzen96ba0442021-04-20 13:03:58 +020017281
17282uint32_t CompilerGLSL::type_to_location_count(const SPIRType &type) const
17283{
17284 uint32_t count;
17285 if (type.basetype == SPIRType::Struct)
17286 {
17287 uint32_t mbr_count = uint32_t(type.member_types.size());
17288 count = 0;
17289 for (uint32_t i = 0; i < mbr_count; i++)
17290 count += type_to_location_count(get<SPIRType>(type.member_types[i]));
17291 }
17292 else
17293 {
17294 count = type.columns > 1 ? type.columns : 1;
17295 }
17296
17297 uint32_t dim_count = uint32_t(type.array.size());
17298 for (uint32_t i = 0; i < dim_count; i++)
17299 count *= to_array_size_literal(type, i);
17300
17301 return count;
17302}