blob: ecc5fb30596cd241ef689a79548c0b7fc2d5ed80 [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzenf9818f02020-01-16 15:24:37 +01002 * Copyright 2015-2020 Arm Limited
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010017/*
18 * At your option, you may choose to accept this material under either:
19 * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
20 * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
21 * SPDX-License-Identifier: Apache-2.0 OR MIT.
22 */
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 Arntzene930f792018-04-17 14:56:49 +020043static bool is_unsigned_opcode(Op op)
44{
45 // Don't have to be exhaustive, only relevant for legacy target checking ...
46 switch (op)
47 {
48 case OpShiftRightLogical:
49 case OpUGreaterThan:
50 case OpUGreaterThanEqual:
51 case OpULessThan:
52 case OpULessThanEqual:
53 case OpUConvert:
54 case OpUDiv:
55 case OpUMod:
56 case OpUMulExtended:
57 case OpConvertUToF:
58 case OpConvertFToU:
59 return true;
60
61 default:
62 return false;
63 }
64}
65
66static bool is_unsigned_glsl_opcode(GLSLstd450 op)
67{
68 // Don't have to be exhaustive, only relevant for legacy target checking ...
69 switch (op)
70 {
71 case GLSLstd450UClamp:
72 case GLSLstd450UMin:
73 case GLSLstd450UMax:
74 case GLSLstd450FindUMsb:
75 return true;
76
77 default:
78 return false;
79 }
80}
81
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +020082static bool packing_is_vec4_padded(BufferPackingStandard packing)
83{
84 switch (packing)
85 {
86 case BufferPackingHLSLCbuffer:
87 case BufferPackingHLSLCbufferPackOffset:
88 case BufferPackingStd140:
89 case BufferPackingStd140EnhancedLayout:
90 return true;
91
92 default:
93 return false;
94 }
95}
96
97static bool packing_is_hlsl(BufferPackingStandard packing)
98{
99 switch (packing)
100 {
101 case BufferPackingHLSLCbuffer:
102 case BufferPackingHLSLCbufferPackOffset:
103 return true;
104
105 default:
106 return false;
107 }
108}
109
110static bool packing_has_flexible_offset(BufferPackingStandard packing)
111{
112 switch (packing)
113 {
114 case BufferPackingStd140:
115 case BufferPackingStd430:
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200116 case BufferPackingScalar:
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200117 case BufferPackingHLSLCbuffer:
118 return false;
119
120 default:
121 return true;
122 }
123}
124
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200125static bool packing_is_scalar(BufferPackingStandard packing)
126{
127 switch (packing)
128 {
129 case BufferPackingScalar:
130 case BufferPackingScalarEnhancedLayout:
131 return true;
132
133 default:
134 return false;
135 }
136}
137
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200138static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard packing)
139{
140 switch (packing)
141 {
142 case BufferPackingStd140EnhancedLayout:
143 return BufferPackingStd140;
144 case BufferPackingStd430EnhancedLayout:
145 return BufferPackingStd430;
146 case BufferPackingHLSLCbufferPackOffset:
147 return BufferPackingHLSLCbuffer;
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +0200148 case BufferPackingScalarEnhancedLayout:
149 return BufferPackingScalar;
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200150 default:
151 return packing;
152 }
153}
154
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100155void CompilerGLSL::init()
156{
157 if (ir.source.known)
158 {
159 options.es = ir.source.es;
160 options.version = ir.source.version;
161 }
162
163 // Query the locale to see what the decimal point is.
164 // We'll rely on fixing it up ourselves in the rare case we have a comma-as-decimal locale
165 // rather than setting locales ourselves. Settings locales in a safe and isolated way is rather
166 // tricky.
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100167#ifdef _WIN32
168 // On Windows, localeconv uses thread-local storage, so it should be fine.
169 const struct lconv *conv = localeconv();
170 if (conv && conv->decimal_point)
171 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen73102742019-03-18 10:13:33 +0100172#elif defined(__ANDROID__) && __ANDROID_API__ < 26
173 // nl_langinfo is not supported on this platform, fall back to the worse alternative.
174 const struct lconv *conv = localeconv();
175 if (conv && conv->decimal_point)
176 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100177#else
178 // localeconv, the portable function is not MT safe ...
Hans-Kristian Arntzen40965522019-02-28 12:32:52 +0100179 const char *decimal_point = nl_langinfo(RADIXCHAR);
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100180 if (decimal_point && *decimal_point != '\0')
181 current_locale_radix_character = *decimal_point;
182#endif
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100183}
184
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200185static const char *to_pls_layout(PlsFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100186{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200187 switch (format)
188 {
189 case PlsR11FG11FB10F:
190 return "layout(r11f_g11f_b10f) ";
191 case PlsR32F:
192 return "layout(r32f) ";
193 case PlsRG16F:
194 return "layout(rg16f) ";
195 case PlsRGB10A2:
196 return "layout(rgb10_a2) ";
197 case PlsRGBA8:
198 return "layout(rgba8) ";
199 case PlsRG16:
200 return "layout(rg16) ";
201 case PlsRGBA8I:
202 return "layout(rgba8i)";
203 case PlsRG16I:
204 return "layout(rg16i) ";
205 case PlsRGB10A2UI:
206 return "layout(rgb10_a2ui) ";
207 case PlsRGBA8UI:
208 return "layout(rgba8ui) ";
209 case PlsRG16UI:
210 return "layout(rg16ui) ";
211 case PlsR32UI:
212 return "layout(r32ui) ";
213 default:
214 return "";
215 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100216}
217
218static SPIRType::BaseType pls_format_to_basetype(PlsFormat format)
219{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200220 switch (format)
221 {
222 default:
223 case PlsR11FG11FB10F:
224 case PlsR32F:
225 case PlsRG16F:
226 case PlsRGB10A2:
227 case PlsRGBA8:
228 case PlsRG16:
229 return SPIRType::Float;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100230
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200231 case PlsRGBA8I:
232 case PlsRG16I:
233 return SPIRType::Int;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100234
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200235 case PlsRGB10A2UI:
236 case PlsRGBA8UI:
237 case PlsRG16UI:
238 case PlsR32UI:
239 return SPIRType::UInt;
240 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100241}
242
243static uint32_t pls_format_to_components(PlsFormat format)
244{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200245 switch (format)
246 {
247 default:
248 case PlsR32F:
249 case PlsR32UI:
250 return 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200252 case PlsRG16F:
253 case PlsRG16:
254 case PlsRG16UI:
255 case PlsRG16I:
256 return 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100257
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200258 case PlsR11FG11FB10F:
259 return 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200261 case PlsRGB10A2:
262 case PlsRGBA8:
263 case PlsRGBA8I:
264 case PlsRGB10A2UI:
265 case PlsRGBA8UI:
266 return 4;
267 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100268}
269
Hans-Kristian Arntzen93f32652020-01-07 14:05:55 +0100270const char *CompilerGLSL::vector_swizzle(int vecsize, int index)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800271{
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +0200272 static const char *const swizzle[4][4] = {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +0200273 { ".x", ".y", ".z", ".w" },
274 { ".xy", ".yz", ".zw", nullptr },
275 { ".xyz", ".yzw", nullptr, nullptr },
Hans-Kristian Arntzen7557ff52019-06-24 10:17:25 +0200276#if defined(__GNUC__) && (__GNUC__ == 9)
277 // This works around a GCC 9 bug, see details in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90947.
278 // This array ends up being compiled as all nullptrs, tripping the assertions below.
279 { "", nullptr, nullptr, "$" },
280#else
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +0200281 { "", nullptr, nullptr, nullptr },
Hans-Kristian Arntzen7557ff52019-06-24 10:17:25 +0200282#endif
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800283 };
284
285 assert(vecsize >= 1 && vecsize <= 4);
286 assert(index >= 0 && index < 4);
287 assert(swizzle[vecsize - 1][index]);
288
289 return swizzle[vecsize - 1][index];
290}
291
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100292void CompilerGLSL::reset()
293{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200294 // We do some speculative optimizations which should pretty much always work out,
295 // but just in case the SPIR-V is rather weird, recompile until it's happy.
296 // This typically only means one extra pass.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200297 clear_force_recompile();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100298
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200299 // Clear invalid expression tracking.
300 invalid_expressions.clear();
301 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200303 // Clear temporary usage tracking.
304 expression_usage_counts.clear();
305 forwarded_temporaries.clear();
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +0200306 suppressed_usage_tracking.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100307
Lukas Hermanns50ac6862019-09-18 14:03:54 -0400308 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -0400309 flushed_phi_variables.clear();
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400310
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +0100311 reset_name_caches();
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200312
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100313 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, SPIRFunction &func) {
314 func.active = false;
315 func.flush_undeclared = true;
316 });
317
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +0100318 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) { var.dependees.clear(); });
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100319
Lukas Hermanns7ad0a842019-09-23 18:05:04 -0400320 ir.reset_all_of_type<SPIRExpression>();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100321 ir.reset_all_of_type<SPIRAccessChain>();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200323 statement_count = 0;
324 indent = 0;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +0200325 current_loop_level = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100326}
327
328void CompilerGLSL::remap_pls_variables()
329{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200330 for (auto &input : pls_inputs)
331 {
332 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200334 bool input_is_target = false;
335 if (var.storage == StorageClassUniformConstant)
336 {
337 auto &type = get<SPIRType>(var.basetype);
338 input_is_target = type.image.dim == DimSubpassData;
339 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 if (var.storage != StorageClassInput && !input_is_target)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100342 SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200343 var.remapped_variable = true;
344 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100345
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200346 for (auto &output : pls_outputs)
347 {
348 auto &var = get<SPIRVariable>(output.id);
349 if (var.storage != StorageClassOutput)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100350 SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200351 var.remapped_variable = true;
352 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100353}
354
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100355void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location)
356{
357 subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
358 inout_color_attachments.insert(color_location);
359}
360
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200361void CompilerGLSL::find_static_extensions()
362{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100363 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
364 if (type.basetype == SPIRType::Double)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200365 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100366 if (options.es)
367 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
368 if (!options.es && options.version < 400)
369 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200370 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100371 else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100372 {
373 if (options.es)
374 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
375 if (!options.es)
376 require_extension_internal("GL_ARB_gpu_shader_int64");
377 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100378 else if (type.basetype == SPIRType::Half)
379 {
380 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_float16");
381 if (options.vulkan_semantics)
382 require_extension_internal("GL_EXT_shader_16bit_storage");
383 }
384 else if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
385 {
386 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int8");
387 if (options.vulkan_semantics)
388 require_extension_internal("GL_EXT_shader_8bit_storage");
389 }
390 else if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
391 {
392 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int16");
393 if (options.vulkan_semantics)
394 require_extension_internal("GL_EXT_shader_16bit_storage");
395 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100396 });
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200397
398 auto &execution = get_entry_point();
399 switch (execution.model)
400 {
401 case ExecutionModelGLCompute:
402 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200403 require_extension_internal("GL_ARB_compute_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200404 if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100405 SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200406 break;
407
408 case ExecutionModelGeometry:
409 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200410 require_extension_internal("GL_EXT_geometry_shader");
robfb1820e2017-06-17 10:06:46 +0900411 if (!options.es && options.version < 150)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200412 require_extension_internal("GL_ARB_geometry_shader4");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200413
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100414 if (execution.flags.get(ExecutionModeInvocations) && execution.invocations != 1)
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200415 {
416 // Instanced GS is part of 400 core or this extension.
417 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200418 require_extension_internal("GL_ARB_gpu_shader5");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200419 }
420 break;
421
422 case ExecutionModelTessellationEvaluation:
423 case ExecutionModelTessellationControl:
424 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200425 require_extension_internal("GL_EXT_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200426 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200427 require_extension_internal("GL_ARB_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200428 break;
429
Patrick Moursc74d7a42019-03-25 15:06:01 +0100430 case ExecutionModelRayGenerationNV:
431 case ExecutionModelIntersectionNV:
432 case ExecutionModelAnyHitNV:
433 case ExecutionModelClosestHitNV:
434 case ExecutionModelMissNV:
435 case ExecutionModelCallableNV:
436 if (options.es || options.version < 460)
437 SPIRV_CROSS_THROW("Ray tracing shaders require non-es profile with version 460 or above.");
Patrick Moursc96bab02019-03-26 14:04:39 +0100438 require_extension_internal("GL_NV_ray_tracing");
Patrick Moursc74d7a42019-03-25 15:06:01 +0100439 break;
440
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200441 default:
442 break;
443 }
444
445 if (!pls_inputs.empty() || !pls_outputs.empty())
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100446 {
447 if (execution.model != ExecutionModelFragment)
448 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_pixel_local_storage in fragment shaders.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200449 require_extension_internal("GL_EXT_shader_pixel_local_storage");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100450 }
451
452 if (!inout_color_attachments.empty())
453 {
454 if (execution.model != ExecutionModelFragment)
455 SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
456 if (options.vulkan_semantics)
457 SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
458 require_extension_internal("GL_EXT_shader_framebuffer_fetch");
459 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +0200460
461 if (options.separate_shader_objects && !options.es && options.version < 410)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200462 require_extension_internal("GL_ARB_separate_shader_objects");
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200463
464 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
465 {
466 if (!options.vulkan_semantics)
467 SPIRV_CROSS_THROW("GL_EXT_buffer_reference is only supported in Vulkan GLSL.");
468 if (options.es && options.version < 320)
469 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires ESSL 320.");
470 else if (!options.es && options.version < 450)
471 SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires GLSL 450.");
472 require_extension_internal("GL_EXT_buffer_reference");
473 }
474 else if (ir.addressing_model != AddressingModelLogical)
475 {
476 SPIRV_CROSS_THROW("Only Logical and PhysicalStorageBuffer64EXT addressing models are supported.");
477 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200478
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100479 // Check for nonuniform qualifier and passthrough.
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200480 // Instead of looping over all decorations to find this, just look at capabilities.
481 for (auto &cap : ir.declared_capabilities)
482 {
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200483 switch (cap)
484 {
485 case CapabilityShaderNonUniformEXT:
Mateusz Kielan127224d2020-04-18 21:21:43 +0200486 if (!options.vulkan_semantics)
487 require_extension_internal("GL_NV_gpu_shader5");
488 else
489 require_extension_internal("GL_EXT_nonuniform_qualifier");
490 break;
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200491 case CapabilityRuntimeDescriptorArrayEXT:
492 if (!options.vulkan_semantics)
493 SPIRV_CROSS_THROW("GL_EXT_nonuniform_qualifier is only supported in Vulkan GLSL.");
494 require_extension_internal("GL_EXT_nonuniform_qualifier");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100495 break;
496
497 case CapabilityGeometryShaderPassthroughNV:
498 if (execution.model == ExecutionModelGeometry)
499 {
500 require_extension_internal("GL_NV_geometry_shader_passthrough");
501 execution.geometry_passthrough = true;
502 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200503 break;
504
Hans-Kristian Arntzendc940842020-12-07 12:16:02 +0100505 case CapabilityVariablePointers:
506 case CapabilityVariablePointersStorageBuffer:
507 SPIRV_CROSS_THROW("VariablePointers capability is not supported in GLSL.");
508
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200509 default:
510 break;
511 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +0200512 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200513}
514
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100515string CompilerGLSL::compile()
516{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200517 ir.fixup_reserved_names();
518
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100519 if (options.vulkan_semantics)
520 backend.allow_precision_qualifiers = true;
Mateusz Kielan127224d2020-04-18 21:21:43 +0200521 else
522 {
523 // only NV_gpu_shader5 supports divergent indexing on OpenGL, and it does so without extra qualifiers
524 backend.nonuniform_qualifier = "";
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +0200525 backend.needs_row_major_load_workaround = true;
Mateusz Kielan127224d2020-04-18 21:21:43 +0200526 }
Hans-Kristian Arntzenf708b492018-01-09 09:16:33 +0100527 backend.force_gl_in_out_block = true;
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +0100528 backend.supports_extensions = true;
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +0200529 backend.use_array_constructor = true;
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100530
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +0200531 if (is_legacy_es())
532 backend.support_case_fallthrough = false;
533
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200534 // Scan the SPIR-V to find trivial uses of extensions.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200535 fixup_type_alias();
536 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200537 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200538 find_static_extensions();
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +0100539 fixup_image_load_store_access();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100540 update_active_builtins();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +0100541 analyze_image_and_sampler_usage();
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200542 analyze_interlocked_resource_usage();
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +0100543 if (!inout_color_attachments.empty())
544 emit_inout_fragment_outputs_copy_to_subpass_inputs();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200545
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200546 // Shaders might cast unrelated data to pointers of non-block types.
547 // Find all such instances and make sure we can cast the pointers to a synthesized block type.
548 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
549 analyze_non_block_pointer_types();
550
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200551 uint32_t pass_count = 0;
552 do
553 {
554 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100555 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200557 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100558
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200559 buffer.reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100560
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200561 emit_header();
562 emit_resources();
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200563 emit_extension_workarounds(get_execution_model());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100564
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200565 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100566
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200567 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200568 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100569
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +0200570 // Implement the interlocked wrapper function at the end.
571 // The body was implemented in lieu of main().
572 if (interlocked_is_complex)
573 {
574 statement("void main()");
575 begin_scope();
576 statement("// Interlocks were used in a way not compatible with GLSL, this is very slow.");
577 if (options.es)
578 statement("beginInvocationInterlockNV();");
579 else
580 statement("beginInvocationInterlockARB();");
581 statement("spvMainInterlockedBody();");
582 if (options.es)
583 statement("endInvocationInterlockNV();");
584 else
585 statement("endInvocationInterlockARB();");
586 end_scope();
587 }
588
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100589 // Entry point in GLSL is always main().
590 get_entry_point().name = "main";
591
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200592 return buffer.str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100593}
594
Bill Hollingsc5c07362016-11-27 12:34:04 -0500595std::string CompilerGLSL::get_partial_source()
596{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200597 return buffer.str();
Bill Hollingsc5c07362016-11-27 12:34:04 -0500598}
599
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200600void CompilerGLSL::build_workgroup_size(SmallVector<string> &arguments, const SpecializationConstant &wg_x,
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +0100601 const SpecializationConstant &wg_y, const SpecializationConstant &wg_z)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100602{
603 auto &execution = get_entry_point();
604
605 if (wg_x.id)
606 {
607 if (options.vulkan_semantics)
608 arguments.push_back(join("local_size_x_id = ", wg_x.constant_id));
609 else
610 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(wg_x.id).specialization_constant_macro_name));
611 }
612 else
613 arguments.push_back(join("local_size_x = ", execution.workgroup_size.x));
614
615 if (wg_y.id)
616 {
617 if (options.vulkan_semantics)
618 arguments.push_back(join("local_size_y_id = ", wg_y.constant_id));
619 else
620 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(wg_y.id).specialization_constant_macro_name));
621 }
622 else
623 arguments.push_back(join("local_size_y = ", execution.workgroup_size.y));
624
625 if (wg_z.id)
626 {
627 if (options.vulkan_semantics)
628 arguments.push_back(join("local_size_z_id = ", wg_z.constant_id));
629 else
630 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(wg_z.id).specialization_constant_macro_name));
631 }
632 else
633 arguments.push_back(join("local_size_z = ", execution.workgroup_size.z));
634}
635
crissdb52e272020-10-08 12:14:52 +0200636void CompilerGLSL::request_subgroup_feature(ShaderSubgroupSupportHelper::Feature feature)
637{
638 if (options.vulkan_semantics)
639 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200640 auto khr_extension = ShaderSubgroupSupportHelper::get_KHR_extension_for_feature(feature);
641 require_extension_internal(ShaderSubgroupSupportHelper::get_extension_name(khr_extension));
crissdb52e272020-10-08 12:14:52 +0200642 }
643 else
644 {
645 if (!shader_subgroup_supporter.is_feature_requested(feature))
646 force_recompile();
647 shader_subgroup_supporter.request_feature(feature);
648 }
649}
650
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100651void CompilerGLSL::emit_header()
652{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200653 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200654 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100655
Ben Claytone9621822017-10-09 10:33:42 +0100656 if (!options.es && options.version < 420)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200657 {
Ben Claytone9621822017-10-09 10:33:42 +0100658 // Needed for binding = # on UBOs, etc.
659 if (options.enable_420pack_extension)
660 {
661 statement("#ifdef GL_ARB_shading_language_420pack");
662 statement("#extension GL_ARB_shading_language_420pack : require");
663 statement("#endif");
664 }
665 // Needed for: layout(early_fragment_tests) in;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100666 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200667 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200668 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100669
Chip Davis1df47db2019-07-10 22:42:39 -0500670 // Needed for: layout(post_depth_coverage) in;
671 if (execution.flags.get(ExecutionModePostDepthCoverage))
672 require_extension_internal("GL_ARB_post_depth_coverage");
673
Chip Davis2eff4202019-08-04 00:07:20 -0500674 // Needed for: layout({pixel,sample}_interlock_[un]ordered) in;
675 if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT) ||
676 execution.flags.get(ExecutionModePixelInterlockUnorderedEXT) ||
677 execution.flags.get(ExecutionModeSampleInterlockOrderedEXT) ||
678 execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT))
679 {
680 if (options.es)
681 {
682 if (options.version < 310)
683 SPIRV_CROSS_THROW("At least ESSL 3.10 required for fragment shader interlock.");
684 require_extension_internal("GL_NV_fragment_shader_interlock");
685 }
686 else
687 {
688 if (options.version < 420)
689 require_extension_internal("GL_ARB_shader_image_load_store");
690 require_extension_internal("GL_ARB_fragment_shader_interlock");
691 }
692 }
693
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200694 for (auto &ext : forced_extensions)
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200695 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100696 if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16")
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200697 {
698 // Special case, this extension has a potential fallback to another vendor extension in normal GLSL.
699 // GL_AMD_gpu_shader_half_float is a superset, so try that first.
700 statement("#if defined(GL_AMD_gpu_shader_half_float)");
701 statement("#extension GL_AMD_gpu_shader_half_float : require");
Chip Davis1fb27b42018-10-31 09:43:03 -0500702 if (!options.vulkan_semantics)
703 {
704 statement("#elif defined(GL_NV_gpu_shader5)");
705 statement("#extension GL_NV_gpu_shader5 : require");
706 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100707 else
708 {
709 statement("#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)");
710 statement("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
711 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200712 statement("#else");
713 statement("#error No extension available for FP16.");
714 statement("#endif");
715 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100716 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16")
Chip Davis1fb27b42018-10-31 09:43:03 -0500717 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100718 if (options.vulkan_semantics)
719 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
720 else
721 {
722 statement("#if defined(GL_AMD_gpu_shader_int16)");
723 statement("#extension GL_AMD_gpu_shader_int16 : require");
724 statement("#else");
725 statement("#error No extension available for Int16.");
726 statement("#endif");
727 }
Chip Davis1fb27b42018-10-31 09:43:03 -0500728 }
Chip Davis5fe1ecc2019-08-02 21:02:05 -0500729 else if (ext == "GL_ARB_post_depth_coverage")
730 {
731 if (options.es)
732 statement("#extension GL_EXT_post_depth_coverage : require");
733 else
734 {
735 statement("#if defined(GL_ARB_post_depth_coverge)");
736 statement("#extension GL_ARB_post_depth_coverage : require");
737 statement("#else");
738 statement("#extension GL_EXT_post_depth_coverage : require");
739 statement("#endif");
740 }
741 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +0200742 else if (!options.vulkan_semantics && ext == "GL_ARB_shader_draw_parameters")
743 {
744 // Soft-enable this extension on plain GLSL.
745 statement("#ifdef ", ext);
746 statement("#extension ", ext, " : enable");
747 statement("#endif");
748 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200749 else
750 statement("#extension ", ext, " : require");
751 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100752
crissdb52e272020-10-08 12:14:52 +0200753 if (!options.vulkan_semantics)
754 {
755 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200756 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +0200757
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200758 for (uint32_t feature_index = 0; feature_index < Supp::FeatureCount; feature_index++)
crissdb52e272020-10-08 12:14:52 +0200759 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200760 auto feature = static_cast<Supp::Feature>(feature_index);
crissdb52e272020-10-08 12:14:52 +0200761 if (!shader_subgroup_supporter.is_feature_requested(feature))
762 continue;
763
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200764 auto exts = Supp::get_candidates_for_feature(feature, result);
crissdb52e272020-10-08 12:14:52 +0200765 if (exts.empty())
766 continue;
767
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200768 statement("");
crissdb52e272020-10-08 12:14:52 +0200769
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200770 for (auto &ext : exts)
771 {
772 const char *name = Supp::get_extension_name(ext);
773 const char *extra_predicate = Supp::get_extra_required_extension_predicate(ext);
774 auto extra_names = Supp::get_extra_required_extension_names(ext);
775 statement(&ext != &exts.front() ? "#elif" : "#if", " defined(", name, ")",
776 (*extra_predicate != '\0' ? " && " : ""), extra_predicate);
777 for (const auto &e : extra_names)
crissdb52e272020-10-08 12:14:52 +0200778 statement("#extension ", e, " : enable");
779 statement("#extension ", name, " : require");
780 }
781
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +0200782 if (!Supp::can_feature_be_implemented_without_extensions(feature))
crissdb52e272020-10-08 12:14:52 +0200783 {
784 statement("#else");
785 statement("#error No extensions available to emulate requested subgroup feature.");
786 }
787
788 statement("#endif");
789 }
790 }
791
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200792 for (auto &header : header_lines)
793 statement(header);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100794
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200795 SmallVector<string> inputs;
796 SmallVector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100797
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200798 switch (execution.model)
799 {
800 case ExecutionModelGeometry:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100801 if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200802 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100803 if (execution.flags.get(ExecutionModeInputPoints))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200804 inputs.push_back("points");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100805 if (execution.flags.get(ExecutionModeInputLines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200806 inputs.push_back("lines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100807 if (execution.flags.get(ExecutionModeInputLinesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200808 inputs.push_back("lines_adjacency");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100809 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200810 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100811 if (execution.flags.get(ExecutionModeInputTrianglesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200812 inputs.push_back("triangles_adjacency");
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100813
814 if (!execution.geometry_passthrough)
815 {
816 // For passthrough, these are implies and cannot be declared in shader.
817 outputs.push_back(join("max_vertices = ", execution.output_vertices));
818 if (execution.flags.get(ExecutionModeOutputTriangleStrip))
819 outputs.push_back("triangle_strip");
820 if (execution.flags.get(ExecutionModeOutputPoints))
821 outputs.push_back("points");
822 if (execution.flags.get(ExecutionModeOutputLineStrip))
823 outputs.push_back("line_strip");
824 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200825 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100826
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200827 case ExecutionModelTessellationControl:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100828 if (execution.flags.get(ExecutionModeOutputVertices))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200829 outputs.push_back(join("vertices = ", execution.output_vertices));
830 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100831
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200832 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100833 if (execution.flags.get(ExecutionModeQuads))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200834 inputs.push_back("quads");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100835 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200836 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100837 if (execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200838 inputs.push_back("isolines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100839 if (execution.flags.get(ExecutionModePointMode))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200840 inputs.push_back("point_mode");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200841
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100842 if (!execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200843 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100844 if (execution.flags.get(ExecutionModeVertexOrderCw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200845 inputs.push_back("cw");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100846 if (execution.flags.get(ExecutionModeVertexOrderCcw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200847 inputs.push_back("ccw");
848 }
849
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100850 if (execution.flags.get(ExecutionModeSpacingFractionalEven))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200851 inputs.push_back("fractional_even_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100852 if (execution.flags.get(ExecutionModeSpacingFractionalOdd))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200853 inputs.push_back("fractional_odd_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100854 if (execution.flags.get(ExecutionModeSpacingEqual))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200855 inputs.push_back("equal_spacing");
856 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200858 case ExecutionModelGLCompute:
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200859 {
860 if (execution.workgroup_size.constant != 0)
861 {
862 SpecializationConstant wg_x, wg_y, wg_z;
863 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
864
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100865 // If there are any spec constants on legacy GLSL, defer declaration, we need to set up macro
866 // declarations before we can emit the work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200867 if (options.vulkan_semantics ||
868 ((wg_x.id == ConstantID(0)) && (wg_y.id == ConstantID(0)) && (wg_z.id == ConstantID(0))))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100869 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200870 }
871 else
872 {
873 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
874 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
875 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
876 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200877 break;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200878 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100879
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200880 case ExecutionModelFragment:
881 if (options.es)
882 {
883 switch (options.fragment.default_float_precision)
884 {
885 case Options::Lowp:
886 statement("precision lowp float;");
887 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100888
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200889 case Options::Mediump:
890 statement("precision mediump float;");
891 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100892
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200893 case Options::Highp:
894 statement("precision highp float;");
895 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100896
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200897 default:
898 break;
899 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100900
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200901 switch (options.fragment.default_int_precision)
902 {
903 case Options::Lowp:
904 statement("precision lowp int;");
905 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100906
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200907 case Options::Mediump:
908 statement("precision mediump int;");
909 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100910
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200911 case Options::Highp:
912 statement("precision highp int;");
913 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100914
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200915 default:
916 break;
917 }
918 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100919
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100920 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200921 inputs.push_back("early_fragment_tests");
Chip Davis1df47db2019-07-10 22:42:39 -0500922 if (execution.flags.get(ExecutionModePostDepthCoverage))
923 inputs.push_back("post_depth_coverage");
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +0100924
Chip Davis2eff4202019-08-04 00:07:20 -0500925 if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT))
926 inputs.push_back("pixel_interlock_ordered");
927 else if (execution.flags.get(ExecutionModePixelInterlockUnorderedEXT))
928 inputs.push_back("pixel_interlock_unordered");
929 else if (execution.flags.get(ExecutionModeSampleInterlockOrderedEXT))
930 inputs.push_back("sample_interlock_ordered");
931 else if (execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT))
932 inputs.push_back("sample_interlock_unordered");
933
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +0100934 if (!options.es && execution.flags.get(ExecutionModeDepthGreater))
935 statement("layout(depth_greater) out float gl_FragDepth;");
936 else if (!options.es && execution.flags.get(ExecutionModeDepthLess))
937 statement("layout(depth_less) out float gl_FragDepth;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100938
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200939 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100940
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200941 default:
942 break;
943 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100944
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200945 if (!inputs.empty())
946 statement("layout(", merge(inputs), ") in;");
947 if (!outputs.empty())
948 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100949
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200950 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100951}
952
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +0100953bool CompilerGLSL::type_is_empty(const SPIRType &type)
954{
955 return type.basetype == SPIRType::Struct && type.member_types.empty();
956}
957
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200958void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100959{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200960 // Struct types can be stamped out multiple times
961 // with just different offsets, matrix layouts, etc ...
962 // Type-punning with these types is legal, which complicates things
963 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzen294259e2018-03-05 16:27:04 +0100964 // 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 +0200965 if (type.type_alias != TypeID(0) &&
966 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200967 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200968
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200969 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200970 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100971
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200972 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200973 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100974
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200975 type.member_name_cache.clear();
976
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200977 uint32_t i = 0;
978 bool emitted = false;
979 for (auto &member : type.member_types)
980 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200981 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -0500982 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200983 i++;
984 emitted = true;
985 }
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +0200986
987 // Don't declare empty structs in GLSL, this is not allowed.
988 if (type_is_empty(type) && !backend.supports_empty_struct)
989 {
990 statement("int empty_struct_member;");
991 emitted = true;
992 }
993
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +0200994 if (has_extended_decoration(type.self, SPIRVCrossDecorationPaddingTarget))
995 emit_struct_padding_target(type);
996
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200997 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100998
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200999 if (emitted)
1000 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001001}
1002
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001003string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001004{
1005 string res;
1006 //if (flags & (1ull << DecorationSmooth))
1007 // res += "smooth ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001008 if (flags.get(DecorationFlat))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001009 res += "flat ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001010 if (flags.get(DecorationNoPerspective))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001011 res += "noperspective ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001012 if (flags.get(DecorationCentroid))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001013 res += "centroid ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001014 if (flags.get(DecorationPatch))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001015 res += "patch ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001016 if (flags.get(DecorationSample))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001017 res += "sample ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001018 if (flags.get(DecorationInvariant))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001019 res += "invariant ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001020 if (flags.get(DecorationExplicitInterpAMD))
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +01001021 res += "__explicitInterpAMD ";
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001022
1023 return res;
1024}
1025
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001026string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
1027{
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001028 if (is_legacy())
1029 return "";
1030
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001031 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
1032 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001033 if (!is_block)
1034 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001035
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001036 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001037 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +02001038 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001039 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001040
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001041 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001042
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001043 if (has_member_decoration(type.self, index, DecorationPassthroughNV))
1044 attr.push_back("passthrough");
1045
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001046 // We can only apply layouts on members in block interfaces.
1047 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
1048 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
1049 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
1050 //
1051 // We would like to go from (SPIR-V style):
1052 //
1053 // struct Foo { layout(row_major) mat4 matrix; };
1054 // buffer UBO { Foo foo; };
1055 //
1056 // to
1057 //
1058 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
1059 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
1060 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001061
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001062 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001063 attr.push_back("row_major");
1064 // We don't emit any global layouts, so column_major is default.
1065 //if (flags & (1ull << DecorationColMajor))
1066 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001067
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001068 if (dec.decoration_flags.get(DecorationLocation) && can_use_io_location(type.storage, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001069 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001070
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001071 // Can only declare component if we can declare location.
1072 if (dec.decoration_flags.get(DecorationComponent) && can_use_io_location(type.storage, true))
1073 {
1074 if (!options.es)
1075 {
1076 if (options.version < 440 && options.version >= 140)
1077 require_extension_internal("GL_ARB_enhanced_layouts");
1078 else if (options.version < 140)
1079 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
1080 attr.push_back(join("component = ", dec.component));
1081 }
1082 else
1083 SPIRV_CROSS_THROW("Component decoration is not supported in ES targets.");
1084 }
1085
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001086 // 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 +02001087 // This is only done selectively in GLSL as needed.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02001088 if (has_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset) &&
1089 dec.decoration_flags.get(DecorationOffset))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001090 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001091 else if (type.storage == StorageClassOutput && dec.decoration_flags.get(DecorationOffset))
1092 attr.push_back(join("xfb_offset = ", dec.offset));
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001094 if (attr.empty())
1095 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001096
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001097 string res = "layout(";
1098 res += merge(attr);
1099 res += ") ";
1100 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001101}
1102
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001103const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001104{
Brad Davis76204002018-06-20 10:25:38 -07001105 if (options.es && is_desktop_only_format(format))
1106 SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001107
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001108 switch (format)
1109 {
1110 case ImageFormatRgba32f:
1111 return "rgba32f";
1112 case ImageFormatRgba16f:
1113 return "rgba16f";
1114 case ImageFormatR32f:
1115 return "r32f";
1116 case ImageFormatRgba8:
1117 return "rgba8";
1118 case ImageFormatRgba8Snorm:
1119 return "rgba8_snorm";
1120 case ImageFormatRg32f:
1121 return "rg32f";
1122 case ImageFormatRg16f:
1123 return "rg16f";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001124 case ImageFormatRgba32i:
1125 return "rgba32i";
1126 case ImageFormatRgba16i:
1127 return "rgba16i";
1128 case ImageFormatR32i:
1129 return "r32i";
1130 case ImageFormatRgba8i:
1131 return "rgba8i";
1132 case ImageFormatRg32i:
1133 return "rg32i";
1134 case ImageFormatRg16i:
1135 return "rg16i";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001136 case ImageFormatRgba32ui:
1137 return "rgba32ui";
1138 case ImageFormatRgba16ui:
1139 return "rgba16ui";
1140 case ImageFormatR32ui:
1141 return "r32ui";
1142 case ImageFormatRgba8ui:
1143 return "rgba8ui";
1144 case ImageFormatRg32ui:
1145 return "rg32ui";
1146 case ImageFormatRg16ui:
1147 return "rg16ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001148 case ImageFormatR11fG11fB10f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001149 return "r11f_g11f_b10f";
1150 case ImageFormatR16f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001151 return "r16f";
1152 case ImageFormatRgb10A2:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001153 return "rgb10_a2";
1154 case ImageFormatR8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001155 return "r8";
1156 case ImageFormatRg8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001157 return "rg8";
1158 case ImageFormatR16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001159 return "r16";
1160 case ImageFormatRg16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001161 return "rg16";
1162 case ImageFormatRgba16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001163 return "rgba16";
1164 case ImageFormatR16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001165 return "r16_snorm";
1166 case ImageFormatRg16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001167 return "rg16_snorm";
1168 case ImageFormatRgba16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001169 return "rgba16_snorm";
1170 case ImageFormatR8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001171 return "r8_snorm";
1172 case ImageFormatRg8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001173 return "rg8_snorm";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001174 case ImageFormatR8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001175 return "r8ui";
1176 case ImageFormatRg8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001177 return "rg8ui";
1178 case ImageFormatR16ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001179 return "r16ui";
1180 case ImageFormatRgb10a2ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001181 return "rgb10_a2ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001182 case ImageFormatR8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001183 return "r8i";
1184 case ImageFormatRg8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001185 return "rg8i";
1186 case ImageFormatR16i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001187 return "r16i";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +02001188 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001189 case ImageFormatUnknown:
1190 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001191 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001192}
1193
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001194uint32_t CompilerGLSL::type_to_packed_base_size(const SPIRType &type, BufferPackingStandard)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001195{
1196 switch (type.basetype)
1197 {
1198 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02001199 case SPIRType::Int64:
1200 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001201 return 8;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001202 case SPIRType::Float:
1203 case SPIRType::Int:
1204 case SPIRType::UInt:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001205 return 4;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001206 case SPIRType::Half:
Chip Davis117ccf42018-11-01 17:20:07 -05001207 case SPIRType::Short:
1208 case SPIRType::UShort:
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001209 return 2;
Chip Davis117ccf42018-11-01 17:20:07 -05001210 case SPIRType::SByte:
1211 case SPIRType::UByte:
1212 return 1;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001213
1214 default:
1215 SPIRV_CROSS_THROW("Unrecognized type in type_to_packed_base_size.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001216 }
1217}
1218
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001219uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bitset &flags,
1220 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001221{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001222 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1223 // and is 64-bit.
1224 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1225 {
1226 if (!type.pointer)
1227 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1228
1229 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1230 {
1231 if (packing_is_vec4_padded(packing) && type_is_array_of_pointers(type))
1232 return 16;
1233 else
1234 return 8;
1235 }
1236 else
1237 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1238 }
1239
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001240 if (!type.array.empty())
1241 {
1242 uint32_t minimum_alignment = 1;
1243 if (packing_is_vec4_padded(packing))
1244 minimum_alignment = 16;
1245
1246 auto *tmp = &get<SPIRType>(type.parent_type);
1247 while (!tmp->array.empty())
1248 tmp = &get<SPIRType>(tmp->parent_type);
1249
1250 // Get the alignment of the base type, then maybe round up.
1251 return max(minimum_alignment, type_to_packed_alignment(*tmp, flags, packing));
1252 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001254 if (type.basetype == SPIRType::Struct)
1255 {
1256 // Rule 9. Structs alignments are maximum alignment of its members.
Hans-Kristian Arntzen8c632da2019-01-28 11:02:28 +01001257 uint32_t alignment = 1;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001258 for (uint32_t i = 0; i < type.member_types.size(); i++)
1259 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001260 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +02001261 alignment =
1262 max(alignment, type_to_packed_alignment(get<SPIRType>(type.member_types[i]), member_flags, packing));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001263 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001264
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001265 // In std140, struct alignment is rounded up to 16.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001266 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001267 alignment = max(alignment, 16u);
1268
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001269 return alignment;
1270 }
1271 else
1272 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001273 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1274
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001275 // Alignment requirement for scalar block layout is always the alignment for the most basic component.
1276 if (packing_is_scalar(packing))
1277 return base_alignment;
1278
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001279 // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle
1280 // a vec4, this is handled outside since that part knows our current offset.
1281 if (type.columns == 1 && packing_is_hlsl(packing))
1282 return base_alignment;
1283
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001284 // From 7.6.2.2 in GL 4.5 core spec.
1285 // Rule 1
1286 if (type.vecsize == 1 && type.columns == 1)
1287 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001289 // Rule 2
1290 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
1291 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001292
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001293 // Rule 3
1294 if (type.vecsize == 3 && type.columns == 1)
1295 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001297 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001298
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001299 // Rule 5. Column-major matrices are stored as arrays of
1300 // vectors.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001301 if (flags.get(DecorationColMajor) && type.columns > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001302 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001303 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001304 return 4 * base_alignment;
1305 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001306 return 4 * base_alignment;
1307 else
1308 return type.vecsize * base_alignment;
1309 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001311 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001312
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001313 // Rule 7.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001314 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001315 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001316 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001317 return 4 * base_alignment;
1318 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001319 return 4 * base_alignment;
1320 else
1321 return type.columns * base_alignment;
1322 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001323
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001324 // Rule 8 implied.
1325 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001326
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001327 SPIRV_CROSS_THROW("Did not find suitable rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001328}
1329
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001330uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, const Bitset &flags,
1331 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001332{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001333 // Array stride is equal to aligned size of the underlying type.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001334 uint32_t parent = type.parent_type;
1335 assert(parent);
1336
1337 auto &tmp = get<SPIRType>(parent);
1338
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001339 uint32_t size = type_to_packed_size(tmp, flags, packing);
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001340 uint32_t alignment = type_to_packed_alignment(type, flags, packing);
1341 return (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001342}
1343
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001344uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001345{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001346 if (!type.array.empty())
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001347 {
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001348 uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing);
1349
1350 // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size,
1351 // so that it is possible to pack other vectors into the last element.
1352 if (packing_is_hlsl(packing) && type.basetype != SPIRType::Struct)
1353 packed_size -= (4 - type.vecsize) * (type.width / 8);
1354
1355 return packed_size;
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001356 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001357
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001358 // If using PhysicalStorageBufferEXT storage class, this is a pointer,
1359 // and is 64-bit.
1360 if (type.storage == StorageClassPhysicalStorageBufferEXT)
1361 {
1362 if (!type.pointer)
1363 SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers.");
1364
1365 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
1366 return 8;
1367 else
1368 SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT.");
1369 }
1370
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001371 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001372
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001373 if (type.basetype == SPIRType::Struct)
1374 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001375 uint32_t pad_alignment = 1;
1376
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001377 for (uint32_t i = 0; i < type.member_types.size(); i++)
1378 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001379 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001380 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001381
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001382 uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
1383 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001384
1385 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1386 // GL 4.5 spec, 7.6.2.2.
1387 if (member_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001388 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001389 else
1390 pad_alignment = 1;
1391
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001392 size = (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001393 size += type_to_packed_size(member_type, member_flags, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001394 }
1395 }
1396 else
1397 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001398 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1399
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001400 if (packing_is_scalar(packing))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001401 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001402 size = type.vecsize * type.columns * base_alignment;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001403 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001404 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001405 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001406 if (type.columns == 1)
1407 size = type.vecsize * base_alignment;
1408
1409 if (flags.get(DecorationColMajor) && type.columns > 1)
1410 {
1411 if (packing_is_vec4_padded(packing))
1412 size = type.columns * 4 * base_alignment;
1413 else if (type.vecsize == 3)
1414 size = type.columns * 4 * base_alignment;
1415 else
1416 size = type.columns * type.vecsize * base_alignment;
1417 }
1418
1419 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
1420 {
1421 if (packing_is_vec4_padded(packing))
1422 size = type.vecsize * 4 * base_alignment;
1423 else if (type.columns == 3)
1424 size = type.vecsize * 4 * base_alignment;
1425 else
1426 size = type.vecsize * type.columns * base_alignment;
1427 }
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001428
1429 // For matrices in HLSL, the last element has a size which depends on its vector size,
1430 // so that it is possible to pack other vectors into the last element.
1431 if (packing_is_hlsl(packing) && type.columns > 1)
1432 size -= (4 - type.vecsize) * (type.width / 8);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001433 }
1434 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001436 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001437}
1438
msiglreithd096f5c2017-11-27 16:00:56 +01001439bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001440 uint32_t *failed_validation_index, uint32_t start_offset,
1441 uint32_t end_offset)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001442{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001443 // This is very tricky and error prone, but try to be exhaustive and correct here.
1444 // SPIR-V doesn't directly say if we're using std430 or std140.
1445 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
1446 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
1447 // 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).
1448 //
1449 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
1450 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
1451 //
1452 // The only two differences between std140 and std430 are related to padding alignment/array stride
1453 // in arrays and structs. In std140 they take minimum vec4 alignment.
1454 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001455
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001456 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001457 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001458
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001459 bool is_top_level_block =
1460 has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
1461
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001462 for (uint32_t i = 0; i < type.member_types.size(); i++)
1463 {
1464 auto &memb_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001465 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001466
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001467 // Verify alignment rules.
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001468 uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001469
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001470 // This is a rather dirty workaround to deal with some cases of OpSpecConstantOp used as array size, e.g:
1471 // layout(constant_id = 0) const int s = 10;
1472 // const int S = s + 5; // SpecConstantOp
1473 // buffer Foo { int data[S]; }; // <-- Very hard for us to deduce a fixed value here,
1474 // we would need full implementation of compile-time constant folding. :(
1475 // If we are the last member of a struct, there might be cases where the actual size of that member is irrelevant
1476 // for our analysis (e.g. unsized arrays).
1477 // This lets us simply ignore that there are spec constant op sized arrays in our buffers.
1478 // Querying size of this member will fail, so just don't call it unless we have to.
1479 //
1480 // This is likely "best effort" we can support without going into unacceptably complicated workarounds.
1481 bool member_can_be_unsized =
1482 is_top_level_block && size_t(i + 1) == type.member_types.size() && !memb_type.array.empty();
1483
1484 uint32_t packed_size = 0;
Hans-Kristian Arntzenfad36a62020-08-20 16:05:21 +02001485 if (!member_can_be_unsized || packing_is_hlsl(packing))
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001486 packed_size = type_to_packed_size(memb_type, member_flags, packing);
1487
1488 // 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 +02001489 if (packing_is_hlsl(packing))
1490 {
1491 // If a member straddles across a vec4 boundary, alignment is actually vec4.
1492 uint32_t begin_word = offset / 16;
1493 uint32_t end_word = (offset + packed_size - 1) / 16;
1494 if (begin_word != end_word)
1495 packed_alignment = max(packed_alignment, 16u);
1496 }
1497
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001498 uint32_t actual_offset = type_struct_member_offset(type, i);
1499 // Field is not in the specified range anymore and we can ignore any further fields.
1500 if (actual_offset >= end_offset)
1501 break;
1502
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001503 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001504 offset = (offset + alignment - 1) & ~(alignment - 1);
1505
1506 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1507 // GL 4.5 spec, 7.6.2.2.
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001508 if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001509 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001510 else
1511 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001512
msiglreithd096f5c2017-11-27 16:00:56 +01001513 // Only care about packing if we are in the given range
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001514 if (actual_offset >= start_offset)
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001515 {
msiglreithd096f5c2017-11-27 16:00:56 +01001516 // We only care about offsets in std140, std430, etc ...
1517 // For EnhancedLayout variants, we have the flexibility to choose our own offsets.
1518 if (!packing_has_flexible_offset(packing))
1519 {
msiglreithd096f5c2017-11-27 16:00:56 +01001520 if (actual_offset != offset) // This cannot be the packing we're looking for.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001521 {
1522 if (failed_validation_index)
1523 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001524 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001525 }
msiglreithd096f5c2017-11-27 16:00:56 +01001526 }
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001527 else if ((actual_offset & (alignment - 1)) != 0)
1528 {
1529 // We still need to verify that alignment rules are observed, even if we have explicit offset.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001530 if (failed_validation_index)
1531 *failed_validation_index = i;
Hans-Kristian Arntzen46e757b2019-07-23 11:53:33 +02001532 return false;
1533 }
msiglreithd096f5c2017-11-27 16:00:56 +01001534
1535 // Verify array stride rules.
1536 if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
1537 type_struct_member_array_stride(type, i))
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001538 {
1539 if (failed_validation_index)
1540 *failed_validation_index = i;
msiglreithd096f5c2017-11-27 16:00:56 +01001541 return false;
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001542 }
msiglreithd096f5c2017-11-27 16:00:56 +01001543
1544 // Verify that sub-structs also follow packing rules.
1545 // We cannot use enhanced layouts on substructs, so they better be up to spec.
1546 auto substruct_packing = packing_to_substruct_packing(packing);
1547
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001548 if (!memb_type.pointer && !memb_type.member_types.empty() &&
1549 !buffer_is_packing_standard(memb_type, substruct_packing))
1550 {
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01001551 if (failed_validation_index)
1552 *failed_validation_index = i;
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001553 return false;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001554 }
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001555 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001557 // Bump size.
Hans-Kristian Arntzendd1f53f2020-08-20 15:26:55 +02001558 offset = actual_offset + packed_size;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001559 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001560
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001561 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001562}
1563
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001564bool CompilerGLSL::can_use_io_location(StorageClass storage, bool block)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001565{
1566 // Location specifiers are must have in SPIR-V, but they aren't really supported in earlier versions of GLSL.
1567 // Be very explicit here about how to solve the issue.
1568 if ((get_execution_model() != ExecutionModelVertex && storage == StorageClassInput) ||
1569 (get_execution_model() != ExecutionModelFragment && storage == StorageClassOutput))
1570 {
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001571 uint32_t minimum_desktop_version = block ? 440 : 410;
1572 // ARB_enhanced_layouts vs ARB_separate_shader_objects ...
1573
1574 if (!options.es && options.version < minimum_desktop_version && !options.separate_shader_objects)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001575 return false;
1576 else if (options.es && options.version < 310)
1577 return false;
1578 }
1579
1580 if ((get_execution_model() == ExecutionModelVertex && storage == StorageClassInput) ||
1581 (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput))
1582 {
1583 if (options.es && options.version < 300)
1584 return false;
1585 else if (!options.es && options.version < 330)
1586 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001587 }
1588
Hans-Kristian Arntzen1389aa32019-03-19 11:20:25 +01001589 if (storage == StorageClassUniform || storage == StorageClassUniformConstant || storage == StorageClassPushConstant)
Andrei Alexeyev4a430242018-04-07 22:14:35 +03001590 {
1591 if (options.es && options.version < 310)
1592 return false;
1593 else if (!options.es && options.version < 430)
1594 return false;
1595 }
1596
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001597 return true;
1598}
1599
1600string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
1601{
Hans-Kristian Arntzen62d223a2016-09-21 08:20:04 +02001602 // FIXME: Come up with a better solution for when to disable layouts.
1603 // Having layouts depend on extensions as well as which types
1604 // of layouts are used. For now, the simple solution is to just disable
1605 // layouts for legacy versions.
1606 if (is_legacy())
rob42fe8c32016-09-18 13:18:33 +09001607 return "";
1608
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01001609 if (subpass_input_is_framebuffer_fetch(var.self))
1610 return "";
1611
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001612 SmallVector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001613
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001614 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001615 auto &flags = get_decoration_bitset(var.self);
1616 auto &typeflags = get_decoration_bitset(type.self);
1617
1618 if (flags.get(DecorationPassthroughNV))
1619 attr.push_back("passthrough");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001620
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001621 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
1622 attr.push_back("push_constant");
Patrick Mours78917862019-06-03 15:25:21 +02001623 else if (var.storage == StorageClassShaderRecordBufferNV)
1624 attr.push_back("shaderRecordNV");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001625
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001626 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001627 attr.push_back("row_major");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001628 if (flags.get(DecorationColMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001629 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001630
1631 if (options.vulkan_semantics)
1632 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001633 if (flags.get(DecorationInputAttachmentIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001634 attr.push_back(join("input_attachment_index = ", get_decoration(var.self, DecorationInputAttachmentIndex)));
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001635 }
1636
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001637 bool is_block = has_decoration(type.self, DecorationBlock);
1638 if (flags.get(DecorationLocation) && can_use_io_location(var.storage, is_block))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001639 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001640 Bitset combined_decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001641 for (uint32_t i = 0; i < ir.meta[type.self].members.size(); i++)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001642 combined_decoration.merge_or(combined_decoration_for_member(type, i));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001643
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001644 // If our members have location decorations, we don't need to
1645 // emit location decorations at the top as well (looks weird).
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001646 if (!combined_decoration.get(DecorationLocation))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001647 attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation)));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001648 }
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001649
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001650 // Transform feedback
1651 bool uses_enhanced_layouts = false;
1652 if (is_block && var.storage == StorageClassOutput)
1653 {
1654 // For blocks, there is a restriction where xfb_stride/xfb_buffer must only be declared on the block itself,
1655 // since all members must match the same xfb_buffer. The only thing we will declare for members of the block
1656 // is the xfb_offset.
1657 uint32_t member_count = uint32_t(type.member_types.size());
1658 bool have_xfb_buffer_stride = false;
1659 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001660 bool have_geom_stream = false;
1661 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001662
1663 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride))
1664 {
1665 have_xfb_buffer_stride = true;
1666 xfb_buffer = get_decoration(var.self, DecorationXfbBuffer);
1667 xfb_stride = get_decoration(var.self, DecorationXfbStride);
1668 }
1669
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001670 if (flags.get(DecorationStream))
1671 {
1672 have_geom_stream = true;
1673 geom_stream = get_decoration(var.self, DecorationStream);
1674 }
1675
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001676 // Verify that none of the members violate our assumption.
1677 for (uint32_t i = 0; i < member_count; i++)
1678 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001679 if (has_member_decoration(type.self, i, DecorationStream))
1680 {
1681 uint32_t member_geom_stream = get_member_decoration(type.self, i, DecorationStream);
1682 if (have_geom_stream && member_geom_stream != geom_stream)
1683 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
1684 have_geom_stream = true;
1685 geom_stream = member_geom_stream;
1686 }
1687
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001688 // Only members with an Offset decoration participate in XFB.
1689 if (!has_member_decoration(type.self, i, DecorationOffset))
1690 continue;
1691 have_any_xfb_offset = true;
1692
1693 if (has_member_decoration(type.self, i, DecorationXfbBuffer))
1694 {
1695 uint32_t buffer_index = get_member_decoration(type.self, i, DecorationXfbBuffer);
1696 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
1697 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
1698 have_xfb_buffer_stride = true;
1699 xfb_buffer = buffer_index;
1700 }
1701
1702 if (has_member_decoration(type.self, i, DecorationXfbStride))
1703 {
1704 uint32_t stride = get_member_decoration(type.self, i, DecorationXfbStride);
1705 if (have_xfb_buffer_stride && stride != xfb_stride)
1706 SPIRV_CROSS_THROW("IO block member XfbStride mismatch.");
1707 have_xfb_buffer_stride = true;
1708 xfb_stride = stride;
1709 }
1710 }
1711
1712 if (have_xfb_buffer_stride && have_any_xfb_offset)
1713 {
1714 attr.push_back(join("xfb_buffer = ", xfb_buffer));
1715 attr.push_back(join("xfb_stride = ", xfb_stride));
1716 uses_enhanced_layouts = true;
1717 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001718
1719 if (have_geom_stream)
1720 {
1721 if (get_execution_model() != ExecutionModelGeometry)
1722 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
1723 if (options.es)
1724 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
1725 if (options.version < 400)
1726 require_extension_internal("GL_ARB_transform_feedback3");
1727 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
1728 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001729 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001730 else if (var.storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001731 {
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01001732 if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) && flags.get(DecorationOffset))
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001733 {
1734 // XFB for standalone variables, we can emit all decorations.
1735 attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer)));
1736 attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride)));
1737 attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset)));
1738 uses_enhanced_layouts = true;
1739 }
1740
1741 if (flags.get(DecorationStream))
1742 {
1743 if (get_execution_model() != ExecutionModelGeometry)
1744 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
1745 if (options.es)
1746 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
1747 if (options.version < 400)
1748 require_extension_internal("GL_ARB_transform_feedback3");
1749 attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
1750 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001751 }
1752
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001753 // Can only declare Component if we can declare location.
1754 if (flags.get(DecorationComponent) && can_use_io_location(var.storage, is_block))
1755 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001756 uses_enhanced_layouts = true;
1757 attr.push_back(join("component = ", get_decoration(var.self, DecorationComponent)));
1758 }
1759
1760 if (uses_enhanced_layouts)
1761 {
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001762 if (!options.es)
1763 {
1764 if (options.version < 440 && options.version >= 140)
1765 require_extension_internal("GL_ARB_enhanced_layouts");
1766 else if (options.version < 140)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001767 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in targets below GLSL 1.40.");
1768 if (!options.es && options.version < 440)
1769 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001770 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001771 else if (options.es)
1772 SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in ESSL.");
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001773 }
1774
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001775 if (flags.get(DecorationIndex))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001776 attr.push_back(join("index = ", get_decoration(var.self, DecorationIndex)));
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001777
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001778 // Do not emit set = decoration in regular GLSL output, but
1779 // we need to preserve it in Vulkan GLSL mode.
Patrick Mours8d64d5e2019-06-05 13:29:01 +02001780 if (var.storage != StorageClassPushConstant && var.storage != StorageClassShaderRecordBufferNV)
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001781 {
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001782 if (flags.get(DecorationDescriptorSet) && options.vulkan_semantics)
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001783 attr.push_back(join("set = ", get_decoration(var.self, DecorationDescriptorSet)));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001784 }
1785
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001786 bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
Patrick Mours8d64d5e2019-06-05 13:29:01 +02001787 bool ssbo_block = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferNV ||
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001788 (var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
1789 bool emulated_ubo = var.storage == StorageClassPushConstant && options.emit_push_constant_as_uniform_buffer;
1790 bool ubo_block = var.storage == StorageClassUniform && typeflags.get(DecorationBlock);
1791
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001792 // GL 3.0/GLSL 1.30 is not considered legacy, but it doesn't have UBOs ...
1793 bool can_use_buffer_blocks = (options.es && options.version >= 300) || (!options.es && options.version >= 140);
1794
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001795 // pretend no UBOs when options say so
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001796 if (ubo_block && options.emit_uniform_buffer_as_plain_uniforms)
1797 can_use_buffer_blocks = false;
1798
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001799 bool can_use_binding;
1800 if (options.es)
1801 can_use_binding = options.version >= 310;
1802 else
1803 can_use_binding = options.enable_420pack_extension || (options.version >= 420);
1804
Hans-Kristian Arntzen938040b2018-04-03 16:58:05 +02001805 // Make sure we don't emit binding layout for a classic uniform on GLSL 1.30.
1806 if (!can_use_buffer_blocks && var.storage == StorageClassUniform)
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001807 can_use_binding = false;
1808
Patrick Mours8d64d5e2019-06-05 13:29:01 +02001809 if (var.storage == StorageClassShaderRecordBufferNV)
1810 can_use_binding = false;
1811
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001812 if (can_use_binding && flags.get(DecorationBinding))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001813 attr.push_back(join("binding = ", get_decoration(var.self, DecorationBinding)));
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001814
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001815 if (var.storage != StorageClassOutput && flags.get(DecorationOffset))
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01001816 attr.push_back(join("offset = ", get_decoration(var.self, DecorationOffset)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001817
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001818 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
1819 // If SPIR-V does not comply with either layout, we cannot really work around it.
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001820 if (can_use_buffer_blocks && (ubo_block || emulated_ubo))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001821 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001822 attr.push_back(buffer_to_packing_standard(type, false));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001823 }
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001824 else if (can_use_buffer_blocks && (push_constant_block || ssbo_block))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001825 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001826 attr.push_back(buffer_to_packing_standard(type, true));
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001827 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001828
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001829 // For images, the type itself adds a layout qualifer.
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02001830 // Only emit the format for storage images.
1831 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001832 {
1833 const char *fmt = format_to_glsl(type.image.format);
1834 if (fmt)
1835 attr.push_back(fmt);
1836 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001837
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001838 if (attr.empty())
1839 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001840
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001841 string res = "layout(";
1842 res += merge(attr);
1843 res += ") ";
1844 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001845}
1846
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001847string CompilerGLSL::buffer_to_packing_standard(const SPIRType &type, bool support_std430_without_scalar_layout)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001848{
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001849 if (support_std430_without_scalar_layout && buffer_is_packing_standard(type, BufferPackingStd430))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001850 return "std430";
1851 else if (buffer_is_packing_standard(type, BufferPackingStd140))
1852 return "std140";
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001853 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalar))
1854 {
1855 require_extension_internal("GL_EXT_scalar_block_layout");
1856 return "scalar";
1857 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001858 else if (support_std430_without_scalar_layout &&
1859 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001860 {
1861 if (options.es && !options.vulkan_semantics)
1862 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1863 "not support GL_ARB_enhanced_layouts.");
1864 if (!options.es && !options.vulkan_semantics && options.version < 440)
1865 require_extension_internal("GL_ARB_enhanced_layouts");
1866
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001867 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001868 return "std430";
1869 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001870 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
1871 {
1872 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
1873 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
1874 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
1875 if (options.es && !options.vulkan_semantics)
1876 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1877 "not support GL_ARB_enhanced_layouts.");
1878 if (!options.es && !options.vulkan_semantics && options.version < 440)
1879 require_extension_internal("GL_ARB_enhanced_layouts");
1880
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001881 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001882 return "std140";
1883 }
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001884 else if (options.vulkan_semantics && buffer_is_packing_standard(type, BufferPackingScalarEnhancedLayout))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001885 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001886 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001887 require_extension_internal("GL_EXT_scalar_block_layout");
1888 return "scalar";
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001889 }
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001890 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
1891 buffer_is_packing_standard(type, BufferPackingStd430))
1892 {
1893 // UBOs can support std430 with GL_EXT_scalar_block_layout.
1894 require_extension_internal("GL_EXT_scalar_block_layout");
1895 return "std430";
1896 }
1897 else if (!support_std430_without_scalar_layout && options.vulkan_semantics &&
1898 buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
1899 {
1900 // UBOs can support std430 with GL_EXT_scalar_block_layout.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001901 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
Hans-Kristian Arntzen23889f72019-05-28 12:21:08 +02001902 require_extension_internal("GL_EXT_scalar_block_layout");
1903 return "std430";
1904 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001905 else
1906 {
Hans-Kristian Arntzen6f091e72019-04-26 13:05:44 +02001907 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 +02001908 "layouts. You can try flattening this block to support a more flexible layout.");
1909 }
1910}
1911
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001912void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
1913{
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01001914 if (flattened_buffer_blocks.count(var.self))
1915 emit_buffer_block_flattened(var);
1916 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001917 emit_push_constant_block_vulkan(var);
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001918 else if (options.emit_push_constant_as_uniform_buffer)
1919 emit_buffer_block_native(var);
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001920 else
1921 emit_push_constant_block_glsl(var);
1922}
1923
1924void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
1925{
1926 emit_buffer_block(var);
1927}
1928
1929void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
1930{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001931 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
1932 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001933
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001934 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001935 flags.clear(DecorationBinding);
1936 flags.clear(DecorationDescriptorSet);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001937
1938#if 0
1939 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001940 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001941 "Remap to location with reflection API first or disable these decorations.");
1942#endif
1943
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001944 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1945 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001946 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001947 bool block_flag = block_flags.get(DecorationBlock);
1948 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001949
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001950 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001951
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001952 if (block_flag)
1953 block_flags.set(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001954
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001955 emit_uniform(var);
1956 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001957}
1958
1959void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
1960{
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001961 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001962 bool ubo_block = var.storage == StorageClassUniform && has_decoration(type.self, DecorationBlock);
Laszlo Agocs7bc31492019-05-11 16:30:33 +02001963
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001964 if (flattened_buffer_blocks.count(var.self))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001965 emit_buffer_block_flattened(var);
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02001966 else if (is_legacy() || (!options.es && options.version == 130) ||
1967 (ubo_block && options.emit_uniform_buffer_as_plain_uniforms))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001968 emit_buffer_block_legacy(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001969 else
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001970 emit_buffer_block_native(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001971}
1972
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001973void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
1974{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001975 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001976 bool ssbo = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001977 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001978 if (ssbo)
1979 SPIRV_CROSS_THROW("SSBOs not supported in legacy targets.");
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001980
1981 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1982 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001983 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001984 bool block_flag = block_flags.get(DecorationBlock);
1985 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001986 emit_struct(type);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001987 if (block_flag)
1988 block_flags.set(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001989 emit_uniform(var);
1990 statement("");
1991}
1992
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02001993void CompilerGLSL::emit_buffer_reference_block(SPIRType &type, bool forward_declaration)
1994{
1995 string buffer_name;
1996
1997 if (forward_declaration)
1998 {
1999 // Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
2000 // Allow aliased name since we might be declaring the block twice. Once with buffer reference (forward declared) and one proper declaration.
2001 // The names must match up.
2002 buffer_name = to_name(type.self, false);
2003
2004 // Shaders never use the block by interface name, so we don't
2005 // have to track this other than updating name caches.
2006 // If we have a collision for any reason, just fallback immediately.
2007 if (ir.meta[type.self].decoration.alias.empty() ||
2008 block_ssbo_names.find(buffer_name) != end(block_ssbo_names) ||
2009 resource_names.find(buffer_name) != end(resource_names))
2010 {
2011 buffer_name = join("_", type.self);
2012 }
2013
2014 // Make sure we get something unique for both global name scope and block name scope.
2015 // See GLSL 4.5 spec: section 4.3.9 for details.
2016 add_variable(block_ssbo_names, resource_names, buffer_name);
2017
2018 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2019 // This cannot conflict with anything else, so we're safe now.
2020 // We cannot reuse this fallback name in neither global scope (blocked by block_names) nor block name scope.
2021 if (buffer_name.empty())
2022 buffer_name = join("_", type.self);
2023
2024 block_names.insert(buffer_name);
2025 block_ssbo_names.insert(buffer_name);
Hans-Kristian Arntzene07f0a92020-11-23 16:36:49 +01002026
2027 // Ensure we emit the correct name when emitting non-forward pointer type.
2028 ir.meta[type.self].decoration.alias = buffer_name;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002029 }
2030 else if (type.basetype != SPIRType::Struct)
2031 buffer_name = type_to_glsl(type);
2032 else
2033 buffer_name = to_name(type.self, false);
2034
2035 if (!forward_declaration)
2036 {
2037 if (type.basetype == SPIRType::Struct)
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +01002038 {
2039 auto flags = ir.get_buffer_block_type_flags(type);
2040 string decorations;
2041 if (flags.get(DecorationRestrict))
2042 decorations += " restrict";
2043 if (flags.get(DecorationCoherent))
2044 decorations += " coherent";
2045 if (flags.get(DecorationNonReadable))
2046 decorations += " writeonly";
2047 if (flags.get(DecorationNonWritable))
2048 decorations += " readonly";
2049 statement("layout(buffer_reference, ", buffer_to_packing_standard(type, true),
2050 ")", decorations, " buffer ", buffer_name);
2051 }
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002052 else
2053 statement("layout(buffer_reference) buffer ", buffer_name);
2054
2055 begin_scope();
2056
2057 if (type.basetype == SPIRType::Struct)
2058 {
2059 type.member_name_cache.clear();
2060
2061 uint32_t i = 0;
2062 for (auto &member : type.member_types)
2063 {
2064 add_member_name(type, i);
2065 emit_struct_member(type, member, i);
2066 i++;
2067 }
2068 }
2069 else
2070 {
2071 auto &pointee_type = get_pointee_type(type);
2072 statement(type_to_glsl(pointee_type), " value", type_to_array_glsl(pointee_type), ";");
2073 }
2074
2075 end_scope_decl();
2076 statement("");
2077 }
2078 else
2079 {
2080 statement("layout(buffer_reference) buffer ", buffer_name, ";");
2081 }
2082}
2083
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002084void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002085{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002086 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002087
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002088 Bitset flags = ir.get_buffer_block_flags(var);
Patrick Mours78917862019-06-03 15:25:21 +02002089 bool ssbo = var.storage == StorageClassStorageBuffer || var.storage == StorageClassShaderRecordBufferNV ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002090 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002091 bool is_restrict = ssbo && flags.get(DecorationRestrict);
2092 bool is_writeonly = ssbo && flags.get(DecorationNonReadable);
2093 bool is_readonly = ssbo && flags.get(DecorationNonWritable);
2094 bool is_coherent = ssbo && flags.get(DecorationCoherent);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02002095
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002096 // 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 +02002097 auto buffer_name = to_name(type.self, false);
2098
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002099 auto &block_namespace = ssbo ? block_ssbo_names : block_ubo_names;
2100
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002101 // Shaders never use the block by interface name, so we don't
2102 // have to track this other than updating name caches.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002103 // If we have a collision for any reason, just fallback immediately.
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01002104 if (ir.meta[type.self].decoration.alias.empty() || block_namespace.find(buffer_name) != end(block_namespace) ||
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002105 resource_names.find(buffer_name) != end(resource_names))
2106 {
Hans-Kristian Arntzenaab31072017-09-29 12:16:53 +02002107 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002108 }
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002109
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002110 // Make sure we get something unique for both global name scope and block name scope.
2111 // See GLSL 4.5 spec: section 4.3.9 for details.
2112 add_variable(block_namespace, resource_names, buffer_name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002113
2114 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2115 // This cannot conflict with anything else, so we're safe now.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002116 // 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 +01002117 if (buffer_name.empty())
2118 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2119
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002120 block_names.insert(buffer_name);
2121 block_namespace.insert(buffer_name);
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002122
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002123 // Save for post-reflection later.
2124 declared_block_names[var.self] = buffer_name;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002125
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02002126 statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
2127 is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
2128 buffer_name);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01002129
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002130 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002131
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002132 type.member_name_cache.clear();
2133
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002134 uint32_t i = 0;
2135 for (auto &member : type.member_types)
2136 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002137 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002138 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002139 i++;
2140 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002141
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +01002142 // var.self can be used as a backup name for the block name,
2143 // so we need to make sure we don't disturb the name here on a recompile.
2144 // It will need to be reset if we have to recompile.
2145 preserve_alias_on_reset(var.self);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002146 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002147 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
2148 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002149}
2150
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08002151void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002152{
2153 auto &type = get<SPIRType>(var.basetype);
2154
2155 // Block names should never alias.
2156 auto buffer_name = to_name(type.self, false);
2157 size_t buffer_size = (get_declared_struct_size(type) + 15) / 16;
2158
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002159 SPIRType::BaseType basic_type;
2160 if (get_common_basic_type(type, basic_type))
2161 {
2162 SPIRType tmp;
2163 tmp.basetype = basic_type;
Hans-Kristian Arntzenefba6102017-01-22 08:53:52 +01002164 tmp.vecsize = 4;
2165 if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt)
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002166 SPIRV_CROSS_THROW("Basic types in a flattened UBO must be float, int or uint.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002167
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002168 auto flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002169 statement("uniform ", flags_to_qualifiers_glsl(tmp, flags), type_to_glsl(tmp), " ", buffer_name, "[",
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01002170 buffer_size, "];");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01002171 }
2172 else
2173 SPIRV_CROSS_THROW("All basic types in a flattened block must be the same.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08002174}
2175
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002176const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002177{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002178 auto &execution = get_entry_point();
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002179
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002180 if (subpass_input_is_framebuffer_fetch(var.self))
2181 return "";
2182
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002183 if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
2184 {
2185 if (is_legacy() && execution.model == ExecutionModelVertex)
2186 return var.storage == StorageClassInput ? "attribute " : "varying ";
2187 else if (is_legacy() && execution.model == ExecutionModelFragment)
2188 return "varying "; // Fragment outputs are renamed so they never hit this case.
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002189 else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
2190 {
2191 if (inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
2192 return "inout ";
2193 else
2194 return "out ";
2195 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002196 else
2197 return var.storage == StorageClassInput ? "in " : "out ";
2198 }
2199 else if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
2200 var.storage == StorageClassPushConstant)
2201 {
2202 return "uniform ";
2203 }
Patrick Moursda39a7b2019-02-26 15:43:03 +01002204 else if (var.storage == StorageClassRayPayloadNV)
2205 {
2206 return "rayPayloadNV ";
2207 }
2208 else if (var.storage == StorageClassIncomingRayPayloadNV)
2209 {
2210 return "rayPayloadInNV ";
2211 }
2212 else if (var.storage == StorageClassHitAttributeNV)
2213 {
2214 return "hitAttributeNV ";
2215 }
Patrick Mours78917862019-06-03 15:25:21 +02002216 else if (var.storage == StorageClassCallableDataNV)
2217 {
Patrick Moursbe3035d2019-06-05 13:19:41 +02002218 return "callableDataNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002219 }
2220 else if (var.storage == StorageClassIncomingCallableDataNV)
2221 {
Patrick Moursbe3035d2019-06-05 13:19:41 +02002222 return "callableDataInNV ";
Patrick Mours78917862019-06-03 15:25:21 +02002223 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002224
2225 return "";
2226}
2227
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002228void CompilerGLSL::emit_flattened_io_block_member(const std::string &basename, const SPIRType &type, const char *qual,
2229 const SmallVector<uint32_t> &indices)
2230{
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002231 uint32_t member_type_id = type.self;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002232 const SPIRType *member_type = &type;
2233 const SPIRType *parent_type = nullptr;
2234 auto flattened_name = basename;
2235 for (auto &index : indices)
2236 {
2237 flattened_name += "_";
2238 flattened_name += to_member_name(*member_type, index);
2239 parent_type = member_type;
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002240 member_type_id = member_type->member_types[index];
2241 member_type = &get<SPIRType>(member_type_id);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002242 }
2243
2244 assert(member_type->basetype != SPIRType::Struct);
2245
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002246 // We're overriding struct member names, so ensure we do so on the primary type.
2247 if (parent_type->type_alias)
2248 parent_type = &get<SPIRType>(parent_type->type_alias);
2249
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002250 // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row,
2251 // which is not allowed.
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02002252 ParsedIR::sanitize_underscores(flattened_name);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002253
2254 uint32_t last_index = indices.back();
2255
2256 // Pass in the varying qualifier here so it will appear in the correct declaration order.
2257 // Replace member name while emitting it so it encodes both struct name and member name.
2258 auto backup_name = get_member_name(parent_type->self, last_index);
2259 auto member_name = to_member_name(*parent_type, last_index);
2260 set_member_name(parent_type->self, last_index, flattened_name);
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002261 emit_struct_member(*parent_type, member_type_id, last_index, qual);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002262 // Restore member name.
2263 set_member_name(parent_type->self, last_index, member_name);
2264}
2265
2266void CompilerGLSL::emit_flattened_io_block_struct(const std::string &basename, const SPIRType &type, const char *qual,
2267 const SmallVector<uint32_t> &indices)
2268{
2269 auto sub_indices = indices;
2270 sub_indices.push_back(0);
2271
2272 const SPIRType *member_type = &type;
2273 for (auto &index : indices)
2274 member_type = &get<SPIRType>(member_type->member_types[index]);
2275
2276 assert(member_type->basetype == SPIRType::Struct);
2277
Hans-Kristian Arntzen2ac8f512020-07-06 09:18:30 +02002278 if (!member_type->array.empty())
2279 SPIRV_CROSS_THROW("Cannot flatten array of structs in I/O blocks.");
2280
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002281 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
2282 {
2283 sub_indices.back() = i;
2284 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
2285 emit_flattened_io_block_struct(basename, type, qual, sub_indices);
2286 else
2287 emit_flattened_io_block_member(basename, type, qual, sub_indices);
2288 }
2289}
2290
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002291void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual)
2292{
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002293 auto &var_type = get<SPIRType>(var.basetype);
2294 if (!var_type.array.empty())
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002295 SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings.");
2296
Hans-Kristian Arntzeneb580d62020-07-29 13:02:25 +02002297 // Emit flattened types based on the type alias. Normally, we are never supposed to emit
2298 // struct declarations for aliased types.
2299 auto &type = var_type.type_alias ? get<SPIRType>(var_type.type_alias) : var_type;
2300
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002301 auto old_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002302 // Emit the members as if they are part of a block to get all qualifiers.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002303 ir.meta[type.self].decoration.decoration_flags.set(DecorationBlock);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002304
Hans-Kristian Arntzena8df0802017-11-22 11:19:54 +01002305 type.member_name_cache.clear();
2306
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002307 SmallVector<uint32_t> member_indices;
2308 member_indices.push_back(0);
2309 auto basename = to_name(var.self);
2310
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002311 uint32_t i = 0;
2312 for (auto &member : type.member_types)
2313 {
2314 add_member_name(type, i);
2315 auto &membertype = get<SPIRType>(member);
2316
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002317 member_indices.back() = i;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002318 if (membertype.basetype == SPIRType::Struct)
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002319 emit_flattened_io_block_struct(basename, type, qual, member_indices);
2320 else
2321 emit_flattened_io_block_member(basename, type, qual, member_indices);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002322 i++;
2323 }
2324
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002325 ir.meta[type.self].decoration.decoration_flags = old_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002326
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002327 // Treat this variable as fully flattened from now on.
2328 flattened_structs[var.self] = true;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002329}
2330
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002331void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
2332{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002333 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002334
rdbdf5e3732020-11-12 22:59:28 +01002335 if (var.storage == StorageClassInput && type.basetype == SPIRType::Double &&
2336 !options.es && options.version < 410)
2337 {
2338 require_extension_internal("GL_ARB_vertex_attrib_64bit");
2339 }
2340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002341 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002342 bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002343 const char *qual = to_storage_qualifiers_glsl(var);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002345 if (block)
2346 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002347 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2348 // I/O variables which are struct types.
2349 // To support this, flatten the struct into separate varyings instead.
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002350 if (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2351 (!options.es && options.version < 150))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002352 {
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002353 // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320.
2354 // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150).
2355 emit_flattened_io_block(var, qual);
2356 }
2357 else
2358 {
2359 if (options.es && options.version < 320)
2360 {
2361 // Geometry and tessellation extensions imply this extension.
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01002362 if (!has_extension("GL_EXT_geometry_shader") && !has_extension("GL_EXT_tessellation_shader"))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002363 require_extension_internal("GL_EXT_shader_io_blocks");
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002364 }
2365
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002366 // Block names should never alias.
2367 auto block_name = to_name(type.self, false);
2368
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002369 // The namespace for I/O blocks is separate from other variables in GLSL.
2370 auto &block_namespace = type.storage == StorageClassInput ? block_input_names : block_output_names;
2371
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002372 // Shaders never use the block by interface name, so we don't
2373 // have to track this other than updating name caches.
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002374 if (block_name.empty() || block_namespace.find(block_name) != end(block_namespace))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002375 block_name = get_fallback_name(type.self);
2376 else
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002377 block_namespace.insert(block_name);
2378
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02002379 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2380 // This cannot conflict with anything else, so we're safe now.
2381 if (block_name.empty())
2382 block_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2383
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02002384 // Instance names cannot alias block names.
2385 resource_names.insert(block_name);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002386
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002387 statement(layout_for_variable(var), qual, block_name);
2388 begin_scope();
2389
2390 type.member_name_cache.clear();
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002391
2392 uint32_t i = 0;
2393 for (auto &member : type.member_types)
2394 {
2395 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05002396 emit_struct_member(type, member, i);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002397 i++;
2398 }
2399
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01002400 add_resource_name(var.self);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002401 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
2402 statement("");
2403 }
2404 }
2405 else
2406 {
2407 // ESSL earlier than 310 and GLSL earlier than 150 did not support
2408 // I/O variables which are struct types.
2409 // To support this, flatten the struct into separate varyings instead.
2410 if (type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen57c93d42020-07-28 15:15:24 +02002411 (options.force_flattened_io_blocks || (options.es && options.version < 310) ||
2412 (!options.es && options.version < 150)))
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01002413 {
2414 emit_flattened_io_block(var, qual);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002415 }
2416 else
2417 {
2418 add_resource_name(var.self);
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002419
2420 // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays.
2421 // Opt for unsized as it's the more "correct" variant to use.
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +01002422 bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() &&
2423 !has_decoration(var.self, DecorationPatch) &&
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002424 (get_entry_point().model == ExecutionModelTessellationControl ||
2425 get_entry_point().model == ExecutionModelTessellationEvaluation);
2426
2427 uint32_t old_array_size = 0;
2428 bool old_array_size_literal = true;
2429
2430 if (control_point_input_array)
2431 {
2432 swap(type.array.back(), old_array_size);
2433 swap(type.array_size_literal.back(), old_array_size_literal);
2434 }
2435
Chip Davis3bfb2f92018-12-03 02:06:33 -06002436 statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
2437 variable_decl(type, to_name(var.self), var.self), ";");
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002438
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01002439 if (control_point_input_array)
2440 {
2441 swap(type.array.back(), old_array_size);
2442 swap(type.array_size_literal.back(), old_array_size_literal);
2443 }
2444
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002445 // If a StorageClassOutput variable has an initializer, we need to initialize it in main().
2446 if (var.storage == StorageClassOutput && var.initializer)
2447 {
2448 auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
Hans-Kristian Arntzen2edee352019-01-30 13:42:50 +01002449 entry_func.fixup_hooks_in.push_back(
2450 [&]() { statement(to_name(var.self), " = ", to_expression(var.initializer), ";"); });
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01002451 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01002452 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002453 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002454}
2455
2456void CompilerGLSL::emit_uniform(const SPIRVariable &var)
2457{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002458 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01002459 if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002460 {
2461 if (!options.es && options.version < 420)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002462 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002463 else if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002464 SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002465 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002466
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002467 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01002468 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002469}
2470
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002471string CompilerGLSL::constant_value_macro_name(uint32_t id)
2472{
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002473 return join("SPIRV_CROSS_CONSTANT_ID_", id);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002474}
2475
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002476void CompilerGLSL::emit_specialization_constant_op(const SPIRConstantOp &constant)
2477{
2478 auto &type = get<SPIRType>(constant.basetype);
2479 auto name = to_name(constant.self);
2480 statement("const ", variable_decl(type, name), " = ", constant_op_expression(constant), ";");
2481}
2482
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002483void CompilerGLSL::emit_constant(const SPIRConstant &constant)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002484{
2485 auto &type = get<SPIRType>(constant.constant_type);
2486 auto name = to_name(constant.self);
2487
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002488 SpecializationConstant wg_x, wg_y, wg_z;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002489 ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002490
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002491 // This specialization constant is implicitly declared by emitting layout() in;
2492 if (constant.self == workgroup_size_id)
2493 return;
2494
2495 // These specialization constants are implicitly declared by emitting layout() in;
2496 // In legacy GLSL, we will still need to emit macros for these, so a layout() in; declaration
2497 // later can use macro overrides for work group size.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002498 bool is_workgroup_size_constant = ConstantID(constant.self) == wg_x.id || ConstantID(constant.self) == wg_y.id ||
2499 ConstantID(constant.self) == wg_z.id;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002500
2501 if (options.vulkan_semantics && is_workgroup_size_constant)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002502 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002503 // Vulkan GLSL does not need to declare workgroup spec constants explicitly, it is handled in layout().
2504 return;
2505 }
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002506 else if (!options.vulkan_semantics && is_workgroup_size_constant &&
2507 !has_decoration(constant.self, DecorationSpecId))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002508 {
2509 // 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 +02002510 return;
2511 }
2512
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002513 // Only scalars have constant IDs.
2514 if (has_decoration(constant.self, DecorationSpecId))
2515 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002516 if (options.vulkan_semantics)
2517 {
2518 statement("layout(constant_id = ", get_decoration(constant.self, DecorationSpecId), ") const ",
2519 variable_decl(type, name), " = ", constant_expression(constant), ";");
2520 }
2521 else
2522 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002523 const string &macro_name = constant.specialization_constant_macro_name;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002524 statement("#ifndef ", macro_name);
2525 statement("#define ", macro_name, " ", constant_expression(constant));
2526 statement("#endif");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002527
2528 // For workgroup size constants, only emit the macros.
2529 if (!is_workgroup_size_constant)
2530 statement("const ", variable_decl(type, name), " = ", macro_name, ";");
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002531 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002532 }
2533 else
2534 {
2535 statement("const ", variable_decl(type, name), " = ", constant_expression(constant), ";");
2536 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002537}
2538
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +02002539void CompilerGLSL::emit_entry_point_declarations()
2540{
2541}
2542
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002543void CompilerGLSL::replace_illegal_names(const unordered_set<string> &keywords)
2544{
2545 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
2546 if (is_hidden_variable(var))
2547 return;
2548
2549 auto *meta = ir.find_meta(var.self);
2550 if (!meta)
2551 return;
2552
2553 auto &m = meta->decoration;
2554 if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords))
2555 m.alias = join("_", m.alias);
2556 });
2557
2558 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
2559 auto *meta = ir.find_meta(type.self);
2560 if (!meta)
2561 return;
2562
2563 auto &m = meta->decoration;
2564 if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords))
2565 m.alias = join("_", m.alias);
2566
2567 for (auto &memb : meta->members)
2568 if (memb.alias.compare(0, 3, "gl_") == 0 || keywords.find(memb.alias) != end(keywords))
2569 memb.alias = join("_", memb.alias);
2570 });
2571}
2572
Robert Konrad76936562016-08-13 00:14:52 +02002573void CompilerGLSL::replace_illegal_names()
2574{
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002575 // clang-format off
2576 static const unordered_set<string> keywords = {
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002577 "abs", "acos", "acosh", "all", "any", "asin", "asinh", "atan", "atanh",
2578 "atomicAdd", "atomicCompSwap", "atomicCounter", "atomicCounterDecrement", "atomicCounterIncrement",
2579 "atomicExchange", "atomicMax", "atomicMin", "atomicOr", "atomicXor",
2580 "bitCount", "bitfieldExtract", "bitfieldInsert", "bitfieldReverse",
2581 "ceil", "cos", "cosh", "cross", "degrees",
2582 "dFdx", "dFdxCoarse", "dFdxFine",
2583 "dFdy", "dFdyCoarse", "dFdyFine",
2584 "distance", "dot", "EmitStreamVertex", "EmitVertex", "EndPrimitive", "EndStreamPrimitive", "equal", "exp", "exp2",
Chip Davis0d949e12018-11-05 14:55:56 -06002585 "faceforward", "findLSB", "findMSB", "float16BitsToInt16", "float16BitsToUint16", "floatBitsToInt", "floatBitsToUint", "floor", "fma", "fract",
2586 "frexp", "fwidth", "fwidthCoarse", "fwidthFine",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002587 "greaterThan", "greaterThanEqual", "groupMemoryBarrier",
2588 "imageAtomicAdd", "imageAtomicAnd", "imageAtomicCompSwap", "imageAtomicExchange", "imageAtomicMax", "imageAtomicMin", "imageAtomicOr", "imageAtomicXor",
Chip Davis0d949e12018-11-05 14:55:56 -06002589 "imageLoad", "imageSamples", "imageSize", "imageStore", "imulExtended", "int16BitsToFloat16", "intBitsToFloat", "interpolateAtOffset", "interpolateAtCentroid", "interpolateAtSample",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002590 "inverse", "inversesqrt", "isinf", "isnan", "ldexp", "length", "lessThan", "lessThanEqual", "log", "log2",
2591 "matrixCompMult", "max", "memoryBarrier", "memoryBarrierAtomicCounter", "memoryBarrierBuffer", "memoryBarrierImage", "memoryBarrierShared",
2592 "min", "mix", "mod", "modf", "noise", "noise1", "noise2", "noise3", "noise4", "normalize", "not", "notEqual",
Chip Davis0d949e12018-11-05 14:55:56 -06002593 "outerProduct", "packDouble2x32", "packHalf2x16", "packInt2x16", "packInt4x16", "packSnorm2x16", "packSnorm4x8",
2594 "packUint2x16", "packUint4x16", "packUnorm2x16", "packUnorm4x8", "pow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002595 "radians", "reflect", "refract", "round", "roundEven", "sign", "sin", "sinh", "smoothstep", "sqrt", "step",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002596 "tan", "tanh", "texelFetch", "texelFetchOffset", "texture", "textureGather", "textureGatherOffset", "textureGatherOffsets",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002597 "textureGrad", "textureGradOffset", "textureLod", "textureLodOffset", "textureOffset", "textureProj", "textureProjGrad",
2598 "textureProjGradOffset", "textureProjLod", "textureProjLodOffset", "textureProjOffset", "textureQueryLevels", "textureQueryLod", "textureSamples", "textureSize",
Chip Davis0d949e12018-11-05 14:55:56 -06002599 "transpose", "trunc", "uaddCarry", "uint16BitsToFloat16", "uintBitsToFloat", "umulExtended", "unpackDouble2x32", "unpackHalf2x16", "unpackInt2x16", "unpackInt4x16",
2600 "unpackSnorm2x16", "unpackSnorm4x8", "unpackUint2x16", "unpackUint4x16", "unpackUnorm2x16", "unpackUnorm4x8", "usubBorrow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01002601
Pascal Muetschardaced6052018-05-04 14:53:32 -07002602 "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002603 "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard",
2604 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4",
2605 "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float",
2606 "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray",
2607 "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
2608 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect",
2609 "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant",
2610 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002611 "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp",
2612 "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump",
2613 "namespace", "noinline", "noperspective", "out", "output", "packed", "partition", "patch", "precise", "precision", "public", "readonly",
2614 "resource", "restrict", "return", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002615 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
2616 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002617 "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "shared", "short", "sizeof", "smooth", "static",
David Srbeckyedec5ea2017-06-27 15:35:47 +01002618 "struct", "subroutine", "superp", "switch", "template", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D",
2619 "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube",
2620 "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
2621 "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube",
Pascal Muetschardaced6052018-05-04 14:53:32 -07002622 "usamplerCubeArray", "using", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile",
2623 "while", "writeonly",
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02002624 };
2625 // clang-format on
Bas Zalmstraf537adf2016-10-27 12:51:22 +02002626
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01002627 replace_illegal_names(keywords);
Robert Konrad76936562016-08-13 00:14:52 +02002628}
2629
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002630void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
2631{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002632 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002633 uint32_t location = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002634 if (m.decoration_flags.get(DecorationLocation))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002635 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002636
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002637 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
2638 // do the access chain part of this for us.
2639 auto &type = get<SPIRType>(var.basetype);
2640
2641 if (type.array.empty())
2642 {
2643 // Redirect the write to a specific render target in legacy GLSL.
2644 m.alias = join("gl_FragData[", location, "]");
Lubos Lenco52158642016-09-17 15:56:23 +02002645
2646 if (is_legacy_es() && location != 0)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002647 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002648 }
2649 else if (type.array.size() == 1)
2650 {
2651 // If location is non-zero, we probably have to add an offset.
2652 // This gets really tricky since we'd have to inject an offset in the access chain.
2653 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
2654 m.alias = "gl_FragData";
2655 if (location != 0)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002656 SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
2657 "This is unimplemented in SPIRV-Cross.");
Hans-Kristian Arntzen6cc96242016-09-17 18:46:10 +02002658
Lubos Lenco80c39412016-09-17 14:33:16 +02002659 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02002660 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002661 }
2662 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002663 SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02002664
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002665 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 +01002666}
2667
2668void CompilerGLSL::replace_fragment_outputs()
2669{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002670 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002671 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002672
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +01002673 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer && var.storage == StorageClassOutput)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002674 replace_fragment_output(var);
2675 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002676}
2677
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002678string CompilerGLSL::remap_swizzle(const SPIRType &out_type, uint32_t input_components, const string &expr)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002679{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002680 if (out_type.vecsize == input_components)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002681 return expr;
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01002682 else if (input_components == 1 && !backend.can_swizzle_scalar)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002683 return join(type_to_glsl(out_type), "(", expr, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002684 else
2685 {
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02002686 // FIXME: This will not work with packed expressions.
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002687 auto e = enclose_expression(expr) + ".";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002688 // Just clamp the swizzle index if we have more outputs than inputs.
2689 for (uint32_t c = 0; c < out_type.vecsize; c++)
2690 e += index_to_swizzle(min(c, input_components - 1));
2691 if (backend.swizzle_is_function && out_type.vecsize > 1)
2692 e += "()";
Hans-Kristian Arntzenffad50b2017-12-12 13:01:10 +01002693
2694 remove_duplicate_swizzle(e);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002695 return e;
2696 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002697}
2698
2699void CompilerGLSL::emit_pls()
2700{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002701 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002702 if (execution.model != ExecutionModelFragment)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002703 SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002705 if (!options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002706 SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002707
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002708 if (options.version < 300)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002709 SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002711 if (!pls_inputs.empty())
2712 {
2713 statement("__pixel_local_inEXT _PLSIn");
2714 begin_scope();
2715 for (auto &input : pls_inputs)
2716 statement(pls_decl(input), ";");
2717 end_scope_decl();
2718 statement("");
2719 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002720
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002721 if (!pls_outputs.empty())
2722 {
2723 statement("__pixel_local_outEXT _PLSOut");
2724 begin_scope();
2725 for (auto &output : pls_outputs)
2726 statement(pls_decl(output), ";");
2727 end_scope_decl();
2728 statement("");
2729 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002730}
2731
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002732void CompilerGLSL::fixup_image_load_store_access()
2733{
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002734 if (!options.enable_storage_image_qualifier_deduction)
2735 return;
2736
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002737 ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002738 auto &vartype = expression_type(var);
Hans-Kristian Arntzenb691b7d2020-04-03 12:26:13 +02002739 if (vartype.basetype == SPIRType::Image && vartype.image.sampled == 2)
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002740 {
Hans-Kristian Arntzen01968c42020-03-04 16:15:01 +01002741 // Very old glslangValidator and HLSL compilers do not emit required qualifiers here.
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002742 // Solve this by making the image access as restricted as possible and loosen up if we need to.
2743 // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
2744
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01002745 auto &flags = ir.meta[var].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002746 if (!flags.get(DecorationNonWritable) && !flags.get(DecorationNonReadable))
2747 {
2748 flags.set(DecorationNonWritable);
2749 flags.set(DecorationNonReadable);
2750 }
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002751 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002752 });
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002753}
2754
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002755static bool is_block_builtin(BuiltIn builtin)
2756{
2757 return builtin == BuiltInPosition || builtin == BuiltInPointSize || builtin == BuiltInClipDistance ||
2758 builtin == BuiltInCullDistance;
2759}
2760
2761bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage)
2762{
2763 // If the builtin block uses XFB, we need to force explicit redeclaration of the builtin block.
2764
2765 if (storage != StorageClassOutput)
2766 return false;
2767 bool should_force = false;
2768
2769 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
2770 if (should_force)
2771 return;
2772
2773 auto &type = this->get<SPIRType>(var.basetype);
2774 bool block = has_decoration(type.self, DecorationBlock);
2775 if (var.storage == storage && block && is_builtin_variable(var))
2776 {
2777 uint32_t member_count = uint32_t(type.member_types.size());
2778 for (uint32_t i = 0; i < member_count; i++)
2779 {
2780 if (has_member_decoration(type.self, i, DecorationBuiltIn) &&
2781 is_block_builtin(BuiltIn(get_member_decoration(type.self, i, DecorationBuiltIn))) &&
2782 has_member_decoration(type.self, i, DecorationOffset))
2783 {
2784 should_force = true;
2785 }
2786 }
2787 }
2788 else if (var.storage == storage && !block && is_builtin_variable(var))
2789 {
2790 if (is_block_builtin(BuiltIn(get_decoration(type.self, DecorationBuiltIn))) &&
2791 has_decoration(var.self, DecorationOffset))
2792 {
2793 should_force = true;
2794 }
2795 }
2796 });
2797
2798 return should_force;
2799}
2800
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02002801void CompilerGLSL::fixup_implicit_builtin_block_names()
2802{
2803 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
2804 auto &type = this->get<SPIRType>(var.basetype);
2805 bool block = has_decoration(type.self, DecorationBlock);
2806 if ((var.storage == StorageClassOutput || var.storage == StorageClassInput) && block &&
2807 is_builtin_variable(var))
2808 {
2809 // Make sure the array has a supported name in the code.
2810 if (var.storage == StorageClassOutput)
2811 set_name(var.self, "gl_out");
2812 else if (var.storage == StorageClassInput)
2813 set_name(var.self, "gl_in");
2814 }
2815 });
2816}
2817
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002818void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
2819{
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002820 Bitset emitted_builtins;
2821 Bitset global_builtins;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002822 const SPIRVariable *block_var = nullptr;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002823 bool emitted_block = false;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002824 bool builtin_array = false;
2825
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002826 // Need to use declared size in the type.
2827 // These variables might have been declared, but not statically used, so we haven't deduced their size yet.
2828 uint32_t cull_distance_size = 0;
2829 uint32_t clip_distance_size = 0;
2830
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002831 bool have_xfb_buffer_stride = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002832 bool have_geom_stream = false;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002833 bool have_any_xfb_offset = false;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002834 uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
Hans-Kristian Arntzendfffbb12020-01-27 15:56:47 +01002835 std::unordered_map<uint32_t, uint32_t> builtin_xfb_offsets;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002836
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002837 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002838 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002839 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002840 Bitset builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002841
2842 if (var.storage == storage && block && is_builtin_variable(var))
2843 {
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002844 uint32_t index = 0;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002845 for (auto &m : ir.meta[type.self].members)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002846 {
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002847 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002848 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002849 builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002850 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02002851 cull_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002852 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02002853 clip_distance_size = to_array_size_literal(this->get<SPIRType>(type.member_types[index]));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002854
2855 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationOffset))
2856 {
2857 have_any_xfb_offset = true;
2858 builtin_xfb_offsets[m.builtin_type] = m.offset;
2859 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002860
2861 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
2862 {
2863 uint32_t stream = m.stream;
2864 if (have_geom_stream && geom_stream != stream)
2865 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
2866 have_geom_stream = true;
2867 geom_stream = stream;
2868 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002869 }
2870 index++;
2871 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002872
2873 if (storage == StorageClassOutput && has_decoration(var.self, DecorationXfbBuffer) &&
2874 has_decoration(var.self, DecorationXfbStride))
2875 {
2876 uint32_t buffer_index = get_decoration(var.self, DecorationXfbBuffer);
2877 uint32_t stride = get_decoration(var.self, DecorationXfbStride);
2878 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
2879 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2880 if (have_xfb_buffer_stride && stride != xfb_stride)
2881 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2882 have_xfb_buffer_stride = true;
2883 xfb_buffer = buffer_index;
2884 xfb_stride = stride;
2885 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002886
2887 if (storage == StorageClassOutput && has_decoration(var.self, DecorationStream))
2888 {
2889 uint32_t stream = get_decoration(var.self, DecorationStream);
2890 if (have_geom_stream && geom_stream != stream)
2891 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
2892 have_geom_stream = true;
2893 geom_stream = stream;
2894 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002895 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002896 else if (var.storage == storage && !block && is_builtin_variable(var))
2897 {
2898 // While we're at it, collect all declared global builtins (HLSL mostly ...).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002899 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002900 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002901 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002902 global_builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002903 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02002904 cull_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002905 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen7a99d1c2020-09-30 13:01:18 +02002906 clip_distance_size = to_array_size_literal(type);
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002907
2908 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationXfbStride) &&
2909 m.decoration_flags.get(DecorationXfbBuffer) && m.decoration_flags.get(DecorationOffset))
2910 {
2911 have_any_xfb_offset = true;
2912 builtin_xfb_offsets[m.builtin_type] = m.offset;
2913 uint32_t buffer_index = m.xfb_buffer;
2914 uint32_t stride = m.xfb_stride;
2915 if (have_xfb_buffer_stride && buffer_index != xfb_buffer)
2916 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2917 if (have_xfb_buffer_stride && stride != xfb_stride)
2918 SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch.");
2919 have_xfb_buffer_stride = true;
2920 xfb_buffer = buffer_index;
2921 xfb_stride = stride;
2922 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002923
2924 if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
2925 {
2926 uint32_t stream = get_decoration(var.self, DecorationStream);
2927 if (have_geom_stream && geom_stream != stream)
2928 SPIRV_CROSS_THROW("IO block member Stream mismatch.");
2929 have_geom_stream = true;
2930 geom_stream = stream;
2931 }
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002932 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002933 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002934
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002935 if (builtins.empty())
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002936 return;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002937
2938 if (emitted_block)
2939 SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
2940
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002941 emitted_builtins = builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002942 emitted_block = true;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002943 builtin_array = !type.array.empty();
2944 block_var = &var;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002945 });
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002946
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01002947 global_builtins =
2948 Bitset(global_builtins.get_lower() & ((1ull << BuiltInPosition) | (1ull << BuiltInPointSize) |
2949 (1ull << BuiltInClipDistance) | (1ull << BuiltInCullDistance)));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002950
2951 // Try to collect all other declared builtins.
2952 if (!emitted_block)
2953 emitted_builtins = global_builtins;
2954
2955 // Can't declare an empty interface block.
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002956 if (emitted_builtins.empty())
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002957 return;
2958
2959 if (storage == StorageClassOutput)
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002960 {
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002961 SmallVector<string> attr;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002962 if (have_xfb_buffer_stride && have_any_xfb_offset)
2963 {
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002964 if (!options.es)
2965 {
2966 if (options.version < 440 && options.version >= 140)
2967 require_extension_internal("GL_ARB_enhanced_layouts");
2968 else if (options.version < 140)
2969 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
2970 if (!options.es && options.version < 440)
2971 require_extension_internal("GL_ARB_enhanced_layouts");
2972 }
2973 else if (options.es)
2974 SPIRV_CROSS_THROW("Need GL_ARB_enhanced_layouts for xfb_stride or xfb_buffer.");
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002975 attr.push_back(join("xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride));
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002976 }
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02002977
2978 if (have_geom_stream)
2979 {
2980 if (get_execution_model() != ExecutionModelGeometry)
2981 SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
2982 if (options.es)
2983 SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
2984 if (options.version < 400)
2985 require_extension_internal("GL_ARB_transform_feedback3");
2986 attr.push_back(join("stream = ", geom_stream));
2987 }
2988
2989 if (!attr.empty())
2990 statement("layout(", merge(attr), ") out gl_PerVertex");
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01002991 else
2992 statement("out gl_PerVertex");
2993 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002994 else
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01002995 {
2996 // If we have passthrough, there is no way PerVertex cannot be passthrough.
2997 if (get_entry_point().geometry_passthrough)
2998 statement("layout(passthrough) in gl_PerVertex");
2999 else
3000 statement("in gl_PerVertex");
3001 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003002
3003 begin_scope();
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003004 if (emitted_builtins.get(BuiltInPosition))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003005 {
3006 auto itr = builtin_xfb_offsets.find(BuiltInPosition);
3007 if (itr != end(builtin_xfb_offsets))
3008 statement("layout(xfb_offset = ", itr->second, ") vec4 gl_Position;");
3009 else
3010 statement("vec4 gl_Position;");
3011 }
3012
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003013 if (emitted_builtins.get(BuiltInPointSize))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003014 {
3015 auto itr = builtin_xfb_offsets.find(BuiltInPointSize);
3016 if (itr != end(builtin_xfb_offsets))
3017 statement("layout(xfb_offset = ", itr->second, ") float gl_PointSize;");
3018 else
3019 statement("float gl_PointSize;");
3020 }
3021
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003022 if (emitted_builtins.get(BuiltInClipDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003023 {
3024 auto itr = builtin_xfb_offsets.find(BuiltInClipDistance);
3025 if (itr != end(builtin_xfb_offsets))
3026 statement("layout(xfb_offset = ", itr->second, ") float gl_ClipDistance[", clip_distance_size, "];");
3027 else
3028 statement("float gl_ClipDistance[", clip_distance_size, "];");
3029 }
3030
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01003031 if (emitted_builtins.get(BuiltInCullDistance))
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003032 {
3033 auto itr = builtin_xfb_offsets.find(BuiltInCullDistance);
3034 if (itr != end(builtin_xfb_offsets))
3035 statement("layout(xfb_offset = ", itr->second, ") float gl_CullDistance[", cull_distance_size, "];");
3036 else
3037 statement("float gl_CullDistance[", cull_distance_size, "];");
3038 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003039
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003040 if (builtin_array)
3041 {
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003042 if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
3043 end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]"));
3044 else
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +01003045 end_scope_decl(join(to_name(block_var->self), "[]"));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01003046 }
3047 else
3048 end_scope_decl();
3049 statement("");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003050}
3051
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003052void CompilerGLSL::declare_undefined_values()
3053{
3054 bool emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003055 ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003056 auto &type = this->get<SPIRType>(undef.basetype);
3057 // OpUndef can be void for some reason ...
3058 if (type.basetype == SPIRType::Void)
3059 return;
3060
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003061 string initializer;
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02003062 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003063 initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
3064
crissdb52e272020-10-08 12:14:52 +02003065 statement(variable_decl(type, to_name(undef.self), undef.self), initializer, ";");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003066 emitted = true;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003067 });
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003068
3069 if (emitted)
3070 statement("");
3071}
3072
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003073bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const
3074{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003075 bool statically_assigned = var.statically_assigned && var.static_expression != ID(0) && var.remapped_variable;
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003076
3077 if (statically_assigned)
3078 {
3079 auto *constant = maybe_get<SPIRConstant>(var.static_expression);
3080 if (constant && constant->is_used_as_lut)
3081 return true;
3082 }
3083
3084 return false;
3085}
3086
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003087void CompilerGLSL::emit_resources()
3088{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02003089 auto &execution = get_entry_point();
3090
Robert Konrad76936562016-08-13 00:14:52 +02003091 replace_illegal_names();
3092
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003093 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
3094 // with builtins.
3095 if (execution.model == ExecutionModelFragment && is_legacy())
3096 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003097
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003098 // Emit PLS blocks if we have such variables.
3099 if (!pls_inputs.empty() || !pls_outputs.empty())
3100 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003101
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02003102 switch (execution.model)
3103 {
3104 case ExecutionModelGeometry:
3105 case ExecutionModelTessellationControl:
3106 case ExecutionModelTessellationEvaluation:
3107 fixup_implicit_builtin_block_names();
3108 break;
3109
3110 default:
3111 break;
3112 }
3113
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003114 // Emit custom gl_PerVertex for SSO compatibility.
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003115 if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment)
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003116 {
3117 switch (execution.model)
3118 {
3119 case ExecutionModelGeometry:
3120 case ExecutionModelTessellationControl:
3121 case ExecutionModelTessellationEvaluation:
3122 emit_declared_builtin_block(StorageClassInput, execution.model);
3123 emit_declared_builtin_block(StorageClassOutput, execution.model);
3124 break;
3125
3126 case ExecutionModelVertex:
3127 emit_declared_builtin_block(StorageClassOutput, execution.model);
3128 break;
3129
3130 default:
3131 break;
3132 }
3133 }
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003134 else if (should_force_emit_builtin_block(StorageClassOutput))
3135 {
3136 emit_declared_builtin_block(StorageClassOutput, execution.model);
3137 }
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +01003138 else if (execution.geometry_passthrough)
3139 {
3140 // Need to declare gl_in with Passthrough.
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01003141 // 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 +01003142 emit_declared_builtin_block(StorageClassInput, execution.model);
3143 }
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01003144 else
3145 {
3146 // Need to redeclare clip/cull distance with explicit size to use them.
3147 // SPIR-V mandates these builtins have a size declared.
3148 const char *storage = execution.model == ExecutionModelFragment ? "in" : "out";
3149 if (clip_distance_count != 0)
3150 statement(storage, " float gl_ClipDistance[", clip_distance_count, "];");
3151 if (cull_distance_count != 0)
3152 statement(storage, " float gl_CullDistance[", cull_distance_count, "];");
3153 if (clip_distance_count != 0 || cull_distance_count != 0)
3154 statement("");
3155 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02003156
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01003157 if (position_invariant)
3158 {
3159 statement("invariant gl_Position;");
3160 statement("");
3161 }
3162
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003163 bool emitted = false;
3164
3165 // If emitted Vulkan GLSL,
3166 // emit specialization constants as actual floats,
3167 // spec op expressions will redirect to the constant name.
3168 //
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003169 {
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +02003170 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003171 for (auto &id_ : ir.ids_for_constant_or_type)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003172 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003173 auto &id = ir.ids[id_];
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003174
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003175 if (id.get_type() == TypeConstant)
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003176 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003177 auto &c = id.get<SPIRConstant>();
3178
3179 bool needs_declaration = c.specialization || c.is_used_as_lut;
3180
3181 if (needs_declaration)
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003182 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003183 if (!options.vulkan_semantics && c.specialization)
3184 {
3185 c.specialization_constant_macro_name =
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02003186 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003187 }
3188 emit_constant(c);
3189 emitted = true;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003190 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003191 }
3192 else if (id.get_type() == TypeConstantOp)
3193 {
3194 emit_specialization_constant_op(id.get<SPIRConstantOp>());
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02003195 emitted = true;
3196 }
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003197 else if (id.get_type() == TypeType)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003198 {
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003199 auto *type = &id.get<SPIRType>();
3200
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003201 bool is_natural_struct = type->basetype == SPIRType::Struct && type->array.empty() && !type->pointer &&
3202 (!has_decoration(type->self, DecorationBlock) &&
3203 !has_decoration(type->self, DecorationBufferBlock));
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003204
3205 // Special case, ray payload and hit attribute blocks are not really blocks, just regular structs.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003206 if (type->basetype == SPIRType::Struct && type->pointer &&
3207 has_decoration(type->self, DecorationBlock) &&
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003208 (type->storage == StorageClassRayPayloadNV || type->storage == StorageClassIncomingRayPayloadNV ||
3209 type->storage == StorageClassHitAttributeNV))
3210 {
3211 type = &get<SPIRType>(type->parent_type);
3212 is_natural_struct = true;
3213 }
3214
3215 if (is_natural_struct)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003216 {
3217 if (emitted)
3218 statement("");
3219 emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003220
Hans-Kristian Arntzen66ec3e32020-05-20 14:51:45 +02003221 emit_struct(*type);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003222 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003223 }
3224 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003225 }
3226
3227 if (emitted)
3228 statement("");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003229
3230 // If we needed to declare work group size late, check here.
3231 // If the work group size depends on a specialization constant, we need to declare the layout() block
3232 // after constants (and their macros) have been declared.
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01003233 if (execution.model == ExecutionModelGLCompute && !options.vulkan_semantics &&
3234 execution.workgroup_size.constant != 0)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003235 {
3236 SpecializationConstant wg_x, wg_y, wg_z;
3237 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
3238
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02003239 if ((wg_x.id != ConstantID(0)) || (wg_y.id != ConstantID(0)) || (wg_z.id != ConstantID(0)))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003240 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02003241 SmallVector<string> inputs;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01003242 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
3243 statement("layout(", merge(inputs), ") in;");
3244 statement("");
3245 }
3246 }
3247
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02003248 emitted = false;
3249
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003250 if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT)
3251 {
3252 for (auto type : physical_storage_non_block_pointer_types)
3253 {
3254 emit_buffer_reference_block(get<SPIRType>(type), false);
3255 }
3256
3257 // Output buffer reference blocks.
3258 // Do this in two stages, one with forward declaration,
3259 // and one without. Buffer reference blocks can reference themselves
3260 // to support things like linked lists.
3261 ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
3262 bool has_block_flags = has_decoration(type.self, DecorationBlock);
3263 if (has_block_flags && type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
3264 type.storage == StorageClassPhysicalStorageBufferEXT)
3265 {
3266 emit_buffer_reference_block(type, true);
3267 }
3268 });
3269
3270 ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
3271 bool has_block_flags = has_decoration(type.self, DecorationBlock);
3272 if (has_block_flags && type.pointer && type.pointer_depth == 1 && !type_is_array_of_pointers(type) &&
3273 type.storage == StorageClassPhysicalStorageBufferEXT)
3274 {
3275 emit_buffer_reference_block(type, false);
3276 }
3277 });
3278 }
3279
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003280 // Output UBOs and SSBOs
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003281 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003282 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003283
Patrick Mours78917862019-06-03 15:25:21 +02003284 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform ||
3285 type.storage == StorageClassShaderRecordBufferNV;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003286 bool has_block_flags = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
3287 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
3288
3289 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
3290 has_block_flags)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003291 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003292 emit_buffer_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003293 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003294 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003295
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003296 // Output push constant blocks
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003297 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003298 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003299 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
3300 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003301 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003302 emit_push_constant_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003303 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003304 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003305
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02003306 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003307
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003308 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003309 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003310 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003311
3312 // If we're remapping separate samplers and images, only emit the combined samplers.
3313 if (skip_separate_image_sampler)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003314 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003315 // Sampler buffers are always used without a sampler, and they will also work in regular GL.
3316 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
3317 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
3318 bool separate_sampler = type.basetype == SPIRType::Sampler;
3319 if (!sampler_buffer && (separate_image || separate_sampler))
3320 return;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003321 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003322
3323 if (var.storage != StorageClassFunction && type.pointer &&
Patrick Moursda39a7b2019-02-26 15:43:03 +01003324 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter ||
Patrick Moursbe3035d2019-06-05 13:19:41 +02003325 type.storage == StorageClassRayPayloadNV || type.storage == StorageClassIncomingRayPayloadNV ||
3326 type.storage == StorageClassCallableDataNV || type.storage == StorageClassIncomingCallableDataNV ||
3327 type.storage == StorageClassHitAttributeNV) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003328 !is_hidden_variable(var))
3329 {
3330 emit_uniform(var);
3331 emitted = true;
3332 }
3333 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003335 if (emitted)
3336 statement("");
3337 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003338
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003339 bool emitted_base_instance = false;
3340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003341 // Output in/out interfaces.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003342 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01003343 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003344
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003345 bool is_hidden = is_hidden_variable(var);
3346
3347 // Unused output I/O variables might still be required to implement framebuffer fetch.
3348 if (var.storage == StorageClassOutput && !is_legacy() &&
3349 inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
3350 {
3351 is_hidden = false;
3352 }
3353
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003354 if (var.storage != StorageClassFunction && type.pointer &&
3355 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01003356 interface_variable_exists_in_entry_point(var.self) && !is_hidden)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003357 {
3358 emit_interface_block(var);
3359 emitted = true;
3360 }
3361 else if (is_builtin_variable(var))
3362 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003363 auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003364 // For gl_InstanceIndex emulation on GLES, the API user needs to
3365 // supply this uniform.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003366
3367 // The draw parameter extension is soft-enabled on GL with some fallbacks.
3368 if (!options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003369 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02003370 if (!emitted_base_instance &&
3371 ((options.vertex.support_nonzero_base_instance && builtin == BuiltInInstanceIndex) ||
3372 (builtin == BuiltInBaseInstance)))
3373 {
3374 statement("#ifdef GL_ARB_shader_draw_parameters");
3375 statement("#define SPIRV_Cross_BaseInstance gl_BaseInstanceARB");
3376 statement("#else");
3377 // A crude, but simple workaround which should be good enough for non-indirect draws.
3378 statement("uniform int SPIRV_Cross_BaseInstance;");
3379 statement("#endif");
3380 emitted = true;
3381 emitted_base_instance = true;
3382 }
3383 else if (builtin == BuiltInBaseVertex)
3384 {
3385 statement("#ifdef GL_ARB_shader_draw_parameters");
3386 statement("#define SPIRV_Cross_BaseVertex gl_BaseVertexARB");
3387 statement("#else");
3388 // A crude, but simple workaround which should be good enough for non-indirect draws.
3389 statement("uniform int SPIRV_Cross_BaseVertex;");
3390 statement("#endif");
3391 }
3392 else if (builtin == BuiltInDrawIndex)
3393 {
3394 statement("#ifndef GL_ARB_shader_draw_parameters");
3395 // Cannot really be worked around.
3396 statement("#error GL_ARB_shader_draw_parameters is not supported.");
3397 statement("#endif");
3398 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003399 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003400 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01003401 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003402
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003403 // Global variables.
3404 for (auto global : global_variables)
3405 {
3406 auto &var = get<SPIRVariable>(global);
3407 if (var.storage != StorageClassOutput)
3408 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003409 if (!variable_is_lut(var))
3410 {
3411 add_resource_name(var.self);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01003412
3413 string initializer;
3414 if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate &&
3415 !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var)))
3416 {
3417 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var)));
3418 }
3419
3420 statement(variable_decl(var), initializer, ";");
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01003421 emitted = true;
3422 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003423 }
3424 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003425
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003426 if (emitted)
3427 statement("");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02003428
3429 declare_undefined_values();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003430}
3431
crissdb52e272020-10-08 12:14:52 +02003432void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
3433{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01003434 static const char *workaround_types[] = { "int", "ivec2", "ivec3", "ivec4", "uint", "uvec2", "uvec3", "uvec4",
3435 "float", "vec2", "vec3", "vec4", "double", "dvec2", "dvec3", "dvec4" };
crissdb52e272020-10-08 12:14:52 +02003436
3437 if (!options.vulkan_semantics)
3438 {
3439 using Supp = ShaderSubgroupSupportHelper;
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003440 auto result = shader_subgroup_supporter.resolve();
crissdb52e272020-10-08 12:14:52 +02003441
3442 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMask))
3443 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003444 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupMask, result);
crissdb52e272020-10-08 12:14:52 +02003445
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003446 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003447 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003448 const char *name = Supp::get_extension_name(e);
3449 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003450
crissdb52e272020-10-08 12:14:52 +02003451 switch (e)
3452 {
3453 case Supp::NV_shader_thread_group:
3454 statement("#define gl_SubgroupEqMask uvec4(gl_ThreadEqMaskNV, 0u, 0u, 0u)");
3455 statement("#define gl_SubgroupGeMask uvec4(gl_ThreadGeMaskNV, 0u, 0u, 0u)");
3456 statement("#define gl_SubgroupGtMask uvec4(gl_ThreadGtMaskNV, 0u, 0u, 0u)");
3457 statement("#define gl_SubgroupLeMask uvec4(gl_ThreadLeMaskNV, 0u, 0u, 0u)");
3458 statement("#define gl_SubgroupLtMask uvec4(gl_ThreadLtMaskNV, 0u, 0u, 0u)");
3459 break;
3460 case Supp::ARB_shader_ballot:
3461 statement("#define gl_SubgroupEqMask uvec4(unpackUint2x32(gl_SubGroupEqMaskARB), 0u, 0u)");
3462 statement("#define gl_SubgroupGeMask uvec4(unpackUint2x32(gl_SubGroupGeMaskARB), 0u, 0u)");
3463 statement("#define gl_SubgroupGtMask uvec4(unpackUint2x32(gl_SubGroupGtMaskARB), 0u, 0u)");
3464 statement("#define gl_SubgroupLeMask uvec4(unpackUint2x32(gl_SubGroupLeMaskARB), 0u, 0u)");
3465 statement("#define gl_SubgroupLtMask uvec4(unpackUint2x32(gl_SubGroupLtMaskARB), 0u, 0u)");
3466 break;
3467 default:
3468 break;
3469 }
3470 }
3471 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003472 statement("");
crissdb52e272020-10-08 12:14:52 +02003473 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003474
crissdb52e272020-10-08 12:14:52 +02003475 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupSize))
3476 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003477 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupSize, result);
crissdb52e272020-10-08 12:14:52 +02003478
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003479 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003480 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003481 const char *name = Supp::get_extension_name(e);
3482 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003483
crissdb52e272020-10-08 12:14:52 +02003484 switch (e)
3485 {
3486 case Supp::NV_shader_thread_group:
3487 statement("#define gl_SubgroupSize gl_WarpSizeNV");
3488 break;
3489 case Supp::ARB_shader_ballot:
3490 statement("#define gl_SubgroupSize gl_SubGroupSizeARB");
3491 break;
3492 case Supp::AMD_gcn_shader:
3493 statement("#define gl_SubgroupSize uint(gl_SIMDGroupSizeAMD)");
3494 break;
3495 default:
3496 break;
3497 }
3498 }
3499 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003500 statement("");
crissdb52e272020-10-08 12:14:52 +02003501 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003502
crissdb52e272020-10-08 12:14:52 +02003503 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInvocationID))
3504 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003505 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupInvocationID, result);
crissdb52e272020-10-08 12:14:52 +02003506
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003507 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003508 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003509 const char *name = Supp::get_extension_name(e);
3510 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003511
crissdb52e272020-10-08 12:14:52 +02003512 switch (e)
3513 {
3514 case Supp::NV_shader_thread_group:
3515 statement("#define gl_SubgroupInvocationID gl_ThreadInWarpNV");
3516 break;
3517 case Supp::ARB_shader_ballot:
3518 statement("#define gl_SubgroupInvocationID gl_SubGroupInvocationARB");
3519 break;
3520 default:
3521 break;
3522 }
3523 }
3524 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003525 statement("");
crissdb52e272020-10-08 12:14:52 +02003526 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003527
crissdb52e272020-10-08 12:14:52 +02003528 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupID))
3529 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003530 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupID, result);
crissdb52e272020-10-08 12:14:52 +02003531
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003532 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003533 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003534 const char *name = Supp::get_extension_name(e);
3535 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003536
crissdb52e272020-10-08 12:14:52 +02003537 switch (e)
3538 {
3539 case Supp::NV_shader_thread_group:
3540 statement("#define gl_SubgroupID gl_WarpIDNV");
3541 break;
3542 default:
3543 break;
3544 }
3545 }
3546 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003547 statement("");
crissdb52e272020-10-08 12:14:52 +02003548 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003549
crissdb52e272020-10-08 12:14:52 +02003550 if (shader_subgroup_supporter.is_feature_requested(Supp::NumSubgroups))
3551 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003552 auto exts = Supp::get_candidates_for_feature(Supp::NumSubgroups, result);
crissdb52e272020-10-08 12:14:52 +02003553
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003554 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003555 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003556 const char *name = Supp::get_extension_name(e);
3557 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003558
crissdb52e272020-10-08 12:14:52 +02003559 switch (e)
3560 {
3561 case Supp::NV_shader_thread_group:
3562 statement("#define gl_NumSubgroups gl_WarpsPerSMNV");
3563 break;
3564 default:
3565 break;
3566 }
3567 }
3568 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003569 statement("");
crissdb52e272020-10-08 12:14:52 +02003570 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003571
crissdb52e272020-10-08 12:14:52 +02003572 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBrodcast_First))
3573 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003574 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBrodcast_First, result);
crissdb52e272020-10-08 12:14:52 +02003575
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003576 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003577 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003578 const char *name = Supp::get_extension_name(e);
3579 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003580
crissdb52e272020-10-08 12:14:52 +02003581 switch (e)
3582 {
3583 case Supp::NV_shader_thread_shuffle:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003584 for (const char *t : workaround_types)
3585 {
3586 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02003587 " value) { return shuffleNV(value, findLSB(ballotThreadNV(true)), gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003588 }
3589 for (const char *t : workaround_types)
3590 {
3591 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02003592 " value, uint id) { return shuffleNV(value, id, gl_WarpSizeNV); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003593 }
crissdb52e272020-10-08 12:14:52 +02003594 break;
3595 case Supp::ARB_shader_ballot:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003596 for (const char *t : workaround_types)
3597 {
3598 statement(t, " subgroupBroadcastFirst(", t,
crissdb52e272020-10-08 12:14:52 +02003599 " value) { return readFirstInvocationARB(value); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003600 }
3601 for (const char *t : workaround_types)
3602 {
3603 statement(t, " subgroupBroadcast(", t,
crissdb52e272020-10-08 12:14:52 +02003604 " value, uint id) { return readInvocationARB(value, id); }");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003605 }
crissdb52e272020-10-08 12:14:52 +02003606 break;
3607 default:
3608 break;
3609 }
3610 }
3611 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003612 statement("");
crissdb52e272020-10-08 12:14:52 +02003613 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003614
crissdb52e272020-10-08 12:14:52 +02003615 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotFindLSB_MSB))
3616 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003617 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallotFindLSB_MSB, result);
crissdb52e272020-10-08 12:14:52 +02003618
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003619 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003620 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003621 const char *name = Supp::get_extension_name(e);
3622 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003623
crissdb52e272020-10-08 12:14:52 +02003624 switch (e)
3625 {
3626 case Supp::NV_shader_thread_group:
3627 statement("uint subgroupBallotFindLSB(uvec4 value) { return findLSB(value.x); }");
3628 statement("uint subgroupBallotFindMSB(uvec4 value) { return findMSB(value.x); }");
3629 break;
3630 default:
3631 break;
3632 }
3633 }
3634 statement("#else");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003635 statement("uint subgroupBallotFindLSB(uvec4 value)");
3636 begin_scope();
crissdb52e272020-10-08 12:14:52 +02003637 statement("int firstLive = findLSB(value.x);");
3638 statement("return uint(firstLive != -1 ? firstLive : (findLSB(value.y) + 32));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003639 end_scope();
3640 statement("uint subgroupBallotFindMSB(uvec4 value)");
3641 begin_scope();
crissdb52e272020-10-08 12:14:52 +02003642 statement("int firstLive = findMSB(value.y);");
3643 statement("return uint(firstLive != -1 ? (firstLive + 32) : findMSB(value.x));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003644 end_scope();
crissdb52e272020-10-08 12:14:52 +02003645 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003646 statement("");
crissdb52e272020-10-08 12:14:52 +02003647 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003648
crissdb52e272020-10-08 12:14:52 +02003649 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAll_Any_AllEqualBool))
3650 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003651 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupAll_Any_AllEqualBool, result);
crissdb52e272020-10-08 12:14:52 +02003652
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003653 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003654 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003655 const char *name = Supp::get_extension_name(e);
3656 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003657
crissdb52e272020-10-08 12:14:52 +02003658 switch (e)
3659 {
3660 case Supp::NV_gpu_shader_5:
3661 statement("bool subgroupAll(bool value) { return allThreadsNV(value); }");
3662 statement("bool subgroupAny(bool value) { return anyThreadNV(value); }");
3663 statement("bool subgroupAllEqual(bool value) { return allThreadsEqualNV(value); }");
3664 break;
3665 case Supp::ARB_shader_group_vote:
3666 statement("bool subgroupAll(bool v) { return allInvocationsARB(v); }");
3667 statement("bool subgroupAny(bool v) { return anyInvocationARB(v); }");
3668 statement("bool subgroupAllEqual(bool v) { return allInvocationsEqualARB(v); }");
3669 break;
3670 case Supp::AMD_gcn_shader:
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003671 statement("bool subgroupAll(bool value) { return ballotAMD(value) == ballotAMD(true); }");
3672 statement("bool subgroupAny(bool value) { return ballotAMD(value) != 0ull; }");
3673 statement("bool subgroupAllEqual(bool value) { uint64_t b = ballotAMD(value); return b == 0ull || "
3674 "b == ballotAMD(true); }");
crissdb52e272020-10-08 12:14:52 +02003675 break;
3676 default:
3677 break;
3678 }
3679 }
3680 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003681 statement("");
crissdb52e272020-10-08 12:14:52 +02003682 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003683
crissdb52e272020-10-08 12:14:52 +02003684 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupAllEqualT))
3685 {
3686 statement("#ifndef GL_KHR_shader_subgroup_vote");
3687 statement(
3688 "#define _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(type) bool subgroupAllEqual(type value) { return "
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003689 "subgroupAllEqual(subgroupBroadcastFirst(value) == value); }");
3690 for (const char *t : workaround_types)
3691 statement("_SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND(", t, ")");
crissdb52e272020-10-08 12:14:52 +02003692 statement("#undef _SPIRV_CROSS_SUBGROUP_ALL_EQUAL_WORKAROUND");
3693 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003694 statement("");
crissdb52e272020-10-08 12:14:52 +02003695 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003696
crissdb52e272020-10-08 12:14:52 +02003697 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallot))
3698 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003699 auto exts = Supp::get_candidates_for_feature(Supp::SubgroupBallot, result);
crissdb52e272020-10-08 12:14:52 +02003700
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003701 for (auto &e : exts)
crissdb52e272020-10-08 12:14:52 +02003702 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003703 const char *name = Supp::get_extension_name(e);
3704 statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")");
crissdb52e272020-10-08 12:14:52 +02003705
crissdb52e272020-10-08 12:14:52 +02003706 switch (e)
3707 {
3708 case Supp::NV_shader_thread_group:
3709 statement("uvec4 subgroupBallot(bool v) { return uvec4(ballotThreadNV(v), 0u, 0u, 0u); }");
3710 break;
3711 case Supp::ARB_shader_ballot:
3712 statement("uvec4 subgroupBallot(bool v) { return uvec4(unpackUint2x32(ballotARB(v)), 0u, 0u); }");
3713 break;
3714 default:
3715 break;
3716 }
3717 }
3718 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003719 statement("");
crissdb52e272020-10-08 12:14:52 +02003720 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003721
crissdb52e272020-10-08 12:14:52 +02003722 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupElect))
3723 {
3724 statement("#ifndef GL_KHR_shader_subgroup_basic");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003725 statement("bool subgroupElect()");
3726 begin_scope();
crissdb52e272020-10-08 12:14:52 +02003727 statement("uvec4 activeMask = subgroupBallot(true);");
3728 statement("uint firstLive = subgroupBallotFindLSB(activeMask);");
3729 statement("return gl_SubgroupInvocationID == firstLive;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003730 end_scope();
crissdb52e272020-10-08 12:14:52 +02003731 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003732 statement("");
crissdb52e272020-10-08 12:14:52 +02003733 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003734
crissdb52e272020-10-08 12:14:52 +02003735 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBarrier))
3736 {
3737 // Extensions we're using in place of GL_KHR_shader_subgroup_basic state
3738 // that subgroup execute in lockstep so this barrier is implicit.
devsh6c5f3942020-10-31 21:46:59 +01003739 // However the GL 4.6 spec also states that `barrier` implies a shared memory barrier,
3740 // and a specific test of optimizing scans by leveraging lock-step invocation execution,
3741 // has shown that a `memoryBarrierShared` is needed in place of a `subgroupBarrier`.
3742 // https://github.com/buildaworldnet/IrrlichtBAW/commit/d8536857991b89a30a6b65d29441e51b64c2c7ad#diff-9f898d27be1ea6fc79b03d9b361e299334c1a347b6e4dc344ee66110c6aa596aR19
crissdb52e272020-10-08 12:14:52 +02003743 statement("#ifndef GL_KHR_shader_subgroup_basic");
devsh6c5f3942020-10-31 21:46:59 +01003744 statement("void subgroupBarrier() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02003745 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003746 statement("");
crissdb52e272020-10-08 12:14:52 +02003747 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003748
crissdb52e272020-10-08 12:14:52 +02003749 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupMemBarrier))
3750 {
3751 if (model == spv::ExecutionModelGLCompute)
3752 {
3753 statement("#ifndef GL_KHR_shader_subgroup_basic");
3754 statement("void subgroupMemoryBarrier() { groupMemoryBarrier(); }");
3755 statement("void subgroupMemoryBarrierBuffer() { groupMemoryBarrier(); }");
devsh6c5f3942020-10-31 21:46:59 +01003756 statement("void subgroupMemoryBarrierShared() { memoryBarrierShared(); }");
crissdb52e272020-10-08 12:14:52 +02003757 statement("void subgroupMemoryBarrierImage() { groupMemoryBarrier(); }");
3758 statement("#endif");
3759 }
3760 else
3761 {
3762 statement("#ifndef GL_KHR_shader_subgroup_basic");
3763 statement("void subgroupMemoryBarrier() { memoryBarrier(); }");
3764 statement("void subgroupMemoryBarrierBuffer() { memoryBarrierBuffer(); }");
3765 statement("void subgroupMemoryBarrierImage() { memoryBarrierImage(); }");
3766 statement("#endif");
3767 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003768 statement("");
crissdb52e272020-10-08 12:14:52 +02003769 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003770
crissdb52e272020-10-08 12:14:52 +02003771 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupInverseBallot_InclBitCount_ExclBitCout))
3772 {
3773 statement("#ifndef GL_KHR_shader_subgroup_ballot");
3774 statement("bool subgroupInverseBallot(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003775 begin_scope();
crissdb52e272020-10-08 12:14:52 +02003776 statement("return any(notEqual(value.xy & gl_SubgroupEqMask.xy, uvec2(0u)));");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003777 end_scope();
crissdb52e272020-10-08 12:14:52 +02003778
3779 statement("uint subgroupBallotInclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003780 begin_scope();
crissdb52e272020-10-08 12:14:52 +02003781 statement("uvec2 v = value.xy & gl_SubgroupLeMask.xy;");
3782 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003783 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02003784 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003785 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02003786 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003787 statement_no_indent("#endif");
3788 end_scope();
crissdb52e272020-10-08 12:14:52 +02003789
3790 statement("uint subgroupBallotExclusiveBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003791 begin_scope();
crissdb52e272020-10-08 12:14:52 +02003792 statement("uvec2 v = value.xy & gl_SubgroupLtMask.xy;");
3793 statement("ivec2 c = bitCount(v);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003794 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02003795 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003796 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02003797 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003798 statement_no_indent("#endif");
3799 end_scope();
crissdb52e272020-10-08 12:14:52 +02003800 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003801 statement("");
crissdb52e272020-10-08 12:14:52 +02003802 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003803
crissdb52e272020-10-08 12:14:52 +02003804 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitCount))
3805 {
3806 statement("#ifndef GL_KHR_shader_subgroup_ballot");
3807 statement("uint subgroupBallotBitCount(uvec4 value)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003808 begin_scope();
crissdb52e272020-10-08 12:14:52 +02003809 statement("ivec2 c = bitCount(value.xy);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003810 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02003811 statement("return uint(c.x);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003812 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02003813 statement("return uint(c.x + c.y);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003814 statement_no_indent("#endif");
3815 end_scope();
crissdb52e272020-10-08 12:14:52 +02003816 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003817 statement("");
crissdb52e272020-10-08 12:14:52 +02003818 }
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003819
crissdb52e272020-10-08 12:14:52 +02003820 if (shader_subgroup_supporter.is_feature_requested(Supp::SubgroupBallotBitExtract))
3821 {
3822 statement("#ifndef GL_KHR_shader_subgroup_ballot");
3823 statement("bool subgroupBallotBitExtract(uvec4 value, uint index)");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003824 begin_scope();
3825 statement_no_indent("#ifdef GL_NV_shader_thread_group");
crissdb52e272020-10-08 12:14:52 +02003826 statement("uint shifted = value.x >> index;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003827 statement_no_indent("#else");
crissdb52e272020-10-08 12:14:52 +02003828 statement("uint shifted = value[index >> 5u] >> (index & 0x1fu);");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003829 statement_no_indent("#endif");
crissdb52e272020-10-08 12:14:52 +02003830 statement("return (shifted & 1u) != 0u;");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003831 end_scope();
crissdb52e272020-10-08 12:14:52 +02003832 statement("#endif");
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02003833 statement("");
crissdb52e272020-10-08 12:14:52 +02003834 }
3835 }
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02003836
3837 if (!workaround_ubo_load_overload_types.empty())
3838 {
3839 for (auto &type_id : workaround_ubo_load_overload_types)
3840 {
3841 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003842 statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type),
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02003843 " wrap) { return wrap; }");
3844 }
3845 statement("");
3846 }
rdbbf719942020-11-05 17:09:33 +01003847
3848 if (requires_transpose_2x2)
3849 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003850 statement("mat2 spvTranspose(mat2 m)");
rdbbf719942020-11-05 17:09:33 +01003851 begin_scope();
3852 statement("return mat2(m[0][0], m[1][0], m[0][1], m[1][1]);");
3853 end_scope();
3854 statement("");
3855 }
3856
3857 if (requires_transpose_3x3)
3858 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003859 statement("mat3 spvTranspose(mat3 m)");
rdbbf719942020-11-05 17:09:33 +01003860 begin_scope();
3861 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]);");
3862 end_scope();
3863 statement("");
3864 }
3865
3866 if (requires_transpose_4x4)
3867 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003868 statement("mat4 spvTranspose(mat4 m)");
rdbbf719942020-11-05 17:09:33 +01003869 begin_scope();
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01003870 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], "
3871 "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 +01003872 end_scope();
3873 statement("");
3874 }
crissdb52e272020-10-08 12:14:52 +02003875}
3876
Bill Hollingsb321b832016-07-06 20:30:47 -04003877// Returns a string representation of the ID, usable as a function arg.
3878// Default is to simply return the expression representation fo the arg ID.
3879// Subclasses may override to modify the return value.
Chip Davis39dce882019-08-02 15:11:19 -05003880string CompilerGLSL::to_func_call_arg(const SPIRFunction::Parameter &, uint32_t id)
Bill Hollingsb321b832016-07-06 20:30:47 -04003881{
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +02003882 // Make sure that we use the name of the original variable, and not the parameter alias.
3883 uint32_t name_id = id;
3884 auto *var = maybe_get<SPIRVariable>(id);
3885 if (var && var->basevariable)
3886 name_id = var->basevariable;
3887 return to_expression(name_id);
Bill Hollingsb321b832016-07-06 20:30:47 -04003888}
3889
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003890void CompilerGLSL::handle_invalid_expression(uint32_t id)
3891{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003892 // We tried to read an invalidated expression.
3893 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
3894 forced_temporaries.insert(id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003895 force_recompile();
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003896}
3897
Bill Hollingsb332bae2017-03-01 13:07:40 -05003898// Converts the format of the current expression from packed to unpacked,
3899// by wrapping the expression in a constructor of the appropriate type.
3900// GLSL does not support packed formats, so simply return the expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02003901// Subclasses that do will override.
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02003902string CompilerGLSL::unpack_expression_type(string expr_str, const SPIRType &, uint32_t, bool, bool)
Bill Hollingsb332bae2017-03-01 13:07:40 -05003903{
3904 return expr_str;
3905}
3906
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01003907// Sometimes we proactively enclosed an expression where it turns out we might have not needed it after all.
3908void CompilerGLSL::strip_enclosed_expression(string &expr)
3909{
3910 if (expr.size() < 2 || expr.front() != '(' || expr.back() != ')')
3911 return;
3912
3913 // Have to make sure that our first and last parens actually enclose everything inside it.
3914 uint32_t paren_count = 0;
3915 for (auto &c : expr)
3916 {
3917 if (c == '(')
3918 paren_count++;
3919 else if (c == ')')
3920 {
3921 paren_count--;
3922
3923 // If we hit 0 and this is not the final char, our first and final parens actually don't
3924 // enclose the expression, and we cannot strip, e.g.: (a + b) * (c + d).
3925 if (paren_count == 0 && &c != &expr.back())
3926 return;
3927 }
3928 }
Corentin Walleze88c88c2017-01-18 17:22:19 -05003929 expr.erase(expr.size() - 1, 1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01003930 expr.erase(begin(expr));
3931}
3932
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02003933string CompilerGLSL::enclose_expression(const string &expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003934{
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003935 bool need_parens = false;
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02003936
3937 // If the expression starts with a unary we need to enclose to deal with cases where we have back-to-back
3938 // unary expressions.
3939 if (!expr.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003940 {
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02003941 auto c = expr.front();
Chip Davis3bfb2f92018-12-03 02:06:33 -06003942 if (c == '-' || c == '+' || c == '!' || c == '~' || c == '&' || c == '*')
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003943 need_parens = true;
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003944 }
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02003945
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003946 if (!need_parens)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003947 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003948 uint32_t paren_count = 0;
3949 for (auto c : expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003950 {
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02003951 if (c == '(' || c == '[')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003952 paren_count++;
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02003953 else if (c == ')' || c == ']')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003954 {
3955 assert(paren_count);
3956 paren_count--;
3957 }
3958 else if (c == ' ' && paren_count == 0)
3959 {
3960 need_parens = true;
3961 break;
3962 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003963 }
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02003964 assert(paren_count == 0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003965 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003966
3967 // If this expression contains any spaces which are not enclosed by parentheses,
3968 // we need to enclose it so we can treat the whole string as an expression.
3969 // This happens when two expressions have been part of a binary op earlier.
3970 if (need_parens)
3971 return join('(', expr, ')');
3972 else
3973 return expr;
3974}
3975
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02003976string CompilerGLSL::dereference_expression(const SPIRType &expr_type, const std::string &expr)
Chip Davis3bfb2f92018-12-03 02:06:33 -06003977{
3978 // If this expression starts with an address-of operator ('&'), then
3979 // just return the part after the operator.
3980 // TODO: Strip parens if unnecessary?
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01003981 if (expr.front() == '&')
Chip Davis3bfb2f92018-12-03 02:06:33 -06003982 return expr.substr(1);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003983 else if (backend.native_pointers)
Chip Davis3bfb2f92018-12-03 02:06:33 -06003984 return join('*', expr);
Hans-Kristian Arntzen758427e2019-04-26 13:09:54 +02003985 else if (expr_type.storage == StorageClassPhysicalStorageBufferEXT && expr_type.basetype != SPIRType::Struct &&
3986 expr_type.pointer_depth == 1)
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02003987 {
3988 return join(enclose_expression(expr), ".value");
3989 }
3990 else
3991 return expr;
Chip Davis3bfb2f92018-12-03 02:06:33 -06003992}
3993
3994string CompilerGLSL::address_of_expression(const std::string &expr)
3995{
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02003996 if (expr.size() > 3 && expr[0] == '(' && expr[1] == '*' && expr.back() == ')')
3997 {
3998 // If we have an expression which looks like (*foo), taking the address of it is the same as stripping
3999 // the first two and last characters. We might have to enclose the expression.
4000 // This doesn't work for cases like (*foo + 10),
4001 // but this is an r-value expression which we cannot take the address of anyways.
4002 return enclose_expression(expr.substr(2, expr.size() - 3));
4003 }
4004 else if (expr.front() == '*')
4005 {
4006 // If this expression starts with a dereference operator ('*'), then
4007 // just return the part after the operator.
Chip Davis3bfb2f92018-12-03 02:06:33 -06004008 return expr.substr(1);
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004009 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06004010 else
Hans-Kristian Arntzen7b9e0fb2019-05-27 11:59:29 +02004011 return join('&', enclose_expression(expr));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004012}
4013
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004014// Just like to_expression except that we enclose the expression inside parentheses if needed.
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004015string CompilerGLSL::to_enclosed_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004016{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004017 return enclose_expression(to_expression(id, register_expression_read));
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004018}
4019
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004020// Used explicitly when we want to read a row-major expression, but without any transpose shenanigans.
4021// need_transpose must be forced to false.
4022string CompilerGLSL::to_unpacked_row_major_matrix_expression(uint32_t id)
4023{
4024 return unpack_expression_type(to_expression(id), expression_type(id),
4025 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
4026 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), true);
4027}
4028
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004029string CompilerGLSL::to_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004030{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02004031 // If we need to transpose, it will also take care of unpacking rules.
4032 auto *e = maybe_get<SPIRExpression>(id);
4033 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004034 bool is_remapped = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4035 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +02004036
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004037 if (!need_transpose && (is_remapped || is_packed))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004038 {
Hans-Kristian Arntzen1ece67a2019-07-23 17:06:37 +02004039 return unpack_expression_type(to_expression(id, register_expression_read),
4040 get_pointee_type(expression_type_id(id)),
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004041 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004042 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), false);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004043 }
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004044 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004045 return to_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004046}
4047
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004048string CompilerGLSL::to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004049{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02004050 // If we need to transpose, it will also take care of unpacking rules.
4051 auto *e = maybe_get<SPIRExpression>(id);
4052 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzen6c1f97b2019-07-19 14:50:35 +02004053 bool is_remapped = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4054 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
4055 if (!need_transpose && (is_remapped || is_packed))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004056 {
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01004057 return unpack_expression_type(to_expression(id, register_expression_read), expression_type(id),
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004058 get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID),
Hans-Kristian Arntzen12c50202019-07-19 13:03:08 +02004059 has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked), false);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004060 }
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004061 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004062 return to_enclosed_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02004063}
4064
Chip Davis3bfb2f92018-12-03 02:06:33 -06004065string CompilerGLSL::to_dereferenced_expression(uint32_t id, bool register_expression_read)
4066{
4067 auto &type = expression_type(id);
4068 if (type.pointer && should_dereference(id))
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02004069 return dereference_expression(type, to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004070 else
4071 return to_expression(id, register_expression_read);
4072}
4073
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004074string CompilerGLSL::to_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004075{
4076 auto &type = expression_type(id);
4077 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004078 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004079 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004080 return to_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004081}
4082
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004083string CompilerGLSL::to_enclosed_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004084{
4085 auto &type = expression_type(id);
4086 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01004087 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06004088 else
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01004089 return to_enclosed_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06004090}
4091
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004092string CompilerGLSL::to_extract_component_expression(uint32_t id, uint32_t index)
4093{
4094 auto expr = to_enclosed_expression(id);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004095 if (has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02004096 return join(expr, "[", index, "]");
4097 else
4098 return join(expr, ".", index_to_swizzle(index));
4099}
4100
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004101string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
4102{
4103 uint32_t size = to_array_size_literal(type);
4104 auto &parent = get<SPIRType>(type.parent_type);
4105 string expr = "{ ";
4106
4107 for (uint32_t i = 0; i < size; i++)
4108 {
4109 auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
4110 if (parent.array.empty())
4111 expr += subexpr;
4112 else
4113 expr += to_rerolled_array_expression(subexpr, parent);
4114
4115 if (i + 1 < size)
4116 expr += ", ";
4117 }
4118
4119 expr += " }";
4120 return expr;
4121}
4122
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004123string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool uses_buffer_offset)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004124{
4125 auto &type = expression_type(id);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004126
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004127 bool reroll_array = !type.array.empty() && (!backend.array_is_value_type ||
4128 (uses_buffer_offset && !backend.buffer_offset_array_is_value_type));
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02004129
4130 if (reroll_array)
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004131 {
4132 // For this case, we need to "re-roll" an array initializer from a temporary.
4133 // We cannot simply pass the array directly, since it decays to a pointer and it cannot
4134 // participate in a struct initializer. E.g.
4135 // float arr[2] = { 1.0, 2.0 };
4136 // Foo foo = { arr }; must be transformed to
4137 // Foo foo = { { arr[0], arr[1] } };
4138 // The array sizes cannot be deduced from specialization constants since we cannot use any loops.
4139
4140 // We're only triggering one read of the array expression, but this is fine since arrays have to be declared
4141 // as temporaries anyways.
4142 return to_rerolled_array_expression(to_enclosed_expression(id), type);
4143 }
4144 else
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02004145 return to_unpacked_expression(id);
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02004146}
4147
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004148string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004149{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004150 auto itr = invalid_expressions.find(id);
4151 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004152 handle_invalid_expression(id);
4153
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004154 if (ir.ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004155 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004156 // We might have a more complex chain of dependencies.
4157 // A possible scenario is that we
4158 //
4159 // %1 = OpLoad
4160 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
4161 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
4162 // 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.
4163 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
4164 //
4165 // 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,
4166 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004167 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004168 for (uint32_t dep : expr.expression_dependencies)
4169 if (invalid_expressions.find(dep) != end(invalid_expressions))
4170 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004171 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004172
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004173 if (register_expression_read)
4174 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004175
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004176 switch (ir.ids[id].get_type())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004177 {
4178 case TypeExpression:
4179 {
4180 auto &e = get<SPIRExpression>(id);
4181 if (e.base_expression)
Hans-Kristian Arntzenea781e62016-12-06 17:19:34 +01004182 return to_enclosed_expression(e.base_expression) + e.expression;
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02004183 else if (e.need_transpose)
Bill Hollings607b0d62018-02-11 16:52:57 -05004184 {
Hans-Kristian Arntzen2172b192019-07-22 16:27:47 +02004185 // This should not be reached for access chains, since we always deal explicitly with transpose state
4186 // when consuming an access chain expression.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02004187 uint32_t physical_type_id = get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
4188 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02004189 return convert_row_major_matrix(e.expression, get<SPIRType>(e.expression_type), physical_type_id,
4190 is_packed);
Bill Hollings607b0d62018-02-11 16:52:57 -05004191 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004192 else if (flattened_structs.count(id))
4193 {
4194 return load_flattened_struct(e.expression, get<SPIRType>(e.expression_type));
4195 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004196 else
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004197 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02004198 if (is_forcing_recompilation())
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01004199 {
4200 // During first compilation phase, certain expression patterns can trigger exponential growth of memory.
4201 // Avoid this by returning dummy expressions during this phase.
4202 // Do not use empty expressions here, because those are sentinels for other cases.
4203 return "_";
4204 }
4205 else
4206 return e.expression;
4207 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004208 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004209
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004210 case TypeConstant:
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004211 {
4212 auto &c = get<SPIRConstant>(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004213 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02004214
4215 // WorkGroupSize may be a constant.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004216 auto &dec = ir.meta[c.self].decoration;
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02004217 if (dec.builtin)
4218 return builtin_to_glsl(dec.builtin_type, StorageClassGeneric);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004219 else if (c.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004220 return to_name(id);
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02004221 else if (c.is_used_as_lut)
4222 return to_name(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01004223 else if (type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
4224 return to_name(id);
4225 else if (!type.array.empty() && !backend.can_declare_arrays_inline)
4226 return to_name(id);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004227 else
4228 return constant_expression(c);
4229 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004230
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004231 case TypeConstantOp:
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01004232 return to_name(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004233
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004234 case TypeVariable:
4235 {
4236 auto &var = get<SPIRVariable>(id);
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01004237 // If we try to use a loop variable before the loop header, we have to redirect it to the static expression,
4238 // the variable has not been declared yet.
4239 if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004240 return to_expression(var.static_expression);
4241 else if (var.deferred_declaration)
4242 {
4243 var.deferred_declaration = false;
4244 return variable_decl(var);
4245 }
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004246 else if (flattened_structs.count(id))
4247 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02004248 return load_flattened_struct(to_name(id), get<SPIRType>(var.basetype));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004249 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004250 else
4251 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004252 auto &dec = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004253 if (dec.builtin)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004254 return builtin_to_glsl(dec.builtin_type, var.storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004255 else
4256 return to_name(id);
4257 }
4258 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004259
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02004260 case TypeCombinedImageSampler:
4261 // This type should never be taken the expression of directly.
4262 // The intention is that texture sampling functions will extract the image and samplers
4263 // separately and take their expressions as needed.
4264 // GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
4265 // expression ala sampler2D(texture, sampler).
4266 SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
4267
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004268 case TypeAccessChain:
4269 // We cannot express this type. They only have meaning in other OpAccessChains, OpStore or OpLoad.
4270 SPIRV_CROSS_THROW("Access chains have no default expression representation.");
4271
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004272 default:
4273 return to_name(id);
4274 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004275}
4276
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004277string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
4278{
4279 auto &type = get<SPIRType>(cop.basetype);
4280 bool binary = false;
4281 bool unary = false;
4282 string op;
4283
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004284 if (is_legacy() && is_unsigned_opcode(cop.opcode))
4285 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
4286
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004287 // TODO: Find a clean way to reuse emit_instruction.
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004288 switch (cop.opcode)
4289 {
4290 case OpSConvert:
4291 case OpUConvert:
4292 case OpFConvert:
4293 op = type_to_glsl_constructor(type);
4294 break;
4295
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004296#define GLSL_BOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004297 case Op##opname: \
4298 binary = true; \
4299 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004300 break
4301
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004302#define GLSL_UOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004303 case Op##opname: \
4304 unary = true; \
4305 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004306 break
4307
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004308 GLSL_UOP(SNegate, "-");
4309 GLSL_UOP(Not, "~");
4310 GLSL_BOP(IAdd, "+");
4311 GLSL_BOP(ISub, "-");
4312 GLSL_BOP(IMul, "*");
4313 GLSL_BOP(SDiv, "/");
4314 GLSL_BOP(UDiv, "/");
4315 GLSL_BOP(UMod, "%");
4316 GLSL_BOP(SMod, "%");
4317 GLSL_BOP(ShiftRightLogical, ">>");
4318 GLSL_BOP(ShiftRightArithmetic, ">>");
4319 GLSL_BOP(ShiftLeftLogical, "<<");
4320 GLSL_BOP(BitwiseOr, "|");
4321 GLSL_BOP(BitwiseXor, "^");
4322 GLSL_BOP(BitwiseAnd, "&");
4323 GLSL_BOP(LogicalOr, "||");
4324 GLSL_BOP(LogicalAnd, "&&");
4325 GLSL_UOP(LogicalNot, "!");
4326 GLSL_BOP(LogicalEqual, "==");
4327 GLSL_BOP(LogicalNotEqual, "!=");
4328 GLSL_BOP(IEqual, "==");
4329 GLSL_BOP(INotEqual, "!=");
4330 GLSL_BOP(ULessThan, "<");
4331 GLSL_BOP(SLessThan, "<");
4332 GLSL_BOP(ULessThanEqual, "<=");
4333 GLSL_BOP(SLessThanEqual, "<=");
4334 GLSL_BOP(UGreaterThan, ">");
4335 GLSL_BOP(SGreaterThan, ">");
4336 GLSL_BOP(UGreaterThanEqual, ">=");
4337 GLSL_BOP(SGreaterThanEqual, ">=");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004338
4339 case OpSelect:
4340 {
4341 if (cop.arguments.size() < 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004342 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004343
4344 // This one is pretty annoying. It's triggered from
4345 // uint(bool), int(bool) from spec constants.
4346 // In order to preserve its compile-time constness in Vulkan GLSL,
4347 // we need to reduce the OpSelect expression back to this simplified model.
4348 // If we cannot, fail.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004349 if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004350 {
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004351 // Implement as a simple cast down below.
4352 }
4353 else
4354 {
4355 // Implement a ternary and pray the compiler understands it :)
4356 return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004357 }
4358 break;
4359 }
4360
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02004361 case OpVectorShuffle:
4362 {
4363 string expr = type_to_glsl_constructor(type);
4364 expr += "(";
4365
4366 uint32_t left_components = expression_type(cop.arguments[0]).vecsize;
4367 string left_arg = to_enclosed_expression(cop.arguments[0]);
4368 string right_arg = to_enclosed_expression(cop.arguments[1]);
4369
4370 for (uint32_t i = 2; i < uint32_t(cop.arguments.size()); i++)
4371 {
4372 uint32_t index = cop.arguments[i];
4373 if (index >= left_components)
4374 expr += right_arg + "." + "xyzw"[index - left_components];
4375 else
4376 expr += left_arg + "." + "xyzw"[index];
4377
4378 if (i + 1 < uint32_t(cop.arguments.size()))
4379 expr += ", ";
4380 }
4381
4382 expr += ")";
4383 return expr;
4384 }
4385
4386 case OpCompositeExtract:
4387 {
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01004388 auto expr = access_chain_internal(cop.arguments[0], &cop.arguments[1], uint32_t(cop.arguments.size() - 1),
4389 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02004390 return expr;
4391 }
4392
4393 case OpCompositeInsert:
4394 SPIRV_CROSS_THROW("OpCompositeInsert spec constant op is not supported.");
4395
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004396 default:
4397 // Some opcodes are unimplemented here, these are currently not possible to test from glslang.
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004398 SPIRV_CROSS_THROW("Unimplemented spec constant op.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004399 }
4400
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004401 uint32_t bit_width = 0;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004402 if (unary || binary || cop.opcode == OpSConvert || cop.opcode == OpUConvert)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004403 bit_width = expression_type(cop.arguments[0]).width;
4404
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004405 SPIRType::BaseType input_type;
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004406 bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004407
4408 switch (cop.opcode)
4409 {
4410 case OpIEqual:
4411 case OpINotEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004412 input_type = to_signed_basetype(bit_width);
4413 break;
4414
4415 case OpSLessThan:
4416 case OpSLessThanEqual:
4417 case OpSGreaterThan:
4418 case OpSGreaterThanEqual:
4419 case OpSMod:
4420 case OpSDiv:
4421 case OpShiftRightArithmetic:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004422 case OpSConvert:
4423 case OpSNegate:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004424 input_type = to_signed_basetype(bit_width);
4425 break;
4426
4427 case OpULessThan:
4428 case OpULessThanEqual:
4429 case OpUGreaterThan:
4430 case OpUGreaterThanEqual:
4431 case OpUMod:
4432 case OpUDiv:
4433 case OpShiftRightLogical:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004434 case OpUConvert:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004435 input_type = to_unsigned_basetype(bit_width);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004436 break;
4437
4438 default:
4439 input_type = type.basetype;
4440 break;
4441 }
4442
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004443#undef GLSL_BOP
4444#undef GLSL_UOP
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004445 if (binary)
4446 {
4447 if (cop.arguments.size() < 2)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004448 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004449
4450 string cast_op0;
4451 string cast_op1;
4452 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, cop.arguments[0],
4453 cop.arguments[1], skip_cast_if_equal_type);
4454
4455 if (type.basetype != input_type && type.basetype != SPIRType::Boolean)
4456 {
4457 expected_type.basetype = input_type;
4458 auto expr = bitcast_glsl_op(type, expected_type);
4459 expr += '(';
4460 expr += join(cast_op0, " ", op, " ", cast_op1);
4461 expr += ')';
4462 return expr;
4463 }
4464 else
4465 return join("(", cast_op0, " ", op, " ", cast_op1, ")");
4466 }
4467 else if (unary)
4468 {
4469 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004470 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004471
4472 // Auto-bitcast to result type as needed.
4473 // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
4474 return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")");
4475 }
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02004476 else if (cop.opcode == OpSConvert || cop.opcode == OpUConvert)
4477 {
4478 if (cop.arguments.size() < 1)
4479 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
4480
4481 auto &arg_type = expression_type(cop.arguments[0]);
4482 if (arg_type.width < type.width && input_type != arg_type.basetype)
4483 {
4484 auto expected = arg_type;
4485 expected.basetype = input_type;
4486 return join(op, "(", bitcast_glsl(expected, cop.arguments[0]), ")");
4487 }
4488 else
4489 return join(op, "(", to_expression(cop.arguments[0]), ")");
4490 }
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004491 else
4492 {
4493 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004494 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004495 return join(op, "(", to_expression(cop.arguments[0]), ")");
4496 }
4497}
4498
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004499string CompilerGLSL::constant_expression(const SPIRConstant &c)
4500{
Chip Davis3bfb2f92018-12-03 02:06:33 -06004501 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004502
Chip Davis3bfb2f92018-12-03 02:06:33 -06004503 if (type.pointer)
4504 {
4505 return backend.null_pointer_literal;
4506 }
4507 else if (!c.subconstants.empty())
4508 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004509 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004510 string res;
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004511
Lukas Hermanns50ac6862019-09-18 14:03:54 -04004512 // Allow Metal to use the array<T> template to make arrays a value type
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004513 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen57a15df2018-09-10 10:08:02 +02004514 if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004515 type.array.empty())
4516 {
4517 res = type_to_glsl_constructor(type) + "{ ";
4518 }
Hans-Kristian Arntzenc2655ab2020-03-19 14:21:42 +01004519 else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
4520 !type.array.empty())
Mark Satterthwaited50659a2019-08-13 18:18:48 -04004521 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02004522 res = type_to_glsl_constructor(type) + "({ ";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004523 needs_trailing_tracket = true;
Mark Satterthwaited50659a2019-08-13 18:18:48 -04004524 }
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004525 else if (backend.use_initializer_list)
4526 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004527 res = "{ ";
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004528 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004529 else
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02004530 {
4531 res = type_to_glsl_constructor(type) + "(";
4532 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004534 for (auto &elem : c.subconstants)
4535 {
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004536 auto &subc = get<SPIRConstant>(elem);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004537 if (subc.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004538 res += to_name(elem);
4539 else
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02004540 res += constant_expression(subc);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02004541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004542 if (&elem != &c.subconstants.back())
4543 res += ", ";
4544 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004545
4546 res += backend.use_initializer_list ? " }" : ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004547 if (needs_trailing_tracket)
Mark Satterthwaited50659a2019-08-13 18:18:48 -04004548 res += ")";
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04004549
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004550 return res;
4551 }
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04004552 else if (type.basetype == SPIRType::Struct && type.member_types.size() == 0)
4553 {
4554 // Metal tessellation likes empty structs which are then constant expressions.
Hans-Kristian Arntzen3b5c4c72019-10-24 17:05:55 +02004555 if (backend.supports_empty_struct)
4556 return "{ }";
4557 else if (backend.use_typed_initializer_list)
4558 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "{ 0 }");
4559 else if (backend.use_initializer_list)
4560 return "{ 0 }";
4561 else
4562 return join(type_to_glsl(get<SPIRType>(c.constant_type)), "(0)");
Lukas Hermannsf3a6d282019-09-27 15:49:54 -04004563 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004564 else if (c.columns() == 1)
4565 {
4566 return constant_expression_vector(c, 0);
4567 }
4568 else
4569 {
4570 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
4571 for (uint32_t col = 0; col < c.columns(); col++)
4572 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004573 if (c.specialization_constant_id(col) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004574 res += to_name(c.specialization_constant_id(col));
4575 else
4576 res += constant_expression_vector(c, col);
4577
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004578 if (col + 1 < c.columns())
4579 res += ", ";
4580 }
4581 res += ")";
4582 return res;
4583 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004584}
4585
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004586#ifdef _MSC_VER
4587// sprintf warning.
4588// We cannot rely on snprintf existing because, ..., MSVC.
4589#pragma warning(push)
4590#pragma warning(disable : 4996)
4591#endif
4592
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004593string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
4594{
4595 string res;
4596 float float_value = c.scalar_f16(col, row);
4597
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01004598 // There is no literal "hf" in GL_NV_gpu_shader5, so to avoid lots
4599 // of complicated workarounds, just value-cast to the half type always.
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004600 if (std::isnan(float_value) || std::isinf(float_value))
4601 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01004602 SPIRType type;
4603 type.basetype = SPIRType::Half;
4604 type.vecsize = 1;
4605 type.columns = 1;
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01004606
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01004607 if (float_value == numeric_limits<float>::infinity())
4608 res = join(type_to_glsl(type), "(1.0 / 0.0)");
4609 else if (float_value == -numeric_limits<float>::infinity())
4610 res = join(type_to_glsl(type), "(-1.0 / 0.0)");
4611 else if (std::isnan(float_value))
4612 res = join(type_to_glsl(type), "(0.0 / 0.0)");
4613 else
4614 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004615 }
4616 else
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01004617 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01004618 SPIRType type;
4619 type.basetype = SPIRType::Half;
4620 type.vecsize = 1;
4621 type.columns = 1;
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01004622 res = join(type_to_glsl(type), "(", convert_to_string(float_value, current_locale_radix_character), ")");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01004623 }
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004624
4625 return res;
4626}
4627
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004628string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
4629{
4630 string res;
4631 float float_value = c.scalar_f32(col, row);
4632
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01004633 if (std::isnan(float_value) || std::isinf(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004634 {
4635 // Use special representation.
4636 if (!is_legacy())
4637 {
4638 SPIRType out_type;
4639 SPIRType in_type;
4640 out_type.basetype = SPIRType::Float;
4641 in_type.basetype = SPIRType::UInt;
4642 out_type.vecsize = 1;
4643 in_type.vecsize = 1;
4644 out_type.width = 32;
4645 in_type.width = 32;
4646
4647 char print_buffer[32];
4648 sprintf(print_buffer, "0x%xu", c.scalar(col, row));
4649 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
4650 }
4651 else
4652 {
4653 if (float_value == numeric_limits<float>::infinity())
4654 {
4655 if (backend.float_literal_suffix)
4656 res = "(1.0f / 0.0f)";
4657 else
4658 res = "(1.0 / 0.0)";
4659 }
4660 else if (float_value == -numeric_limits<float>::infinity())
4661 {
4662 if (backend.float_literal_suffix)
4663 res = "(-1.0f / 0.0f)";
4664 else
4665 res = "(-1.0 / 0.0)";
4666 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01004667 else if (std::isnan(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004668 {
4669 if (backend.float_literal_suffix)
4670 res = "(0.0f / 0.0f)";
4671 else
4672 res = "(0.0 / 0.0)";
4673 }
4674 else
4675 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
4676 }
4677 }
4678 else
4679 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01004680 res = convert_to_string(float_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004681 if (backend.float_literal_suffix)
4682 res += "f";
4683 }
4684
4685 return res;
4686}
4687
4688std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
4689{
4690 string res;
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01004691 double double_value = c.scalar_f64(col, row);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004692
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01004693 if (std::isnan(double_value) || std::isinf(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004694 {
4695 // Use special representation.
4696 if (!is_legacy())
4697 {
4698 SPIRType out_type;
4699 SPIRType in_type;
4700 out_type.basetype = SPIRType::Double;
4701 in_type.basetype = SPIRType::UInt64;
4702 out_type.vecsize = 1;
4703 in_type.vecsize = 1;
4704 out_type.width = 64;
4705 in_type.width = 64;
4706
4707 uint64_t u64_value = c.scalar_u64(col, row);
4708
4709 if (options.es)
4710 SPIRV_CROSS_THROW("64-bit integers/float not supported in ES profile.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02004711 require_extension_internal("GL_ARB_gpu_shader_int64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004712
4713 char print_buffer[64];
4714 sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
4715 backend.long_long_literal_suffix ? "ull" : "ul");
4716 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
4717 }
4718 else
4719 {
4720 if (options.es)
4721 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
4722 if (options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02004723 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004724
4725 if (double_value == numeric_limits<double>::infinity())
4726 {
4727 if (backend.double_literal_suffix)
4728 res = "(1.0lf / 0.0lf)";
4729 else
4730 res = "(1.0 / 0.0)";
4731 }
4732 else if (double_value == -numeric_limits<double>::infinity())
4733 {
4734 if (backend.double_literal_suffix)
4735 res = "(-1.0lf / 0.0lf)";
4736 else
4737 res = "(-1.0 / 0.0)";
4738 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01004739 else if (std::isnan(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004740 {
4741 if (backend.double_literal_suffix)
4742 res = "(0.0lf / 0.0lf)";
4743 else
4744 res = "(0.0 / 0.0)";
4745 }
4746 else
4747 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
4748 }
4749 }
4750 else
4751 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01004752 res = convert_to_string(double_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004753 if (backend.double_literal_suffix)
4754 res += "lf";
4755 }
4756
4757 return res;
4758}
4759
4760#ifdef _MSC_VER
4761#pragma warning(pop)
4762#endif
4763
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004764string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
4765{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004766 auto type = get<SPIRType>(c.constant_type);
4767 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004768
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004769 auto scalar_type = type;
4770 scalar_type.vecsize = 1;
4771
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004772 string res;
Robert Konradea24ee82016-09-23 18:57:18 +02004773 bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004774 bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004775
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004776 if (!type_is_floating_point(type))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004777 {
4778 // Cannot swizzle literal integers as a special case.
4779 swizzle_splat = false;
4780 }
4781
4782 if (splat || swizzle_splat)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004783 {
4784 // Cannot use constant splatting if we have specialization constants somewhere in the vector.
4785 for (uint32_t i = 0; i < c.vector_size(); i++)
4786 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004787 if (c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004788 {
4789 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004790 swizzle_splat = false;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004791 break;
4792 }
4793 }
4794 }
4795
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004796 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004797 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02004798 if (type.width == 64)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004799 {
4800 uint64_t ident = c.scalar_u64(vector, 0);
4801 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004802 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004803 if (ident != c.scalar_u64(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004804 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004805 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004806 swizzle_splat = false;
4807 break;
4808 }
4809 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004810 }
4811 else
4812 {
4813 uint32_t ident = c.scalar(vector, 0);
4814 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004815 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004816 if (ident != c.scalar(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004817 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004818 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004819 swizzle_splat = false;
4820 }
4821 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004822 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004823 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004824
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004825 if (c.vector_size() > 1 && !swizzle_splat)
4826 res += type_to_glsl(type) + "(";
4827
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004828 switch (type.basetype)
4829 {
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004830 case SPIRType::Half:
4831 if (splat || swizzle_splat)
4832 {
4833 res += convert_half_to_string(c, vector, 0);
4834 if (swizzle_splat)
4835 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
4836 }
4837 else
4838 {
4839 for (uint32_t i = 0; i < c.vector_size(); i++)
4840 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004841 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004842 res += to_name(c.specialization_constant_id(vector, i));
4843 else
4844 res += convert_half_to_string(c, vector, i);
4845
4846 if (i + 1 < c.vector_size())
4847 res += ", ";
4848 }
4849 }
4850 break;
4851
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004852 case SPIRType::Float:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004853 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004854 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004855 res += convert_float_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004856 if (swizzle_splat)
4857 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004858 }
4859 else
4860 {
4861 for (uint32_t i = 0; i < c.vector_size(); i++)
4862 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004863 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004864 res += to_name(c.specialization_constant_id(vector, i));
4865 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004866 res += convert_float_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004867
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004868 if (i + 1 < c.vector_size())
4869 res += ", ";
4870 }
4871 }
4872 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004873
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004874 case SPIRType::Double:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004875 if (splat || swizzle_splat)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004876 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004877 res += convert_double_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004878 if (swizzle_splat)
4879 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004880 }
4881 else
4882 {
4883 for (uint32_t i = 0; i < c.vector_size(); i++)
4884 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004885 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004886 res += to_name(c.specialization_constant_id(vector, i));
4887 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01004888 res += convert_double_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004889
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004890 if (i + 1 < c.vector_size())
4891 res += ", ";
4892 }
4893 }
4894 break;
4895
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004896 case SPIRType::Int64:
4897 if (splat)
4898 {
4899 res += convert_to_string(c.scalar_i64(vector, 0));
4900 if (backend.long_long_literal_suffix)
4901 res += "ll";
4902 else
4903 res += "l";
4904 }
4905 else
4906 {
4907 for (uint32_t i = 0; i < c.vector_size(); i++)
4908 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004909 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004910 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004911 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004912 {
4913 res += convert_to_string(c.scalar_i64(vector, i));
4914 if (backend.long_long_literal_suffix)
4915 res += "ll";
4916 else
4917 res += "l";
4918 }
4919
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004920 if (i + 1 < c.vector_size())
4921 res += ", ";
4922 }
4923 }
4924 break;
4925
4926 case SPIRType::UInt64:
4927 if (splat)
4928 {
4929 res += convert_to_string(c.scalar_u64(vector, 0));
4930 if (backend.long_long_literal_suffix)
4931 res += "ull";
4932 else
4933 res += "ul";
4934 }
4935 else
4936 {
4937 for (uint32_t i = 0; i < c.vector_size(); i++)
4938 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004939 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004940 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004941 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004942 {
4943 res += convert_to_string(c.scalar_u64(vector, i));
4944 if (backend.long_long_literal_suffix)
4945 res += "ull";
4946 else
4947 res += "ul";
4948 }
4949
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004950 if (i + 1 < c.vector_size())
4951 res += ", ";
4952 }
4953 }
4954 break;
4955
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004956 case SPIRType::UInt:
4957 if (splat)
4958 {
4959 res += convert_to_string(c.scalar(vector, 0));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004960 if (is_legacy())
4961 {
4962 // Fake unsigned constant literals with signed ones if possible.
4963 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
4964 if (c.scalar_i32(vector, 0) < 0)
4965 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative.");
4966 }
4967 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004968 res += "u";
4969 }
4970 else
4971 {
4972 for (uint32_t i = 0; i < c.vector_size(); i++)
4973 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07004974 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004975 res += to_name(c.specialization_constant_id(vector, i));
4976 else
4977 {
4978 res += convert_to_string(c.scalar(vector, i));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004979 if (is_legacy())
4980 {
4981 // Fake unsigned constant literals with signed ones if possible.
4982 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
4983 if (c.scalar_i32(vector, i) < 0)
crissdb52e272020-10-08 12:14:52 +02004984 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made "
4985 "the literal negative.");
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004986 }
4987 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02004988 res += "u";
4989 }
4990
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004991 if (i + 1 < c.vector_size())
4992 res += ", ";
4993 }
4994 }
4995 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004996
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004997 case SPIRType::Int:
4998 if (splat)
4999 res += convert_to_string(c.scalar_i32(vector, 0));
5000 else
5001 {
5002 for (uint32_t i = 0; i < c.vector_size(); i++)
5003 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005004 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005005 res += to_name(c.specialization_constant_id(vector, i));
5006 else
5007 res += convert_to_string(c.scalar_i32(vector, i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005008 if (i + 1 < c.vector_size())
5009 res += ", ";
5010 }
5011 }
5012 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005013
Chip Davisca4744a2018-11-02 14:39:55 -05005014 case SPIRType::UShort:
5015 if (splat)
5016 {
5017 res += convert_to_string(c.scalar(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005018 }
5019 else
5020 {
5021 for (uint32_t i = 0; i < c.vector_size(); i++)
5022 {
5023 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
5024 res += to_name(c.specialization_constant_id(vector, i));
5025 else
5026 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005027 if (*backend.uint16_t_literal_suffix)
Chip Davisca4744a2018-11-02 14:39:55 -05005028 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005029 res += convert_to_string(c.scalar_u16(vector, i));
5030 res += backend.uint16_t_literal_suffix;
Chip Davisca4744a2018-11-02 14:39:55 -05005031 }
Bill Hollingsc48702d2019-03-28 14:23:32 -04005032 else
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005033 {
5034 // If backend doesn't have a literal suffix, we need to value cast.
5035 res += type_to_glsl(scalar_type);
5036 res += "(";
5037 res += convert_to_string(c.scalar_u16(vector, i));
5038 res += ")";
5039 }
Chip Davisca4744a2018-11-02 14:39:55 -05005040 }
5041
5042 if (i + 1 < c.vector_size())
5043 res += ", ";
5044 }
5045 }
5046 break;
5047
5048 case SPIRType::Short:
5049 if (splat)
5050 {
5051 res += convert_to_string(c.scalar_i16(vector, 0));
Chip Davisca4744a2018-11-02 14:39:55 -05005052 }
5053 else
5054 {
5055 for (uint32_t i = 0; i < c.vector_size(); i++)
5056 {
5057 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
5058 res += to_name(c.specialization_constant_id(vector, i));
5059 else
5060 {
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005061 if (*backend.int16_t_literal_suffix)
5062 {
5063 res += convert_to_string(c.scalar_i16(vector, i));
5064 res += backend.int16_t_literal_suffix;
5065 }
5066 else
5067 {
5068 // If backend doesn't have a literal suffix, we need to value cast.
5069 res += type_to_glsl(scalar_type);
5070 res += "(";
5071 res += convert_to_string(c.scalar_i16(vector, i));
5072 res += ")";
5073 }
Chip Davisca4744a2018-11-02 14:39:55 -05005074 }
Hans-Kristian Arntzen3c112542019-09-19 10:19:51 +02005075
Chip Davisca4744a2018-11-02 14:39:55 -05005076 if (i + 1 < c.vector_size())
5077 res += ", ";
5078 }
5079 }
5080 break;
5081
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005082 case SPIRType::UByte:
5083 if (splat)
5084 {
5085 res += convert_to_string(c.scalar_u8(vector, 0));
5086 }
5087 else
5088 {
5089 for (uint32_t i = 0; i < c.vector_size(); i++)
5090 {
5091 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
5092 res += to_name(c.specialization_constant_id(vector, i));
5093 else
5094 {
5095 res += type_to_glsl(scalar_type);
5096 res += "(";
5097 res += convert_to_string(c.scalar_u8(vector, i));
5098 res += ")";
5099 }
5100
5101 if (i + 1 < c.vector_size())
5102 res += ", ";
5103 }
5104 }
5105 break;
5106
5107 case SPIRType::SByte:
5108 if (splat)
5109 {
5110 res += convert_to_string(c.scalar_i8(vector, 0));
5111 }
5112 else
5113 {
5114 for (uint32_t i = 0; i < c.vector_size(); i++)
5115 {
5116 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
5117 res += to_name(c.specialization_constant_id(vector, i));
5118 else
5119 {
5120 res += type_to_glsl(scalar_type);
5121 res += "(";
5122 res += convert_to_string(c.scalar_i8(vector, i));
5123 res += ")";
5124 }
5125
5126 if (i + 1 < c.vector_size())
5127 res += ", ";
5128 }
5129 }
5130 break;
5131
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005132 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005133 if (splat)
5134 res += c.scalar(vector, 0) ? "true" : "false";
5135 else
5136 {
5137 for (uint32_t i = 0; i < c.vector_size(); i++)
5138 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07005139 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02005140 res += to_name(c.specialization_constant_id(vector, i));
5141 else
5142 res += c.scalar(vector, i) ? "true" : "false";
5143
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005144 if (i + 1 < c.vector_size())
5145 res += ", ";
5146 }
5147 }
5148 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005149
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005150 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005151 SPIRV_CROSS_THROW("Invalid constant expression basetype.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005152 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005153
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01005154 if (c.vector_size() > 1 && !swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005155 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005156
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005157 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005158}
5159
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005160SPIRExpression &CompilerGLSL::emit_uninitialized_temporary_expression(uint32_t type, uint32_t id)
5161{
5162 forced_temporaries.insert(id);
5163 emit_uninitialized_temporary(type, id);
5164 return set<SPIRExpression>(id, to_name(id), type, true);
5165}
5166
5167void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t result_id)
5168{
5169 // If we're declaring temporaries inside continue blocks,
5170 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
5171 if (current_continue_block && !hoisted_temporaries.count(result_id))
5172 {
5173 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5174 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
5175 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
5176 return tmp.first == result_type && tmp.second == result_id;
5177 }) == end(header.declare_temporary))
5178 {
5179 header.declare_temporary.emplace_back(result_type, result_id);
5180 hoisted_temporaries.insert(result_id);
5181 force_recompile();
5182 }
5183 }
5184 else if (hoisted_temporaries.count(result_id) == 0)
5185 {
5186 auto &type = get<SPIRType>(result_type);
5187 auto &flags = ir.meta[result_id].decoration.decoration_flags;
5188
5189 // The result_id has not been made into an expression yet, so use flags interface.
5190 add_local_variable_name(result_id);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01005191
5192 string initializer;
5193 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
5194 initializer = join(" = ", to_zero_initialized_expression(result_type));
5195
5196 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), initializer, ";");
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02005197 }
5198}
5199
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005200string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
5201{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005202 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01005203 auto &flags = ir.meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005204
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005205 // If we're declaring temporaries inside continue blocks,
5206 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
Hans-Kristian Arntzen0fd02812017-11-21 18:19:51 +01005207 if (current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005208 {
5209 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
5210 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005211 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005212 return tmp.first == result_type && tmp.second == result_id;
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01005213 }) == end(header.declare_temporary))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005214 {
5215 header.declare_temporary.emplace_back(result_type, result_id);
Hans-Kristian Arntzen7d223b82018-01-18 12:07:10 +01005216 hoisted_temporaries.insert(result_id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02005217 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005218 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005219
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005220 return join(to_name(result_id), " = ");
5221 }
Hans-Kristian Arntzenb629ca12017-11-21 09:27:49 +01005222 else if (hoisted_temporaries.count(result_id))
5223 {
5224 // The temporary has already been declared earlier, so just "declare" the temporary by writing to it.
5225 return join(to_name(result_id), " = ");
5226 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005227 else
5228 {
5229 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen35f64d02018-03-24 01:53:08 +01005230 add_local_variable_name(result_id);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02005231 return join(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005232 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005233}
5234
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005235bool CompilerGLSL::expression_is_forwarded(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005236{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005237 return forwarded_temporaries.count(id) != 0;
5238}
5239
5240bool CompilerGLSL::expression_suppresses_usage_tracking(uint32_t id) const
5241{
5242 return suppressed_usage_tracking.count(id) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005243}
5244
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02005245bool CompilerGLSL::expression_read_implies_multiple_reads(uint32_t id) const
5246{
5247 auto *expr = maybe_get<SPIRExpression>(id);
5248 if (!expr)
5249 return false;
5250
5251 // If we're emitting code at a deeper loop level than when we emitted the expression,
5252 // we're probably reading the same expression over and over.
5253 return current_loop_level > expr->emitted_loop_level;
5254}
5255
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005256SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005257 bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005258{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005259 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
5260 {
5261 // Just forward it without temporary.
5262 // If the forward is trivial, we do not force flushing to temporary for this expression.
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02005263 forwarded_temporaries.insert(result_id);
5264 if (suppress_usage_tracking)
5265 suppressed_usage_tracking.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005266
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005267 return set<SPIRExpression>(result_id, rhs, result_type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005268 }
5269 else
5270 {
5271 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
5272 statement(declare_temporary(result_type, result_id), rhs, ";");
5273 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
5274 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005275}
5276
5277void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
5278{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005279 bool forward = should_forward(op0);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005280 emit_op(result_type, result_id, join(op, to_enclosed_unpacked_expression(op0)), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005281 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005282}
5283
5284void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
5285{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005286 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02005287 emit_op(result_type, result_id,
5288 join(to_enclosed_unpacked_expression(op0), " ", op, " ", to_enclosed_unpacked_expression(op1)), forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005289
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005290 inherit_expression_dependencies(result_id, op0);
5291 inherit_expression_dependencies(result_id, op1);
5292}
5293
Robert Konradf3a82772017-03-24 15:00:48 +01005294void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
5295{
5296 auto &type = get<SPIRType>(result_type);
5297 auto expr = type_to_glsl_constructor(type);
5298 expr += '(';
5299 for (uint32_t i = 0; i < type.vecsize; i++)
5300 {
5301 // Make sure to call to_expression multiple times to ensure
5302 // that these expressions are properly flushed to temporaries if needed.
5303 expr += op;
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02005304 expr += to_extract_component_expression(operand, i);
Robert Konradf3a82772017-03-24 15:00:48 +01005305
5306 if (i + 1 < type.vecsize)
5307 expr += ", ";
5308 }
5309 expr += ')';
5310 emit_op(result_type, result_id, expr, should_forward(operand));
5311
5312 inherit_expression_dependencies(result_id, operand);
5313}
5314
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005315void 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 +02005316 const char *op, bool negate, SPIRType::BaseType expected_type)
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005317{
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005318 auto &type0 = expression_type(op0);
5319 auto &type1 = expression_type(op1);
5320
5321 SPIRType target_type0 = type0;
5322 SPIRType target_type1 = type1;
5323 target_type0.basetype = expected_type;
5324 target_type1.basetype = expected_type;
5325 target_type0.vecsize = 1;
5326 target_type1.vecsize = 1;
5327
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005328 auto &type = get<SPIRType>(result_type);
5329 auto expr = type_to_glsl_constructor(type);
5330 expr += '(';
5331 for (uint32_t i = 0; i < type.vecsize; i++)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005332 {
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005333 // Make sure to call to_expression multiple times to ensure
5334 // that these expressions are properly flushed to temporaries if needed.
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005335 if (negate)
5336 expr += "!(";
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005337
5338 if (expected_type != SPIRType::Unknown && type0.basetype != expected_type)
5339 expr += bitcast_expression(target_type0, type0.basetype, to_extract_component_expression(op0, i));
5340 else
5341 expr += to_extract_component_expression(op0, i);
5342
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005343 expr += ' ';
5344 expr += op;
5345 expr += ' ';
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005346
5347 if (expected_type != SPIRType::Unknown && type1.basetype != expected_type)
5348 expr += bitcast_expression(target_type1, type1.basetype, to_extract_component_expression(op1, i));
5349 else
5350 expr += to_extract_component_expression(op1, i);
5351
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005352 if (negate)
5353 expr += ")";
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005354
5355 if (i + 1 < type.vecsize)
5356 expr += ", ";
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005357 }
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005358 expr += ')';
5359 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
5360
5361 inherit_expression_dependencies(result_id, op0);
5362 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005363}
5364
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005365SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
5366 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
5367{
5368 auto &type0 = expression_type(op0);
5369 auto &type1 = expression_type(op1);
5370
5371 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
5372 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
5373 // since equality test is exactly the same.
5374 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
5375
5376 // Create a fake type so we can bitcast to it.
5377 // We only deal with regular arithmetic types here like int, uints and so on.
5378 SPIRType expected_type;
5379 expected_type.basetype = input_type;
5380 expected_type.vecsize = type0.vecsize;
5381 expected_type.columns = type0.columns;
5382 expected_type.width = type0.width;
5383
5384 if (cast)
5385 {
5386 cast_op0 = bitcast_glsl(expected_type, op0);
5387 cast_op1 = bitcast_glsl(expected_type, op1);
5388 }
5389 else
5390 {
5391 // 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 +02005392 cast_op0 = to_enclosed_unpacked_expression(op0);
5393 cast_op1 = to_enclosed_unpacked_expression(op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005394 input_type = type0.basetype;
5395 }
5396
5397 return expected_type;
5398}
5399
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02005400bool CompilerGLSL::emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0)
5401{
5402 // Some bitcasts may require complex casting sequences, and are implemented here.
5403 // Otherwise a simply unary function will do with bitcast_glsl_op.
5404
5405 auto &output_type = get<SPIRType>(result_type);
5406 auto &input_type = expression_type(op0);
5407 string expr;
5408
5409 if (output_type.basetype == SPIRType::Half && input_type.basetype == SPIRType::Float && input_type.vecsize == 1)
5410 expr = join("unpackFloat2x16(floatBitsToUint(", to_unpacked_expression(op0), "))");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02005411 else if (output_type.basetype == SPIRType::Float && input_type.basetype == SPIRType::Half &&
5412 input_type.vecsize == 2)
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02005413 expr = join("uintBitsToFloat(packFloat2x16(", to_unpacked_expression(op0), "))");
5414 else
5415 return false;
5416
5417 emit_op(result_type, id, expr, should_forward(op0));
5418 return true;
5419}
5420
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005421void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5422 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
5423{
5424 string cast_op0, cast_op1;
5425 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
5426 auto &out_type = get<SPIRType>(result_type);
5427
5428 // We might have casted away from the result type, so bitcast again.
5429 // For example, arithmetic right shift with uint inputs.
5430 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005431 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005432 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005433 {
5434 expected_type.basetype = input_type;
5435 expr = bitcast_glsl_op(out_type, expected_type);
5436 expr += '(';
5437 expr += join(cast_op0, " ", op, " ", cast_op1);
5438 expr += ')';
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005439 }
5440 else
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005441 expr += join(cast_op0, " ", op, " ", cast_op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005442
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005443 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005444 inherit_expression_dependencies(result_id, op0);
5445 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005446}
5447
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005448void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
5449{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005450 bool forward = should_forward(op0);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005451 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005452 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005453}
5454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005455void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5456 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005457{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005458 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005459 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ")"),
5460 forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005461 inherit_expression_dependencies(result_id, op0);
5462 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005463}
5464
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005465void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op,
5466 SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type)
5467{
5468 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005469 auto &expr_type = expression_type(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005470 auto expected_type = out_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005471
5472 // 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 +01005473 expected_type.basetype = input_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005474 expected_type.width = expr_type.width;
5475 string cast_op = expr_type.basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005476
5477 string expr;
5478 if (out_type.basetype != expected_result_type)
5479 {
5480 expected_type.basetype = expected_result_type;
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005481 expected_type.width = out_type.width;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005482 expr = bitcast_glsl_op(out_type, expected_type);
5483 expr += '(';
5484 expr += join(op, "(", cast_op, ")");
5485 expr += ')';
5486 }
5487 else
5488 {
5489 expr += join(op, "(", cast_op, ")");
5490 }
5491
5492 emit_op(result_type, result_id, expr, should_forward(op0));
5493 inherit_expression_dependencies(result_id, op0);
5494}
5495
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005496// Very special case. Handling bitfieldExtract requires us to deal with different bitcasts of different signs
5497// and different vector sizes all at once. Need a special purpose method here.
5498void CompilerGLSL::emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5499 uint32_t op2, const char *op,
5500 SPIRType::BaseType expected_result_type,
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02005501 SPIRType::BaseType input_type0, SPIRType::BaseType input_type1,
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005502 SPIRType::BaseType input_type2)
5503{
5504 auto &out_type = get<SPIRType>(result_type);
5505 auto expected_type = out_type;
5506 expected_type.basetype = input_type0;
5507
5508 string cast_op0 =
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02005509 expression_type(op0).basetype != input_type0 ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005510
5511 auto op1_expr = to_unpacked_expression(op1);
5512 auto op2_expr = to_unpacked_expression(op2);
5513
5514 // Use value casts here instead. Input must be exactly int or uint, but SPIR-V might be 16-bit.
5515 expected_type.basetype = input_type1;
5516 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02005517 string cast_op1 = expression_type(op1).basetype != input_type1 ?
5518 join(type_to_glsl_constructor(expected_type), "(", op1_expr, ")") :
5519 op1_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005520
5521 expected_type.basetype = input_type2;
5522 expected_type.vecsize = 1;
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02005523 string cast_op2 = expression_type(op2).basetype != input_type2 ?
5524 join(type_to_glsl_constructor(expected_type), "(", op2_expr, ")") :
5525 op2_expr;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005526
5527 string expr;
5528 if (out_type.basetype != expected_result_type)
5529 {
5530 expected_type.vecsize = out_type.vecsize;
5531 expected_type.basetype = expected_result_type;
5532 expr = bitcast_glsl_op(out_type, expected_type);
5533 expr += '(';
5534 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
5535 expr += ')';
5536 }
5537 else
5538 {
5539 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
5540 }
5541
5542 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
5543 inherit_expression_dependencies(result_id, op0);
5544 inherit_expression_dependencies(result_id, op1);
5545 inherit_expression_dependencies(result_id, op2);
5546}
5547
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02005548void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5549 uint32_t op2, const char *op, SPIRType::BaseType input_type)
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005550{
5551 auto &out_type = get<SPIRType>(result_type);
5552 auto expected_type = out_type;
5553 expected_type.basetype = input_type;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02005554 string cast_op0 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005555 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02005556 string cast_op1 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005557 expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_unpacked_expression(op1);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02005558 string cast_op2 =
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02005559 expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_unpacked_expression(op2);
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005560
5561 string expr;
5562 if (out_type.basetype != input_type)
5563 {
5564 expr = bitcast_glsl_op(out_type, expected_type);
5565 expr += '(';
5566 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
5567 expr += ')';
5568 }
5569 else
5570 {
5571 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
5572 }
5573
5574 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
5575 inherit_expression_dependencies(result_id, op0);
5576 inherit_expression_dependencies(result_id, op1);
5577 inherit_expression_dependencies(result_id, op2);
5578}
5579
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01005580void CompilerGLSL::emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0,
5581 uint32_t op1, const char *op, SPIRType::BaseType input_type)
5582{
5583 // Special purpose method for implementing clustered subgroup opcodes.
5584 // Main difference is that op1 does not participate in any casting, it needs to be a literal.
5585 auto &out_type = get<SPIRType>(result_type);
5586 auto expected_type = out_type;
5587 expected_type.basetype = input_type;
5588 string cast_op0 =
5589 expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0);
5590
5591 string expr;
5592 if (out_type.basetype != input_type)
5593 {
5594 expr = bitcast_glsl_op(out_type, expected_type);
5595 expr += '(';
5596 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
5597 expr += ')';
5598 }
5599 else
5600 {
5601 expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")");
5602 }
5603
5604 emit_op(result_type, result_id, expr, should_forward(op0));
5605 inherit_expression_dependencies(result_id, op0);
5606}
5607
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005608void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5609 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
5610{
5611 string cast_op0, cast_op1;
5612 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
5613 auto &out_type = get<SPIRType>(result_type);
5614
5615 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
5616 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02005617 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005618 {
5619 expected_type.basetype = input_type;
5620 expr = bitcast_glsl_op(out_type, expected_type);
5621 expr += '(';
5622 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
5623 expr += ')';
5624 }
5625 else
5626 {
5627 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
5628 }
5629
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005630 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005631 inherit_expression_dependencies(result_id, op0);
5632 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005633}
5634
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005635void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5636 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005637{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005638 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005639 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005640 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
5641 to_unpacked_expression(op2), ")"),
5642 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005643
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005644 inherit_expression_dependencies(result_id, op0);
5645 inherit_expression_dependencies(result_id, op1);
5646 inherit_expression_dependencies(result_id, op2);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005647}
5648
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005649void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5650 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005651{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005652 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01005653 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02005654 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
5655 to_unpacked_expression(op2), ", ", to_unpacked_expression(op3), ")"),
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005656 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005657
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005658 inherit_expression_dependencies(result_id, op0);
5659 inherit_expression_dependencies(result_id, op1);
5660 inherit_expression_dependencies(result_id, op2);
5661 inherit_expression_dependencies(result_id, op3);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005662}
5663
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005664void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
5665 uint32_t op2, uint32_t op3, const char *op,
5666 SPIRType::BaseType offset_count_type)
5667{
5668 // Only need to cast offset/count arguments. Types of base/insert must be same as result type,
5669 // and bitfieldInsert is sign invariant.
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02005670 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005671
5672 auto op0_expr = to_unpacked_expression(op0);
5673 auto op1_expr = to_unpacked_expression(op1);
5674 auto op2_expr = to_unpacked_expression(op2);
5675 auto op3_expr = to_unpacked_expression(op3);
5676
5677 SPIRType target_type;
5678 target_type.vecsize = 1;
5679 target_type.basetype = offset_count_type;
5680
5681 if (expression_type(op2).basetype != offset_count_type)
5682 {
5683 // Value-cast here. Input might be 16-bit. GLSL requires int.
5684 op2_expr = join(type_to_glsl_constructor(target_type), "(", op2_expr, ")");
5685 }
5686
5687 if (expression_type(op3).basetype != offset_count_type)
5688 {
5689 // Value-cast here. Input might be 16-bit. GLSL requires int.
5690 op3_expr = join(type_to_glsl_constructor(target_type), "(", op3_expr, ")");
5691 }
5692
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +02005693 emit_op(result_type, result_id, join(op, "(", op0_expr, ", ", op1_expr, ", ", op2_expr, ", ", op3_expr, ")"),
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005694 forward);
5695
5696 inherit_expression_dependencies(result_id, op0);
5697 inherit_expression_dependencies(result_id, op1);
5698 inherit_expression_dependencies(result_id, op2);
5699 inherit_expression_dependencies(result_id, op3);
5700}
5701
rdbb3bd6742020-11-07 12:43:53 +01005702string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t tex)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005703{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005704 const char *type;
5705 switch (imgtype.image.dim)
5706 {
5707 case spv::Dim1D:
Rob Fischer21990632016-09-17 17:01:50 +09005708 type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005709 break;
5710 case spv::Dim2D:
Rob Fischer21990632016-09-17 17:01:50 +09005711 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005712 break;
5713 case spv::Dim3D:
5714 type = "3D";
5715 break;
5716 case spv::DimCube:
5717 type = "Cube";
5718 break;
Sidney Justfbb4df32019-01-06 12:21:59 -08005719 case spv::DimRect:
5720 type = "2DRect";
5721 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005722 case spv::DimBuffer:
5723 type = "Buffer";
5724 break;
5725 case spv::DimSubpassData:
5726 type = "2D";
5727 break;
5728 default:
5729 type = "";
5730 break;
5731 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005732
rdbe8c500c2020-11-05 22:55:44 +01005733 // In legacy GLSL, an extension is required for textureLod in the fragment
5734 // shader or textureGrad anywhere.
5735 bool legacy_lod_ext = false;
5736 auto &execution = get_entry_point();
5737 if (op == "textureGrad" || op == "textureProjGrad" ||
5738 ((op == "textureLod" || op == "textureProjLod") && execution.model != ExecutionModelVertex))
Lubos Lenco0028b4f2016-11-21 22:37:20 +01005739 {
Robert Konradedfc2972017-03-23 13:25:24 +01005740 if (is_legacy_es())
5741 {
rdbe8c500c2020-11-05 22:55:44 +01005742 legacy_lod_ext = true;
5743 require_extension_internal("GL_EXT_shader_texture_lod");
Robert Konradedfc2972017-03-23 13:25:24 +01005744 }
rdbe8c500c2020-11-05 22:55:44 +01005745 else if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005746 require_extension_internal("GL_ARB_shader_texture_lod");
Lubos Lenco0028b4f2016-11-21 22:37:20 +01005747 }
Lubos Lenco52158642016-09-17 15:56:23 +02005748
Sidney Just5ac55ee2018-06-25 02:11:46 -07005749 if (op == "textureLodOffset" || op == "textureProjLodOffset")
5750 {
5751 if (is_legacy_es())
5752 SPIRV_CROSS_THROW(join(op, " not allowed in legacy ES"));
5753
5754 require_extension_internal("GL_EXT_gpu_shader4");
5755 }
5756
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02005757 // GLES has very limited support for shadow samplers.
Sidney Just5ac55ee2018-06-25 02:11:46 -07005758 // Basically shadow2D and shadow2DProj work through EXT_shadow_samplers,
5759 // everything else can just throw
rdb10fa5f62020-11-09 15:26:46 +01005760 bool is_comparison = image_is_comparison(imgtype, tex);
5761 if (is_comparison && is_legacy_es())
Sidney Just5ac55ee2018-06-25 02:11:46 -07005762 {
5763 if (op == "texture" || op == "textureProj")
5764 require_extension_internal("GL_EXT_shadow_samplers");
5765 else
5766 SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
5767 }
5768
rdb10fa5f62020-11-09 15:26:46 +01005769 if (op == "textureSize")
5770 {
5771 if (is_legacy_es())
5772 SPIRV_CROSS_THROW("textureSize not supported in legacy ES");
5773 if (is_comparison)
5774 SPIRV_CROSS_THROW("textureSize not supported on shadow sampler in legacy GLSL");
5775 require_extension_internal("GL_EXT_gpu_shader4");
5776 }
5777
5778 if (op == "texelFetch" && is_legacy_es())
5779 SPIRV_CROSS_THROW("texelFetch not supported in legacy ES");
5780
5781 bool is_es_and_depth = is_legacy_es() && is_comparison;
5782 std::string type_prefix = is_comparison ? "shadow" : "texture";
Sidney Just0f62b5d2018-06-22 01:40:01 -07005783
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005784 if (op == "texture")
Sidney Just5ac55ee2018-06-25 02:11:46 -07005785 return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
Robert Konradedfc2972017-03-23 13:25:24 +01005786 else if (op == "textureLod")
rdbe8c500c2020-11-05 22:55:44 +01005787 return join(type_prefix, type, legacy_lod_ext ? "LodEXT" : "Lod");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005788 else if (op == "textureProj")
Sidney Just5ac55ee2018-06-25 02:11:46 -07005789 return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
Sidney Juste66fd6c2018-03-12 00:59:06 +10005790 else if (op == "textureGrad")
Sidney Just0f62b5d2018-06-22 01:40:01 -07005791 return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005792 else if (op == "textureProjLod")
rdbe8c500c2020-11-05 22:55:44 +01005793 return join(type_prefix, type, legacy_lod_ext ? "ProjLodEXT" : "ProjLod");
Sidney Just0f62b5d2018-06-22 01:40:01 -07005794 else if (op == "textureLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01005795 return join(type_prefix, type, "LodOffset");
Sidney Just0f62b5d2018-06-22 01:40:01 -07005796 else if (op == "textureProjGrad")
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02005797 return join(type_prefix, type,
5798 is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
Sidney Just0f62b5d2018-06-22 01:40:01 -07005799 else if (op == "textureProjLodOffset")
rdbe8c500c2020-11-05 22:55:44 +01005800 return join(type_prefix, type, "ProjLodOffset");
rdb10fa5f62020-11-09 15:26:46 +01005801 else if (op == "textureSize")
5802 return join("textureSize", type);
5803 else if (op == "texelFetch")
5804 return join("texelFetch", type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005805 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005806 {
5807 SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
5808 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005809}
5810
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005811bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
5812{
5813 auto *cleft = maybe_get<SPIRConstant>(left);
5814 auto *cright = maybe_get<SPIRConstant>(right);
5815 auto &lerptype = expression_type(lerp);
5816
5817 // If our targets aren't constants, we cannot use construction.
5818 if (!cleft || !cright)
5819 return false;
5820
5821 // If our targets are spec constants, we cannot use construction.
5822 if (cleft->specialization || cright->specialization)
5823 return false;
5824
5825 // We can only use trivial construction if we have a scalar
5826 // (should be possible to do it for vectors as well, but that is overkill for now).
5827 if (lerptype.basetype != SPIRType::Boolean || lerptype.vecsize > 1)
5828 return false;
5829
5830 // If our bool selects between 0 and 1, we can cast from bool instead, making our trivial constructor.
5831 bool ret = false;
5832 switch (type.basetype)
5833 {
Chip Davis117ccf42018-11-01 17:20:07 -05005834 case SPIRType::Short:
5835 case SPIRType::UShort:
5836 ret = cleft->scalar_u16() == 0 && cright->scalar_u16() == 1;
5837 break;
5838
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005839 case SPIRType::Int:
5840 case SPIRType::UInt:
5841 ret = cleft->scalar() == 0 && cright->scalar() == 1;
5842 break;
5843
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01005844 case SPIRType::Half:
5845 ret = cleft->scalar_f16() == 0.0f && cright->scalar_f16() == 1.0f;
5846 break;
5847
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005848 case SPIRType::Float:
5849 ret = cleft->scalar_f32() == 0.0f && cright->scalar_f32() == 1.0f;
5850 break;
5851
5852 case SPIRType::Double:
5853 ret = cleft->scalar_f64() == 0.0 && cright->scalar_f64() == 1.0;
5854 break;
5855
5856 case SPIRType::Int64:
5857 case SPIRType::UInt64:
5858 ret = cleft->scalar_u64() == 0 && cright->scalar_u64() == 1;
5859 break;
5860
5861 default:
5862 break;
5863 }
5864
5865 if (ret)
5866 op = type_to_glsl_constructor(type);
5867 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005868}
5869
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005870string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
5871 uint32_t false_value)
5872{
5873 string expr;
5874 auto &lerptype = expression_type(select);
5875
5876 if (lerptype.vecsize == 1)
Chip Davis3bfb2f92018-12-03 02:06:33 -06005877 expr = join(to_enclosed_expression(select), " ? ", to_enclosed_pointer_expression(true_value), " : ",
5878 to_enclosed_pointer_expression(false_value));
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005879 else
5880 {
5881 auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
5882
5883 expr = type_to_glsl_constructor(restype);
5884 expr += "(";
5885 for (uint32_t i = 0; i < restype.vecsize; i++)
5886 {
5887 expr += swiz(select, i);
5888 expr += " ? ";
5889 expr += swiz(true_value, i);
5890 expr += " : ";
5891 expr += swiz(false_value, i);
5892 if (i + 1 < restype.vecsize)
5893 expr += ", ";
5894 }
5895 expr += ")";
5896 }
5897
5898 return expr;
5899}
5900
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005901void 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 +01005902{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005903 auto &lerptype = expression_type(lerp);
5904 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005905
Chip Davis3bfb2f92018-12-03 02:06:33 -06005906 // If this results in a variable pointer, assume it may be written through.
5907 if (restype.pointer)
5908 {
5909 register_write(left);
5910 register_write(right);
5911 }
5912
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005913 string mix_op;
Chip Davis6628ea62019-07-10 23:46:40 -05005914 bool has_boolean_mix = *backend.boolean_mix_function &&
Hans-Kristian Arntzen851acf32017-05-04 10:28:30 +02005915 ((options.es && options.version >= 310) || (!options.es && options.version >= 450));
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005916 bool trivial_mix = to_trivial_mix_op(restype, mix_op, left, right, lerp);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005917
Hans-Kristian Arntzen0e7c33f2017-02-11 10:52:34 +01005918 // Cannot use boolean mix when the lerp argument is just one boolean,
5919 // fall back to regular trinary statements.
5920 if (lerptype.vecsize == 1)
5921 has_boolean_mix = false;
5922
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005923 // If we can reduce the mix to a simple cast, do so.
5924 // This helps for cases like int(bool), uint(bool) which is implemented with
5925 // OpSelect bool 1 0.
5926 if (trivial_mix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005927 {
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005928 emit_unary_func_op(result_type, id, lerp, mix_op.c_str());
5929 }
5930 else if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
5931 {
5932 // Boolean mix not supported on desktop without extension.
5933 // Was added in OpenGL 4.5 with ES 3.1 compat.
5934 //
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005935 // Could use GL_EXT_shader_integer_mix on desktop at least,
5936 // but Apple doesn't support it. :(
5937 // Just implement it as ternary expressions.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02005938 auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005939 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005940 inherit_expression_dependencies(id, left);
5941 inherit_expression_dependencies(id, right);
5942 inherit_expression_dependencies(id, lerp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005943 }
Chip Davis6628ea62019-07-10 23:46:40 -05005944 else if (lerptype.basetype == SPIRType::Boolean)
5945 emit_trinary_func_op(result_type, id, left, right, lerp, backend.boolean_mix_function);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005946 else
5947 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005948}
5949
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005950string CompilerGLSL::to_combined_image_sampler(VariableID image_id, VariableID samp_id)
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005951{
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02005952 // Keep track of the array indices we have used to load the image.
5953 // We'll need to use the same array index into the combined image sampler array.
5954 auto image_expr = to_expression(image_id);
5955 string array_expr;
5956 auto array_index = image_expr.find_first_of('[');
5957 if (array_index != string::npos)
5958 array_expr = image_expr.substr(array_index, string::npos);
5959
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005960 auto &args = current_function->arguments;
5961
5962 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
5963 // all possible combinations into new sampler2D uniforms.
5964 auto *image = maybe_get_backing_variable(image_id);
5965 auto *samp = maybe_get_backing_variable(samp_id);
5966 if (image)
5967 image_id = image->self;
5968 if (samp)
5969 samp_id = samp->self;
5970
5971 auto image_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005972 [image_id](const SPIRFunction::Parameter &param) { return image_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005973
5974 auto sampler_itr = find_if(begin(args), end(args),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005975 [samp_id](const SPIRFunction::Parameter &param) { return samp_id == param.id; });
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005976
5977 if (image_itr != end(args) || sampler_itr != end(args))
5978 {
5979 // If any parameter originates from a parameter, we will find it in our argument list.
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02005980 bool global_image = image_itr == end(args);
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005981 bool global_sampler = sampler_itr == end(args);
Hans-Kristian Arntzenc3ff67c2019-09-17 10:16:47 +02005982 VariableID iid = global_image ? image_id : VariableID(uint32_t(image_itr - begin(args)));
5983 VariableID sid = global_sampler ? samp_id : VariableID(uint32_t(sampler_itr - begin(args)));
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005984
5985 auto &combined = current_function->combined_parameters;
5986 auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02005987 return p.global_image == global_image && p.global_sampler == global_sampler && p.image_id == iid &&
5988 p.sampler_id == sid;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005989 });
5990
5991 if (itr != end(combined))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02005992 return to_expression(itr->id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005993 else
5994 {
crissdb52e272020-10-08 12:14:52 +02005995 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler parameter, was "
5996 "build_combined_image_samplers() used "
5997 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02005998 }
5999 }
6000 else
6001 {
6002 // For global sampler2D, look directly at the global remapping table.
6003 auto &mapping = combined_image_samplers;
6004 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
6005 return combined.image_id == image_id && combined.sampler_id == samp_id;
6006 });
6007
6008 if (itr != end(combined_image_samplers))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02006009 return to_expression(itr->combined_id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006010 else
6011 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006012 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
6013 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02006014 }
6015 }
6016}
6017
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02006018bool CompilerGLSL::is_supported_subgroup_op_in_opengl(spv::Op op)
crissdb52e272020-10-08 12:14:52 +02006019{
6020 switch (op)
6021 {
6022 case OpGroupNonUniformElect:
6023 case OpGroupNonUniformBallot:
6024 case OpGroupNonUniformBallotFindLSB:
6025 case OpGroupNonUniformBallotFindMSB:
6026 case OpGroupNonUniformBroadcast:
6027 case OpGroupNonUniformBroadcastFirst:
6028 case OpGroupNonUniformAll:
6029 case OpGroupNonUniformAny:
6030 case OpGroupNonUniformAllEqual:
6031 case OpControlBarrier:
6032 case OpMemoryBarrier:
6033 case OpGroupNonUniformBallotBitCount:
6034 case OpGroupNonUniformBallotBitExtract:
6035 case OpGroupNonUniformInverseBallot:
6036 return true;
6037 default:
6038 return false;
6039 }
6040}
6041
Bill Hollings5aafb282016-04-23 21:47:41 -04006042void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
6043{
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006044 if (options.vulkan_semantics && combined_image_samplers.empty())
6045 {
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006046 emit_binary_func_op(result_type, result_id, image_id, samp_id,
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02006047 type_to_glsl(get<SPIRType>(result_type), result_id).c_str());
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02006048 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02006049 else
Hans-Kristian Arntzen02808002018-04-27 09:34:13 +02006050 {
6051 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
6052 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true);
6053 }
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02006054
6055 // Make sure to suppress usage tracking and any expression invalidation.
6056 // It is illegal to create temporaries of opaque types.
6057 forwarded_temporaries.erase(result_id);
Bill Hollings5aafb282016-04-23 21:47:41 -04006058}
6059
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006060static inline bool image_opcode_is_sample_no_dref(Op op)
6061{
6062 switch (op)
6063 {
6064 case OpImageSampleExplicitLod:
6065 case OpImageSampleImplicitLod:
6066 case OpImageSampleProjExplicitLod:
6067 case OpImageSampleProjImplicitLod:
6068 case OpImageFetch:
6069 case OpImageRead:
6070 case OpImageSparseSampleExplicitLod:
6071 case OpImageSparseSampleImplicitLod:
6072 case OpImageSparseSampleProjExplicitLod:
6073 case OpImageSparseSampleProjImplicitLod:
6074 case OpImageSparseFetch:
6075 case OpImageSparseRead:
6076 return true;
6077
6078 default:
6079 return false;
6080 }
6081}
6082
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006083void CompilerGLSL::emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id, uint32_t &feedback_id,
6084 uint32_t &texel_id)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006085{
6086 // Need to allocate two temporaries.
6087 if (options.es)
6088 SPIRV_CROSS_THROW("Sparse texture feedback is not supported on ESSL.");
6089 require_extension_internal("GL_ARB_sparse_texture2");
6090
6091 auto &temps = extra_sub_expressions[id];
6092 if (temps == 0)
6093 temps = ir.increase_bound_by(2);
6094
6095 feedback_id = temps + 0;
6096 texel_id = temps + 1;
6097
6098 auto &return_type = get<SPIRType>(result_type_id);
6099 if (return_type.basetype != SPIRType::Struct || return_type.member_types.size() != 2)
6100 SPIRV_CROSS_THROW("Invalid return type for sparse feedback.");
6101 emit_uninitialized_temporary(return_type.member_types[0], feedback_id);
6102 emit_uninitialized_temporary(return_type.member_types[1], texel_id);
6103}
6104
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006105uint32_t CompilerGLSL::get_sparse_feedback_texel_id(uint32_t id) const
6106{
6107 auto itr = extra_sub_expressions.find(id);
6108 if (itr == extra_sub_expressions.end())
6109 return 0;
6110 else
6111 return itr->second + 1;
6112}
6113
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006114void CompilerGLSL::emit_texture_op(const Instruction &i, bool sparse)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006115{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02006116 auto *ops = stream(i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006117 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006118
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006119 SmallVector<uint32_t> inherited_expressions;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006120
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006121 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006122 uint32_t id = ops[1];
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006123 auto &return_type = get<SPIRType>(result_type_id);
6124
6125 uint32_t sparse_code_id = 0;
6126 uint32_t sparse_texel_id = 0;
6127 if (sparse)
6128 emit_sparse_feedback_temporaries(result_type_id, id, sparse_code_id, sparse_texel_id);
Chip Davis39dce882019-08-02 15:11:19 -05006129
6130 bool forward = false;
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006131 string expr = to_texture_op(i, sparse, &forward, inherited_expressions);
6132
6133 if (sparse)
6134 {
6135 statement(to_expression(sparse_code_id), " = ", expr, ";");
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006136 expr = join(type_to_glsl(return_type), "(", to_expression(sparse_code_id), ", ", to_expression(sparse_texel_id),
6137 ")");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006138 forward = true;
6139 inherited_expressions.clear();
6140 }
6141
Chip Davis39dce882019-08-02 15:11:19 -05006142 emit_op(result_type_id, id, expr, forward);
6143 for (auto &inherit : inherited_expressions)
6144 inherit_expression_dependencies(id, inherit);
6145
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006146 // Do not register sparse ops as control dependent as they are always lowered to a temporary.
Chip Davis39dce882019-08-02 15:11:19 -05006147 switch (op)
6148 {
6149 case OpImageSampleDrefImplicitLod:
6150 case OpImageSampleImplicitLod:
6151 case OpImageSampleProjImplicitLod:
6152 case OpImageSampleProjDrefImplicitLod:
6153 register_control_dependent_expression(id);
6154 break;
6155
6156 default:
6157 break;
6158 }
6159}
6160
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006161std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool *forward,
Chip Davis39dce882019-08-02 15:11:19 -05006162 SmallVector<uint32_t> &inherited_expressions)
6163{
6164 auto *ops = stream(i);
6165 auto op = static_cast<Op>(i.op);
6166 uint32_t length = i.length;
6167
6168 uint32_t result_type_id = ops[0];
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006169 VariableID img = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006170 uint32_t coord = ops[3];
6171 uint32_t dref = 0;
6172 uint32_t comp = 0;
6173 bool gather = false;
6174 bool proj = false;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006175 bool fetch = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006176 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006177
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006178 auto &result_type = get<SPIRType>(result_type_id);
6179
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006180 inherited_expressions.push_back(coord);
6181
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02006182 // Make sure non-uniform decoration is back-propagated to where it needs to be.
6183 if (has_decoration(img, DecorationNonUniformEXT))
6184 propagate_nonuniform_qualifier(img);
6185
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006186 switch (op)
6187 {
6188 case OpImageSampleDrefImplicitLod:
6189 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006190 case OpImageSparseSampleDrefImplicitLod:
6191 case OpImageSparseSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006192 dref = ops[4];
6193 opt = &ops[5];
6194 length -= 5;
6195 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006196
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006197 case OpImageSampleProjDrefImplicitLod:
6198 case OpImageSampleProjDrefExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006199 case OpImageSparseSampleProjDrefImplicitLod:
6200 case OpImageSparseSampleProjDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006201 dref = ops[4];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006202 opt = &ops[5];
6203 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006204 proj = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006205 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006207 case OpImageDrefGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006208 case OpImageSparseDrefGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006209 dref = ops[4];
6210 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006211 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006212 gather = true;
rdb509908d2020-11-07 00:01:57 +01006213 if (options.es && options.version < 310)
6214 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6215 else if (!options.es && options.version < 400)
6216 SPIRV_CROSS_THROW("textureGather with depth compare requires GLSL 400.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006217 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006218
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006219 case OpImageGather:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006220 case OpImageSparseGather:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006221 comp = ops[4];
6222 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006223 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006224 gather = true;
rdb509908d2020-11-07 00:01:57 +01006225 if (options.es && options.version < 310)
6226 SPIRV_CROSS_THROW("textureGather requires ESSL 310.");
6227 else if (!options.es && options.version < 400)
6228 {
6229 if (!expression_is_constant_null(comp))
6230 SPIRV_CROSS_THROW("textureGather with component requires GLSL 400.");
6231 require_extension_internal("GL_ARB_texture_gather");
6232 }
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006233 break;
6234
6235 case OpImageFetch:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006236 case OpImageSparseFetch:
Bill Hollings8f6df772017-05-19 18:14:08 -04006237 case OpImageRead: // Reads == fetches in Metal (other langs will not get here)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006238 opt = &ops[4];
6239 length -= 4;
6240 fetch = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006241 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006242
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006243 case OpImageSampleProjImplicitLod:
6244 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006245 case OpImageSparseSampleProjImplicitLod:
6246 case OpImageSparseSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006247 opt = &ops[4];
6248 length -= 4;
6249 proj = true;
6250 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006252 default:
6253 opt = &ops[4];
6254 length -= 4;
6255 break;
6256 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006257
Bill Hollings8f6df772017-05-19 18:14:08 -04006258 // Bypass pointers because we need the real image struct
6259 auto &type = expression_type(img);
6260 auto &imgtype = get<SPIRType>(type.self);
6261
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006262 uint32_t coord_components = 0;
6263 switch (imgtype.image.dim)
6264 {
6265 case spv::Dim1D:
6266 coord_components = 1;
6267 break;
6268 case spv::Dim2D:
6269 coord_components = 2;
6270 break;
6271 case spv::Dim3D:
6272 coord_components = 3;
6273 break;
6274 case spv::DimCube:
6275 coord_components = 3;
6276 break;
6277 case spv::DimBuffer:
6278 coord_components = 1;
6279 break;
6280 default:
6281 coord_components = 2;
6282 break;
6283 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006284
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006285 if (dref)
6286 inherited_expressions.push_back(dref);
6287
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006288 if (proj)
6289 coord_components++;
6290 if (imgtype.image.arrayed)
6291 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006292
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006293 uint32_t bias = 0;
6294 uint32_t lod = 0;
6295 uint32_t grad_x = 0;
6296 uint32_t grad_y = 0;
6297 uint32_t coffset = 0;
6298 uint32_t offset = 0;
6299 uint32_t coffsets = 0;
6300 uint32_t sample = 0;
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006301 uint32_t minlod = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006302 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006303
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006304 if (length)
6305 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006306 flags = *opt++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006307 length--;
6308 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006309
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02006310 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006311 if (length && (flags & flag))
6312 {
6313 v = *opt++;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01006314 inherited_expressions.push_back(v);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006315 length--;
6316 }
6317 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006318
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006319 test(bias, ImageOperandsBiasMask);
6320 test(lod, ImageOperandsLodMask);
6321 test(grad_x, ImageOperandsGradMask);
6322 test(grad_y, ImageOperandsGradMask);
6323 test(coffset, ImageOperandsConstOffsetMask);
6324 test(offset, ImageOperandsOffsetMask);
6325 test(coffsets, ImageOperandsConstOffsetsMask);
6326 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006327 test(minlod, ImageOperandsMinLodMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006328
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006329 TextureFunctionBaseArguments base_args = {};
6330 base_args.img = img;
6331 base_args.imgtype = &imgtype;
6332 base_args.is_fetch = fetch != 0;
6333 base_args.is_gather = gather != 0;
6334 base_args.is_proj = proj != 0;
6335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006336 string expr;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006337 TextureFunctionNameArguments name_args = {};
6338
6339 name_args.base = base_args;
6340 name_args.has_array_offsets = coffsets != 0;
6341 name_args.has_offset = coffset != 0 || offset != 0;
6342 name_args.has_grad = grad_x != 0 || grad_y != 0;
6343 name_args.has_dref = dref != 0;
6344 name_args.is_sparse_feedback = sparse;
6345 name_args.has_min_lod = minlod != 0;
6346 name_args.lod = lod;
6347 expr += to_function_name(name_args);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006348 expr += "(";
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006349
6350 uint32_t sparse_texel_id = 0;
6351 if (sparse)
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006352 sparse_texel_id = get_sparse_feedback_texel_id(ops[1]);
6353
6354 TextureFunctionArguments args = {};
6355 args.base = base_args;
6356 args.coord = coord;
6357 args.coord_components = coord_components;
6358 args.dref = dref;
6359 args.grad_x = grad_x;
6360 args.grad_y = grad_y;
6361 args.lod = lod;
6362 args.coffset = coffset;
6363 args.offset = offset;
6364 args.bias = bias;
6365 args.component = comp;
6366 args.sample = sample;
6367 args.sparse_texel = sparse_texel_id;
6368 args.min_lod = minlod;
6369 expr += to_function_args(args, forward);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006370 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006371
Sidney Justf6dad782018-06-22 00:28:40 -07006372 // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02006373 if (is_legacy() && image_is_comparison(imgtype, img))
Sidney Justf6dad782018-06-22 00:28:40 -07006374 expr += ".r";
6375
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006376 // Sampling from a texture which was deduced to be a depth image, might actually return 1 component here.
6377 // Remap back to 4 components as sampling opcodes expect.
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006378 if (backend.comparison_image_samples_scalar && image_opcode_is_sample_no_dref(op))
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006379 {
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006380 bool image_is_depth = false;
6381 const auto *combined = maybe_get<SPIRCombinedImageSampler>(img);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02006382 VariableID image_id = combined ? combined->image : img;
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02006383
6384 if (combined && image_is_comparison(imgtype, combined->image))
6385 image_is_depth = true;
6386 else if (image_is_comparison(imgtype, img))
6387 image_is_depth = true;
6388
6389 // We must also check the backing variable for the image.
6390 // We might have loaded an OpImage, and used that handle for two different purposes.
6391 // Once with comparison, once without.
6392 auto *image_variable = maybe_get_backing_variable(image_id);
6393 if (image_variable && image_is_comparison(get<SPIRType>(image_variable->basetype), image_variable->self))
6394 image_is_depth = true;
6395
6396 if (image_is_depth)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006397 expr = remap_swizzle(result_type, 1, expr);
6398 }
6399
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006400 if (!sparse && !backend.support_small_type_sampling_result && result_type.width < 32)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006401 {
6402 // Just value cast (narrowing) to expected type since we cannot rely on narrowing to work automatically.
6403 // Hopefully compiler picks this up and converts the texturing instruction to the appropriate precision.
6404 expr = join(type_to_glsl_constructor(result_type), "(", expr, ")");
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01006405 }
6406
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01006407 // Deals with reads from MSL. We might need to downconvert to fewer components.
6408 if (op == OpImageRead)
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +02006409 expr = remap_swizzle(result_type, 4, expr);
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01006410
Chip Davis39dce882019-08-02 15:11:19 -05006411 return expr;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006412}
6413
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006414bool CompilerGLSL::expression_is_constant_null(uint32_t id) const
6415{
6416 auto *c = maybe_get<SPIRConstant>(id);
6417 if (!c)
6418 return false;
6419 return c->constant_is_null();
6420}
6421
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02006422bool CompilerGLSL::expression_is_non_value_type_array(uint32_t ptr)
6423{
6424 auto &type = expression_type(ptr);
6425 if (type.array.empty())
6426 return false;
6427
6428 if (!backend.array_is_value_type)
6429 return true;
6430
6431 auto *var = maybe_get_backing_variable(ptr);
6432 if (!var)
6433 return false;
6434
6435 auto &backed_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006436 return !backend.buffer_offset_array_is_value_type && backed_type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02006437 has_member_decoration(backed_type.self, 0, DecorationOffset);
6438}
6439
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006440// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
6441// For some subclasses, the function is a method on the specified image.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006442string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006443{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006444 if (args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006445 {
6446 if (options.es)
6447 SPIRV_CROSS_THROW("Sparse residency is not supported in ESSL.");
6448 require_extension_internal("GL_ARB_sparse_texture_clamp");
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006449 }
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02006450
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006451 string fname;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006452 auto &imgtype = *args.base.imgtype;
6453 VariableID tex = args.base.img;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006454
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006455 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006456 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
6457 // 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 +02006458 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006459 bool workaround_lod_array_shadow_as_grad = false;
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006460 if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006461 image_is_comparison(imgtype, tex) && args.lod)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006462 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006463 if (!expression_is_constant_null(args.lod))
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006464 {
crissdb52e272020-10-08 12:14:52 +02006465 SPIRV_CROSS_THROW("textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be "
6466 "expressed in GLSL.");
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01006467 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006468 workaround_lod_array_shadow_as_grad = true;
6469 }
6470
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006471 if (args.is_sparse_feedback)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006472 fname += "sparse";
6473
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006474 if (args.base.is_fetch)
6475 fname += args.is_sparse_feedback ? "TexelFetch" : "texelFetch";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006476 else
6477 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006478 fname += args.is_sparse_feedback ? "Texture" : "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006479
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006480 if (args.base.is_gather)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006481 fname += "Gather";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006482 if (args.has_array_offsets)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006483 fname += "Offsets";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006484 if (args.base.is_proj)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006485 fname += "Proj";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006486 if (args.has_grad || workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006487 fname += "Grad";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006488 if (args.lod != 0 && !workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006489 fname += "Lod";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006490 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006491
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006492 if (args.has_offset)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006493 fname += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006494
Hans-Kristian Arntzenf383cc92020-06-08 13:39:02 +02006495 if (args.has_min_lod)
6496 fname += "Clamp";
6497
6498 if (args.is_sparse_feedback || args.has_min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006499 fname += "ARB";
6500
rdb509908d2020-11-07 00:01:57 +01006501 return (is_legacy() && !args.base.is_gather) ? legacy_tex_op(fname, imgtype, tex) : fname;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006502}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006503
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02006504std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id)
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006505{
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006506 auto *var = maybe_get_backing_variable(id);
6507
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02006508 // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler in GLSL.
6509 // In Vulkan GLSL, we can make use of the newer GL_EXT_samplerless_texture_functions.
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006510 if (var)
6511 {
6512 auto &type = get<SPIRType>(var->basetype);
6513 if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer)
6514 {
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006515 if (options.vulkan_semantics)
6516 {
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02006517 if (dummy_sampler_id)
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02006518 {
6519 // Don't need to consider Shadow state since the dummy sampler is always non-shadow.
6520 auto sampled_type = type;
6521 sampled_type.basetype = SPIRType::SampledImage;
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02006522 return join(type_to_glsl(sampled_type), "(", to_expression(id), ", ",
6523 to_expression(dummy_sampler_id), ")");
Hans-Kristian Arntzen12ca9d12019-07-25 11:07:14 +02006524 }
6525 else
6526 {
6527 // Newer glslang supports this extension to deal with texture2D as argument to texture functions.
6528 require_extension_internal("GL_EXT_samplerless_texture_functions");
6529 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006530 }
6531 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02006532 {
6533 if (!dummy_sampler_id)
crissdb52e272020-10-08 12:14:52 +02006534 SPIRV_CROSS_THROW("Cannot find dummy sampler ID. Was "
6535 "build_dummy_sampler_for_combined_images() called?");
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02006536
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006537 return to_combined_image_sampler(id, dummy_sampler_id);
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02006538 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006539 }
6540 }
6541
6542 return to_expression(id);
6543}
6544
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006545// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006546string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool *p_forward)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006547{
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006548 VariableID img = args.base.img;
6549 auto &imgtype = *args.base.imgtype;
6550
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006551 string farg_str;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006552 if (args.base.is_fetch)
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02006553 farg_str = convert_separate_image_to_expression(img);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02006554 else
6555 farg_str = to_expression(img);
Hans-Kristian Arntzen1a2e4de2018-02-21 13:43:16 +01006556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006557 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02006558 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006559 if (comps == in_comps)
6560 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006561
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006562 switch (comps)
6563 {
6564 case 1:
6565 return ".x";
6566 case 2:
6567 return swizz_func ? ".xy()" : ".xy";
6568 case 3:
6569 return swizz_func ? ".xyz()" : ".xyz";
6570 default:
6571 return "";
6572 }
6573 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006574
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006575 bool forward = should_forward(args.coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006576
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006577 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006578 auto swizzle_expr = swizzle(args.coord_components, expression_type(args.coord).vecsize);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006579 // Only enclose the UV expression if needed.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006580 auto coord_expr =
6581 (*swizzle_expr == '\0') ? to_expression(args.coord) : (to_enclosed_expression(args.coord) + swizzle_expr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006582
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006583 // texelFetch only takes int, not uint.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006584 auto &coord_type = expression_type(args.coord);
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006585 if (coord_type.basetype == SPIRType::UInt)
6586 {
6587 auto expected_type = coord_type;
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006588 expected_type.vecsize = args.coord_components;
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006589 expected_type.basetype = SPIRType::Int;
6590 coord_expr = bitcast_expression(expected_type, coord_type.basetype, coord_expr);
6591 }
6592
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006593 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006594 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
6595 // 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 +02006596 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02006597 bool workaround_lod_array_shadow_as_grad =
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006598 ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006599 image_is_comparison(imgtype, img) && args.lod != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006600
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006601 if (args.dref)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006602 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006603 forward = forward && should_forward(args.dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006604
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006605 // SPIR-V splits dref and coordinate.
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006606 if (args.base.is_gather ||
6607 args.coord_components == 4) // GLSL also splits the arguments in two. Same for textureGather.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006608 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006609 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006610 farg_str += to_expression(args.coord);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006611 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006612 farg_str += to_expression(args.dref);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006613 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006614 else if (args.base.is_proj)
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02006615 {
6616 // Have to reshuffle so we get vec4(coord, dref, proj), special case.
6617 // Other shading languages splits up the arguments for coord and compare value like SPIR-V.
6618 // The coordinate type for textureProj shadow is always vec4 even for sampler1DShadow.
6619 farg_str += ", vec4(";
6620
6621 if (imgtype.image.dim == Dim1D)
6622 {
6623 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006624 farg_str += to_enclosed_expression(args.coord) + ".x";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02006625 farg_str += ", ";
6626 farg_str += "0.0, ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006627 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02006628 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006629 farg_str += to_enclosed_expression(args.coord) + ".y)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02006630 }
6631 else if (imgtype.image.dim == Dim2D)
6632 {
6633 // Could reuse coord_expr, but we will mess up the temporary usage checking.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006634 farg_str += to_enclosed_expression(args.coord) + (swizz_func ? ".xy()" : ".xy");
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02006635 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006636 farg_str += to_expression(args.dref);
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02006637 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006638 farg_str += to_enclosed_expression(args.coord) + ".z)";
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02006639 }
6640 else
6641 SPIRV_CROSS_THROW("Invalid type for textureProj with shadow.");
6642 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006643 else
6644 {
6645 // Create a composite which merges coord/dref into a single vector.
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006646 auto type = expression_type(args.coord);
6647 type.vecsize = args.coord_components + 1;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006648 farg_str += ", ";
6649 farg_str += type_to_glsl_constructor(type);
6650 farg_str += "(";
6651 farg_str += coord_expr;
6652 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006653 farg_str += to_expression(args.dref);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006654 farg_str += ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006655 }
6656 }
6657 else
6658 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006659 farg_str += ", ";
6660 farg_str += coord_expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006661 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006662
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006663 if (args.grad_x || args.grad_y)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006664 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006665 forward = forward && should_forward(args.grad_x);
6666 forward = forward && should_forward(args.grad_y);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006667 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006668 farg_str += to_expression(args.grad_x);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006669 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006670 farg_str += to_expression(args.grad_y);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006671 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006672
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006673 if (args.lod)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006674 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006675 if (workaround_lod_array_shadow_as_grad)
Robert Konrad3f745032017-03-23 09:55:32 +01006676 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006677 // Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
6678 // Implementing this as plain texture() is not safe on some implementations.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02006679 if (imgtype.image.dim == Dim2D)
6680 farg_str += ", vec2(0.0), vec2(0.0)";
6681 else if (imgtype.image.dim == DimCube)
6682 farg_str += ", vec3(0.0), vec3(0.0)";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006683 }
6684 else
6685 {
rdbe8c500c2020-11-05 22:55:44 +01006686 forward = forward && should_forward(args.lod);
6687 farg_str += ", ";
6688
6689 auto &lod_expr_type = expression_type(args.lod);
6690
6691 // Lod expression for TexelFetch in GLSL must be int, and only int.
6692 if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms &&
6693 lod_expr_type.basetype != SPIRType::Int)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006694 {
rdbe8c500c2020-11-05 22:55:44 +01006695 farg_str += join("int(", to_expression(args.lod), ")");
6696 }
6697 else
6698 {
6699 farg_str += to_expression(args.lod);
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02006700 }
Robert Konrad3f745032017-03-23 09:55:32 +01006701 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006702 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006703 else if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms)
Hans-Kristian Arntzend93807a2018-04-30 10:53:21 +02006704 {
6705 // Lod argument is optional in OpImageFetch, but we require a LOD value, pick 0 as the default.
6706 farg_str += ", 0";
6707 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006708
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006709 if (args.coffset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006710 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006711 forward = forward && should_forward(args.coffset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006712 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006713 farg_str += to_expression(args.coffset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006714 }
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006715 else if (args.offset)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006716 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006717 forward = forward && should_forward(args.offset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006718 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006719 farg_str += to_expression(args.offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006720 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006721
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006722 if (args.sample)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006723 {
6724 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006725 farg_str += to_expression(args.sample);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006726 }
6727
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006728 if (args.min_lod)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006729 {
6730 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006731 farg_str += to_expression(args.min_lod);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006732 }
6733
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006734 if (args.sparse_texel)
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006735 {
6736 // Sparse texel output parameter comes after everything else, except it's before the optional, component/bias arguments.
6737 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006738 farg_str += to_expression(args.sparse_texel);
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02006739 }
6740
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006741 if (args.bias)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006742 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006743 forward = forward && should_forward(args.bias);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006744 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006745 farg_str += to_expression(args.bias);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006746 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006747
rdb509908d2020-11-07 00:01:57 +01006748 if (args.component && !expression_is_constant_null(args.component))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006749 {
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006750 forward = forward && should_forward(args.component);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006751 farg_str += ", ";
Hans-Kristian Arntzencbe0cca2020-06-05 15:49:17 +02006752 farg_str += to_expression(args.component);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006753 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006754
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006755 *p_forward = forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006756
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05006757 return farg_str;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006758}
6759
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006760void 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 +01006761{
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02006762 auto op = static_cast<GLSLstd450>(eop);
6763
6764 if (is_legacy() && is_unsigned_glsl_opcode(op))
6765 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy GLSL targets.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006766
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006767 // If we need to do implicit bitcasts, make sure we do it with the correct type.
6768 uint32_t integer_width = get_integer_width_for_glsl_instruction(op, args, length);
6769 auto int_type = to_signed_basetype(integer_width);
6770 auto uint_type = to_unsigned_basetype(integer_width);
6771
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006772 switch (op)
6773 {
6774 // FP fiddling
6775 case GLSLstd450Round:
rdb9e6e5d22020-11-06 17:34:38 +01006776 if (!is_legacy())
6777 emit_unary_func_op(result_type, id, args[0], "round");
6778 else
6779 {
6780 auto op0 = to_enclosed_expression(args[0]);
6781 auto &op0_type = expression_type(args[0]);
6782 auto expr = join("floor(", op0, " + ", type_to_glsl_constructor(op0_type), "(0.5))");
6783 bool forward = should_forward(args[0]);
6784 emit_op(result_type, id, expr, forward);
6785 inherit_expression_dependencies(id, args[0]);
6786 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006787 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006788
6789 case GLSLstd450RoundEven:
rdb9e6e5d22020-11-06 17:34:38 +01006790 if (!is_legacy())
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006791 emit_unary_func_op(result_type, id, args[0], "roundEven");
rdb9e6e5d22020-11-06 17:34:38 +01006792 else if (!options.es)
6793 {
6794 // This extension provides round() with round-to-even semantics.
6795 require_extension_internal("GL_EXT_gpu_shader4");
6796 emit_unary_func_op(result_type, id, args[0], "round");
6797 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006798 else
rdb9e6e5d22020-11-06 17:34:38 +01006799 SPIRV_CROSS_THROW("roundEven supported only in ESSL 300.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006800 break;
6801
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006802 case GLSLstd450Trunc:
6803 emit_unary_func_op(result_type, id, args[0], "trunc");
6804 break;
6805 case GLSLstd450SAbs:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006806 emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type);
6807 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006808 case GLSLstd450FAbs:
6809 emit_unary_func_op(result_type, id, args[0], "abs");
6810 break;
6811 case GLSLstd450SSign:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006812 emit_unary_func_op_cast(result_type, id, args[0], "sign", int_type, int_type);
6813 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006814 case GLSLstd450FSign:
6815 emit_unary_func_op(result_type, id, args[0], "sign");
6816 break;
6817 case GLSLstd450Floor:
6818 emit_unary_func_op(result_type, id, args[0], "floor");
6819 break;
6820 case GLSLstd450Ceil:
6821 emit_unary_func_op(result_type, id, args[0], "ceil");
6822 break;
6823 case GLSLstd450Fract:
6824 emit_unary_func_op(result_type, id, args[0], "fract");
6825 break;
6826 case GLSLstd450Radians:
6827 emit_unary_func_op(result_type, id, args[0], "radians");
6828 break;
6829 case GLSLstd450Degrees:
6830 emit_unary_func_op(result_type, id, args[0], "degrees");
6831 break;
6832 case GLSLstd450Fma:
Hans-Kristian Arntzen3ca8bc52019-04-08 10:33:34 +02006833 if ((!options.es && options.version < 400) || (options.es && options.version < 320))
6834 {
6835 auto expr = join(to_enclosed_expression(args[0]), " * ", to_enclosed_expression(args[1]), " + ",
6836 to_enclosed_expression(args[2]));
6837
6838 emit_op(result_type, id, expr,
6839 should_forward(args[0]) && should_forward(args[1]) && should_forward(args[2]));
6840 for (uint32_t i = 0; i < 3; i++)
6841 inherit_expression_dependencies(id, args[i]);
6842 }
6843 else
6844 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006845 break;
6846 case GLSLstd450Modf:
6847 register_call_out_argument(args[1]);
6848 forced_temporaries.insert(id);
6849 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
6850 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006851
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006852 case GLSLstd450ModfStruct:
6853 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006854 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02006855 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006856 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
6857 to_expression(id), ".", to_member_name(type, 1), ");");
6858 break;
6859 }
6860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006861 // Minmax
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006862 case GLSLstd450UMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006863 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", uint_type, false);
6864 break;
6865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006866 case GLSLstd450SMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006867 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", int_type, false);
6868 break;
6869
6870 case GLSLstd450FMin:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006871 emit_binary_func_op(result_type, id, args[0], args[1], "min");
6872 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006873
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006874 case GLSLstd450FMax:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006875 emit_binary_func_op(result_type, id, args[0], args[1], "max");
6876 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006877
6878 case GLSLstd450UMax:
6879 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", uint_type, false);
6880 break;
6881
6882 case GLSLstd450SMax:
6883 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", int_type, false);
6884 break;
6885
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006886 case GLSLstd450FClamp:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006887 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
6888 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006889
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01006890 case GLSLstd450UClamp:
6891 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", uint_type);
6892 break;
6893
6894 case GLSLstd450SClamp:
6895 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", int_type);
6896 break;
6897
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006898 // Trig
6899 case GLSLstd450Sin:
6900 emit_unary_func_op(result_type, id, args[0], "sin");
6901 break;
6902 case GLSLstd450Cos:
6903 emit_unary_func_op(result_type, id, args[0], "cos");
6904 break;
6905 case GLSLstd450Tan:
6906 emit_unary_func_op(result_type, id, args[0], "tan");
6907 break;
6908 case GLSLstd450Asin:
6909 emit_unary_func_op(result_type, id, args[0], "asin");
6910 break;
6911 case GLSLstd450Acos:
6912 emit_unary_func_op(result_type, id, args[0], "acos");
6913 break;
6914 case GLSLstd450Atan:
6915 emit_unary_func_op(result_type, id, args[0], "atan");
6916 break;
6917 case GLSLstd450Sinh:
6918 emit_unary_func_op(result_type, id, args[0], "sinh");
6919 break;
6920 case GLSLstd450Cosh:
6921 emit_unary_func_op(result_type, id, args[0], "cosh");
6922 break;
6923 case GLSLstd450Tanh:
6924 emit_unary_func_op(result_type, id, args[0], "tanh");
6925 break;
6926 case GLSLstd450Asinh:
6927 emit_unary_func_op(result_type, id, args[0], "asinh");
6928 break;
6929 case GLSLstd450Acosh:
6930 emit_unary_func_op(result_type, id, args[0], "acosh");
6931 break;
6932 case GLSLstd450Atanh:
6933 emit_unary_func_op(result_type, id, args[0], "atanh");
6934 break;
6935 case GLSLstd450Atan2:
6936 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
6937 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006938
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006939 // Exponentials
6940 case GLSLstd450Pow:
6941 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
6942 break;
6943 case GLSLstd450Exp:
6944 emit_unary_func_op(result_type, id, args[0], "exp");
6945 break;
6946 case GLSLstd450Log:
6947 emit_unary_func_op(result_type, id, args[0], "log");
6948 break;
6949 case GLSLstd450Exp2:
6950 emit_unary_func_op(result_type, id, args[0], "exp2");
6951 break;
6952 case GLSLstd450Log2:
6953 emit_unary_func_op(result_type, id, args[0], "log2");
6954 break;
6955 case GLSLstd450Sqrt:
6956 emit_unary_func_op(result_type, id, args[0], "sqrt");
6957 break;
6958 case GLSLstd450InverseSqrt:
6959 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
6960 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006961
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006962 // Matrix math
6963 case GLSLstd450Determinant:
6964 emit_unary_func_op(result_type, id, args[0], "determinant");
6965 break;
6966 case GLSLstd450MatrixInverse:
6967 emit_unary_func_op(result_type, id, args[0], "inverse");
6968 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006969
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006970 // Lerping
6971 case GLSLstd450FMix:
6972 case GLSLstd450IMix:
6973 {
6974 emit_mix_op(result_type, id, args[0], args[1], args[2]);
6975 break;
6976 }
6977 case GLSLstd450Step:
6978 emit_binary_func_op(result_type, id, args[0], args[1], "step");
6979 break;
6980 case GLSLstd450SmoothStep:
6981 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
6982 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006983
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006984 // Packing
6985 case GLSLstd450Frexp:
6986 register_call_out_argument(args[1]);
6987 forced_temporaries.insert(id);
6988 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
6989 break;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006990
6991 case GLSLstd450FrexpStruct:
6992 {
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006993 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02006994 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02006995 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
6996 to_expression(id), ".", to_member_name(type, 1), ");");
6997 break;
6998 }
6999
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007000 case GLSLstd450Ldexp:
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007001 {
7002 bool forward = should_forward(args[0]) && should_forward(args[1]);
7003
7004 auto op0 = to_unpacked_expression(args[0]);
7005 auto op1 = to_unpacked_expression(args[1]);
7006 auto &op1_type = expression_type(args[1]);
7007 if (op1_type.basetype != SPIRType::Int)
7008 {
7009 // Need a value cast here.
7010 auto target_type = op1_type;
7011 target_type.basetype = SPIRType::Int;
7012 op1 = join(type_to_glsl_constructor(target_type), "(", op1, ")");
7013 }
7014
7015 auto expr = join("ldexp(", op0, ", ", op1, ")");
7016
7017 emit_op(result_type, id, expr, forward);
7018 inherit_expression_dependencies(id, args[0]);
7019 inherit_expression_dependencies(id, args[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007020 break;
Hans-Kristian Arntzen2f7848d2019-08-27 11:19:54 +02007021 }
7022
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007023 case GLSLstd450PackSnorm4x8:
7024 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
7025 break;
7026 case GLSLstd450PackUnorm4x8:
7027 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
7028 break;
7029 case GLSLstd450PackSnorm2x16:
7030 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
7031 break;
7032 case GLSLstd450PackUnorm2x16:
7033 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
7034 break;
7035 case GLSLstd450PackHalf2x16:
7036 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
7037 break;
7038 case GLSLstd450UnpackSnorm4x8:
7039 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
7040 break;
7041 case GLSLstd450UnpackUnorm4x8:
7042 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
7043 break;
7044 case GLSLstd450UnpackSnorm2x16:
7045 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
7046 break;
7047 case GLSLstd450UnpackUnorm2x16:
7048 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
7049 break;
7050 case GLSLstd450UnpackHalf2x16:
7051 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
7052 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007053
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007054 case GLSLstd450PackDouble2x32:
7055 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
7056 break;
7057 case GLSLstd450UnpackDouble2x32:
7058 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
7059 break;
7060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007061 // Vector math
7062 case GLSLstd450Length:
7063 emit_unary_func_op(result_type, id, args[0], "length");
7064 break;
7065 case GLSLstd450Distance:
7066 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
7067 break;
7068 case GLSLstd450Cross:
7069 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
7070 break;
7071 case GLSLstd450Normalize:
7072 emit_unary_func_op(result_type, id, args[0], "normalize");
7073 break;
7074 case GLSLstd450FaceForward:
7075 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
7076 break;
7077 case GLSLstd450Reflect:
7078 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
7079 break;
7080 case GLSLstd450Refract:
7081 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
7082 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007083
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007084 // Bit-fiddling
7085 case GLSLstd450FindILsb:
Hans-Kristian Arntzen932ee0e2019-07-12 10:57:56 +02007086 // findLSB always returns int.
7087 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 +02007088 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007090 case GLSLstd450FindSMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007091 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", int_type, int_type);
7092 break;
7093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007094 case GLSLstd450FindUMsb:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02007095 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type,
7096 int_type); // findMSB always returns int.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007097 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007098
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007099 // Multisampled varying
7100 case GLSLstd450InterpolateAtCentroid:
7101 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
7102 break;
7103 case GLSLstd450InterpolateAtSample:
7104 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
7105 break;
7106 case GLSLstd450InterpolateAtOffset:
7107 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
7108 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007109
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007110 case GLSLstd450NMin:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007111 case GLSLstd450NMax:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007112 {
7113 emit_nminmax_op(result_type, id, args[0], args[1], op);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007114 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007115 }
7116
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007117 case GLSLstd450NClamp:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007118 {
7119 // Make sure we have a unique ID here to avoid aliasing the extra sub-expressions between clamp and NMin sub-op.
7120 // IDs cannot exceed 24 bits, so we can make use of the higher bits for some unique flags.
7121 uint32_t &max_id = extra_sub_expressions[id | 0x80000000u];
7122 if (!max_id)
7123 max_id = ir.increase_bound_by(1);
7124
7125 // Inherit precision qualifiers.
7126 ir.meta[max_id] = ir.meta[id];
7127
7128 emit_nminmax_op(result_type, max_id, args[0], args[1], GLSLstd450NMax);
7129 emit_nminmax_op(result_type, id, max_id, args[2], GLSLstd450NMin);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007130 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007131 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02007132
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007133 default:
7134 statement("// unimplemented GLSL op ", eop);
7135 break;
7136 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007137}
7138
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01007139void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op)
7140{
7141 // Need to emulate this call.
7142 uint32_t &ids = extra_sub_expressions[id];
7143 if (!ids)
7144 {
7145 ids = ir.increase_bound_by(5);
7146 auto btype = get<SPIRType>(result_type);
7147 btype.basetype = SPIRType::Boolean;
7148 set<SPIRType>(ids, btype);
7149 }
7150
7151 uint32_t btype_id = ids + 0;
7152 uint32_t left_nan_id = ids + 1;
7153 uint32_t right_nan_id = ids + 2;
7154 uint32_t tmp_id = ids + 3;
7155 uint32_t mixed_first_id = ids + 4;
7156
7157 // Inherit precision qualifiers.
7158 ir.meta[tmp_id] = ir.meta[id];
7159 ir.meta[mixed_first_id] = ir.meta[id];
7160
7161 emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
7162 emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
7163 emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max");
7164 emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id);
7165 emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id);
7166}
7167
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007168void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
7169 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007170{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007171 require_extension_internal("GL_AMD_shader_ballot");
Lou Kramer6671f522017-11-21 14:04:57 +01007172
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007173 enum AMDShaderBallot
7174 {
Lou Kramer6671f522017-11-21 14:04:57 +01007175 SwizzleInvocationsAMD = 1,
7176 SwizzleInvocationsMaskedAMD = 2,
7177 WriteInvocationAMD = 3,
7178 MbcntAMD = 4
7179 };
7180
7181 auto op = static_cast<AMDShaderBallot>(eop);
7182
7183 switch (op)
7184 {
7185 case SwizzleInvocationsAMD:
7186 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007187 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007188 break;
7189
7190 case SwizzleInvocationsMaskedAMD:
7191 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsMaskedAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007192 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007193 break;
7194
7195 case WriteInvocationAMD:
7196 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "writeInvocationAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007197 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007198 break;
7199
7200 case MbcntAMD:
7201 emit_unary_func_op(result_type, id, args[0], "mbcntAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007202 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007203 break;
7204
7205 default:
7206 statement("// unimplemented SPV AMD shader ballot op ", eop);
7207 break;
7208 }
7209}
7210
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007211void CompilerGLSL::emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t id, uint32_t eop,
7212 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007213{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007214 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Lou Kramer6671f522017-11-21 14:04:57 +01007215
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007216 enum AMDShaderExplicitVertexParameter
7217 {
Lou Kramer6671f522017-11-21 14:04:57 +01007218 InterpolateAtVertexAMD = 1
7219 };
7220
7221 auto op = static_cast<AMDShaderExplicitVertexParameter>(eop);
7222
7223 switch (op)
7224 {
7225 case InterpolateAtVertexAMD:
7226 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtVertexAMD");
7227 break;
7228
7229 default:
7230 statement("// unimplemented SPV AMD shader explicit vertex parameter op ", eop);
7231 break;
7232 }
7233}
7234
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007235void CompilerGLSL::emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t id, uint32_t eop,
7236 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007237{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007238 require_extension_internal("GL_AMD_shader_trinary_minmax");
Lou Kramer6671f522017-11-21 14:04:57 +01007239
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007240 enum AMDShaderTrinaryMinMax
7241 {
Lou Kramer6671f522017-11-21 14:04:57 +01007242 FMin3AMD = 1,
7243 UMin3AMD = 2,
7244 SMin3AMD = 3,
7245 FMax3AMD = 4,
7246 UMax3AMD = 5,
7247 SMax3AMD = 6,
7248 FMid3AMD = 7,
7249 UMid3AMD = 8,
7250 SMid3AMD = 9
7251 };
7252
7253 auto op = static_cast<AMDShaderTrinaryMinMax>(eop);
7254
7255 switch (op)
7256 {
7257 case FMin3AMD:
7258 case UMin3AMD:
7259 case SMin3AMD:
7260 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "min3");
7261 break;
7262
7263 case FMax3AMD:
7264 case UMax3AMD:
7265 case SMax3AMD:
7266 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "max3");
7267 break;
7268
7269 case FMid3AMD:
7270 case UMid3AMD:
7271 case SMid3AMD:
7272 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mid3");
7273 break;
7274
7275 default:
7276 statement("// unimplemented SPV AMD shader trinary minmax op ", eop);
7277 break;
7278 }
7279}
7280
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007281void CompilerGLSL::emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
7282 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01007283{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007284 require_extension_internal("GL_AMD_gcn_shader");
Lou Kramer6671f522017-11-21 14:04:57 +01007285
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007286 enum AMDGCNShader
7287 {
Lou Kramer6671f522017-11-21 14:04:57 +01007288 CubeFaceIndexAMD = 1,
7289 CubeFaceCoordAMD = 2,
7290 TimeAMD = 3
7291 };
7292
7293 auto op = static_cast<AMDGCNShader>(eop);
7294
7295 switch (op)
7296 {
7297 case CubeFaceIndexAMD:
7298 emit_unary_func_op(result_type, id, args[0], "cubeFaceIndexAMD");
7299 break;
7300 case CubeFaceCoordAMD:
7301 emit_unary_func_op(result_type, id, args[0], "cubeFaceCoordAMD");
7302 break;
7303 case TimeAMD:
7304 {
7305 string expr = "timeAMD()";
7306 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01007307 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01007308 break;
7309 }
7310
7311 default:
7312 statement("// unimplemented SPV AMD gcn shader op ", eop);
7313 break;
7314 }
7315}
7316
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007317void CompilerGLSL::emit_subgroup_op(const Instruction &i)
7318{
7319 const uint32_t *ops = stream(i);
7320 auto op = static_cast<Op>(i.op);
7321
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +02007322 if (!options.vulkan_semantics && !is_supported_subgroup_op_in_opengl(op))
crissdb52e272020-10-08 12:14:52 +02007323 SPIRV_CROSS_THROW("This subgroup operation is only supported in Vulkan semantics.");
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007324
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01007325 // If we need to do implicit bitcasts, make sure we do it with the correct type.
7326 uint32_t integer_width = get_integer_width_for_instruction(i);
7327 auto int_type = to_signed_basetype(integer_width);
7328 auto uint_type = to_unsigned_basetype(integer_width);
7329
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007330 switch (op)
7331 {
7332 case OpGroupNonUniformElect:
crissdb52e272020-10-08 12:14:52 +02007333 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupElect);
7334 break;
7335
7336 case OpGroupNonUniformBallotBitCount:
7337 {
7338 const GroupOperation operation = static_cast<GroupOperation>(ops[3]);
7339 if (operation == GroupOperationReduce)
7340 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitCount);
7341 else if (operation == GroupOperationInclusiveScan || operation == GroupOperationExclusiveScan)
7342 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
7343 }
7344 break;
7345
7346 case OpGroupNonUniformBallotBitExtract:
7347 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotBitExtract);
7348 break;
7349
7350 case OpGroupNonUniformInverseBallot:
7351 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInverseBallot_InclBitCount_ExclBitCout);
7352 break;
7353
7354 case OpGroupNonUniformBallot:
7355 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallot);
7356 break;
7357
7358 case OpGroupNonUniformBallotFindLSB:
7359 case OpGroupNonUniformBallotFindMSB:
7360 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBallotFindLSB_MSB);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007361 break;
7362
7363 case OpGroupNonUniformBroadcast:
7364 case OpGroupNonUniformBroadcastFirst:
crissdb52e272020-10-08 12:14:52 +02007365 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBrodcast_First);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007366 break;
7367
7368 case OpGroupNonUniformShuffle:
7369 case OpGroupNonUniformShuffleXor:
7370 require_extension_internal("GL_KHR_shader_subgroup_shuffle");
7371 break;
7372
7373 case OpGroupNonUniformShuffleUp:
7374 case OpGroupNonUniformShuffleDown:
7375 require_extension_internal("GL_KHR_shader_subgroup_shuffle_relative");
7376 break;
7377
7378 case OpGroupNonUniformAll:
7379 case OpGroupNonUniformAny:
7380 case OpGroupNonUniformAllEqual:
crissdb52e272020-10-08 12:14:52 +02007381 {
7382 const SPIRType &type = expression_type(ops[3]);
7383 if (type.basetype == SPIRType::BaseType::Boolean && type.vecsize == 1u)
7384 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAll_Any_AllEqualBool);
7385 else
7386 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupAllEqualT);
7387 }
7388 break;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007389
7390 case OpGroupNonUniformFAdd:
7391 case OpGroupNonUniformFMul:
7392 case OpGroupNonUniformFMin:
7393 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007394 case OpGroupNonUniformIAdd:
7395 case OpGroupNonUniformIMul:
7396 case OpGroupNonUniformSMin:
7397 case OpGroupNonUniformSMax:
7398 case OpGroupNonUniformUMin:
7399 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007400 case OpGroupNonUniformBitwiseAnd:
7401 case OpGroupNonUniformBitwiseOr:
7402 case OpGroupNonUniformBitwiseXor:
7403 {
7404 auto operation = static_cast<GroupOperation>(ops[3]);
7405 if (operation == GroupOperationClusteredReduce)
7406 {
7407 require_extension_internal("GL_KHR_shader_subgroup_clustered");
7408 }
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02007409 else if (operation == GroupOperationExclusiveScan || operation == GroupOperationInclusiveScan ||
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007410 operation == GroupOperationReduce)
7411 {
7412 require_extension_internal("GL_KHR_shader_subgroup_arithmetic");
7413 }
7414 else
7415 SPIRV_CROSS_THROW("Invalid group operation.");
7416 break;
7417 }
7418
7419 case OpGroupNonUniformQuadSwap:
7420 case OpGroupNonUniformQuadBroadcast:
7421 require_extension_internal("GL_KHR_shader_subgroup_quad");
7422 break;
7423
7424 default:
7425 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
7426 }
7427
7428 uint32_t result_type = ops[0];
7429 uint32_t id = ops[1];
7430
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02007431 auto scope = static_cast<Scope>(evaluate_constant_u32(ops[2]));
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007432 if (scope != ScopeSubgroup)
7433 SPIRV_CROSS_THROW("Only subgroup scope is supported.");
7434
7435 switch (op)
7436 {
7437 case OpGroupNonUniformElect:
7438 emit_op(result_type, id, "subgroupElect()", true);
7439 break;
7440
7441 case OpGroupNonUniformBroadcast:
7442 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBroadcast");
7443 break;
7444
7445 case OpGroupNonUniformBroadcastFirst:
7446 emit_unary_func_op(result_type, id, ops[3], "subgroupBroadcastFirst");
7447 break;
7448
7449 case OpGroupNonUniformBallot:
7450 emit_unary_func_op(result_type, id, ops[3], "subgroupBallot");
7451 break;
7452
7453 case OpGroupNonUniformInverseBallot:
7454 emit_unary_func_op(result_type, id, ops[3], "subgroupInverseBallot");
7455 break;
7456
7457 case OpGroupNonUniformBallotBitExtract:
7458 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBallotBitExtract");
7459 break;
7460
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007461 case OpGroupNonUniformBallotFindLSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007462 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindLSB");
7463 break;
7464
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007465 case OpGroupNonUniformBallotFindMSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007466 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindMSB");
7467 break;
7468
7469 case OpGroupNonUniformBallotBitCount:
7470 {
7471 auto operation = static_cast<GroupOperation>(ops[3]);
7472 if (operation == GroupOperationReduce)
7473 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotBitCount");
7474 else if (operation == GroupOperationInclusiveScan)
7475 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotInclusiveBitCount");
7476 else if (operation == GroupOperationExclusiveScan)
7477 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotExclusiveBitCount");
7478 else
7479 SPIRV_CROSS_THROW("Invalid BitCount operation.");
7480 break;
7481 }
7482
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007483 case OpGroupNonUniformShuffle:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007484 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffle");
7485 break;
7486
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007487 case OpGroupNonUniformShuffleXor:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007488 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleXor");
7489 break;
7490
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007491 case OpGroupNonUniformShuffleUp:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007492 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleUp");
7493 break;
7494
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007495 case OpGroupNonUniformShuffleDown:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007496 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleDown");
7497 break;
7498
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007499 case OpGroupNonUniformAll:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007500 emit_unary_func_op(result_type, id, ops[3], "subgroupAll");
7501 break;
7502
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007503 case OpGroupNonUniformAny:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007504 emit_unary_func_op(result_type, id, ops[3], "subgroupAny");
7505 break;
7506
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007507 case OpGroupNonUniformAllEqual:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007508 emit_unary_func_op(result_type, id, ops[3], "subgroupAllEqual");
7509 break;
7510
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02007511 // clang-format off
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007512#define GLSL_GROUP_OP(op, glsl_op) \
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007513case OpGroupNonUniform##op: \
7514 { \
7515 auto operation = static_cast<GroupOperation>(ops[3]); \
7516 if (operation == GroupOperationReduce) \
7517 emit_unary_func_op(result_type, id, ops[4], "subgroup" #glsl_op); \
7518 else if (operation == GroupOperationInclusiveScan) \
7519 emit_unary_func_op(result_type, id, ops[4], "subgroupInclusive" #glsl_op); \
7520 else if (operation == GroupOperationExclusiveScan) \
7521 emit_unary_func_op(result_type, id, ops[4], "subgroupExclusive" #glsl_op); \
7522 else if (operation == GroupOperationClusteredReduce) \
7523 emit_binary_func_op(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op); \
7524 else \
7525 SPIRV_CROSS_THROW("Invalid group operation."); \
7526 break; \
7527 }
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01007528
7529#define GLSL_GROUP_OP_CAST(op, glsl_op, type) \
7530case OpGroupNonUniform##op: \
7531 { \
7532 auto operation = static_cast<GroupOperation>(ops[3]); \
7533 if (operation == GroupOperationReduce) \
7534 emit_unary_func_op_cast(result_type, id, ops[4], "subgroup" #glsl_op, type, type); \
7535 else if (operation == GroupOperationInclusiveScan) \
7536 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupInclusive" #glsl_op, type, type); \
7537 else if (operation == GroupOperationExclusiveScan) \
7538 emit_unary_func_op_cast(result_type, id, ops[4], "subgroupExclusive" #glsl_op, type, type); \
7539 else if (operation == GroupOperationClusteredReduce) \
7540 emit_binary_func_op_cast_clustered(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op, type); \
7541 else \
7542 SPIRV_CROSS_THROW("Invalid group operation."); \
7543 break; \
7544 }
7545
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007546 GLSL_GROUP_OP(FAdd, Add)
7547 GLSL_GROUP_OP(FMul, Mul)
7548 GLSL_GROUP_OP(FMin, Min)
7549 GLSL_GROUP_OP(FMax, Max)
7550 GLSL_GROUP_OP(IAdd, Add)
7551 GLSL_GROUP_OP(IMul, Mul)
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01007552 GLSL_GROUP_OP_CAST(SMin, Min, int_type)
7553 GLSL_GROUP_OP_CAST(SMax, Max, int_type)
7554 GLSL_GROUP_OP_CAST(UMin, Min, uint_type)
7555 GLSL_GROUP_OP_CAST(UMax, Max, uint_type)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007556 GLSL_GROUP_OP(BitwiseAnd, And)
7557 GLSL_GROUP_OP(BitwiseOr, Or)
7558 GLSL_GROUP_OP(BitwiseXor, Xor)
7559#undef GLSL_GROUP_OP
Hans-Kristian Arntzen5253da92020-01-09 12:01:54 +01007560#undef GLSL_GROUP_OP_CAST
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02007561 // clang-format on
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007562
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007563 case OpGroupNonUniformQuadSwap:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007564 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02007565 uint32_t direction = evaluate_constant_u32(ops[4]);
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007566 if (direction == 0)
7567 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapHorizontal");
7568 else if (direction == 1)
7569 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapVertical");
7570 else if (direction == 2)
7571 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapDiagonal");
7572 else
7573 SPIRV_CROSS_THROW("Invalid quad swap direction.");
7574 break;
7575 }
7576
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007577 case OpGroupNonUniformQuadBroadcast:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02007578 {
7579 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupQuadBroadcast");
7580 break;
7581 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007582
7583 default:
7584 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
7585 }
7586
7587 register_control_dependent_expression(id);
7588}
7589
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007590string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007591{
Hans-Kristian Arntzen6fcf8c82019-05-09 10:27:28 +02007592 // OpBitcast can deal with pointers.
7593 if (out_type.pointer || in_type.pointer)
7594 return type_to_glsl(out_type);
7595
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007596 if (out_type.basetype == in_type.basetype)
7597 return "";
7598
Chip Davisef0b1fc2019-01-30 20:19:05 -06007599 assert(out_type.basetype != SPIRType::Boolean);
7600 assert(in_type.basetype != SPIRType::Boolean);
7601
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007602 bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
7603 bool same_size_cast = out_type.width == in_type.width;
7604
7605 // Trivial bitcast case, casts between integers.
7606 if (integral_cast && same_size_cast)
Chip Davis0d949e12018-11-05 14:55:56 -06007607 return type_to_glsl(out_type);
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007608
7609 // Catch-all 8-bit arithmetic casts (GL_EXT_shader_explicit_arithmetic_types).
7610 if (out_type.width == 8 && in_type.width >= 16 && integral_cast && in_type.vecsize == 1)
7611 return "unpack8";
7612 else if (in_type.width == 8 && out_type.width == 16 && integral_cast && out_type.vecsize == 1)
7613 return "pack16";
7614 else if (in_type.width == 8 && out_type.width == 32 && integral_cast && out_type.vecsize == 1)
7615 return "pack32";
7616
7617 // Floating <-> Integer special casts. Just have to enumerate all cases. :(
7618 // 16-bit, 32-bit and 64-bit floats.
7619 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007620 {
7621 if (is_legacy_es())
7622 SPIRV_CROSS_THROW("Float -> Uint bitcast not supported on legacy ESSL.");
7623 else if (!options.es && options.version < 330)
7624 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007625 return "floatBitsToUint";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007626 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007627 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007628 {
7629 if (is_legacy_es())
7630 SPIRV_CROSS_THROW("Float -> Int bitcast not supported on legacy ESSL.");
7631 else if (!options.es && options.version < 330)
7632 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007633 return "floatBitsToInt";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007634 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007635 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007636 {
7637 if (is_legacy_es())
7638 SPIRV_CROSS_THROW("Uint -> Float bitcast not supported on legacy ESSL.");
7639 else if (!options.es && options.version < 330)
7640 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007641 return "uintBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007642 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007643 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007644 {
7645 if (is_legacy_es())
7646 SPIRV_CROSS_THROW("Int -> Float bitcast not supported on legacy ESSL.");
7647 else if (!options.es && options.version < 330)
7648 require_extension_internal("GL_ARB_shader_bit_encoding");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007649 return "intBitsToFloat";
Hans-Kristian Arntzen63bcbd52019-07-11 15:32:57 +02007650 }
7651
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02007652 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
7653 return "doubleBitsToInt64";
7654 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
7655 return "doubleBitsToUint64";
7656 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
7657 return "int64BitsToDouble";
7658 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
7659 return "uint64BitsToDouble";
Chip Davis0d949e12018-11-05 14:55:56 -06007660 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Half)
7661 return "float16BitsToInt16";
7662 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half)
7663 return "float16BitsToUint16";
7664 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Short)
7665 return "int16BitsToFloat16";
7666 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
7667 return "uint16BitsToFloat16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007668
7669 // And finally, some even more special purpose casts.
7670 if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
Lou Kramer6671f522017-11-21 14:04:57 +01007671 return "packUint2x32";
Asuka55dfbea2020-04-17 22:46:06 +08007672 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UInt64 && out_type.vecsize == 2)
7673 return "unpackUint2x32";
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01007674 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
7675 return "unpackFloat2x16";
7676 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)
7677 return "packFloat2x16";
Chip Davis0d949e12018-11-05 14:55:56 -06007678 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Short && in_type.vecsize == 2)
7679 return "packInt2x16";
7680 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int && in_type.vecsize == 1)
7681 return "unpackInt2x16";
7682 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UShort && in_type.vecsize == 2)
7683 return "packUint2x16";
7684 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
7685 return "unpackUint2x16";
7686 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Short && in_type.vecsize == 4)
7687 return "packInt4x16";
7688 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int64 && in_type.vecsize == 1)
7689 return "unpackInt4x16";
7690 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UShort && in_type.vecsize == 4)
7691 return "packUint4x16";
7692 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt64 && in_type.vecsize == 1)
7693 return "unpackUint4x16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007694
7695 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007696}
7697
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007698string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007699{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007700 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007701 if (op.empty())
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02007702 return to_enclosed_unpacked_expression(argument);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007703 else
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02007704 return join(op, "(", to_unpacked_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007705}
7706
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02007707std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg)
7708{
7709 auto expr = to_expression(arg);
7710 auto &src_type = expression_type(arg);
7711 if (src_type.basetype != target_type)
7712 {
7713 auto target = src_type;
7714 target.basetype = target_type;
7715 expr = join(bitcast_glsl_op(target, src_type), "(", expr, ")");
7716 }
7717
7718 return expr;
7719}
7720
7721std::string CompilerGLSL::bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type,
7722 const std::string &expr)
7723{
7724 if (target_type.basetype == expr_type)
7725 return expr;
7726
7727 auto src_type = target_type;
7728 src_type.basetype = expr_type;
7729 return join(bitcast_glsl_op(target_type, src_type), "(", expr, ")");
7730}
7731
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007732string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007733{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007734 switch (builtin)
7735 {
7736 case BuiltInPosition:
7737 return "gl_Position";
7738 case BuiltInPointSize:
7739 return "gl_PointSize";
Bill Hollingse73e8e42016-12-17 17:07:53 -05007740 case BuiltInClipDistance:
7741 return "gl_ClipDistance";
Hans-Kristian Arntzen7f2e1792017-03-05 12:44:29 +01007742 case BuiltInCullDistance:
7743 return "gl_CullDistance";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007744 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02007745 if (options.vulkan_semantics)
crissdb52e272020-10-08 12:14:52 +02007746 SPIRV_CROSS_THROW("Cannot implement gl_VertexID in Vulkan GLSL. This shader was created "
7747 "with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007748 return "gl_VertexID";
7749 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02007750 if (options.vulkan_semantics)
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02007751 {
7752 auto model = get_entry_point().model;
7753 switch (model)
7754 {
7755 case spv::ExecutionModelIntersectionKHR:
7756 case spv::ExecutionModelAnyHitKHR:
7757 case spv::ExecutionModelClosestHitKHR:
7758 // gl_InstanceID is allowed in these shaders.
7759 break;
7760
7761 default:
crissdb52e272020-10-08 12:14:52 +02007762 SPIRV_CROSS_THROW("Cannot implement gl_InstanceID in Vulkan GLSL. This shader was "
7763 "created with GL semantics.");
Hans-Kristian Arntzen86380ac2020-05-08 13:39:43 +02007764 }
7765 }
rdb031cbaa2020-06-12 22:42:26 +02007766 if (!options.es && options.version < 140)
7767 {
7768 require_extension_internal("GL_ARB_draw_instanced");
7769 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007770 return "gl_InstanceID";
7771 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02007772 if (options.vulkan_semantics)
7773 return "gl_VertexIndex";
7774 else
7775 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007776 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02007777 if (options.vulkan_semantics)
7778 return "gl_InstanceIndex";
rdb031cbaa2020-06-12 22:42:26 +02007779
7780 if (!options.es && options.version < 140)
7781 {
7782 require_extension_internal("GL_ARB_draw_instanced");
7783 }
7784
7785 if (options.vertex.support_nonzero_base_instance)
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007786 {
7787 if (!options.vulkan_semantics)
7788 {
7789 // This is a soft-enable. We will opt-in to using gl_BaseInstanceARB if supported.
7790 require_extension_internal("GL_ARB_shader_draw_parameters");
7791 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02007792 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007793 }
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02007794 else
7795 return "gl_InstanceID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007796 case BuiltInPrimitiveId:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02007797 if (storage == StorageClassInput && get_entry_point().model == ExecutionModelGeometry)
7798 return "gl_PrimitiveIDIn";
7799 else
7800 return "gl_PrimitiveID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007801 case BuiltInInvocationId:
7802 return "gl_InvocationID";
7803 case BuiltInLayer:
7804 return "gl_Layer";
Hans-Kristian Arntzenf825bd92018-01-04 12:41:25 +01007805 case BuiltInViewportIndex:
7806 return "gl_ViewportIndex";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007807 case BuiltInTessLevelOuter:
7808 return "gl_TessLevelOuter";
7809 case BuiltInTessLevelInner:
7810 return "gl_TessLevelInner";
7811 case BuiltInTessCoord:
7812 return "gl_TessCoord";
7813 case BuiltInFragCoord:
7814 return "gl_FragCoord";
7815 case BuiltInPointCoord:
7816 return "gl_PointCoord";
7817 case BuiltInFrontFacing:
7818 return "gl_FrontFacing";
7819 case BuiltInFragDepth:
7820 return "gl_FragDepth";
7821 case BuiltInNumWorkgroups:
7822 return "gl_NumWorkGroups";
7823 case BuiltInWorkgroupSize:
7824 return "gl_WorkGroupSize";
7825 case BuiltInWorkgroupId:
7826 return "gl_WorkGroupID";
7827 case BuiltInLocalInvocationId:
7828 return "gl_LocalInvocationID";
7829 case BuiltInGlobalInvocationId:
7830 return "gl_GlobalInvocationID";
7831 case BuiltInLocalInvocationIndex:
7832 return "gl_LocalInvocationIndex";
Hans-Kristian Arntzen61f1d8b2018-11-28 15:18:43 +01007833 case BuiltInHelperInvocation:
7834 return "gl_HelperInvocation";
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007835
Chip Davisfcad0192018-08-28 13:47:29 -05007836 case BuiltInBaseVertex:
7837 if (options.es)
7838 SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007839
7840 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05007841 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007842 if (options.version < 460)
7843 {
7844 require_extension_internal("GL_ARB_shader_draw_parameters");
7845 return "gl_BaseVertexARB";
7846 }
7847 return "gl_BaseVertex";
Chip Davisfcad0192018-08-28 13:47:29 -05007848 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007849 else
7850 {
7851 // On regular GL, this is soft-enabled and we emit ifdefs in code.
7852 require_extension_internal("GL_ARB_shader_draw_parameters");
7853 return "SPIRV_Cross_BaseVertex";
7854 }
7855 break;
7856
Chip Davisfcad0192018-08-28 13:47:29 -05007857 case BuiltInBaseInstance:
7858 if (options.es)
7859 SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007860
7861 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05007862 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007863 if (options.version < 460)
7864 {
7865 require_extension_internal("GL_ARB_shader_draw_parameters");
7866 return "gl_BaseInstanceARB";
7867 }
7868 return "gl_BaseInstance";
Chip Davisfcad0192018-08-28 13:47:29 -05007869 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007870 else
7871 {
7872 // On regular GL, this is soft-enabled and we emit ifdefs in code.
7873 require_extension_internal("GL_ARB_shader_draw_parameters");
7874 return "SPIRV_Cross_BaseInstance";
7875 }
7876 break;
7877
Chip Davisfcad0192018-08-28 13:47:29 -05007878 case BuiltInDrawIndex:
7879 if (options.es)
7880 SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007881
7882 if (options.vulkan_semantics)
Chip Davis3dc23612018-08-29 10:08:33 -05007883 {
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007884 if (options.version < 460)
7885 {
7886 require_extension_internal("GL_ARB_shader_draw_parameters");
7887 return "gl_DrawIDARB";
7888 }
7889 return "gl_DrawID";
7890 }
7891 else
7892 {
7893 // On regular GL, this is soft-enabled and we emit ifdefs in code.
Chip Davisfcad0192018-08-28 13:47:29 -05007894 require_extension_internal("GL_ARB_shader_draw_parameters");
7895 return "gl_DrawIDARB";
7896 }
Hans-Kristian Arntzenef247e72020-05-22 12:44:56 +02007897 break;
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007898
7899 case BuiltInSampleId:
7900 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007901 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007902 if (!options.es && options.version < 400)
7903 SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
7904 return "gl_SampleID";
7905
7906 case BuiltInSampleMask:
7907 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007908 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007909 if (!options.es && options.version < 400)
7910 SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
7911
7912 if (storage == StorageClassInput)
7913 return "gl_SampleMaskIn";
7914 else
7915 return "gl_SampleMask";
7916
7917 case BuiltInSamplePosition:
7918 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007919 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02007920 if (!options.es && options.version < 400)
7921 SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
7922 return "gl_SamplePosition";
7923
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02007924 case BuiltInViewIndex:
7925 if (options.vulkan_semantics)
7926 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007927 require_extension_internal("GL_EXT_multiview");
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02007928 return "gl_ViewIndex";
7929 }
7930 else
7931 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02007932 require_extension_internal("GL_OVR_multiview2");
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02007933 return "gl_ViewID_OVR";
7934 }
7935
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007936 case BuiltInNumSubgroups:
crissdb52e272020-10-08 12:14:52 +02007937 request_subgroup_feature(ShaderSubgroupSupportHelper::NumSubgroups);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007938 return "gl_NumSubgroups";
7939
7940 case BuiltInSubgroupId:
crissdb52e272020-10-08 12:14:52 +02007941 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007942 return "gl_SubgroupID";
7943
7944 case BuiltInSubgroupSize:
crissdb52e272020-10-08 12:14:52 +02007945 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupSize);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007946 return "gl_SubgroupSize";
7947
7948 case BuiltInSubgroupLocalInvocationId:
crissdb52e272020-10-08 12:14:52 +02007949 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupInvocationID);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007950 return "gl_SubgroupInvocationID";
7951
7952 case BuiltInSubgroupEqMask:
crissdb52e272020-10-08 12:14:52 +02007953 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007954 return "gl_SubgroupEqMask";
7955
7956 case BuiltInSubgroupGeMask:
crissdb52e272020-10-08 12:14:52 +02007957 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007958 return "gl_SubgroupGeMask";
7959
7960 case BuiltInSubgroupGtMask:
crissdb52e272020-10-08 12:14:52 +02007961 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007962 return "gl_SubgroupGtMask";
7963
7964 case BuiltInSubgroupLeMask:
crissdb52e272020-10-08 12:14:52 +02007965 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007966 return "gl_SubgroupLeMask";
7967
7968 case BuiltInSubgroupLtMask:
crissdb52e272020-10-08 12:14:52 +02007969 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMask);
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02007970 return "gl_SubgroupLtMask";
7971
Patrick Moursda39a7b2019-02-26 15:43:03 +01007972 case BuiltInLaunchIdNV:
7973 return "gl_LaunchIDNV";
7974 case BuiltInLaunchSizeNV:
7975 return "gl_LaunchSizeNV";
7976 case BuiltInWorldRayOriginNV:
7977 return "gl_WorldRayOriginNV";
7978 case BuiltInWorldRayDirectionNV:
7979 return "gl_WorldRayDirectionNV";
7980 case BuiltInObjectRayOriginNV:
7981 return "gl_ObjectRayOriginNV";
7982 case BuiltInObjectRayDirectionNV:
7983 return "gl_ObjectRayDirectionNV";
7984 case BuiltInRayTminNV:
7985 return "gl_RayTminNV";
7986 case BuiltInRayTmaxNV:
7987 return "gl_RayTmaxNV";
7988 case BuiltInInstanceCustomIndexNV:
7989 return "gl_InstanceCustomIndexNV";
7990 case BuiltInObjectToWorldNV:
7991 return "gl_ObjectToWorldNV";
7992 case BuiltInWorldToObjectNV:
7993 return "gl_WorldToObjectNV";
7994 case BuiltInHitTNV:
7995 return "gl_HitTNV";
7996 case BuiltInHitKindNV:
7997 return "gl_HitKindNV";
7998 case BuiltInIncomingRayFlagsNV:
7999 return "gl_IncomingRayFlagsNV";
8000
Hans-Kristian Arntzen707312b2019-06-13 11:33:19 +02008001 case BuiltInBaryCoordNV:
8002 {
8003 if (options.es && options.version < 320)
8004 SPIRV_CROSS_THROW("gl_BaryCoordNV requires ESSL 320.");
8005 else if (!options.es && options.version < 450)
8006 SPIRV_CROSS_THROW("gl_BaryCoordNV requires GLSL 450.");
8007 require_extension_internal("GL_NV_fragment_shader_barycentric");
8008 return "gl_BaryCoordNV";
8009 }
8010
8011 case BuiltInBaryCoordNoPerspNV:
8012 {
8013 if (options.es && options.version < 320)
8014 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires ESSL 320.");
8015 else if (!options.es && options.version < 450)
8016 SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires GLSL 450.");
8017 require_extension_internal("GL_NV_fragment_shader_barycentric");
8018 return "gl_BaryCoordNoPerspNV";
8019 }
8020
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +02008021 case BuiltInFragStencilRefEXT:
8022 {
8023 if (!options.es)
8024 {
8025 require_extension_internal("GL_ARB_shader_stencil_export");
8026 return "gl_FragStencilRefARB";
8027 }
8028 else
8029 SPIRV_CROSS_THROW("Stencil export not supported in GLES.");
8030 }
8031
Chip Davis6a585542019-07-12 21:50:50 -05008032 case BuiltInDeviceIndex:
8033 if (!options.vulkan_semantics)
8034 SPIRV_CROSS_THROW("Need Vulkan semantics for device group support.");
8035 require_extension_internal("GL_EXT_device_group");
8036 return "gl_DeviceIndex";
8037
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008038 default:
Bill Hollingse73e8e42016-12-17 17:07:53 -05008039 return join("gl_BuiltIn_", convert_to_string(builtin));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008040 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008041}
8042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008043const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008044{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008045 switch (index)
8046 {
8047 case 0:
8048 return "x";
8049 case 1:
8050 return "y";
8051 case 2:
8052 return "z";
8053 case 3:
8054 return "w";
8055 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008056 SPIRV_CROSS_THROW("Swizzle index out of range");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008057 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008058}
8059
Lukas Hermanns6673a672019-10-22 11:06:16 -04008060void CompilerGLSL::access_chain_internal_append_index(std::string &expr, uint32_t /*base*/, const SPIRType *type,
8061 AccessChainFlags flags, bool & /*access_chain_is_arrayed*/,
8062 uint32_t index)
8063{
8064 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
8065 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
8066
8067 expr += "[";
8068
8069 // If we are indexing into an array of SSBOs or UBOs, we need to index it with a non-uniform qualifier.
8070 bool nonuniform_index =
8071 has_decoration(index, DecorationNonUniformEXT) &&
8072 (has_decoration(type->self, DecorationBlock) || has_decoration(type->self, DecorationBufferBlock));
8073 if (nonuniform_index)
8074 {
8075 expr += backend.nonuniform_qualifier;
8076 expr += "(";
8077 }
8078
8079 if (index_is_literal)
8080 expr += convert_to_string(index);
8081 else
8082 expr += to_expression(index, register_expression_read);
8083
8084 if (nonuniform_index)
8085 expr += ")";
8086
8087 expr += "]";
8088}
8089
Hans-Kristian Arntzeneb5e09f2017-02-23 19:33:14 +01008090string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008091 AccessChainFlags flags, AccessChainMeta *meta)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008092{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008093 string expr;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008094
8095 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008096 bool msb_is_id = (flags & ACCESS_CHAIN_LITERAL_MSB_FORCE_ID) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008097 bool chain_only = (flags & ACCESS_CHAIN_CHAIN_ONLY_BIT) != 0;
8098 bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0;
8099 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008100 bool flatten_member_reference = (flags & ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT) != 0;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008102 if (!chain_only)
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008103 {
8104 // We handle transpose explicitly, so don't resolve that here.
8105 auto *e = maybe_get<SPIRExpression>(base);
8106 bool old_transpose = e && e->need_transpose;
8107 if (e)
8108 e->need_transpose = false;
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008109 expr = to_enclosed_expression(base, register_expression_read);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02008110 if (e)
8111 e->need_transpose = old_transpose;
8112 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008113
Bill Hollings1e84a372017-08-12 00:21:13 -04008114 // Start traversing type hierarchy at the proper non-pointer types,
8115 // but keep type_id referencing the original pointer for use below.
Bill Hollingse0910312018-06-24 15:06:12 -04008116 uint32_t type_id = expression_type_id(base);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02008117
8118 if (!backend.native_pointers)
8119 {
8120 if (ptr_chain)
8121 SPIRV_CROSS_THROW("Backend does not support native pointers and does not support OpPtrAccessChain.");
8122
8123 // Wrapped buffer reference pointer types will need to poke into the internal "value" member before
8124 // continuing the access chain.
8125 if (should_dereference(base))
8126 {
8127 auto &type = get<SPIRType>(type_id);
8128 expr = dereference_expression(type, expr);
8129 }
8130 }
8131
Chip Davisfc02b3d2019-01-08 12:54:40 -06008132 const auto *type = &get_pointee_type(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008133
Hans-Kristian Arntzenb71f5df2018-05-08 15:33:51 +02008134 bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos;
Bill Hollings13583622016-12-14 02:12:52 -05008135 bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008136 bool is_packed = has_extended_decoration(base, SPIRVCrossDecorationPhysicalTypePacked);
8137 uint32_t physical_type = get_extended_decoration(base, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008138 bool is_invariant = has_decoration(base, DecorationInvariant);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008139 bool pending_array_enclose = false;
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008140 bool dimension_flatten = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008141
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008142 const auto append_index = [&](uint32_t index, bool is_literal) {
8143 AccessChainFlags mod_flags = flags;
8144 if (!is_literal)
8145 mod_flags &= ~ACCESS_CHAIN_INDEX_IS_LITERAL_BIT;
8146 access_chain_internal_append_index(expr, base, type, mod_flags, access_chain_is_arrayed, index);
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02008147 };
8148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008149 for (uint32_t i = 0; i < count; i++)
8150 {
8151 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008152
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008153 bool is_literal = index_is_literal;
8154 if (is_literal && msb_is_id && (index >> 31u) != 0u)
8155 {
8156 is_literal = false;
8157 index &= 0x7fffffffu;
8158 }
8159
Chip Davis3bfb2f92018-12-03 02:06:33 -06008160 // Pointer chains
8161 if (ptr_chain && i == 0)
8162 {
8163 // If we are flattening multidimensional arrays, only create opening bracket on first
8164 // array index.
8165 if (options.flatten_multidimensional_arrays)
8166 {
8167 dimension_flatten = type->array.size() >= 1;
8168 pending_array_enclose = dimension_flatten;
8169 if (pending_array_enclose)
8170 expr += "[";
8171 }
8172
8173 if (options.flatten_multidimensional_arrays && dimension_flatten)
8174 {
8175 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008176 if (is_literal)
Chip Davis3bfb2f92018-12-03 02:06:33 -06008177 expr += convert_to_string(index);
8178 else
8179 expr += to_enclosed_expression(index, register_expression_read);
8180
8181 for (auto j = uint32_t(type->array.size()); j; j--)
8182 {
8183 expr += " * ";
8184 expr += enclose_expression(to_array_size(*type, j - 1));
8185 }
8186
8187 if (type->array.empty())
8188 pending_array_enclose = false;
8189 else
8190 expr += " + ";
8191
8192 if (!pending_array_enclose)
8193 expr += "]";
8194 }
8195 else
8196 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008197 append_index(index, is_literal);
Chip Davis3bfb2f92018-12-03 02:06:33 -06008198 }
8199
Chip Davise75add42019-02-05 18:13:26 -06008200 if (type->basetype == SPIRType::ControlPointArray)
8201 {
8202 type_id = type->parent_type;
8203 type = &get<SPIRType>(type_id);
8204 }
8205
Chip Davis3bfb2f92018-12-03 02:06:33 -06008206 access_chain_is_arrayed = true;
8207 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008208 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06008209 else if (!type->array.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008210 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008211 // If we are flattening multidimensional arrays, only create opening bracket on first
8212 // array index.
8213 if (options.flatten_multidimensional_arrays && !pending_array_enclose)
8214 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008215 dimension_flatten = type->array.size() > 1;
8216 pending_array_enclose = dimension_flatten;
8217 if (pending_array_enclose)
8218 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008219 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008220
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01008221 assert(type->parent_type);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008222
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008223 auto *var = maybe_get<SPIRVariable>(base);
Bill Hollings27d4af72018-01-08 16:18:34 -05008224 if (backend.force_gl_in_out_block && i == 0 && var && is_builtin_variable(*var) &&
8225 !has_decoration(type->self, DecorationBlock))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008226 {
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008227 // This deals with scenarios for tesc/geom where arrays of gl_Position[] are declared.
8228 // Normally, these variables live in blocks when compiled from GLSL,
8229 // but HLSL seems to just emit straight arrays here.
8230 // We must pretend this access goes through gl_in/gl_out arrays
8231 // to be able to access certain builtins as arrays.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02008232 auto builtin = ir.meta[base].decoration.builtin_type;
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008233 switch (builtin)
8234 {
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01008235 // case BuiltInCullDistance: // These are already arrays, need to figure out rules for these in tess/geom.
8236 // case BuiltInClipDistance:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008237 case BuiltInPosition:
8238 case BuiltInPointSize:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008239 if (var->storage == StorageClassInput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008240 expr = join("gl_in[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008241 else if (var->storage == StorageClassOutput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008242 expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008243 else
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008244 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008245 break;
8246
8247 default:
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008248 append_index(index, is_literal);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008249 break;
8250 }
8251 }
8252 else if (options.flatten_multidimensional_arrays && dimension_flatten)
8253 {
8254 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008255 auto &parent_type = get<SPIRType>(type->parent_type);
8256
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008257 if (is_literal)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008258 expr += convert_to_string(index);
8259 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008260 expr += to_enclosed_expression(index, register_expression_read);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008261
8262 for (auto j = uint32_t(parent_type.array.size()); j; j--)
8263 {
8264 expr += " * ";
8265 expr += enclose_expression(to_array_size(parent_type, j - 1));
8266 }
8267
8268 if (parent_type.array.empty())
8269 pending_array_enclose = false;
8270 else
8271 expr += " + ";
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01008272
8273 if (!pending_array_enclose)
8274 expr += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008275 }
Hans-Kristian Arntzen9d18c822019-10-24 17:10:22 +02008276 // 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.
8277 // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask.
8278 else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn))))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008279 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008280 append_index(index, is_literal);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008281 }
8282
Bill Hollings1e84a372017-08-12 00:21:13 -04008283 type_id = type->parent_type;
8284 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008285
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008286 access_chain_is_arrayed = true;
8287 }
8288 // For structs, the index refers to a constant, which indexes into the members.
8289 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
8290 else if (type->basetype == SPIRType::Struct)
8291 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008292 if (!is_literal)
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008293 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008294
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008295 if (index >= type->member_types.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008296 SPIRV_CROSS_THROW("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008297
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008298 BuiltIn builtin;
8299 if (is_member_builtin(*type, index, &builtin))
8300 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008301 if (access_chain_is_arrayed)
8302 {
8303 expr += ".";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008304 expr += builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008305 }
8306 else
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02008307 expr = builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008308 }
8309 else
8310 {
Bill Hollingsc1b81542017-05-22 21:41:19 -04008311 // If the member has a qualified name, use it as the entire chain
Bill Hollings1e84a372017-08-12 00:21:13 -04008312 string qual_mbr_name = get_member_qualified_name(type_id, index);
Bill Hollingsc1b81542017-05-22 21:41:19 -04008313 if (!qual_mbr_name.empty())
8314 expr = qual_mbr_name;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008315 else if (flatten_member_reference)
8316 expr += join("_", to_member_name(*type, index));
Bill Hollingsc1b81542017-05-22 21:41:19 -04008317 else
Chip Davis3bfb2f92018-12-03 02:06:33 -06008318 expr += to_member_reference(base, *type, index, ptr_chain);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008319 }
Bill Hollingsb332bae2017-03-01 13:07:40 -05008320
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008321 if (has_member_decoration(type->self, index, DecorationInvariant))
8322 is_invariant = true;
8323
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008324 is_packed = member_is_packed_physical_type(*type, index);
Hans-Kristian Arntzenf6251e42019-07-19 11:21:02 +02008325 if (member_is_remapped_physical_type(*type, index))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008326 physical_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008327 else
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008328 physical_type = 0;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01008329
Bill Hollings13583622016-12-14 02:12:52 -05008330 row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008331 type = &get<SPIRType>(type->member_types[index]);
8332 }
8333 // Matrix -> Vector
8334 else if (type->columns > 1)
8335 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008336 // If we have a row-major matrix here, we need to defer any transpose in case this access chain
8337 // is used to store a column. We can resolve it right here and now if we access a scalar directly,
8338 // by flipping indexing order of the matrix.
Bill Hollings343677e2016-12-11 11:01:08 -05008339
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008340 expr += "[";
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008341 if (is_literal)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008342 expr += convert_to_string(index);
8343 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008344 expr += to_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008345 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008346
Bill Hollings1e84a372017-08-12 00:21:13 -04008347 type_id = type->parent_type;
8348 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008349 }
8350 // Vector -> Scalar
8351 else if (type->vecsize > 1)
8352 {
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008353 string deferred_index;
8354 if (row_major_matrix_needs_conversion)
8355 {
8356 // Flip indexing order.
8357 auto column_index = expr.find_last_of('[');
8358 if (column_index != string::npos)
8359 {
8360 deferred_index = expr.substr(column_index);
8361 expr.resize(column_index);
8362 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008363 }
8364
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008365 // Internally, access chain implementation can also be used on composites,
8366 // ignore scalar access workarounds in this case.
8367 StorageClass effective_storage;
8368 if (expression_type(base).pointer)
8369 effective_storage = get_expression_effective_storage_class(base);
8370 else
8371 effective_storage = StorageClassGeneric;
8372
8373 if (!row_major_matrix_needs_conversion)
8374 {
8375 // On some backends, we might not be able to safely access individual scalars in a vector.
8376 // To work around this, we might have to cast the access chain reference to something which can,
8377 // like a pointer to scalar, which we can then index into.
8378 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
8379 is_packed);
8380 }
8381
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008382 if (is_literal && !is_packed && !row_major_matrix_needs_conversion)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008383 {
8384 expr += ".";
8385 expr += index_to_swizzle(index);
8386 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008387 else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008388 {
8389 auto &c = get<SPIRConstant>(index);
Hans-Kristian Arntzen4550f182019-10-17 11:11:23 +02008390 if (c.specialization)
8391 {
8392 // If the index is a spec constant, we cannot turn extract into a swizzle.
8393 expr += join("[", to_expression(index), "]");
8394 }
8395 else
8396 {
8397 expr += ".";
8398 expr += index_to_swizzle(c.scalar());
8399 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008400 }
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01008401 else if (is_literal)
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01008402 {
8403 // For packed vectors, we can only access them as an array, not by swizzle.
8404 expr += join("[", index, "]");
8405 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008406 else
8407 {
8408 expr += "[";
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008409 expr += to_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008410 expr += "]";
8411 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008412
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008413 if (row_major_matrix_needs_conversion)
8414 {
8415 prepare_access_chain_for_scalar_access(expr, get<SPIRType>(type->parent_type), effective_storage,
8416 is_packed);
8417 }
8418
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +02008419 expr += deferred_index;
8420 row_major_matrix_needs_conversion = false;
8421
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01008422 is_packed = false;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008423 physical_type = 0;
Bill Hollings1e84a372017-08-12 00:21:13 -04008424 type_id = type->parent_type;
8425 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008426 }
Bill Hollings2964e322018-02-13 14:44:40 -05008427 else if (!backend.allow_truncated_access_chain)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008428 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008429 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008430
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008431 if (pending_array_enclose)
8432 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02008433 SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
8434 "but the access chain was terminated in the middle of a multidimensional array. "
8435 "This is not supported.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02008436 }
8437
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008438 if (meta)
8439 {
8440 meta->need_transpose = row_major_matrix_needs_conversion;
8441 meta->storage_is_packed = is_packed;
8442 meta->storage_is_invariant = is_invariant;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008443 meta->storage_physical_type = physical_type;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008444 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05008445
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008446 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008447}
8448
Hans-Kristian Arntzenfa5b2062020-07-01 13:02:11 +02008449void CompilerGLSL::prepare_access_chain_for_scalar_access(std::string &, const SPIRType &, spv::StorageClass, bool &)
8450{
8451}
8452
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008453string CompilerGLSL::to_flattened_struct_member(const string &basename, const SPIRType &type, uint32_t index)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01008454{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02008455 auto ret = join(basename, "_", to_member_name(type, index));
8456 ParsedIR::sanitize_underscores(ret);
8457 return ret;
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01008458}
8459
Bill Hollings2d0d3282017-01-20 11:33:59 -05008460string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
Chip Davis3bfb2f92018-12-03 02:06:33 -06008461 AccessChainMeta *meta, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008462{
Arseny Kapoulkine24c66252017-01-16 14:19:49 -08008463 if (flattened_buffer_blocks.count(base))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008464 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008465 uint32_t matrix_stride = 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008466 uint32_t array_stride = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008467 bool need_transpose = false;
Chip Davis3bfb2f92018-12-03 02:06:33 -06008468 flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008469 &array_stride, ptr_chain);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008470
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008471 if (meta)
8472 {
8473 meta->need_transpose = target_type.columns > 1 && need_transpose;
8474 meta->storage_is_packed = false;
8475 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008476
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01008477 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, array_stride,
8478 need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008479 }
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01008480 else if (flattened_structs.count(base) && count > 0)
8481 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008482 AccessChainFlags flags = ACCESS_CHAIN_CHAIN_ONLY_BIT | ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
8483 if (ptr_chain)
8484 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
8485
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008486 if (flattened_structs[base])
8487 {
8488 flags |= ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT;
8489 if (meta)
8490 meta->flattened_struct = target_type.basetype == SPIRType::Struct;
8491 }
8492
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008493 auto chain = access_chain_internal(base, indices, count, flags, nullptr).substr(1);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01008494 if (meta)
8495 {
8496 meta->need_transpose = false;
8497 meta->storage_is_packed = false;
8498 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008499
8500 auto basename = to_flattened_access_chain_expression(base);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02008501 auto ret = join(basename, "_", chain);
8502 ParsedIR::sanitize_underscores(ret);
8503 return ret;
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01008504 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008505 else
8506 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01008507 AccessChainFlags flags = ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
8508 if (ptr_chain)
8509 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
8510 return access_chain_internal(base, indices, count, flags, meta);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008511 }
8512}
8513
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008514string CompilerGLSL::load_flattened_struct(const string &basename, const SPIRType &type)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01008515{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008516 auto expr = type_to_glsl_constructor(type);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01008517 expr += '(';
8518
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01008519 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
8520 {
8521 if (i)
8522 expr += ", ";
8523
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008524 auto &member_type = get<SPIRType>(type.member_types[i]);
8525 if (member_type.basetype == SPIRType::Struct)
8526 expr += load_flattened_struct(to_flattened_struct_member(basename, type, i), member_type);
8527 else
8528 expr += to_flattened_struct_member(basename, type, i);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01008529 }
8530 expr += ')';
8531 return expr;
8532}
8533
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008534std::string CompilerGLSL::to_flattened_access_chain_expression(uint32_t id)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008535{
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008536 // Do not use to_expression as that will unflatten access chains.
8537 string basename;
8538 if (const auto *var = maybe_get<SPIRVariable>(id))
8539 basename = to_name(var->self);
8540 else if (const auto *expr = maybe_get<SPIRExpression>(id))
8541 basename = expr->expression;
8542 else
8543 basename = to_expression(id);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008544
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008545 return basename;
8546}
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008547
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008548void CompilerGLSL::store_flattened_struct(const string &basename, uint32_t rhs_id, const SPIRType &type,
8549 const SmallVector<uint32_t> &indices)
8550{
8551 SmallVector<uint32_t> sub_indices = indices;
8552 sub_indices.push_back(0);
8553
8554 auto *member_type = &type;
8555 for (auto &index : indices)
8556 member_type = &get<SPIRType>(member_type->member_types[index]);
8557
8558 for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008559 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008560 sub_indices.back() = i;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02008561 auto lhs = join(basename, "_", to_member_name(*member_type, i));
8562 ParsedIR::sanitize_underscores(lhs);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01008563
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008564 if (get<SPIRType>(member_type->member_types[i]).basetype == SPIRType::Struct)
8565 {
8566 store_flattened_struct(lhs, rhs_id, type, sub_indices);
8567 }
8568 else
8569 {
8570 auto rhs = to_expression(rhs_id) + to_multi_member_reference(type, sub_indices);
8571 statement(lhs, " = ", rhs, ";");
8572 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008573 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02008574}
8575
8576void CompilerGLSL::store_flattened_struct(uint32_t lhs_id, uint32_t value)
8577{
8578 auto &type = expression_type(lhs_id);
8579 auto basename = to_flattened_access_chain_expression(lhs_id);
8580 store_flattened_struct(basename, value, type, {});
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01008581}
8582
Bill Hollings2d0d3282017-01-20 11:33:59 -05008583std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008584 const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008585 uint32_t /* array_stride */, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008586{
8587 if (!target_type.array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008588 SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008589 else if (target_type.basetype == SPIRType::Struct)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008590 return flattened_access_chain_struct(base, indices, count, target_type, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008591 else if (target_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008592 return flattened_access_chain_matrix(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008593 else
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008594 return flattened_access_chain_vector(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008595}
8596
Bill Hollings2d0d3282017-01-20 11:33:59 -05008597std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
8598 const SPIRType &target_type, uint32_t offset)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008599{
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008600 std::string expr;
8601
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01008602 expr += type_to_glsl_constructor(target_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008603 expr += "(";
8604
Henrik Rydgårdbfae0412017-03-07 09:59:26 +01008605 for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008606 {
8607 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08008608 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008609
8610 const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008611 uint32_t member_offset = type_struct_member_offset(target_type, i);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008612
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008613 // The access chain terminates at the struct, so we need to find matrix strides and row-major information
8614 // ahead of time.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008615 bool need_transpose = false;
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008616 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008617 if (member_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008618 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01008619 need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008620 matrix_stride = type_struct_member_matrix_stride(target_type, i);
8621 }
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008622
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008623 auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride,
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008624 0 /* array_stride */, need_transpose);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008625
8626 // Cannot forward transpositions, so resolve them here.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008627 if (need_transpose)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02008628 expr += convert_row_major_matrix(tmp, member_type, 0, false);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008629 else
8630 expr += tmp;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008631 }
8632
8633 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008634
8635 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008636}
8637
Bill Hollings2d0d3282017-01-20 11:33:59 -05008638std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01008639 const SPIRType &target_type, uint32_t offset,
8640 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008641{
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008642 assert(matrix_stride);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008643 SPIRType tmp_type = target_type;
8644 if (need_transpose)
8645 swap(tmp_type.vecsize, tmp_type.columns);
8646
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008647 std::string expr;
8648
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008649 expr += type_to_glsl_constructor(tmp_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008650 expr += "(";
8651
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008652 for (uint32_t i = 0; i < tmp_type.columns; i++)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008653 {
8654 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08008655 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008656
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008657 expr += flattened_access_chain_vector(base, indices, count, tmp_type, offset + i * matrix_stride, matrix_stride,
8658 /* need_transpose= */ false);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008659 }
8660
8661 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008662
8663 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008664}
8665
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008666std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
8667 const SPIRType &target_type, uint32_t offset,
8668 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008669{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02008670 auto result = flattened_access_chain_offset(expression_type(base), indices, count, offset, 16);
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008671
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008672 auto buffer_name = to_name(expression_type(base).self);
8673
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008674 if (need_transpose)
8675 {
8676 std::string expr;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008677
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08008678 if (target_type.vecsize > 1)
8679 {
8680 expr += type_to_glsl_constructor(target_type);
8681 expr += "(";
8682 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008683
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008684 for (uint32_t i = 0; i < target_type.vecsize; ++i)
8685 {
8686 if (i != 0)
8687 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008688
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008689 uint32_t component_offset = result.second + i * matrix_stride;
8690
8691 assert(component_offset % (target_type.width / 8) == 0);
8692 uint32_t index = component_offset / (target_type.width / 8);
8693
8694 expr += buffer_name;
8695 expr += "[";
8696 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
8697 expr += convert_to_string(index / 4);
8698 expr += "]";
8699
8700 expr += vector_swizzle(1, index % 4);
8701 }
8702
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08008703 if (target_type.vecsize > 1)
8704 {
8705 expr += ")";
8706 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08008707
8708 return expr;
8709 }
8710 else
8711 {
8712 assert(result.second % (target_type.width / 8) == 0);
8713 uint32_t index = result.second / (target_type.width / 8);
8714
8715 std::string expr;
8716
8717 expr += buffer_name;
8718 expr += "[";
8719 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
8720 expr += convert_to_string(index / 4);
8721 expr += "]";
8722
8723 expr += vector_swizzle(target_type.vecsize, index % 4);
8724
8725 return expr;
8726 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008727}
8728
Chip Davis3bfb2f92018-12-03 02:06:33 -06008729std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(
8730 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 +01008731 bool *need_transpose, uint32_t *out_matrix_stride, uint32_t *out_array_stride, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008732{
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01008733 // Start traversing type hierarchy at the proper non-pointer types.
Chip Davisfc02b3d2019-01-08 12:54:40 -06008734 const auto *type = &get_pointee_type(basetype);
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01008735
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008736 std::string expr;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008737
8738 // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout.
8739 bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false;
8740 uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008741 uint32_t array_stride = out_array_stride ? *out_array_stride : 0;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008742
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008743 for (uint32_t i = 0; i < count; i++)
8744 {
8745 uint32_t index = indices[i];
8746
Chip Davis3bfb2f92018-12-03 02:06:33 -06008747 // Pointers
8748 if (ptr_chain && i == 0)
8749 {
8750 // Here, the pointer type will be decorated with an array stride.
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008751 array_stride = get_decoration(basetype.self, DecorationArrayStride);
Chip Davis3bfb2f92018-12-03 02:06:33 -06008752 if (!array_stride)
8753 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
8754
8755 auto *constant = maybe_get<SPIRConstant>(index);
8756 if (constant)
8757 {
8758 // Constant array access.
8759 offset += constant->scalar() * array_stride;
8760 }
8761 else
8762 {
8763 // Dynamic array access.
8764 if (array_stride % word_stride)
8765 {
crissdb52e272020-10-08 12:14:52 +02008766 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
8767 "of a 4-component vector. "
8768 "Likely culprit here is a float or vec2 array inside a push "
8769 "constant block which is std430. "
8770 "This cannot be flattened. Try using std140 layout instead.");
Chip Davis3bfb2f92018-12-03 02:06:33 -06008771 }
8772
8773 expr += to_enclosed_expression(index);
8774 expr += " * ";
8775 expr += convert_to_string(array_stride / word_stride);
8776 expr += " + ";
8777 }
Chip Davis3bfb2f92018-12-03 02:06:33 -06008778 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008779 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06008780 else if (!type->array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008781 {
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01008782 auto *constant = maybe_get<SPIRConstant>(index);
8783 if (constant)
8784 {
8785 // Constant array access.
8786 offset += constant->scalar() * array_stride;
8787 }
8788 else
8789 {
8790 // Dynamic array access.
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01008791 if (array_stride % word_stride)
8792 {
crissdb52e272020-10-08 12:14:52 +02008793 SPIRV_CROSS_THROW("Array stride for dynamic indexing must be divisible by the size "
8794 "of a 4-component vector. "
8795 "Likely culprit here is a float or vec2 array inside a push "
8796 "constant block which is std430. "
8797 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01008798 }
8799
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008800 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01008801 expr += " * ";
8802 expr += convert_to_string(array_stride / word_stride);
8803 expr += " + ";
8804 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008805
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008806 uint32_t parent_type = type->parent_type;
8807 type = &get<SPIRType>(parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01008808
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008809 if (!type->array.empty())
8810 array_stride = get_decoration(parent_type, DecorationArrayStride);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008811 }
8812 // For structs, the index refers to a constant, which indexes into the members.
8813 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
8814 else if (type->basetype == SPIRType::Struct)
8815 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008816 index = evaluate_constant_u32(index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008817
8818 if (index >= type->member_types.size())
8819 SPIRV_CROSS_THROW("Member index is out of bounds!");
8820
8821 offset += type_struct_member_offset(*type, index);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008822
8823 auto &struct_type = *type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008824 type = &get<SPIRType>(type->member_types[index]);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008825
8826 if (type->columns > 1)
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008827 {
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008828 matrix_stride = type_struct_member_matrix_stride(struct_type, index);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008829 row_major_matrix_needs_conversion =
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01008830 combined_decoration_for_member(struct_type, index).get(DecorationRowMajor);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01008831 }
8832 else
8833 row_major_matrix_needs_conversion = false;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008834
8835 if (!type->array.empty())
8836 array_stride = type_struct_member_array_stride(struct_type, index);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008837 }
8838 // Matrix -> Vector
8839 else if (type->columns > 1)
8840 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008841 auto *constant = maybe_get<SPIRConstant>(index);
8842 if (constant)
8843 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008844 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008845 offset += index * (row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride);
8846 }
8847 else
8848 {
8849 uint32_t indexing_stride = row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride;
8850 // Dynamic array access.
8851 if (indexing_stride % word_stride)
8852 {
crissdb52e272020-10-08 12:14:52 +02008853 SPIRV_CROSS_THROW("Matrix stride for dynamic indexing must be divisible by the size of a "
8854 "4-component vector. "
8855 "Likely culprit here is a row-major matrix being accessed dynamically. "
8856 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008857 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008858
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008859 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008860 expr += " * ";
8861 expr += convert_to_string(indexing_stride / word_stride);
8862 expr += " + ";
8863 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008864
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008865 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008866 }
8867 // Vector -> Scalar
8868 else if (type->vecsize > 1)
8869 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008870 auto *constant = maybe_get<SPIRConstant>(index);
8871 if (constant)
8872 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02008873 index = evaluate_constant_u32(index);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008874 offset += index * (row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8));
8875 }
8876 else
8877 {
8878 uint32_t indexing_stride = row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008879
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008880 // Dynamic array access.
8881 if (indexing_stride % word_stride)
8882 {
crissdb52e272020-10-08 12:14:52 +02008883 SPIRV_CROSS_THROW("Stride for dynamic vector indexing must be divisible by the "
8884 "size of a 4-component vector. "
8885 "This cannot be flattened in legacy targets.");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008886 }
8887
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008888 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02008889 expr += " * ";
8890 expr += convert_to_string(indexing_stride / word_stride);
8891 expr += " + ";
8892 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008893
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01008894 type = &get<SPIRType>(type->parent_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008895 }
8896 else
8897 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
8898 }
8899
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08008900 if (need_transpose)
8901 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01008902 if (out_matrix_stride)
8903 *out_matrix_stride = matrix_stride;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01008904 if (out_array_stride)
8905 *out_array_stride = array_stride;
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08008906
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08008907 return std::make_pair(expr, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08008908}
8909
Chip Davis3bfb2f92018-12-03 02:06:33 -06008910bool CompilerGLSL::should_dereference(uint32_t id)
8911{
8912 const auto &type = expression_type(id);
8913 // Non-pointer expressions don't need to be dereferenced.
8914 if (!type.pointer)
8915 return false;
8916
8917 // Handles shouldn't be dereferenced either.
8918 if (!expression_is_lvalue(id))
8919 return false;
8920
8921 // If id is a variable but not a phi variable, we should not dereference it.
8922 if (auto *var = maybe_get<SPIRVariable>(id))
8923 return var->phi_variable;
8924
8925 // If id is an access chain, we should not dereference it.
8926 if (auto *expr = maybe_get<SPIRExpression>(id))
8927 return !expr->access_chain;
8928
8929 // Otherwise, we should dereference this pointer expression.
8930 return true;
8931}
8932
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02008933bool CompilerGLSL::should_forward(uint32_t id) const
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008934{
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07008935 // If id is a variable we will try to forward it regardless of force_temporary check below
8936 // This is important because otherwise we'll get local sampler copies (highp sampler2D foo = bar) that are invalid in OpenGL GLSL
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02008937 auto *var = maybe_get<SPIRVariable>(id);
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07008938 if (var && var->forwardable)
8939 return true;
8940
8941 // For debugging emit temporary variables for all expressions
8942 if (options.force_temporary)
8943 return false;
8944
8945 // Immutable expression can always be forwarded.
8946 if (is_immutable(id))
8947 return true;
8948
8949 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008950}
8951
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02008952bool CompilerGLSL::should_suppress_usage_tracking(uint32_t id) const
8953{
8954 // Used only by opcodes which don't do any real "work", they just swizzle data in some fashion.
8955 return !expression_is_forwarded(id) || expression_suppresses_usage_tracking(id);
8956}
8957
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008958void CompilerGLSL::track_expression_read(uint32_t id)
8959{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01008960 switch (ir.ids[id].get_type())
8961 {
8962 case TypeExpression:
8963 {
8964 auto &e = get<SPIRExpression>(id);
8965 for (auto implied_read : e.implied_read_expressions)
8966 track_expression_read(implied_read);
8967 break;
8968 }
8969
8970 case TypeAccessChain:
8971 {
8972 auto &e = get<SPIRAccessChain>(id);
8973 for (auto implied_read : e.implied_read_expressions)
8974 track_expression_read(implied_read);
8975 break;
8976 }
8977
8978 default:
8979 break;
8980 }
8981
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008982 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
8983 // 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 +02008984 if (expression_is_forwarded(id) && !expression_suppresses_usage_tracking(id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008985 {
8986 auto &v = expression_usage_counts[id];
8987 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008988
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +02008989 // If we create an expression outside a loop,
8990 // but access it inside a loop, we're implicitly reading it multiple times.
8991 // If the expression in question is expensive, we should hoist it out to avoid relying on loop-invariant code motion
8992 // working inside the backend compiler.
8993 if (expression_read_implies_multiple_reads(id))
8994 v++;
8995
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008996 if (v >= 2)
8997 {
8998 //if (v == 2)
8999 // 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 +01009000
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009001 forced_temporaries.insert(id);
9002 // Force a recompile after this pass to avoid forwarding this variable.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009003 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009004 }
9005 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009006}
9007
9008bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
9009{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009010 if (forced_temporaries.find(id) != end(forced_temporaries))
9011 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009012
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009013 for (uint32_t i = 0; i < num_args; i++)
9014 if (!should_forward(args[i]))
9015 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009016
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009017 // We need to forward globals as well.
9018 if (!pure)
9019 {
9020 for (auto global : global_variables)
9021 if (!should_forward(global))
9022 return false;
9023 for (auto aliased : aliased_variables)
9024 if (!should_forward(aliased))
9025 return false;
9026 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009027
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009028 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009029}
9030
9031void CompilerGLSL::register_impure_function_call()
9032{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009033 // Impure functions can modify globals and aliased variables, so invalidate them as well.
9034 for (auto global : global_variables)
9035 flush_dependees(get<SPIRVariable>(global));
9036 for (auto aliased : aliased_variables)
9037 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009038}
9039
9040void CompilerGLSL::register_call_out_argument(uint32_t id)
9041{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009042 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009043
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009044 auto *var = maybe_get<SPIRVariable>(id);
9045 if (var)
9046 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009047}
9048
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01009049string CompilerGLSL::variable_decl_function_local(SPIRVariable &var)
9050{
9051 // These variables are always function local,
9052 // so make sure we emit the variable without storage qualifiers.
9053 // Some backends will inject custom variables locally in a function
9054 // with a storage qualifier which is not function-local.
9055 auto old_storage = var.storage;
9056 var.storage = StorageClassFunction;
9057 auto expr = variable_decl(var);
9058 var.storage = old_storage;
9059 return expr;
9060}
9061
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009062void CompilerGLSL::emit_variable_temporary_copies(const SPIRVariable &var)
9063{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04009064 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen3f569ed2019-10-24 17:12:23 +02009065 if (var.allocate_temporary_copy && !flushed_phi_variables.count(var.self))
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009066 {
9067 auto &type = get<SPIRType>(var.basetype);
9068 auto &flags = get_decoration_bitset(var.self);
9069 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, join("_", var.self, "_copy")), ";");
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04009070 flushed_phi_variables.insert(var.self);
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +02009071 }
9072}
9073
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009074void CompilerGLSL::flush_variable_declaration(uint32_t id)
9075{
Lukas Hermanns50ac6862019-09-18 14:03:54 -04009076 // Ensure that we declare phi-variable copies even if the original declaration isn't deferred
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009077 auto *var = maybe_get<SPIRVariable>(id);
9078 if (var && var->deferred_declaration)
9079 {
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01009080 string initializer;
9081 if (options.force_zero_initialized_variables &&
9082 (var->storage == StorageClassFunction || var->storage == StorageClassGeneric ||
9083 var->storage == StorageClassPrivate) &&
9084 !var->initializer && type_can_zero_initialize(get_variable_data_type(*var)))
9085 {
9086 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(*var)));
9087 }
9088
9089 statement(variable_decl_function_local(*var), initializer, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009090 var->deferred_declaration = false;
9091 }
Mark Satterthwaitea80c74b2019-08-14 11:04:58 -04009092 if (var)
9093 {
9094 emit_variable_temporary_copies(*var);
9095 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009096}
9097
9098bool CompilerGLSL::remove_duplicate_swizzle(string &op)
9099{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009100 auto pos = op.find_last_of('.');
9101 if (pos == string::npos || pos == 0)
9102 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009103
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009104 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009105
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009106 if (backend.swizzle_is_function)
9107 {
9108 if (final_swiz.size() < 2)
9109 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009110
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009111 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
9112 final_swiz.erase(final_swiz.size() - 2, string::npos);
9113 else
9114 return false;
9115 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009116
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009117 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
9118 // If so, and previous swizzle is of same length,
9119 // we can drop the final swizzle altogether.
9120 for (uint32_t i = 0; i < final_swiz.size(); i++)
9121 {
9122 static const char expected[] = { 'x', 'y', 'z', 'w' };
9123 if (i >= 4 || final_swiz[i] != expected[i])
9124 return false;
9125 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009126
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009127 auto prevpos = op.find_last_of('.', pos - 1);
9128 if (prevpos == string::npos)
9129 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009130
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009131 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009132
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009133 // Make sure there are only swizzles here ...
9134 for (auto i = prevpos; i < pos; i++)
9135 {
9136 if (op[i] < 'w' || op[i] > 'z')
9137 {
9138 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
9139 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
9140 break;
9141 return false;
9142 }
9143 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009144
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009145 // If original swizzle is large enough, just carve out the components we need.
9146 // E.g. foobar.wyx.xy will turn into foobar.wy.
9147 if (pos - prevpos >= final_swiz.size())
9148 {
9149 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009150
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009151 // Add back the function call ...
9152 if (backend.swizzle_is_function)
9153 op += "()";
9154 }
9155 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009156}
9157
9158// Optimizes away vector swizzles where we have something like
9159// vec3 foo;
9160// foo.xyz <-- swizzle expression does nothing.
9161// This is a very common pattern after OpCompositeCombine.
9162bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
9163{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009164 auto pos = op.find_last_of('.');
9165 if (pos == string::npos || pos == 0)
9166 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009167
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009168 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009169
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009170 if (backend.swizzle_is_function)
9171 {
9172 if (final_swiz.size() < 2)
9173 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009174
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009175 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
9176 final_swiz.erase(final_swiz.size() - 2, string::npos);
9177 else
9178 return false;
9179 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009180
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009181 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
9182 // If so, and previous swizzle is of same length,
9183 // we can drop the final swizzle altogether.
9184 for (uint32_t i = 0; i < final_swiz.size(); i++)
9185 {
9186 static const char expected[] = { 'x', 'y', 'z', 'w' };
9187 if (i >= 4 || final_swiz[i] != expected[i])
9188 return false;
9189 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009190
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009191 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009193 // Sanity checking ...
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04009194 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009195
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009196 if (type.vecsize == final_swiz.size())
9197 op.erase(pos, string::npos);
9198 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009199}
9200
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009201string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009202{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009203 ID base = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009204 string op;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009205 string subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009206
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009207 // Can only merge swizzles for vectors.
9208 auto &type = get<SPIRType>(return_type);
9209 bool can_apply_swizzle_opt = type.basetype != SPIRType::Struct && type.array.empty() && type.columns == 1;
9210 bool swizzle_optimization = false;
9211
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009212 for (uint32_t i = 0; i < length; i++)
9213 {
9214 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009215
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009216 // If we're merging another scalar which belongs to the same base
9217 // 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 +01009218 if (can_apply_swizzle_opt && e && e->base_expression && e->base_expression == base)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009219 {
9220 // Only supposed to be used for vector swizzle -> scalar.
9221 assert(!e->expression.empty() && e->expression.front() == '.');
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009222 subop += e->expression.substr(1, string::npos);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009223 swizzle_optimization = true;
9224 }
9225 else
9226 {
9227 // We'll likely end up with duplicated swizzles, e.g.
9228 // foobar.xyz.xyz from patterns like
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009229 // OpVectorShuffle
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009230 // OpCompositeExtract x 3
9231 // OpCompositeConstruct 3x + other scalar.
9232 // Just modify op in-place.
9233 if (swizzle_optimization)
9234 {
9235 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009236 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009238 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
9239 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
9240 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
9241 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
9242 // Case 1:
9243 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
9244 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
9245 // Case 2:
9246 // foo.xyz: Duplicate swizzle won't kick in.
9247 // If foo is vec3, we can remove xyz, giving just foo.
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009248 if (!remove_duplicate_swizzle(subop))
9249 remove_unity_swizzle(base, subop);
9250
9251 // Strips away redundant parens if we created them during component extraction.
9252 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009253 swizzle_optimization = false;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009254 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009255 }
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009256 else
9257 op += subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009258
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009259 if (i)
9260 op += ", ";
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02009261
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02009262 bool uses_buffer_offset =
9263 type.basetype == SPIRType::Struct && has_member_decoration(type.self, i, DecorationOffset);
Hans-Kristian Arntzen03d4bce2020-06-18 11:37:24 +02009264 subop = to_composite_constructor_expression(elems[i], uses_buffer_offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009265 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009266
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009267 base = e ? e->base_expression : ID(0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009268 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009269
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009270 if (swizzle_optimization)
9271 {
9272 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009273 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009274
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009275 if (!remove_duplicate_swizzle(subop))
9276 remove_unity_swizzle(base, subop);
9277 // Strips away redundant parens if we created them during component extraction.
9278 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009279 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009280
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01009281 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009282 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009283}
9284
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02009285bool CompilerGLSL::skip_argument(uint32_t id) const
9286{
9287 if (!combined_image_samplers.empty() || !options.vulkan_semantics)
9288 {
9289 auto &type = expression_type(id);
9290 if (type.basetype == SPIRType::Sampler || (type.basetype == SPIRType::Image && type.image.sampled == 1))
9291 return true;
9292 }
9293 return false;
9294}
9295
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02009296bool CompilerGLSL::optimize_read_modify_write(const SPIRType &type, const string &lhs, const string &rhs)
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009297{
9298 // Do this with strings because we have a very clear pattern we can check for and it avoids
9299 // adding lots of special cases to the code emission.
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01009300 if (rhs.size() < lhs.size() + 3)
9301 return false;
9302
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02009303 // Do not optimize matrices. They are a bit awkward to reason about in general
9304 // (in which order does operation happen?), and it does not work on MSL anyways.
9305 if (type.vecsize > 1 && type.columns > 1)
9306 return false;
9307
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009308 auto index = rhs.find(lhs);
9309 if (index != 0)
9310 return false;
9311
9312 // TODO: Shift operators, but it's not important for now.
9313 auto op = rhs.find_first_of("+-/*%|&^", lhs.size() + 1);
9314 if (op != lhs.size() + 1)
9315 return false;
9316
David Srbeckye596d402017-09-05 16:05:53 +01009317 // Check that the op is followed by space. This excludes && and ||.
Hans-Kristian Arntzen03db5c42017-09-06 09:15:27 +02009318 if (rhs[op + 1] != ' ')
David Srbeckye596d402017-09-05 16:05:53 +01009319 return false;
9320
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01009321 char bop = rhs[op];
9322 auto expr = rhs.substr(lhs.size() + 3);
9323 // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code.
9324 // Find some common patterns which are equivalent.
9325 if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)"))
9326 statement(lhs, bop, bop, ";");
9327 else
9328 statement(lhs, " ", bop, "= ", expr, ";");
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01009329 return true;
9330}
9331
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009332void CompilerGLSL::register_control_dependent_expression(uint32_t expr)
9333{
9334 if (forwarded_temporaries.find(expr) == end(forwarded_temporaries))
9335 return;
9336
9337 assert(current_emitting_block);
9338 current_emitting_block->invalidate_expressions.push_back(expr);
9339}
9340
9341void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02009342{
9343 current_emitting_block = &block;
9344 for (auto &op : block.ops)
9345 emit_instruction(op);
9346 current_emitting_block = nullptr;
9347}
9348
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009349void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression &expr)
9350{
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +02009351 // Allow trivially forwarded expressions like OpLoad or trivial shuffles,
9352 // these will be marked as having suppressed usage tracking.
9353 // Our only concern is to make sure arithmetic operations are done in similar ways.
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009354 if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) &&
9355 forced_invariant_temporaries.count(expr.self) == 0)
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009356 {
9357 forced_temporaries.insert(expr.self);
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009358 forced_invariant_temporaries.insert(expr.self);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009359 force_recompile();
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009360
Hans-Kristian Arntzenb97e9b02019-08-01 09:51:44 +02009361 for (auto &dependent : expr.expression_dependencies)
9362 disallow_forwarding_in_expression_chain(get<SPIRExpression>(dependent));
9363 }
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009364}
9365
9366void CompilerGLSL::handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id)
9367{
9368 // Variables or access chains marked invariant are complicated. We will need to make sure the code-gen leading up to
9369 // this variable is consistent. The failure case for SPIRV-Cross is when an expression is forced to a temporary
9370 // in one translation unit, but not another, e.g. due to multiple use of an expression.
9371 // This causes variance despite the output variable being marked invariant, so the solution here is to force all dependent
9372 // expressions to be temporaries.
9373 // It is uncertain if this is enough to support invariant in all possible cases, but it should be good enough
9374 // for all reasonable uses of invariant.
9375 if (!has_decoration(store_id, DecorationInvariant))
9376 return;
9377
9378 auto *expr = maybe_get<SPIRExpression>(value_id);
9379 if (!expr)
9380 return;
9381
9382 disallow_forwarding_in_expression_chain(*expr);
9383}
9384
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01009385void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009386{
9387 auto rhs = to_pointer_expression(rhs_expression);
9388
9389 // Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
9390 if (!rhs.empty())
9391 {
9392 handle_store_to_invariant_variable(lhs_expression, rhs_expression);
9393
9394 auto lhs = to_dereferenced_expression(lhs_expression);
9395
Chip Davis3e6010d2020-10-14 15:04:03 -05009396 // We might need to cast in order to store to a builtin.
9397 cast_to_builtin_store(lhs_expression, rhs, expression_type(rhs_expression));
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009398
9399 // Tries to optimize assignments like "<lhs> = <lhs> op expr".
9400 // While this is purely cosmetic, this is important for legacy ESSL where loop
9401 // variable increments must be in either i++ or i += const-expr.
9402 // Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
9403 if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
9404 statement(lhs, " = ", rhs, ";");
9405 register_write(lhs_expression);
9406 }
9407}
9408
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009409uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &instr) const
9410{
9411 if (instr.length < 3)
9412 return 32;
9413
9414 auto *ops = stream(instr);
9415
9416 switch (instr.op)
9417 {
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +02009418 case OpSConvert:
9419 case OpConvertSToF:
9420 case OpUConvert:
9421 case OpConvertUToF:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009422 case OpIEqual:
9423 case OpINotEqual:
9424 case OpSLessThan:
9425 case OpSLessThanEqual:
9426 case OpSGreaterThan:
9427 case OpSGreaterThanEqual:
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02009428 case OpULessThan:
9429 case OpULessThanEqual:
9430 case OpUGreaterThan:
9431 case OpUGreaterThanEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009432 return expression_type(ops[2]).width;
9433
9434 default:
9435 {
9436 // We can look at result type which is more robust.
9437 auto *type = maybe_get<SPIRType>(ops[0]);
9438 if (type && type_is_integral(*type))
9439 return type->width;
9440 else
9441 return 32;
9442 }
9443 }
9444}
9445
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01009446uint32_t CompilerGLSL::get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *ops, uint32_t length) const
9447{
9448 if (length < 1)
9449 return 32;
9450
9451 switch (op)
9452 {
9453 case GLSLstd450SAbs:
9454 case GLSLstd450SSign:
9455 case GLSLstd450UMin:
9456 case GLSLstd450SMin:
9457 case GLSLstd450UMax:
9458 case GLSLstd450SMax:
9459 case GLSLstd450UClamp:
9460 case GLSLstd450SClamp:
9461 case GLSLstd450FindSMsb:
9462 case GLSLstd450FindUMsb:
9463 return expression_type(ops[0]).width;
9464
9465 default:
9466 {
9467 // We don't need to care about other opcodes, just return 32.
9468 return 32;
9469 }
9470 }
9471}
9472
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02009473void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009474{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009475 auto ops = stream(instruction);
9476 auto opcode = static_cast<Op>(instruction.op);
9477 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009478
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02009479#define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
9480#define GLSL_BOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009481 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 +02009482#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
9483#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
9484#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
9485#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
9486#define GLSL_BFOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009487 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 +02009488#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
9489#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009490
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01009491 // If we need to do implicit bitcasts, make sure we do it with the correct type.
9492 uint32_t integer_width = get_integer_width_for_instruction(instruction);
9493 auto int_type = to_signed_basetype(integer_width);
9494 auto uint_type = to_unsigned_basetype(integer_width);
9495
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009496 switch (opcode)
9497 {
9498 // Dealing with memory
9499 case OpLoad:
9500 {
9501 uint32_t result_type = ops[0];
9502 uint32_t id = ops[1];
9503 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009504
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009505 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009506
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009507 // If we're loading from memory that cannot be changed by the shader,
9508 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02009509 // If an expression is mutable and forwardable, we speculate that it is immutable.
9510 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
9511
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009512 // If loading a non-native row-major matrix, mark the expression as need_transpose.
9513 bool need_transpose = false;
9514 bool old_need_transpose = false;
9515
9516 auto *ptr_expression = maybe_get<SPIRExpression>(ptr);
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009517
9518 if (forward)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009519 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009520 // If we're forwarding the load, we're also going to forward transpose state, so don't transpose while
9521 // taking the expression.
9522 if (ptr_expression && ptr_expression->need_transpose)
9523 {
9524 old_need_transpose = true;
9525 ptr_expression->need_transpose = false;
9526 need_transpose = true;
9527 }
9528 else if (is_non_native_row_major_matrix(ptr))
9529 need_transpose = true;
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009530 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009531
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009532 // If we are forwarding this load,
9533 // don't register the read to access chain here, defer that to when we actually use the expression,
9534 // using the add_implied_read_expression mechanism.
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009535 string expr;
9536
9537 bool is_packed = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked);
9538 bool is_remapped = has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID);
9539 if (forward || (!is_packed && !is_remapped))
9540 {
9541 // For the simple case, we do not need to deal with repacking.
9542 expr = to_dereferenced_expression(ptr, false);
9543 }
9544 else
9545 {
9546 // If we are not forwarding the expression, we need to unpack and resolve any physical type remapping here before
9547 // storing the expression to a temporary.
9548 expr = to_unpacked_expression(ptr);
9549 }
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009550
Chip Davis5281d992020-06-13 23:03:30 -05009551 auto &type = get<SPIRType>(result_type);
9552 auto &expr_type = expression_type(ptr);
9553
9554 // If the expression has more vector components than the result type, insert
9555 // a swizzle. This shouldn't happen normally on valid SPIR-V, but it might
9556 // happen with e.g. the MSL backend replacing the type of an input variable.
9557 if (expr_type.vecsize > type.vecsize)
9558 expr = enclose_expression(expr + vector_swizzle(type.vecsize, 0));
9559
Chip Davis3e6010d2020-10-14 15:04:03 -05009560 // We might need to cast in order to load from a builtin.
9561 cast_from_builtin_load(ptr, expr, type);
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02009562
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +01009563 // We might be trying to load a gl_Position[N], where we should be
9564 // doing float4[](gl_in[i].gl_Position, ...) instead.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +01009565 // Similar workarounds are required for input arrays in tessellation.
9566 unroll_array_from_complex_load(id, ptr, expr);
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +01009567
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02009568 // Shouldn't need to check for ID, but current glslang codegen requires it in some cases
9569 // when loading Image/Sampler descriptors. It does not hurt to check ID as well.
9570 if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ptr, DecorationNonUniformEXT))
9571 {
9572 propagate_nonuniform_qualifier(ptr);
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02009573 convert_non_uniform_expression(type, expr);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +02009574 }
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +02009575
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009576 if (forward && ptr_expression)
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009577 ptr_expression->need_transpose = old_need_transpose;
Bill Hollings13583622016-12-14 02:12:52 -05009578
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +02009579 bool flattened = ptr_expression && flattened_buffer_blocks.count(ptr_expression->loaded_from) != 0;
9580
9581 if (backend.needs_row_major_load_workaround && !is_non_native_row_major_matrix(ptr) && !flattened)
9582 rewrite_load_for_wrapped_row_major(expr, result_type, ptr);
9583
Hans-Kristian Arntzen18b82ca2018-07-09 14:02:50 +02009584 // 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 +02009585 // However, if we try to load a complex, composite object from a flattened buffer,
9586 // 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 +02009587 bool usage_tracking = flattened && (type.basetype == SPIRType::Struct || (type.columns > 1));
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +02009588
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02009589 SPIRExpression *e = nullptr;
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02009590 if (!forward && expression_is_non_value_type_array(ptr))
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02009591 {
9592 // Complicated load case where we need to make a copy of ptr, but we cannot, because
9593 // it is an array, and our backend does not support arrays as value types.
9594 // Emit the temporary, and copy it explicitly.
9595 e = &emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +02009596 emit_array_copy(to_expression(id), ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02009597 }
9598 else
9599 e = &emit_op(result_type, id, expr, forward, !usage_tracking);
9600
9601 e->need_transpose = need_transpose;
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02009602 register_read(id, ptr, forward);
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009603
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009604 if (forward)
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01009605 {
Hans-Kristian Arntzenebe109d2019-07-23 16:25:19 +02009606 // Pass through whether the result is of a packed type and the physical type ID.
9607 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypePacked))
9608 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
9609 if (has_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID))
9610 {
9611 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID,
9612 get_extended_decoration(ptr, SPIRVCrossDecorationPhysicalTypeID));
9613 }
9614 }
9615 else
9616 {
9617 // This might have been set on an earlier compilation iteration, force it to be unset.
9618 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
9619 unset_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01009620 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009621
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009622 inherit_expression_dependencies(id, ptr);
9623 if (forward)
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +02009624 add_implied_read_expression(*e, ptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009625 break;
9626 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009628 case OpInBoundsAccessChain:
9629 case OpAccessChain:
Chip Davis3bfb2f92018-12-03 02:06:33 -06009630 case OpPtrAccessChain:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009631 {
9632 auto *var = maybe_get<SPIRVariable>(ops[2]);
9633 if (var)
9634 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009636 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02009637 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009638 AccessChainMeta meta;
Chip Davis3bfb2f92018-12-03 02:06:33 -06009639 bool ptr_chain = opcode == OpPtrAccessChain;
9640 auto e = access_chain(ops[2], &ops[3], length - 3, get<SPIRType>(ops[0]), &meta, ptr_chain);
Hans-Kristian Arntzene1367e62018-07-06 10:57:23 +02009641
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02009642 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +02009643
9644 auto *backing_variable = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009645 expr.loaded_from = backing_variable ? backing_variable->self : ID(ops[2]);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009646 expr.need_transpose = meta.need_transpose;
Chip Davis3bfb2f92018-12-03 02:06:33 -06009647 expr.access_chain = true;
Bill Hollingsd8d2da92018-01-05 17:46:56 -05009648
9649 // Mark the result as being packed. Some platforms handled packed vectors differently than non-packed.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009650 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02009651 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypePacked);
9652 if (meta.storage_physical_type != 0)
9653 set_extended_decoration(ops[1], SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009654 if (meta.storage_is_invariant)
9655 set_decoration(ops[1], DecorationInvariant);
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009656 if (meta.flattened_struct)
9657 flattened_structs[ops[1]] = true;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01009658
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +02009659 // If we have some expression dependencies in our access chain, this access chain is technically a forwarded
9660 // temporary which could be subject to invalidation.
9661 // Need to assume we're forwarded while calling inherit_expression_depdendencies.
9662 forwarded_temporaries.insert(ops[1]);
9663 // The access chain itself is never forced to a temporary, but its dependencies might.
9664 suppressed_usage_tracking.insert(ops[1]);
9665
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01009666 for (uint32_t i = 2; i < length; i++)
9667 {
9668 inherit_expression_dependencies(ops[1], ops[i]);
9669 add_implied_read_expression(expr, ops[i]);
9670 }
9671
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +02009672 // If we have no dependencies after all, i.e., all indices in the access chain are immutable temporaries,
9673 // we're not forwarded after all.
9674 if (expr.expression_dependencies.empty())
9675 forwarded_temporaries.erase(ops[1]);
9676
Hans-Kristian Arntzenbdb343e2020-04-21 14:43:26 +02009677 if (has_decoration(ops[1], DecorationNonUniformEXT))
Hans-Kristian Arntzen05004a52020-03-19 12:05:03 +01009678 propagate_nonuniform_qualifier(ops[1]);
9679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009680 break;
9681 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009683 case OpStore:
9684 {
9685 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009687 if (var && var->statically_assigned)
9688 var->static_expression = ops[1];
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01009689 else if (var && var->loop_variable && !var->loop_variable_enable)
9690 var->static_expression = ops[1];
Hans-Kristian Arntzend31bc022020-05-28 11:49:28 +02009691 else if (var && var->remapped_variable && var->static_expression)
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02009692 {
9693 // Skip the write.
9694 }
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009695 else if (flattened_structs.count(ops[0]))
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009696 {
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02009697 store_flattened_struct(ops[0], ops[1]);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01009698 register_write(ops[0]);
9699 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009700 else
9701 {
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01009702 emit_store_statement(ops[0], ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009703 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01009704
Chip Davis3bfb2f92018-12-03 02:06:33 -06009705 // Storing a pointer results in a variable pointer, so we must conservatively assume
9706 // we can write through it.
9707 if (expression_type(ops[1]).pointer)
9708 register_write(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009709 break;
9710 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009711
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009712 case OpArrayLength:
9713 {
9714 uint32_t result_type = ops[0];
9715 uint32_t id = ops[1];
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01009716 auto e = access_chain_internal(ops[2], &ops[3], length - 3, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzenb6f8a202019-05-07 19:02:32 +02009717 set<SPIRExpression>(id, join(type_to_glsl(get<SPIRType>(result_type)), "(", e, ".length())"), result_type,
9718 true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009719 break;
9720 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009721
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009722 // Function calls
9723 case OpFunctionCall:
9724 {
9725 uint32_t result_type = ops[0];
9726 uint32_t id = ops[1];
9727 uint32_t func = ops[2];
9728 const auto *arg = &ops[3];
9729 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009730
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009731 auto &callee = get<SPIRFunction>(func);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01009732 auto &return_type = get<SPIRType>(callee.return_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009733 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009735 bool callee_has_out_variables = false;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01009736 bool emit_return_value_as_argument = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009738 // Invalidate out variables passed to functions since they can be OpStore'd to.
9739 for (uint32_t i = 0; i < length; i++)
9740 {
9741 if (callee.arguments[i].write_count)
9742 {
9743 register_call_out_argument(arg[i]);
9744 callee_has_out_variables = true;
9745 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009746
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009747 flush_variable_declaration(arg[i]);
9748 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009749
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01009750 if (!return_type.array.empty() && !backend.can_return_array)
9751 {
9752 callee_has_out_variables = true;
9753 emit_return_value_as_argument = true;
9754 }
9755
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009756 if (!pure)
9757 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009758
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009759 string funexpr;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02009760 SmallVector<string> arglist;
Bill Hollings1c180782017-11-05 21:34:42 -05009761 funexpr += to_name(func) + "(";
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01009762
9763 if (emit_return_value_as_argument)
9764 {
9765 statement(type_to_glsl(return_type), " ", to_name(id), type_to_array_glsl(return_type), ";");
9766 arglist.push_back(to_name(id));
9767 }
9768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009769 for (uint32_t i = 0; i < length; i++)
9770 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02009771 // Do not pass in separate images or samplers if we're remapping
9772 // to combined image samplers.
9773 if (skip_argument(arg[i]))
9774 continue;
9775
Chip Davis39dce882019-08-02 15:11:19 -05009776 arglist.push_back(to_func_call_arg(callee.arguments[i], arg[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009777 }
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02009778
9779 for (auto &combined : callee.combined_parameters)
9780 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02009781 auto image_id = combined.global_image ? combined.image_id : VariableID(arg[combined.image_id]);
9782 auto sampler_id = combined.global_sampler ? combined.sampler_id : VariableID(arg[combined.sampler_id]);
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02009783 arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02009784 }
Bill Hollingsa759e2c2016-10-19 14:09:51 -07009785
Bill Hollingsac00c602016-10-24 09:24:24 -04009786 append_global_func_args(callee, length, arglist);
Bill Hollingsa759e2c2016-10-19 14:09:51 -07009787
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02009788 funexpr += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009789 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009790
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02009791 // Check for function call constraints.
9792 check_function_call_constraints(arg, length);
9793
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01009794 if (return_type.basetype != SPIRType::Void)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009795 {
9796 // If the function actually writes to an out variable,
9797 // take the conservative route and do not forward.
9798 // The problem is that we might not read the function
9799 // result (and emit the function) before an out variable
9800 // is read (common case when return value is ignored!
9801 // In order to avoid start tracking invalid variables,
9802 // just avoid the forwarding problem altogether.
9803 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
9804 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009805
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01009806 if (emit_return_value_as_argument)
9807 {
9808 statement(funexpr, ";");
9809 set<SPIRExpression>(id, to_name(id), result_type, true);
9810 }
9811 else
9812 emit_op(result_type, id, funexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009814 // Function calls are implicit loads from all variables in question.
9815 // Set dependencies for them.
9816 for (uint32_t i = 0; i < length; i++)
9817 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009819 // If we're going to forward the temporary result,
9820 // put dependencies on every variable that must not change.
9821 if (forward)
9822 register_global_read_dependencies(callee, id);
9823 }
9824 else
9825 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009826
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009827 break;
9828 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009829
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009830 // Composite munging
9831 case OpCompositeConstruct:
9832 {
9833 uint32_t result_type = ops[0];
9834 uint32_t id = ops[1];
Hans-Kristian Arntzen9a527132018-03-09 15:26:36 +01009835 const auto *const elems = &ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009836 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009837
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009838 bool forward = true;
9839 for (uint32_t i = 0; i < length; i++)
9840 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009841
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009842 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009843 auto *in_type = length > 0 ? &expression_type(elems[0]) : nullptr;
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02009844
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009845 // Only splat if we have vector constructors.
9846 // Arrays and structs must be initialized properly in full.
9847 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009848
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009849 bool splat = false;
9850 bool swizzle_splat = false;
9851
9852 if (in_type)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01009853 {
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009854 splat = in_type->vecsize == 1 && in_type->columns == 1 && !composite && backend.use_constructor_splatting;
9855 swizzle_splat = in_type->vecsize == 1 && in_type->columns == 1 && backend.can_swizzle_scalar;
9856
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009857 if (ir.ids[elems[0]].get_type() == TypeConstant && !type_is_floating_point(*in_type))
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009858 {
9859 // Cannot swizzle literal integers as a special case.
9860 swizzle_splat = false;
9861 }
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01009862 }
9863
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01009864 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009865 {
9866 uint32_t input = elems[0];
9867 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01009868 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009869 if (input != elems[i])
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01009870 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009871 splat = false;
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01009872 swizzle_splat = false;
9873 }
9874 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009875 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009876
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01009877 if (out_type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
9878 forward = false;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01009879 if (!out_type.array.empty() && !backend.can_declare_arrays_inline)
9880 forward = false;
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009881 if (type_is_empty(out_type) && !backend.supports_empty_struct)
9882 forward = false;
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01009883
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009884 string constructor_op;
Hans-Kristian Arntzenf6f84932019-07-10 11:19:33 +02009885 if (backend.use_initializer_list && composite)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009886 {
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009887 bool needs_trailing_tracket = false;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009888 // Only use this path if we are building composites.
9889 // This path cannot be used for arithmetic.
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02009890 if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01009891 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
Hans-Kristian Arntzenc9d4f9c2020-02-24 12:47:14 +01009892 else if (backend.use_typed_initializer_list && backend.array_is_value_type && !out_type.array.empty())
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009893 {
9894 // MSL path. Array constructor is baked into type here, do not use _constructor variant.
9895 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
9896 needs_trailing_tracket = true;
9897 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009898 constructor_op += "{ ";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009899
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009900 if (type_is_empty(out_type) && !backend.supports_empty_struct)
9901 constructor_op += "0";
9902 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02009903 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009904 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009905 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009906 constructor_op += " }";
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +02009907 if (needs_trailing_tracket)
9908 constructor_op += ")";
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009909 }
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01009910 else if (swizzle_splat && !composite)
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01009911 {
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02009912 constructor_op = remap_swizzle(get<SPIRType>(result_type), 1, to_unpacked_expression(elems[0]));
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01009913 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009914 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009915 {
9916 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02009917 if (type_is_empty(out_type) && !backend.supports_empty_struct)
9918 constructor_op += "0";
9919 else if (splat)
Hans-Kristian Arntzen07e95012019-10-11 11:21:43 +02009920 constructor_op += to_unpacked_expression(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009921 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01009922 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009923 constructor_op += ")";
9924 }
9925
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +02009926 if (!constructor_op.empty())
9927 {
9928 emit_op(result_type, id, constructor_op, forward);
9929 for (uint32_t i = 0; i < length; i++)
9930 inherit_expression_dependencies(id, elems[i]);
9931 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009932 break;
9933 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009934
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009935 case OpVectorInsertDynamic:
9936 {
9937 uint32_t result_type = ops[0];
9938 uint32_t id = ops[1];
9939 uint32_t vec = ops[2];
9940 uint32_t comp = ops[3];
9941 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009942
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009943 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009944
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009945 // Make a copy, then use access chain to store the variable.
9946 statement(declare_temporary(result_type, id), to_expression(vec), ";");
9947 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009948 auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +02009949 statement(chain, " = ", to_unpacked_expression(comp), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009950 break;
9951 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009952
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009953 case OpVectorExtractDynamic:
9954 {
9955 uint32_t result_type = ops[0];
9956 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009957
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01009958 auto expr = access_chain_internal(ops[2], &ops[3], 1, 0, nullptr);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01009959 emit_op(result_type, id, expr, should_forward(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01009960 inherit_expression_dependencies(id, ops[2]);
9961 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009962 break;
9963 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009964
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009965 case OpCompositeExtract:
9966 {
9967 uint32_t result_type = ops[0];
9968 uint32_t id = ops[1];
9969 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009970
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009971 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009972
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02009973 // We can only split the expression here if our expression is forwarded as a temporary.
9974 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
9975
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01009976 // Do not allow base expression for struct members. We risk doing "swizzle" optimizations in this case.
9977 auto &composite_type = expression_type(ops[2]);
Hans-Kristian Arntzen3fac2892017-11-22 12:07:37 +01009978 if (composite_type.basetype == SPIRType::Struct || !composite_type.array.empty())
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01009979 allow_base_expression = false;
9980
Hans-Kristian Arntzenc7b75a82020-04-07 18:22:14 +02009981 // Packed expressions or physical ID mapped expressions cannot be split up.
9982 if (has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypePacked) ||
9983 has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypeID))
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01009984 allow_base_expression = false;
9985
Hans-Kristian Arntzen7ff2db42019-08-27 11:41:54 +02009986 // Cannot use base expression for row-major matrix row-extraction since we need to interleave access pattern
9987 // into the base expression.
9988 if (is_non_native_row_major_matrix(ops[2]))
9989 allow_base_expression = false;
9990
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01009991 AccessChainMeta meta;
9992 SPIRExpression *e = nullptr;
9993
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009994 // Only apply this optimization if result is scalar.
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02009995 if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009996 {
9997 // We want to split the access chain from the base.
9998 // This is so we can later combine different CompositeExtract results
9999 // with CompositeConstruct without emitting code like
10000 //
10001 // vec3 temp = texture(...).xyz
10002 // vec4(temp.x, temp.y, temp.z, 1.0).
10003 //
10004 // when we actually wanted to emit this
10005 // vec4(texture(...).xyz, 1.0).
10006 //
10007 // Including the base will prevent this and would trigger multiple reads
10008 // from expression causing it to be forced to an actual temporary in GLSL.
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010009 auto expr = access_chain_internal(ops[2], &ops[3], length,
10010 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_CHAIN_ONLY_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010011 e = &emit_op(result_type, id, expr, true, should_suppress_usage_tracking(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010012 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010013 e->base_expression = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010014 }
10015 else
10016 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010017 auto expr = access_chain_internal(ops[2], &ops[3], length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010018 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 +010010019 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010020 }
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010021
10022 // Pass through some meta information to the loaded expression.
10023 // We can still end up loading a buffer type to a variable, then CompositeExtract from it
10024 // instead of loading everything through an access chain.
10025 e->need_transpose = meta.need_transpose;
10026 if (meta.storage_is_packed)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010027 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
10028 if (meta.storage_physical_type != 0)
10029 set_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID, meta.storage_physical_type);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +010010030 if (meta.storage_is_invariant)
10031 set_decoration(id, DecorationInvariant);
10032
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010033 break;
10034 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010036 case OpCompositeInsert:
10037 {
10038 uint32_t result_type = ops[0];
10039 uint32_t id = ops[1];
10040 uint32_t obj = ops[2];
10041 uint32_t composite = ops[3];
10042 const auto *elems = &ops[4];
10043 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010044
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010045 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010046
David Srbecky77b5b442017-06-26 18:32:53 +010010047 // Make a copy, then use access chain to store the variable.
10048 statement(declare_temporary(result_type, id), to_expression(composite), ";");
10049 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +010010050 auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +020010051 statement(chain, " = ", to_unpacked_expression(obj), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010052
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010053 break;
10054 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010055
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010056 case OpCopyMemory:
10057 {
10058 uint32_t lhs = ops[0];
10059 uint32_t rhs = ops[1];
10060 if (lhs != rhs)
10061 {
10062 flush_variable_declaration(lhs);
10063 flush_variable_declaration(rhs);
Hans-Kristian Arntzen3360daa2020-09-02 10:27:39 +020010064 statement(to_expression(lhs), " = ", to_unpacked_expression(rhs), ";");
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010065 register_write(lhs);
10066 }
10067 break;
10068 }
10069
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010010070 case OpCopyLogical:
10071 {
10072 // This is used for copying object of different types, arrays and structs.
10073 // We need to unroll the copy, element-by-element.
10074 uint32_t result_type = ops[0];
10075 uint32_t id = ops[1];
10076 uint32_t rhs = ops[2];
10077
10078 emit_uninitialized_temporary_expression(result_type, id);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010010079 emit_copy_logical_type(id, result_type, rhs, expression_type_id(rhs), {});
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010010080 break;
10081 }
10082
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010083 case OpCopyObject:
10084 {
10085 uint32_t result_type = ops[0];
10086 uint32_t id = ops[1];
10087 uint32_t rhs = ops[2];
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010088 bool pointer = get<SPIRType>(result_type).pointer;
10089
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010090 auto *chain = maybe_get<SPIRAccessChain>(rhs);
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010091 auto *imgsamp = maybe_get<SPIRCombinedImageSampler>(rhs);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010092 if (chain)
10093 {
10094 // Cannot lower to a SPIRExpression, just copy the object.
10095 auto &e = set<SPIRAccessChain>(id, *chain);
10096 e.self = id;
10097 }
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010098 else if (imgsamp)
10099 {
10100 // Cannot lower to a SPIRExpression, just copy the object.
10101 // GLSL does not currently use this type and will never get here, but MSL does.
Bill Hollings7f67abe2020-10-30 16:05:44 -040010102 // Handled here instead of CompilerMSL for better integration and general handling,
Bill Hollingsb7b0e802020-10-29 18:50:42 -040010103 // and in case GLSL or other subclasses require it in the future.
10104 auto &e = set<SPIRCombinedImageSampler>(id, *imgsamp);
10105 e.self = id;
10106 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010107 else if (expression_is_lvalue(rhs) && !pointer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010108 {
10109 // Need a copy.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010110 // For pointer types, we copy the pointer itself.
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010111 statement(declare_temporary(result_type, id), to_unpacked_expression(rhs), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010112 set<SPIRExpression>(id, to_name(id), result_type, true);
10113 }
10114 else
10115 {
10116 // RHS expression is immutable, so just forward it.
10117 // Copying these things really make no sense, but
10118 // seems to be allowed anyways.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010119 auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
10120 if (pointer)
10121 {
10122 auto *var = maybe_get_backing_variable(rhs);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010123 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +010010124 }
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010125
10126 // If we're copying an access chain, need to inherit the read expressions.
10127 auto *rhs_expr = maybe_get<SPIRExpression>(rhs);
10128 if (rhs_expr)
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010129 {
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020010130 e.implied_read_expressions = rhs_expr->implied_read_expressions;
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020010131 e.expression_dependencies = rhs_expr->expression_dependencies;
10132 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010133 }
10134 break;
10135 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010136
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010137 case OpVectorShuffle:
10138 {
10139 uint32_t result_type = ops[0];
10140 uint32_t id = ops[1];
10141 uint32_t vec0 = ops[2];
10142 uint32_t vec1 = ops[3];
10143 const auto *elems = &ops[4];
10144 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010145
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010146 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010147
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010148 // If we have the undefined swizzle index -1, we need to swizzle in undefined data,
10149 // or in our case, T(0).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010150 bool shuffle = false;
10151 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010152 if (elems[i] >= type0.vecsize || elems[i] == 0xffffffffu)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010153 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010154
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010155 // Cannot use swizzles with packed expressions, force shuffle path.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020010156 if (!shuffle && has_extended_decoration(vec0, SPIRVCrossDecorationPhysicalTypePacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010157 shuffle = true;
10158
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010159 string expr;
Bill Hollings1845f312017-12-31 18:55:04 -050010160 bool should_fwd, trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010161
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010162 if (shuffle)
10163 {
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +010010164 should_fwd = should_forward(vec0) && should_forward(vec1);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010165 trivial_forward = should_suppress_usage_tracking(vec0) && should_suppress_usage_tracking(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010166
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010167 // Constructor style and shuffling from two different vectors.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020010168 SmallVector<string> args;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010169 for (uint32_t i = 0; i < length; i++)
10170 {
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010171 if (elems[i] == 0xffffffffu)
10172 {
10173 // Use a constant 0 here.
10174 // We could use the first component or similar, but then we risk propagating
10175 // a value we might not need, and bog down codegen.
10176 SPIRConstant c;
10177 c.constant_type = type0.parent_type;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020010178 assert(type0.parent_type != ID(0));
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010179 args.push_back(constant_expression(c));
10180 }
10181 else if (elems[i] >= type0.vecsize)
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010182 args.push_back(to_extract_component_expression(vec1, elems[i] - type0.vecsize));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010183 else
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +020010184 args.push_back(to_extract_component_expression(vec0, elems[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010185 }
10186 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
10187 }
10188 else
10189 {
Bill Hollings1845f312017-12-31 18:55:04 -050010190 should_fwd = should_forward(vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010191 trivial_forward = should_suppress_usage_tracking(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010193 // We only source from first vector, so can use swizzle.
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010194 // If the vector is packed, unpack it before applying a swizzle (needed for MSL)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +020010195 expr += to_enclosed_unpacked_expression(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010196 expr += ".";
10197 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010198 {
10199 assert(elems[i] != 0xffffffffu);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010200 expr += index_to_swizzle(elems[i]);
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +010010201 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -050010202
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010203 if (backend.swizzle_is_function && length > 1)
10204 expr += "()";
10205 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010207 // A shuffle is trivial in that it doesn't actually *do* anything.
10208 // 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 +010010209
Bill Hollings1845f312017-12-31 18:55:04 -050010210 emit_op(result_type, id, expr, should_fwd, trivial_forward);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010211
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010212 inherit_expression_dependencies(id, vec0);
Hans-Kristian Arntzen18bcc9b2019-07-23 19:14:13 +020010213 if (vec0 != vec1)
10214 inherit_expression_dependencies(id, vec1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010215 break;
10216 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010218 // ALU
10219 case OpIsNan:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010220 GLSL_UFOP(isnan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010221 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010222
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010223 case OpIsInf:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010224 GLSL_UFOP(isinf);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010225 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010226
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010227 case OpSNegate:
10228 case OpFNegate:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010229 GLSL_UOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010230 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010232 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010233 {
10234 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
10235 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010236 GLSL_BOP_CAST(+, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010237 break;
10238 }
10239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010240 case OpFAdd:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010241 GLSL_BOP(+);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010242 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010243
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010244 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010245 {
10246 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010247 GLSL_BOP_CAST(-, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010248 break;
10249 }
10250
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010251 case OpFSub:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010252 GLSL_BOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010253 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010254
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010255 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010256 {
10257 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010258 GLSL_BOP_CAST(*, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010259 break;
10260 }
10261
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010262 case OpVectorTimesMatrix:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010263 case OpMatrixTimesVector:
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010264 {
10265 // If the matrix needs transpose, just flip the multiply order.
10266 auto *e = maybe_get<SPIRExpression>(ops[opcode == OpMatrixTimesVector ? 2 : 3]);
10267 if (e && e->need_transpose)
10268 {
10269 e->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010270 string expr;
10271
10272 if (opcode == OpMatrixTimesVector)
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020010273 expr = join(to_enclosed_unpacked_expression(ops[3]), " * ",
10274 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010275 else
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020010276 expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
10277 to_enclosed_unpacked_expression(ops[2]));
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010278
10279 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
10280 emit_op(ops[0], ops[1], expr, forward);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010281 e->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010282 inherit_expression_dependencies(ops[1], ops[2]);
10283 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010010284 }
10285 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010286 GLSL_BOP(*);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010287 break;
10288 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010289
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010290 case OpMatrixTimesMatrix:
10291 {
10292 auto *a = maybe_get<SPIRExpression>(ops[2]);
10293 auto *b = maybe_get<SPIRExpression>(ops[3]);
10294
10295 // If both matrices need transpose, we can multiply in flipped order and tag the expression as transposed.
10296 // a^T * b^T = (b * a)^T.
10297 if (a && b && a->need_transpose && b->need_transpose)
10298 {
10299 a->need_transpose = false;
10300 b->need_transpose = false;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010301 auto expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), " * ",
10302 enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])));
10303 bool forward = should_forward(ops[2]) && should_forward(ops[3]);
10304 auto &e = emit_op(ops[0], ops[1], expr, forward);
10305 e.need_transpose = true;
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010306 a->need_transpose = true;
10307 b->need_transpose = true;
Hans-Kristian Arntzen7277c7a2019-07-23 11:36:54 +020010308 inherit_expression_dependencies(ops[1], ops[2]);
10309 inherit_expression_dependencies(ops[1], ops[3]);
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +020010310 }
10311 else
10312 GLSL_BOP(*);
10313
10314 break;
10315 }
10316
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010317 case OpFMul:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010318 case OpMatrixTimesScalar:
10319 case OpVectorTimesScalar:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010320 GLSL_BOP(*);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010321 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010323 case OpOuterProduct:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010324 GLSL_BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010325 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010326
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010327 case OpDot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010328 GLSL_BFOP(dot);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010329 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010330
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010331 case OpTranspose:
rdbbf719942020-11-05 17:09:33 +010010332 if (options.version < 120) // Matches GLSL 1.10 / ESSL 1.00
10333 {
10334 // transpose() is not available, so instead, flip need_transpose,
10335 // which can later be turned into an emulated transpose op by
10336 // convert_row_major_matrix(), if necessary.
10337 uint32_t result_type = ops[0];
10338 uint32_t result_id = ops[1];
10339 uint32_t input = ops[2];
10340
10341 // Force need_transpose to false temporarily to prevent
10342 // to_expression() from doing the transpose.
10343 bool need_transpose = false;
10344 auto *input_e = maybe_get<SPIRExpression>(input);
10345 if (input_e)
10346 swap(need_transpose, input_e->need_transpose);
10347
10348 bool forward = should_forward(input);
10349 auto &e = emit_op(result_type, result_id, to_expression(input), forward);
10350 e.need_transpose = !need_transpose;
10351
10352 // Restore the old need_transpose flag.
10353 if (input_e)
10354 input_e->need_transpose = need_transpose;
10355 }
10356 else
10357 GLSL_UFOP(transpose);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010358 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010359
Jin Zhoue792cd62018-05-22 00:44:34 -040010360 case OpSRem:
Jin Zhou6b144cc2018-05-24 01:17:47 -040010361 {
10362 uint32_t result_type = ops[0];
10363 uint32_t result_id = ops[1];
10364 uint32_t op0 = ops[2];
10365 uint32_t op1 = ops[3];
10366
10367 // Needs special handling.
10368 bool forward = should_forward(op0) && should_forward(op1);
10369 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
10370 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
10371
10372 emit_op(result_type, result_id, expr, forward);
10373 inherit_expression_dependencies(result_id, op0);
10374 inherit_expression_dependencies(result_id, op1);
Jin Zhoue792cd62018-05-22 00:44:34 -040010375 break;
Jin Zhou6b144cc2018-05-24 01:17:47 -040010376 }
Jin Zhoue792cd62018-05-22 00:44:34 -040010377
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010378 case OpSDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010379 GLSL_BOP_CAST(/, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010380 break;
10381
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010382 case OpUDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010383 GLSL_BOP_CAST(/, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010384 break;
10385
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010386 case OpIAddCarry:
10387 case OpISubBorrow:
10388 {
10389 if (options.es && options.version < 310)
10390 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
10391 else if (!options.es && options.version < 400)
10392 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 400.");
10393
10394 uint32_t result_type = ops[0];
10395 uint32_t result_id = ops[1];
10396 uint32_t op0 = ops[2];
10397 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010398 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010399 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010400 const char *op = opcode == OpIAddCarry ? "uaddCarry" : "usubBorrow";
10401
10402 statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", op, "(", to_expression(op0), ", ",
10403 to_expression(op1), ", ", to_expression(result_id), ".", to_member_name(type, 1), ");");
10404 break;
10405 }
10406
10407 case OpUMulExtended:
10408 case OpSMulExtended:
10409 {
10410 if (options.es && options.version < 310)
10411 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
10412 else if (!options.es && options.version < 400)
10413 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 4000.");
10414
10415 uint32_t result_type = ops[0];
10416 uint32_t result_id = ops[1];
10417 uint32_t op0 = ops[2];
10418 uint32_t op1 = ops[3];
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010419 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenbf07e5f2019-04-09 11:50:45 +020010420 emit_uninitialized_temporary_expression(result_type, result_id);
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +010010421 const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended";
10422
10423 statement(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(result_id), ".",
10424 to_member_name(type, 1), ", ", to_expression(result_id), ".", to_member_name(type, 0), ");");
10425 break;
10426 }
10427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010428 case OpFDiv:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010429 GLSL_BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010430 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010432 case OpShiftRightLogical:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010433 GLSL_BOP_CAST(>>, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010434 break;
10435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010436 case OpShiftRightArithmetic:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010437 GLSL_BOP_CAST(>>, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010438 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010440 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020010441 {
10442 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010443 GLSL_BOP_CAST(<<, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010444 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +020010445 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010446
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010447 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010448 {
10449 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010450 GLSL_BOP_CAST(|, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010451 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010452 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010453
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010454 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010455 {
10456 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +010010457 GLSL_BOP_CAST(^, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010458 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010459 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010460
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010461 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010462 {
10463 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010464 GLSL_BOP_CAST(&, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010465 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010466 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010467
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010468 case OpNot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010469 GLSL_UOP(~);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010470 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010471
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010472 case OpUMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010473 GLSL_BOP_CAST(%, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010474 break;
10475
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010476 case OpSMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010477 GLSL_BOP_CAST(%, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010478 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010479
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010480 case OpFMod:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010481 GLSL_BFOP(mod);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010482 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +020010483
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010010484 case OpFRem:
10485 {
10486 if (is_legacy())
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010010487 SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is "
10488 "needed for legacy.");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010010489
10490 uint32_t result_type = ops[0];
10491 uint32_t result_id = ops[1];
10492 uint32_t op0 = ops[2];
10493 uint32_t op1 = ops[3];
10494
10495 // Needs special handling.
10496 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +010010497 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
10498 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +010010499
10500 emit_op(result_type, result_id, expr, forward);
10501 inherit_expression_dependencies(result_id, op0);
10502 inherit_expression_dependencies(result_id, op1);
10503 break;
10504 }
10505
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010506 // Relational
10507 case OpAny:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010508 GLSL_UFOP(any);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010509 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010510
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010511 case OpAll:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010512 GLSL_UFOP(all);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010513 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010514
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010515 case OpSelect:
10516 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
10517 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010518
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010519 case OpLogicalOr:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010520 {
10521 // No vector variant in GLSL for logical OR.
10522 auto result_type = ops[0];
10523 auto id = ops[1];
10524 auto &type = get<SPIRType>(result_type);
10525
10526 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020010527 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010528 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010529 GLSL_BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010530 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010531 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010532
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010533 case OpLogicalAnd:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010534 {
10535 // No vector variant in GLSL for logical AND.
10536 auto result_type = ops[0];
10537 auto id = ops[1];
10538 auto &type = get<SPIRType>(result_type);
10539
10540 if (type.vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +020010541 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&", false, SPIRType::Unknown);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010542 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010543 GLSL_BOP(&&);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010544 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010545 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010547 case OpLogicalNot:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010548 {
10549 auto &type = get<SPIRType>(ops[0]);
10550 if (type.vecsize > 1)
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010010551 GLSL_UFOP(not );
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010552 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010553 GLSL_UOP(!);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010554 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +010010555 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010557 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010558 {
10559 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010560 GLSL_BFOP_CAST(equal, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010561 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010562 GLSL_BOP_CAST(==, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010563 break;
10564 }
10565
10566 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010567 case OpFOrdEqual:
10568 {
10569 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010570 GLSL_BFOP(equal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010571 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010572 GLSL_BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010573 break;
10574 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010576 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010577 {
10578 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010579 GLSL_BFOP_CAST(notEqual, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010580 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +010010581 GLSL_BOP_CAST(!=, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010582 break;
10583 }
10584
10585 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010586 case OpFOrdNotEqual:
10587 {
10588 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010589 GLSL_BFOP(notEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010590 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010591 GLSL_BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010592 break;
10593 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010595 case OpUGreaterThan:
10596 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010597 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020010598 auto type = opcode == OpUGreaterThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010599 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010600 GLSL_BFOP_CAST(greaterThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010601 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010602 GLSL_BOP_CAST(>, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010603 break;
10604 }
10605
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010606 case OpFOrdGreaterThan:
10607 {
10608 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010609 GLSL_BFOP(greaterThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010610 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010611 GLSL_BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010612 break;
10613 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010614
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010615 case OpUGreaterThanEqual:
10616 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010617 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020010618 auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010619 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010620 GLSL_BFOP_CAST(greaterThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010621 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010622 GLSL_BOP_CAST(>=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010623 break;
10624 }
10625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010626 case OpFOrdGreaterThanEqual:
10627 {
10628 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010629 GLSL_BFOP(greaterThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010630 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010631 GLSL_BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010632 break;
10633 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010634
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010635 case OpULessThan:
10636 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010637 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020010638 auto type = opcode == OpULessThan ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010639 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010640 GLSL_BFOP_CAST(lessThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010641 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010642 GLSL_BOP_CAST(<, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010643 break;
10644 }
10645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010646 case OpFOrdLessThan:
10647 {
10648 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010649 GLSL_BFOP(lessThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010650 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010651 GLSL_BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010652 break;
10653 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010655 case OpULessThanEqual:
10656 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010657 {
Hans-Kristian Arntzen3bf9fa72019-10-14 15:23:38 +020010658 auto type = opcode == OpULessThanEqual ? uint_type : int_type;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010659 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010660 GLSL_BFOP_CAST(lessThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010661 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010662 GLSL_BOP_CAST(<=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +020010663 break;
10664 }
10665
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010666 case OpFOrdLessThanEqual:
10667 {
10668 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010669 GLSL_BFOP(lessThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010670 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010671 GLSL_BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010672 break;
10673 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010675 // Conversion
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020010676 case OpSConvert:
10677 case OpConvertSToF:
10678 case OpUConvert:
10679 case OpConvertUToF:
10680 {
10681 auto input_type = opcode == OpSConvert || opcode == OpConvertSToF ? int_type : uint_type;
10682 uint32_t result_type = ops[0];
10683 uint32_t id = ops[1];
10684
10685 auto &type = get<SPIRType>(result_type);
10686 auto &arg_type = expression_type(ops[2]);
10687 auto func = type_to_glsl_constructor(type);
10688
Hans-Kristian Arntzen4edb99d2019-11-28 13:49:53 +010010689 if (arg_type.width < type.width || type_is_floating_point(type))
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020010690 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), input_type, type.basetype);
10691 else
10692 emit_unary_func_op(result_type, id, ops[2], func.c_str());
10693 break;
10694 }
10695
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010696 case OpConvertFToU:
10697 case OpConvertFToS:
Hans-Kristian Arntzen9ae91c22019-04-10 11:33:52 +020010698 {
10699 // Cast to expected arithmetic type, then potentially bitcast away to desired signedness.
10700 uint32_t result_type = ops[0];
10701 uint32_t id = ops[1];
10702 auto &type = get<SPIRType>(result_type);
10703 auto expected_type = type;
10704 auto &float_type = expression_type(ops[2]);
10705 expected_type.basetype =
10706 opcode == OpConvertFToS ? to_signed_basetype(type.width) : to_unsigned_basetype(type.width);
10707
10708 auto func = type_to_glsl_constructor(expected_type);
10709 emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), float_type.basetype, expected_type.basetype);
10710 break;
10711 }
10712
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010713 case OpFConvert:
10714 {
10715 uint32_t result_type = ops[0];
10716 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010717
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010718 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
10719 emit_unary_func_op(result_type, id, ops[2], func.c_str());
10720 break;
10721 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010723 case OpBitcast:
10724 {
10725 uint32_t result_type = ops[0];
10726 uint32_t id = ops[1];
10727 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010728
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +020010729 if (!emit_complex_bitcast(result_type, id, arg))
10730 {
10731 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
10732 emit_unary_func_op(result_type, id, arg, op.c_str());
10733 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010734 break;
10735 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010736
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020010737 case OpQuantizeToF16:
10738 {
10739 uint32_t result_type = ops[0];
10740 uint32_t id = ops[1];
10741 uint32_t arg = ops[2];
10742
10743 string op;
10744 auto &type = get<SPIRType>(result_type);
10745
10746 switch (type.vecsize)
10747 {
10748 case 1:
10749 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
10750 break;
10751 case 2:
10752 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
10753 break;
10754 case 3:
10755 {
10756 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
10757 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
10758 op = join("vec3(", op0, ", ", op1, ")");
10759 break;
10760 }
10761 case 4:
10762 {
10763 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
10764 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
10765 op = join("vec4(", op0, ", ", op1, ")");
10766 break;
10767 }
10768 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010769 SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020010770 }
10771
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010010772 emit_op(result_type, id, op, should_forward(arg));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010773 inherit_expression_dependencies(id, arg);
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +020010774 break;
10775 }
10776
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010777 // Derivatives
10778 case OpDPdx:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010779 GLSL_UFOP(dFdx);
Lubos Lenco80c39412016-09-17 14:33:16 +020010780 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010781 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010782 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010783 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010784
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010785 case OpDPdy:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010786 GLSL_UFOP(dFdy);
Lubos Lenco80c39412016-09-17 14:33:16 +020010787 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010788 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010789 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010790 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010791
Robert Konrad9ec9dd02017-03-24 13:59:19 +010010792 case OpDPdxFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010793 GLSL_UFOP(dFdxFine);
Robert Konradcb637db2017-03-24 15:58:54 +010010794 if (options.es)
10795 {
10796 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
10797 }
10798 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010799 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010800 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010010801 break;
10802
10803 case OpDPdyFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010804 GLSL_UFOP(dFdyFine);
Robert Konradcb637db2017-03-24 15:58:54 +010010805 if (options.es)
10806 {
10807 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
10808 }
10809 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010810 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010811 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010010812 break;
10813
10814 case OpDPdxCoarse:
Robert Konradcb637db2017-03-24 15:58:54 +010010815 if (options.es)
10816 {
10817 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
10818 }
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010819 GLSL_UFOP(dFdxCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010010820 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010821 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010822 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010010823 break;
10824
10825 case OpDPdyCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010826 GLSL_UFOP(dFdyCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +010010827 if (options.es)
10828 {
10829 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
10830 }
10831 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010832 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010833 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +010010834 break;
10835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010836 case OpFwidth:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010837 GLSL_UFOP(fwidth);
Lubos Lenco80c39412016-09-17 14:33:16 +020010838 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010839 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010840 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010841 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010842
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010010843 case OpFwidthCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010844 GLSL_UFOP(fwidthCoarse);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010010845 if (options.es)
10846 {
10847 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
10848 }
10849 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010850 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010851 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010010852 break;
10853
10854 case OpFwidthFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010855 GLSL_UFOP(fwidthFine);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010010856 if (options.es)
10857 {
10858 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
10859 }
10860 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020010861 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010862 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +010010863 break;
10864
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010865 // Bitfield
10866 case OpBitFieldInsert:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020010867 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020010868 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 +020010869 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020010870 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010871
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010872 case OpBitFieldSExtract:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020010873 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020010874 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 +020010875 SPIRType::Int, SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010876 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020010877 }
10878
10879 case OpBitFieldUExtract:
10880 {
Hans-Kristian Arntzen3ccfbce2019-08-28 14:25:26 +020010881 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 +020010882 SPIRType::Int, SPIRType::Int);
10883 break;
10884 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010885
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010886 case OpBitReverse:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020010887 // BitReverse does not have issues with sign since result type must match input type.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020010888 GLSL_UFOP(bitfieldReverse);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010889 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010890
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010891 case OpBitCount:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020010892 {
10893 auto basetype = expression_type(ops[2]).basetype;
10894 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "bitCount", basetype, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010895 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +020010896 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010897
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010898 // Atomics
10899 case OpAtomicExchange:
10900 {
10901 uint32_t result_type = ops[0];
10902 uint32_t id = ops[1];
10903 uint32_t ptr = ops[2];
10904 // Ignore semantics for now, probably only relevant to CL.
10905 uint32_t val = ops[5];
10906 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
10907 forced_temporaries.insert(id);
10908 emit_binary_func_op(result_type, id, ptr, val, op);
10909 flush_all_atomic_capable_variables();
10910 break;
10911 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010912
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010913 case OpAtomicCompareExchange:
10914 {
10915 uint32_t result_type = ops[0];
10916 uint32_t id = ops[1];
10917 uint32_t ptr = ops[2];
10918 uint32_t val = ops[6];
10919 uint32_t comp = ops[7];
10920 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010921
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010922 forced_temporaries.insert(id);
10923 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
10924 flush_all_atomic_capable_variables();
10925 break;
10926 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010927
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010928 case OpAtomicLoad:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010929 {
10930 // In plain GLSL, we have no atomic loads, so emulate this by fetch adding by 0 and hope compiler figures it out.
10931 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
10932 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen8b236f22019-04-24 09:31:44 +020010933 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010934 bool atomic_image = check_atomic_image(ops[2]);
10935 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
10936 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
10937 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
10938 const char *increment = unsigned_type ? "0u" : "0";
10939 emit_op(ops[0], ops[1], join(op, "(", to_expression(ops[2]), ", ", increment, ")"), false);
10940 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010941 break;
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010942 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010943
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010010944 case OpAtomicStore:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +020010945 {
10946 // In plain GLSL, we have no atomic stores, so emulate this with an atomic exchange where we don't consume the result.
10947 // Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
10948 uint32_t ptr = ops[0];
10949 // Ignore semantics for now, probably only relevant to CL.
10950 uint32_t val = ops[3];
10951 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
10952 statement(op, "(", to_expression(ptr), ", ", to_expression(val), ");");
10953 flush_all_atomic_capable_variables();
10954 break;
10955 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010956
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010957 case OpAtomicIIncrement:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010958 case OpAtomicIDecrement:
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020010959 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010960 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020010961 auto &type = expression_type(ops[2]);
10962 if (type.storage == StorageClassAtomicCounter)
10963 {
10964 // Legacy GLSL stuff, not sure if this is relevant to support.
10965 if (opcode == OpAtomicIIncrement)
10966 GLSL_UFOP(atomicCounterIncrement);
10967 else
10968 GLSL_UFOP(atomicCounterDecrement);
10969 }
10970 else
10971 {
10972 bool atomic_image = check_atomic_image(ops[2]);
10973 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
10974 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
10975 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
10976
10977 const char *increment = nullptr;
10978 if (opcode == OpAtomicIIncrement && unsigned_type)
10979 increment = "1u";
10980 else if (opcode == OpAtomicIIncrement)
10981 increment = "1";
10982 else if (unsigned_type)
10983 increment = "uint(-1)";
10984 else
10985 increment = "-1";
10986
10987 emit_op(ops[0], ops[1], join(op, "(", to_expression(ops[2]), ", ", increment, ")"), false);
10988 }
10989
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010990 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010991 break;
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +020010992 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010993
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010994 case OpAtomicIAdd:
10995 {
10996 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
10997 forced_temporaries.insert(ops[1]);
10998 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
10999 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011000 break;
11001 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011002
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011003 case OpAtomicISub:
11004 {
11005 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
11006 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011007 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_enclosed_expression(ops[5]), ")");
11008 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011009 flush_all_atomic_capable_variables();
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 case OpAtomicSMin:
11014 case OpAtomicUMin:
11015 {
11016 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
11017 forced_temporaries.insert(ops[1]);
11018 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
11019 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011020 break;
11021 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011022
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011023 case OpAtomicSMax:
11024 case OpAtomicUMax:
11025 {
11026 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
11027 forced_temporaries.insert(ops[1]);
11028 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
11029 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011030 break;
11031 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011032
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011033 case OpAtomicAnd:
11034 {
11035 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
11036 forced_temporaries.insert(ops[1]);
11037 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
11038 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011039 break;
11040 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011042 case OpAtomicOr:
11043 {
11044 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
11045 forced_temporaries.insert(ops[1]);
11046 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
11047 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011048 break;
11049 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011050
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011051 case OpAtomicXor:
11052 {
11053 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
11054 forced_temporaries.insert(ops[1]);
11055 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
11056 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011057 break;
11058 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011059
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011060 // Geometry shaders
11061 case OpEmitVertex:
11062 statement("EmitVertex();");
11063 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011065 case OpEndPrimitive:
11066 statement("EndPrimitive();");
11067 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011068
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011069 case OpEmitStreamVertex:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011070 {
11071 if (options.es)
11072 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
11073 else if (!options.es && options.version < 400)
11074 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
11075
11076 auto stream_expr = to_expression(ops[0]);
11077 if (expression_type(ops[0]).basetype != SPIRType::Int)
11078 stream_expr = join("int(", stream_expr, ")");
11079 statement("EmitStreamVertex(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011080 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011081 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011082
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011083 case OpEndStreamPrimitive:
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011084 {
11085 if (options.es)
11086 SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES.");
11087 else if (!options.es && options.version < 400)
11088 SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400.");
11089
11090 auto stream_expr = to_expression(ops[0]);
11091 if (expression_type(ops[0]).basetype != SPIRType::Int)
11092 stream_expr = join("int(", stream_expr, ")");
11093 statement("EndStreamPrimitive(", stream_expr, ");");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011094 break;
Hans-Kristian Arntzend7e612f2019-12-09 10:45:44 +010011095 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011096
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011097 // Textures
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011098 case OpImageSampleExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011099 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011100 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011101 case OpImageSampleProjDrefExplicitLod:
Lubos Lenco80c39412016-09-17 14:33:16 +020011102 case OpImageSampleImplicitLod:
11103 case OpImageSampleProjImplicitLod:
11104 case OpImageSampleDrefImplicitLod:
11105 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011106 case OpImageFetch:
11107 case OpImageGather:
11108 case OpImageDrefGather:
11109 // Gets a bit hairy, so move this to a separate instruction.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011110 emit_texture_op(instruction, false);
11111 break;
11112
11113 case OpImageSparseSampleExplicitLod:
11114 case OpImageSparseSampleProjExplicitLod:
11115 case OpImageSparseSampleDrefExplicitLod:
11116 case OpImageSparseSampleProjDrefExplicitLod:
11117 case OpImageSparseSampleImplicitLod:
11118 case OpImageSparseSampleProjImplicitLod:
11119 case OpImageSparseSampleDrefImplicitLod:
11120 case OpImageSparseSampleProjDrefImplicitLod:
11121 case OpImageSparseFetch:
11122 case OpImageSparseGather:
11123 case OpImageSparseDrefGather:
11124 // Gets a bit hairy, so move this to a separate instruction.
11125 emit_texture_op(instruction, true);
11126 break;
11127
11128 case OpImageSparseTexelsResident:
11129 if (options.es)
11130 SPIRV_CROSS_THROW("Sparse feedback is not supported in GLSL.");
11131 require_extension_internal("GL_ARB_sparse_texture2");
Hans-Kristian Arntzen857e1c42020-06-08 11:40:02 +020011132 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "sparseTexelsResidentARB", int_type, SPIRType::Boolean);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011133 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011134
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011135 case OpImage:
11136 {
11137 uint32_t result_type = ops[0];
11138 uint32_t id = ops[1];
Hans-Kristian Arntzenaaf397c2018-04-27 11:10:10 +020011139
11140 // Suppress usage tracking.
11141 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011142
11143 // When using the image, we need to know which variable it is actually loaded from.
11144 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020011145 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011146 break;
11147 }
11148
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011149 case OpImageQueryLod:
11150 {
11151 if (!options.es && options.version < 400)
11152 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011153 require_extension_internal("GL_ARB_texture_query_lod");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011154 // For some reason, the ARB spec is all-caps.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011155 GLSL_BFOP(textureQueryLOD);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011156 }
11157 else if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011158 SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011159 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +020011160 GLSL_BFOP(textureQueryLod);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011161 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +020011162 break;
11163 }
11164
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011165 case OpImageQueryLevels:
11166 {
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011167 uint32_t result_type = ops[0];
11168 uint32_t id = ops[1];
11169
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011170 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011171 require_extension_internal("GL_ARB_texture_query_levels");
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011172 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011173 SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011174
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020011175 auto expr = join("textureQueryLevels(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +020011176 auto &restype = get<SPIRType>(ops[0]);
11177 expr = bitcast_expression(restype, SPIRType::Int, expr);
11178 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +020011179 break;
11180 }
11181
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011182 case OpImageQuerySamples:
11183 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011184 auto &type = expression_type(ops[2]);
11185 uint32_t result_type = ops[0];
11186 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011187
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011188 string expr;
11189 if (type.image.sampled == 2)
11190 expr = join("imageSamples(", to_expression(ops[2]), ")");
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011191 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +020011192 expr = join("textureSamples(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011193
11194 auto &restype = get<SPIRType>(ops[0]);
11195 expr = bitcast_expression(restype, SPIRType::Int, expr);
11196 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011197 break;
11198 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011199
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011200 case OpSampledImage:
11201 {
11202 uint32_t result_type = ops[0];
11203 uint32_t id = ops[1];
11204 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020011205 inherit_expression_dependencies(id, ops[2]);
11206 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011207 break;
11208 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +020011209
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011210 case OpImageQuerySizeLod:
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011211 {
11212 uint32_t result_type = ops[0];
11213 uint32_t id = ops[1];
rdb10fa5f62020-11-09 15:26:46 +010011214 uint32_t img = ops[2];
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011215
rdb10fa5f62020-11-09 15:26:46 +010011216 std::string fname = "textureSize";
11217 if (is_legacy_desktop())
11218 {
11219 auto &type = expression_type(img);
11220 auto &imgtype = get<SPIRType>(type.self);
11221 fname = legacy_tex_op(fname, imgtype, img);
11222 }
11223 else if (is_legacy_es())
11224 SPIRV_CROSS_THROW("textureSize is not supported in ESSL 100.");
11225
11226 auto expr = join(fname, "(", convert_separate_image_to_expression(img), ", ",
Hans-Kristian Arntzen7e23e692018-04-30 12:46:21 +020011227 bitcast_expression(SPIRType::Int, ops[3]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011228 auto &restype = get<SPIRType>(ops[0]);
11229 expr = bitcast_expression(restype, SPIRType::Int, expr);
11230 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011231 break;
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011232 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011233
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011234 // Image load/store
11235 case OpImageRead:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011236 case OpImageSparseRead:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011237 {
11238 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
11239 // not adding the proper qualifiers.
11240 // If it turns out we need to read the image after all, remove the qualifier and recompile.
11241 auto *var = maybe_get_backing_variable(ops[2]);
11242 if (var)
11243 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010011244 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011245 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011246 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011247 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011248 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011249 }
11250 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011252 uint32_t result_type = ops[0];
11253 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011254
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011255 bool pure;
11256 string imgexpr;
11257 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011258
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011259 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011260 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011261 if (type.image.ms)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011262 SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011263
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +020011264 auto itr =
11265 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 +010011266
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011267 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011268 {
11269 // For non-PLS inputs, we rely on subpass type remapping information to get it right
11270 // since ImageRead always returns 4-component vectors and the backing type is opaque.
11271 if (!var->remapped_components)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011272 SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011273 imgexpr = remap_swizzle(get<SPIRType>(result_type), var->remapped_components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011274 }
11275 else
11276 {
11277 // PLS input could have different number of components than what the SPIR expects, swizzle to
11278 // the appropriate vector size.
11279 uint32_t components = pls_format_to_components(itr->format);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011280 imgexpr = remap_swizzle(get<SPIRType>(result_type), components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011281 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011282 pure = true;
11283 }
11284 else if (type.image.dim == DimSubpassData)
11285 {
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010011286 if (var && subpass_input_is_framebuffer_fetch(var->self))
11287 {
11288 imgexpr = to_expression(var->self);
11289 }
11290 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011291 {
11292 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011293 if (type.image.ms)
11294 {
11295 uint32_t operands = ops[4];
11296 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011297 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11298 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011299
11300 uint32_t samples = ops[5];
11301 imgexpr = join("subpassLoad(", to_expression(ops[2]), ", ", to_expression(samples), ")");
11302 }
11303 else
11304 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011305 }
11306 else
11307 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011308 if (type.image.ms)
11309 {
11310 uint32_t operands = ops[4];
11311 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011312 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11313 "operand mask was used.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020011314
11315 uint32_t samples = ops[5];
11316 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
11317 to_expression(samples), ")");
11318 }
11319 else
11320 {
11321 // Implement subpass loads via texture barrier style sampling.
11322 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
11323 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020011324 }
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011325 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011326 pure = true;
11327 }
11328 else
11329 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011330 bool sparse = opcode == OpImageSparseRead;
11331 uint32_t sparse_code_id = 0;
11332 uint32_t sparse_texel_id = 0;
11333 if (sparse)
11334 emit_sparse_feedback_temporaries(ops[0], ops[1], sparse_code_id, sparse_texel_id);
11335
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010011336 // imageLoad only accepts int coords, not uint.
11337 auto coord_expr = to_expression(ops[3]);
11338 auto target_coord_type = expression_type(ops[3]);
11339 target_coord_type.basetype = SPIRType::Int;
11340 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
11341
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011342 // Plain image load/store.
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011343 if (sparse)
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011344 {
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011345 if (type.image.ms)
11346 {
11347 uint32_t operands = ops[4];
11348 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011349 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11350 "operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011351
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011352 uint32_t samples = ops[5];
11353 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_expression(ops[2]), ", ",
11354 coord_expr, ", ", to_expression(samples), ", ", to_expression(sparse_texel_id), ");");
11355 }
11356 else
11357 {
11358 statement(to_expression(sparse_code_id), " = sparseImageLoadARB(", to_expression(ops[2]), ", ",
11359 coord_expr, ", ", to_expression(sparse_texel_id), ");");
11360 }
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020011361 imgexpr = join(type_to_glsl(get<SPIRType>(result_type)), "(", to_expression(sparse_code_id), ", ",
11362 to_expression(sparse_texel_id), ")");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011363 }
11364 else
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011365 {
11366 if (type.image.ms)
11367 {
11368 uint32_t operands = ops[4];
11369 if (operands != ImageOperandsSampleMask || length != 6)
crissdb52e272020-10-08 12:14:52 +020011370 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected "
11371 "operand mask was used.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011372
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +020011373 uint32_t samples = ops[5];
11374 imgexpr =
11375 join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ", ", to_expression(samples), ")");
11376 }
11377 else
11378 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ")");
11379 }
11380
11381 if (!sparse)
11382 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011383 pure = false;
11384 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011385
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011386 if (var && var->forwardable)
11387 {
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010011388 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
11389 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011390
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011391 // We only need to track dependencies if we're reading from image load/store.
11392 if (!pure)
11393 {
11394 e.loaded_from = var->self;
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +010011395 if (forward)
11396 var->dependees.push_back(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011397 }
11398 }
11399 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +010011400 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010011401
11402 inherit_expression_dependencies(id, ops[2]);
11403 if (type.image.ms)
11404 inherit_expression_dependencies(id, ops[5]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011405 break;
11406 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011407
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011408 case OpImageTexelPointer:
11409 {
11410 uint32_t result_type = ops[0];
11411 uint32_t id = ops[1];
Mark Satterthwaitec4f97042019-08-26 11:28:13 -040011412
11413 auto coord_expr = to_expression(ops[3]);
11414 auto target_coord_type = expression_type(ops[3]);
11415 target_coord_type.basetype = SPIRType::Int;
11416 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
11417
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +010011418 auto expr = join(to_expression(ops[2]), ", ", coord_expr);
11419 if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
11420 convert_non_uniform_expression(expression_type(ops[2]), expr);
11421
11422 auto &e = set<SPIRExpression>(id, expr, result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011423
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020011424 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011425 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020011426 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen6edbf0c2019-10-24 11:30:20 +020011427 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011428 break;
11429 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011430
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011431 case OpImageWrite:
11432 {
11433 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
11434 // not adding the proper qualifiers.
11435 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
11436 auto *var = maybe_get_backing_variable(ops[0]);
11437 if (var)
11438 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010011439 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011440 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011441 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010011442 flags.clear(DecorationNonWritable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011443 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011444 }
11445 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011446
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011447 auto &type = expression_type(ops[0]);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011448 auto &value_type = expression_type(ops[2]);
11449 auto store_type = value_type;
11450 store_type.vecsize = 4;
11451
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010011452 // imageStore only accepts int coords, not uint.
11453 auto coord_expr = to_expression(ops[1]);
11454 auto target_coord_type = expression_type(ops[1]);
11455 target_coord_type.basetype = SPIRType::Int;
11456 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
11457
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011458 if (type.image.ms)
11459 {
11460 uint32_t operands = ops[3];
11461 if (operands != ImageOperandsSampleMask || length != 5)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011462 SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011463 uint32_t samples = ops[4];
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010011464 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ", to_expression(samples), ", ",
11465 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +020011466 }
11467 else
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +010011468 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ",
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +020011469 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011470
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011471 if (var && variable_storage_is_aliased(*var))
11472 flush_all_aliased_variables();
11473 break;
11474 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011475
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011476 case OpImageQuerySize:
11477 {
11478 auto &type = expression_type(ops[2]);
11479 uint32_t result_type = ops[0];
11480 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011481
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011482 if (type.basetype == SPIRType::Image)
11483 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011484 string expr;
11485 if (type.image.sampled == 2)
11486 {
rdb10fa5f62020-11-09 15:26:46 +010011487 if (!options.es && options.version < 430)
11488 require_extension_internal("GL_ARB_shader_image_size");
11489 else if (options.es && options.version < 310)
11490 SPIRV_CROSS_THROW("At least ESSL 3.10 required for imageSize.");
11491
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011492 // The size of an image is always constant.
11493 expr = join("imageSize(", to_expression(ops[2]), ")");
11494 }
11495 else
11496 {
11497 // This path is hit for samplerBuffers and multisampled images which do not have LOD.
rdb10fa5f62020-11-09 15:26:46 +010011498 std::string fname = "textureSize";
11499 if (is_legacy())
11500 {
11501 auto &imgtype = get<SPIRType>(type.self);
11502 fname = legacy_tex_op(fname, imgtype, ops[2]);
11503 }
11504 expr = join(fname, "(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +020011505 }
11506
11507 auto &restype = get<SPIRType>(ops[0]);
11508 expr = bitcast_expression(restype, SPIRType::Int, expr);
11509 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011510 }
11511 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011512 SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011513 break;
11514 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011516 // Compute
11517 case OpControlBarrier:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011518 case OpMemoryBarrier:
11519 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011520 uint32_t execution_scope = 0;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011521 uint32_t memory;
11522 uint32_t semantics;
11523
11524 if (opcode == OpMemoryBarrier)
11525 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020011526 memory = evaluate_constant_u32(ops[0]);
11527 semantics = evaluate_constant_u32(ops[1]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011528 }
11529 else
11530 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020011531 execution_scope = evaluate_constant_u32(ops[0]);
11532 memory = evaluate_constant_u32(ops[1]);
11533 semantics = evaluate_constant_u32(ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011534 }
11535
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011536 if (execution_scope == ScopeSubgroup || memory == ScopeSubgroup)
11537 {
crissdb52e272020-10-08 12:14:52 +020011538 // OpControlBarrier with ScopeSubgroup is subgroupBarrier()
11539 if (opcode != OpControlBarrier)
11540 {
11541 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupMemBarrier);
11542 }
11543 else
11544 {
11545 request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupBarrier);
11546 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011547 }
11548
11549 if (execution_scope != ScopeSubgroup && get_entry_point().model == ExecutionModelTessellationControl)
11550 {
11551 // Control shaders only have barriers, and it implies memory barriers.
11552 if (opcode == OpControlBarrier)
11553 statement("barrier();");
11554 break;
11555 }
11556
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011557 // We only care about these flags, acquire/release and friends are not relevant to GLSL.
11558 semantics = mask_relevant_memory_semantics(semantics);
11559
11560 if (opcode == OpMemoryBarrier)
11561 {
11562 // If we are a memory barrier, and the next instruction is a control barrier, check if that memory barrier
11563 // does what we need, so we avoid redundant barriers.
11564 const Instruction *next = get_next_instruction_in_block(instruction);
11565 if (next && next->op == OpControlBarrier)
11566 {
11567 auto *next_ops = stream(*next);
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020011568 uint32_t next_memory = evaluate_constant_u32(next_ops[1]);
11569 uint32_t next_semantics = evaluate_constant_u32(next_ops[2]);
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011570 next_semantics = mask_relevant_memory_semantics(next_semantics);
11571
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010011572 bool memory_scope_covered = false;
11573 if (next_memory == memory)
11574 memory_scope_covered = true;
11575 else if (next_semantics == MemorySemanticsWorkgroupMemoryMask)
11576 {
11577 // If we only care about workgroup memory, either Device or Workgroup scope is fine,
11578 // scope does not have to match.
11579 if ((next_memory == ScopeDevice || next_memory == ScopeWorkgroup) &&
11580 (memory == ScopeDevice || memory == ScopeWorkgroup))
11581 {
11582 memory_scope_covered = true;
11583 }
11584 }
11585 else if (memory == ScopeWorkgroup && next_memory == ScopeDevice)
11586 {
11587 // The control barrier has device scope, but the memory barrier just has workgroup scope.
11588 memory_scope_covered = true;
11589 }
11590
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011591 // If we have the same memory scope, and all memory types are covered, we're good.
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +010011592 if (memory_scope_covered && (semantics & next_semantics) == semantics)
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011593 break;
11594 }
11595 }
11596
11597 // We are synchronizing some memory or syncing execution,
11598 // so we cannot forward any loads beyond the memory barrier.
11599 if (semantics || opcode == OpControlBarrier)
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011600 {
11601 assert(current_emitting_block);
11602 flush_control_dependent_expressions(current_emitting_block->self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011603 flush_all_active_variables();
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011604 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011605
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011606 if (memory == ScopeWorkgroup) // Only need to consider memory within a group
11607 {
11608 if (semantics == MemorySemanticsWorkgroupMemoryMask)
Hans-Kristian Arntzen67b29912019-12-04 15:06:19 +010011609 {
11610 // OpControlBarrier implies a memory barrier for shared memory as well.
11611 bool implies_shared_barrier = opcode == OpControlBarrier && execution_scope == ScopeWorkgroup;
11612 if (!implies_shared_barrier)
11613 statement("memoryBarrierShared();");
11614 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011615 else if (semantics != 0)
11616 statement("groupMemoryBarrier();");
11617 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011618 else if (memory == ScopeSubgroup)
11619 {
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +020011620 const uint32_t all_barriers =
11621 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011622
11623 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
11624 {
11625 // These are not relevant for GLSL, but assume it means memoryBarrier().
11626 // memoryBarrier() does everything, so no need to test anything else.
11627 statement("subgroupMemoryBarrier();");
11628 }
11629 else if ((semantics & all_barriers) == all_barriers)
11630 {
11631 // Short-hand instead of emitting 3 barriers.
11632 statement("subgroupMemoryBarrier();");
11633 }
11634 else
11635 {
11636 // Pick out individual barriers.
11637 if (semantics & MemorySemanticsWorkgroupMemoryMask)
11638 statement("subgroupMemoryBarrierShared();");
11639 if (semantics & MemorySemanticsUniformMemoryMask)
11640 statement("subgroupMemoryBarrierBuffer();");
11641 if (semantics & MemorySemanticsImageMemoryMask)
11642 statement("subgroupMemoryBarrierImage();");
11643 }
11644 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011645 else
11646 {
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010011647 const uint32_t all_barriers =
11648 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011649
11650 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
11651 {
11652 // These are not relevant for GLSL, but assume it means memoryBarrier().
11653 // memoryBarrier() does everything, so no need to test anything else.
11654 statement("memoryBarrier();");
11655 }
11656 else if ((semantics & all_barriers) == all_barriers)
11657 {
11658 // Short-hand instead of emitting 4 barriers.
11659 statement("memoryBarrier();");
11660 }
11661 else
11662 {
11663 // Pick out individual barriers.
11664 if (semantics & MemorySemanticsWorkgroupMemoryMask)
11665 statement("memoryBarrierShared();");
11666 if (semantics & MemorySemanticsUniformMemoryMask)
11667 statement("memoryBarrierBuffer();");
11668 if (semantics & MemorySemanticsImageMemoryMask)
11669 statement("memoryBarrierImage();");
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011670 }
11671 }
11672
11673 if (opcode == OpControlBarrier)
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011674 {
11675 if (execution_scope == ScopeSubgroup)
11676 statement("subgroupBarrier();");
11677 else
11678 statement("barrier();");
11679 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011680 break;
11681 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011683 case OpExtInst:
11684 {
11685 uint32_t extension_set = ops[2];
Lou Kramer6671f522017-11-21 14:04:57 +010011686
11687 if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011688 {
Lou Kramer6671f522017-11-21 14:04:57 +010011689 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
11690 }
11691 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_ballot)
11692 {
11693 emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
11694 }
11695 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
11696 {
11697 emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
11698 }
11699 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_trinary_minmax)
11700 {
11701 emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
11702 }
11703 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_gcn_shader)
11704 {
11705 emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
11706 }
Lifeng Pan5ca87792019-07-04 16:03:06 +080011707 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_debug_info)
11708 {
11709 break; // Ignore SPIR-V debug information extended instructions.
11710 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010011711 else
11712 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011713 statement("// unimplemented ext op ", instruction.op);
11714 break;
11715 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011716
Lou Kramer6671f522017-11-21 14:04:57 +010011717 break;
11718 }
11719
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011720 // Legacy sub-group stuff ...
Lou Kramer6671f522017-11-21 14:04:57 +010011721 case OpSubgroupBallotKHR:
11722 {
Lou Kramer6671f522017-11-21 14:04:57 +010011723 uint32_t result_type = ops[0];
11724 uint32_t id = ops[1];
11725 string expr;
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011726 expr = join("uvec4(unpackUint2x32(ballotARB(" + to_expression(ops[2]) + ")), 0u, 0u)");
Hans-Kristian Arntzen4979d102018-03-12 17:51:14 +010011727 emit_op(result_type, id, expr, should_forward(ops[2]));
Lou Kramer6671f522017-11-21 14:04:57 +010011728
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011729 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzenae2680c2018-03-12 17:42:48 +010011730 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011731 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011732 break;
11733 }
11734
11735 case OpSubgroupFirstInvocationKHR:
11736 {
Lou Kramer6671f522017-11-21 14:04:57 +010011737 uint32_t result_type = ops[0];
11738 uint32_t id = ops[1];
11739 emit_unary_func_op(result_type, id, ops[2], "readFirstInvocationARB");
11740
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011741 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011742 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011743 break;
11744 }
11745
11746 case OpSubgroupReadInvocationKHR:
11747 {
Lou Kramer6671f522017-11-21 14:04:57 +010011748 uint32_t result_type = ops[0];
11749 uint32_t id = ops[1];
11750 emit_binary_func_op(result_type, id, ops[2], ops[3], "readInvocationARB");
11751
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011752 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011753 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011754 break;
11755 }
11756
11757 case OpSubgroupAllKHR:
11758 {
Lou Kramer6671f522017-11-21 14:04:57 +010011759 uint32_t result_type = ops[0];
11760 uint32_t id = ops[1];
11761 emit_unary_func_op(result_type, id, ops[2], "allInvocationsARB");
11762
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011763 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011764 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011765 break;
11766 }
11767
11768 case OpSubgroupAnyKHR:
11769 {
Lou Kramer6671f522017-11-21 14:04:57 +010011770 uint32_t result_type = ops[0];
11771 uint32_t id = ops[1];
11772 emit_unary_func_op(result_type, id, ops[2], "anyInvocationARB");
11773
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011774 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011775 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011776 break;
11777 }
11778
11779 case OpSubgroupAllEqualKHR:
11780 {
Lou Kramer6671f522017-11-21 14:04:57 +010011781 uint32_t result_type = ops[0];
11782 uint32_t id = ops[1];
11783 emit_unary_func_op(result_type, id, ops[2], "allInvocationsEqualARB");
11784
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011785 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011786 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011787 break;
11788 }
11789
11790 case OpGroupIAddNonUniformAMD:
11791 case OpGroupFAddNonUniformAMD:
11792 {
Lou Kramer6671f522017-11-21 14:04:57 +010011793 uint32_t result_type = ops[0];
11794 uint32_t id = ops[1];
11795 emit_unary_func_op(result_type, id, ops[4], "addInvocationsNonUniformAMD");
11796
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011797 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011798 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011799 break;
11800 }
11801
11802 case OpGroupFMinNonUniformAMD:
11803 case OpGroupUMinNonUniformAMD:
11804 case OpGroupSMinNonUniformAMD:
11805 {
Lou Kramer6671f522017-11-21 14:04:57 +010011806 uint32_t result_type = ops[0];
11807 uint32_t id = ops[1];
11808 emit_unary_func_op(result_type, id, ops[4], "minInvocationsNonUniformAMD");
11809
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011810 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011811 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011812 break;
11813 }
11814
11815 case OpGroupFMaxNonUniformAMD:
11816 case OpGroupUMaxNonUniformAMD:
11817 case OpGroupSMaxNonUniformAMD:
11818 {
Lou Kramer6671f522017-11-21 14:04:57 +010011819 uint32_t result_type = ops[0];
11820 uint32_t id = ops[1];
11821 emit_unary_func_op(result_type, id, ops[4], "maxInvocationsNonUniformAMD");
11822
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011823 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010011824 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +010011825 break;
11826 }
11827
11828 case OpFragmentMaskFetchAMD:
11829 {
11830 auto &type = expression_type(ops[2]);
11831 uint32_t result_type = ops[0];
11832 uint32_t id = ops[1];
11833
11834 if (type.image.dim == spv::DimSubpassData)
11835 {
11836 emit_unary_func_op(result_type, id, ops[2], "fragmentMaskFetchAMD");
11837 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010011838 else
Lou Kramer6671f522017-11-21 14:04:57 +010011839 {
11840 emit_binary_func_op(result_type, id, ops[2], ops[3], "fragmentMaskFetchAMD");
11841 }
11842
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011843 require_extension_internal("GL_AMD_shader_fragment_mask");
Lou Kramer6671f522017-11-21 14:04:57 +010011844 break;
11845 }
11846
11847 case OpFragmentFetchAMD:
11848 {
11849 auto &type = expression_type(ops[2]);
11850 uint32_t result_type = ops[0];
11851 uint32_t id = ops[1];
11852
11853 if (type.image.dim == spv::DimSubpassData)
11854 {
11855 emit_binary_func_op(result_type, id, ops[2], ops[4], "fragmentFetchAMD");
11856 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010011857 else
Lou Kramer6671f522017-11-21 14:04:57 +010011858 {
11859 emit_trinary_func_op(result_type, id, ops[2], ops[3], ops[4], "fragmentFetchAMD");
11860 }
11861
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020011862 require_extension_internal("GL_AMD_shader_fragment_mask");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011863 break;
11864 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011865
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011866 // Vulkan 1.1 sub-group stuff ...
11867 case OpGroupNonUniformElect:
11868 case OpGroupNonUniformBroadcast:
11869 case OpGroupNonUniformBroadcastFirst:
11870 case OpGroupNonUniformBallot:
11871 case OpGroupNonUniformInverseBallot:
11872 case OpGroupNonUniformBallotBitExtract:
11873 case OpGroupNonUniformBallotBitCount:
11874 case OpGroupNonUniformBallotFindLSB:
11875 case OpGroupNonUniformBallotFindMSB:
11876 case OpGroupNonUniformShuffle:
11877 case OpGroupNonUniformShuffleXor:
11878 case OpGroupNonUniformShuffleUp:
11879 case OpGroupNonUniformShuffleDown:
11880 case OpGroupNonUniformAll:
11881 case OpGroupNonUniformAny:
11882 case OpGroupNonUniformAllEqual:
11883 case OpGroupNonUniformFAdd:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020011884 case OpGroupNonUniformIAdd:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011885 case OpGroupNonUniformFMul:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020011886 case OpGroupNonUniformIMul:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011887 case OpGroupNonUniformFMin:
11888 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +020011889 case OpGroupNonUniformSMin:
11890 case OpGroupNonUniformSMax:
11891 case OpGroupNonUniformUMin:
11892 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011893 case OpGroupNonUniformBitwiseAnd:
11894 case OpGroupNonUniformBitwiseOr:
11895 case OpGroupNonUniformBitwiseXor:
11896 case OpGroupNonUniformQuadSwap:
11897 case OpGroupNonUniformQuadBroadcast:
11898 emit_subgroup_op(instruction);
11899 break;
11900
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011901 case OpFUnordEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011902 case OpFUnordNotEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011903 case OpFUnordLessThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011904 case OpFUnordGreaterThan:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011905 case OpFUnordLessThanEqual:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011906 case OpFUnordGreaterThanEqual:
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020011907 {
11908 // GLSL doesn't specify if floating point comparisons are ordered or unordered,
11909 // but glslang always emits ordered floating point compares for GLSL.
11910 // To get unordered compares, we can test the opposite thing and invert the result.
11911 // This way, we force true when there is any NaN present.
11912 uint32_t op0 = ops[2];
11913 uint32_t op1 = ops[3];
11914
11915 string expr;
11916 if (expression_type(op0).vecsize > 1)
11917 {
11918 const char *comp_op = nullptr;
11919 switch (opcode)
11920 {
11921 case OpFUnordEqual:
11922 comp_op = "notEqual";
11923 break;
11924
11925 case OpFUnordNotEqual:
11926 comp_op = "equal";
11927 break;
11928
11929 case OpFUnordLessThan:
11930 comp_op = "greaterThanEqual";
11931 break;
11932
11933 case OpFUnordLessThanEqual:
11934 comp_op = "greaterThan";
11935 break;
11936
11937 case OpFUnordGreaterThan:
11938 comp_op = "lessThanEqual";
11939 break;
11940
11941 case OpFUnordGreaterThanEqual:
11942 comp_op = "lessThan";
11943 break;
11944
11945 default:
11946 assert(0);
11947 break;
11948 }
11949
11950 expr = join("not(", comp_op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), "))");
11951 }
11952 else
11953 {
11954 const char *comp_op = nullptr;
11955 switch (opcode)
11956 {
11957 case OpFUnordEqual:
11958 comp_op = " != ";
11959 break;
11960
11961 case OpFUnordNotEqual:
11962 comp_op = " == ";
11963 break;
11964
11965 case OpFUnordLessThan:
11966 comp_op = " >= ";
11967 break;
11968
11969 case OpFUnordLessThanEqual:
11970 comp_op = " > ";
11971 break;
11972
11973 case OpFUnordGreaterThan:
11974 comp_op = " <= ";
11975 break;
11976
11977 case OpFUnordGreaterThanEqual:
11978 comp_op = " < ";
11979 break;
11980
11981 default:
11982 assert(0);
11983 break;
11984 }
11985
11986 expr = join("!(", to_enclosed_unpacked_expression(op0), comp_op, to_enclosed_unpacked_expression(op1), ")");
11987 }
11988
11989 emit_op(ops[0], ops[1], expr, should_forward(op0) && should_forward(op1));
11990 inherit_expression_dependencies(ops[1], op0);
11991 inherit_expression_dependencies(ops[1], op1);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011992 break;
Hans-Kristian Arntzen14a4b082019-10-14 13:48:22 +020011993 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +020011994
Patrick Moursda39a7b2019-02-26 15:43:03 +010011995 case OpReportIntersectionNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010011996 statement("reportIntersectionNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020011997 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010011998 break;
11999 case OpIgnoreIntersectionNV:
12000 statement("ignoreIntersectionNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012001 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012002 break;
12003 case OpTerminateRayNV:
12004 statement("terminateRayNV();");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012005 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012006 break;
12007 case OpTraceNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010012008 statement("traceNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
12009 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
12010 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
12011 to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012012 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012013 break;
12014 case OpExecuteCallableNV:
Patrick Moursc96bab02019-03-26 14:04:39 +010012015 statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020012016 flush_control_dependent_expressions(current_emitting_block->self);
Patrick Moursda39a7b2019-02-26 15:43:03 +010012017 break;
12018
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012019 case OpConvertUToPtr:
12020 {
12021 auto &type = get<SPIRType>(ops[0]);
12022 if (type.storage != StorageClassPhysicalStorageBufferEXT)
12023 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertUToPtr.");
12024
12025 auto op = type_to_glsl(type);
12026 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
12027 break;
12028 }
12029
12030 case OpConvertPtrToU:
12031 {
12032 auto &type = get<SPIRType>(ops[0]);
12033 auto &ptr_type = expression_type(ops[2]);
12034 if (ptr_type.storage != StorageClassPhysicalStorageBufferEXT)
12035 SPIRV_CROSS_THROW("Only StorageClassPhysicalStorageBufferEXT is supported by OpConvertPtrToU.");
12036
12037 auto op = type_to_glsl(type);
12038 emit_unary_func_op(ops[0], ops[1], ops[2], op.c_str());
12039 break;
12040 }
12041
lifpan876627d2019-04-08 19:45:31 +080012042 case OpUndef:
12043 // Undefined value has been declared.
12044 break;
12045
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020012046 case OpLine:
12047 {
12048 emit_line_directive(ops[0], ops[1]);
12049 break;
12050 }
12051
Lifeng Pan5ca87792019-07-04 16:03:06 +080012052 case OpNoLine:
12053 break;
12054
Chip Davis50dce102019-07-13 15:57:33 -050012055 case OpDemoteToHelperInvocationEXT:
12056 if (!options.vulkan_semantics)
12057 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
12058 require_extension_internal("GL_EXT_demote_to_helper_invocation");
12059 statement(backend.demote_literal, ";");
12060 break;
12061
12062 case OpIsHelperInvocationEXT:
12063 if (!options.vulkan_semantics)
12064 SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL.");
12065 require_extension_internal("GL_EXT_demote_to_helper_invocation");
Chip Davis12a86542019-07-18 17:32:35 -050012066 emit_op(ops[0], ops[1], "helperInvocationEXT()", false);
Chip Davis50dce102019-07-13 15:57:33 -050012067 break;
12068
Chip Davis2eff4202019-08-04 00:07:20 -050012069 case OpBeginInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012070 // If the interlock is complex, we emit this elsewhere.
12071 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050012072 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012073 if (options.es)
12074 statement("beginInvocationInterlockNV();");
12075 else
12076 statement("beginInvocationInterlockARB();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020012077
12078 flush_all_active_variables();
12079 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050012080 }
12081 break;
12082
12083 case OpEndInvocationInterlockEXT:
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012084 // If the interlock is complex, we emit this elsewhere.
12085 if (!interlocked_is_complex)
Chip Davis2eff4202019-08-04 00:07:20 -050012086 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020012087 if (options.es)
12088 statement("endInvocationInterlockNV();");
12089 else
12090 statement("endInvocationInterlockARB();");
Hans-Kristian Arntzen1dc7e932019-09-04 12:33:20 +020012091
12092 flush_all_active_variables();
12093 // Make sure forwarding doesn't propagate outside interlock region.
Chip Davis2eff4202019-08-04 00:07:20 -050012094 }
12095 break;
12096
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012097 default:
12098 statement("// unimplemented op ", instruction.op);
12099 break;
12100 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012101}
12102
Bill Hollingsa759e2c2016-10-19 14:09:51 -070012103// Appends function arguments, mapped from global variables, beyond the specified arg index.
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012104// This is used when a function call uses fewer arguments than the function defines.
Bill Hollingsa759e2c2016-10-19 14:09:51 -070012105// This situation may occur if the function signature has been dynamically modified to
12106// extract global variables referenced from within the function, and convert them to
12107// function arguments. This is necessary for shader languages that do not support global
12108// access to shader input content from within a function (eg. Metal). Each additional
12109// function args uses the name of the global variable. Function nesting will modify the
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012110// functions and function calls all the way up the nesting chain.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020012111void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<string> &arglist)
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012112{
Bill Hollingsac00c602016-10-24 09:24:24 -040012113 auto &args = func.arguments;
Bill Hollings943191a2016-10-27 10:20:01 -040012114 uint32_t arg_cnt = uint32_t(args.size());
Bill Hollingsac00c602016-10-24 09:24:24 -040012115 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010012116 {
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012117 auto &arg = args[arg_idx];
12118 assert(arg.alias_global_variable);
Bill Hollingsfe3683e2018-01-24 15:38:17 -050012119
12120 // If the underlying variable needs to be declared
12121 // (ie. a local variable with deferred declaration), do so now.
12122 uint32_t var_id = get<SPIRVariable>(arg.id).basevariable;
12123 if (var_id)
12124 flush_variable_declaration(var_id);
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +020012125
Chip Davis39dce882019-08-02 15:11:19 -050012126 arglist.push_back(to_func_call_arg(arg, arg.id));
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +010012127 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -040012128}
12129
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012130string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
12131{
Hans-Kristian Arntzena0c13e42019-10-07 10:31:42 +020012132 if (type.type_alias != TypeID(0) &&
12133 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
12134 {
12135 return to_member_name(get<SPIRType>(type.type_alias), index);
12136 }
12137
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012138 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012139 if (index < memb.size() && !memb[index].alias.empty())
12140 return memb[index].alias;
12141 else
Hans-Kristian Arntzen1c6df1b2017-07-29 21:44:20 +020012142 return join("_m", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012143}
12144
Chip Davis3bfb2f92018-12-03 02:06:33 -060012145string CompilerGLSL::to_member_reference(uint32_t, const SPIRType &type, uint32_t index, bool)
Chip Davis3a9af962018-09-26 20:06:05 -050012146{
12147 return join(".", to_member_name(type, index));
12148}
12149
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +020012150string CompilerGLSL::to_multi_member_reference(const SPIRType &type, const SmallVector<uint32_t> &indices)
12151{
12152 string ret;
12153 auto *member_type = &type;
12154 for (auto &index : indices)
12155 {
12156 ret += join(".", to_member_name(*member_type, index));
12157 member_type = &get<SPIRType>(member_type->member_types[index]);
12158 }
12159 return ret;
12160}
12161
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012162void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
12163{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012164 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012165 if (index < memb.size() && !memb[index].alias.empty())
12166 {
12167 auto &name = memb[index].alias;
12168 if (name.empty())
12169 return;
12170
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020012171 ParsedIR::sanitize_identifier(name, true, true);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012172 update_name_cache(type.member_name_cache, name);
12173 }
12174}
12175
Bill Hollingsb332bae2017-03-01 13:07:40 -050012176// Checks whether the ID is a row_major matrix that requires conversion before use
Bill Hollings13583622016-12-14 02:12:52 -050012177bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012178{
Bill Hollings13583622016-12-14 02:12:52 -050012179 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010012180 // Legacy targets do not support row major.
12181 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050012182 return false;
12183
Hans-Kristian Arntzen120af422020-10-14 16:07:10 +020012184 auto *e = maybe_get<SPIRExpression>(id);
12185 if (e)
12186 return e->need_transpose;
12187 else
12188 return has_decoration(id, DecorationRowMajor);
Bill Hollings343677e2016-12-11 11:01:08 -050012189}
12190
Bill Hollings13583622016-12-14 02:12:52 -050012191// Checks whether the member is a row_major matrix that requires conversion before use
12192bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index)
Bill Hollings343677e2016-12-11 11:01:08 -050012193{
Bill Hollings13583622016-12-14 02:12:52 -050012194 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +010012195 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -050012196 return false;
12197
12198 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +010012199 if (!has_member_decoration(type.self, index, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -050012200 return false;
12201
12202 // Only square row-major matrices can be converted at this time.
12203 // Converting non-square matrices will require defining custom GLSL function that
12204 // swaps matrix elements while retaining the original dimensional form of the matrix.
12205 const auto mbr_type = get<SPIRType>(type.member_types[index]);
12206 if (mbr_type.columns != mbr_type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +010012207 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -050012208
12209 return true;
Bill Hollings343677e2016-12-11 11:01:08 -050012210}
12211
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020012212// Checks if we need to remap physical type IDs when declaring the type in a buffer.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020012213bool CompilerGLSL::member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const
Bill Hollingsb332bae2017-03-01 13:07:40 -050012214{
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020012215 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID);
12216}
12217
12218// Checks whether the member is in packed data type, that might need to be unpacked.
12219bool CompilerGLSL::member_is_packed_physical_type(const SPIRType &type, uint32_t index) const
12220{
12221 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
Bill Hollingsb332bae2017-03-01 13:07:40 -050012222}
12223
Bill Hollings13583622016-12-14 02:12:52 -050012224// Wraps the expression string in a function call that converts the
12225// row_major matrix result of the expression to a column_major matrix.
12226// Base implementation uses the standard library transpose() function.
12227// Subclasses may override to use a different function.
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +020012228string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t /* physical_type_id */,
12229 bool /*is_packed*/)
Bill Hollings343677e2016-12-11 11:01:08 -050012230{
12231 strip_enclosed_expression(exp_str);
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012232 if (!is_matrix(exp_type))
12233 {
12234 auto column_index = exp_str.find_last_of('[');
12235 if (column_index == string::npos)
12236 return exp_str;
12237
12238 auto column_expr = exp_str.substr(column_index);
12239 exp_str.resize(column_index);
12240
12241 auto transposed_expr = type_to_glsl_constructor(exp_type) + "(";
12242
Hans-Kristian Arntzend90eedd2019-07-24 12:14:19 +020012243 // Loading a column from a row-major matrix. Unroll the load.
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012244 for (uint32_t c = 0; c < exp_type.vecsize; c++)
12245 {
12246 transposed_expr += join(exp_str, '[', c, ']', column_expr);
12247 if (c + 1 < exp_type.vecsize)
12248 transposed_expr += ", ";
12249 }
12250
12251 transposed_expr += ")";
12252 return transposed_expr;
12253 }
rdbbf719942020-11-05 17:09:33 +010012254 else if (options.version < 120)
12255 {
12256 // GLSL 110, ES 100 do not have transpose(), so emulate it. Note that
12257 // these GLSL versions do not support non-square matrices.
12258 if (exp_type.vecsize == 2 && exp_type.columns == 2)
12259 {
12260 if (!requires_transpose_2x2)
12261 {
12262 requires_transpose_2x2 = true;
12263 force_recompile();
12264 }
12265 }
12266 else if (exp_type.vecsize == 3 && exp_type.columns == 3)
12267 {
12268 if (!requires_transpose_3x3)
12269 {
12270 requires_transpose_3x3 = true;
12271 force_recompile();
12272 }
12273 }
12274 else if (exp_type.vecsize == 4 && exp_type.columns == 4)
12275 {
12276 if (!requires_transpose_4x4)
12277 {
12278 requires_transpose_4x4 = true;
12279 force_recompile();
12280 }
12281 }
12282 else
12283 SPIRV_CROSS_THROW("Non-square matrices are not supported in legacy GLSL, cannot transpose.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010012284 return join("spvTranspose(", exp_str, ")");
rdbbf719942020-11-05 17:09:33 +010012285 }
Hans-Kristian Arntzen249f8e52019-07-22 11:13:44 +020012286 else
12287 return join("transpose(", exp_str, ")");
Bill Hollings343677e2016-12-11 11:01:08 -050012288}
12289
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020012290string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012291{
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020012292 string type_name = type_to_glsl(type, id);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +020012293 remap_variable_type_name(type, name, type_name);
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +020012294 return join(type_name, " ", name, type_to_array_glsl(type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012295}
12296
Bill Hollings484931d2017-02-28 21:44:36 -050012297// Emit a structure member. Subclasses may override to modify output,
12298// or to dynamically add a padding member if needed.
Bill Hollingsdc694272017-03-11 12:17:22 -050012299void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
msiglreithd096f5c2017-11-27 16:00:56 +010012300 const string &qualifier, uint32_t)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012301{
Bill Hollings484931d2017-02-28 21:44:36 -050012302 auto &membertype = get<SPIRType>(member_type_id);
12303
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012304 Bitset memberflags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012305 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012306 if (index < memb.size())
12307 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012308
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020012309 string qualifiers;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012310 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
12311 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012312
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020012313 if (is_block)
12314 qualifiers = to_interpolation_qualifiers(memberflags);
12315
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012316 statement(layout_for_member(type, index), qualifiers, qualifier, flags_to_qualifiers_glsl(membertype, memberflags),
Bill Hollings484931d2017-02-28 21:44:36 -050012317 variable_decl(membertype, to_member_name(type, index)), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012318}
12319
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +020012320void CompilerGLSL::emit_struct_padding_target(const SPIRType &)
12321{
12322}
12323
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012324const char *CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012325{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012326 // GL_EXT_buffer_reference variables can be marked as restrict.
12327 if (flags.get(DecorationRestrictPointerEXT))
12328 return "restrict ";
12329
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010012330 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
12331 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
12332 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
12333 type.basetype != SPIRType::Sampler)
12334 return "";
12335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012336 if (options.es)
12337 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +020012338 auto &execution = get_entry_point();
12339
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012340 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012341 {
12342 bool implied_fmediump = type.basetype == SPIRType::Float &&
12343 options.fragment.default_float_precision == Options::Mediump &&
12344 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012345
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012346 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
12347 options.fragment.default_int_precision == Options::Mediump &&
12348 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012349
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012350 return implied_fmediump || implied_imediump ? "" : "mediump ";
12351 }
12352 else
12353 {
12354 bool implied_fhighp =
12355 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
12356 execution.model == ExecutionModelFragment) ||
12357 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012358
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012359 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
12360 ((options.fragment.default_int_precision == Options::Highp &&
12361 execution.model == ExecutionModelFragment) ||
12362 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012364 return implied_fhighp || implied_ihighp ? "" : "highp ";
12365 }
12366 }
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010012367 else if (backend.allow_precision_qualifiers)
12368 {
12369 // Vulkan GLSL supports precision qualifiers, even in desktop profiles, which is convenient.
12370 // 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 +010012371 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen01080362018-05-11 10:59:29 +020012372 return "mediump ";
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +010012373 else
12374 return "";
12375 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012376 else
12377 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012378}
12379
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012380const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012381{
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020012382 auto &type = expression_type(id);
12383 bool use_precision_qualifiers = backend.allow_precision_qualifiers || options.es;
12384 if (use_precision_qualifiers && (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage))
12385 {
12386 // Force mediump for the sampler type. We cannot declare 16-bit or smaller image types.
12387 auto &result_type = get<SPIRType>(type.image.type);
12388 if (result_type.width < 32)
12389 return "mediump ";
12390 }
12391 return flags_to_qualifiers_glsl(type, ir.meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012392}
12393
12394string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
12395{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012396 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012397 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012398
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012399 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012400
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012401 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
12402 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012403
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +020012404 res += to_interpolation_qualifiers(flags);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010012405 if (var)
12406 res += to_storage_qualifiers_glsl(*var);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +010012407
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020012408 auto &type = expression_type(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012409 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
12410 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012411 if (flags.get(DecorationCoherent))
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020012412 res += "coherent ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012413 if (flags.get(DecorationRestrict))
Hans-Kristian Arntzen11dfcb62017-08-29 15:54:22 +020012414 res += "restrict ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012415 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012416 res += "readonly ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012417 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012418 res += "writeonly ";
12419 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012420
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +020012421 res += to_precision_qualifiers_glsl(id);
12422
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012423 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012424}
12425
12426string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
12427{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012428 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012429 auto &type = expression_type(arg.id);
12430 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012432 if (type.pointer)
12433 {
12434 if (arg.write_count && arg.read_count)
12435 direction = "inout ";
12436 else if (arg.write_count)
12437 direction = "out ";
12438 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012439
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +020012440 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 +010012441}
12442
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020012443string CompilerGLSL::to_initializer_expression(const SPIRVariable &var)
12444{
12445 return to_expression(var.initializer);
12446}
12447
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010012448string CompilerGLSL::to_zero_initialized_expression(uint32_t type_id)
12449{
12450#ifndef NDEBUG
12451 auto &type = get<SPIRType>(type_id);
12452 assert(type.storage == StorageClassPrivate || type.storage == StorageClassFunction ||
12453 type.storage == StorageClassGeneric);
12454#endif
12455 uint32_t id = ir.increase_bound_by(1);
12456 ir.make_constant_null(id, type_id, false);
12457 return constant_expression(get<SPIRConstant>(id));
12458}
12459
12460bool CompilerGLSL::type_can_zero_initialize(const SPIRType &type) const
12461{
12462 if (type.pointer)
12463 return false;
12464
12465 if (!type.array.empty() && options.flatten_multidimensional_arrays)
12466 return false;
12467
12468 for (auto &literal : type.array_size_literal)
12469 if (!literal)
12470 return false;
12471
12472 for (auto &memb : type.member_types)
12473 if (!type_can_zero_initialize(get<SPIRType>(memb)))
12474 return false;
12475
12476 return true;
12477}
12478
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012479string CompilerGLSL::variable_decl(const SPIRVariable &variable)
12480{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012481 // Ignore the pointer type since GLSL doesn't have pointers.
Chip Davis3bfb2f92018-12-03 02:06:33 -060012482 auto &type = get_variable_data_type(variable);
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +020012483
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +010012484 if (type.pointer_depth > 1)
12485 SPIRV_CROSS_THROW("Cannot declare pointer-to-pointer types.");
12486
Hans-Kristian Arntzenb0f7dee2017-06-17 10:56:24 +020012487 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 +020012488
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010012489 if (variable.loop_variable && variable.static_expression)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012490 {
12491 uint32_t expr = variable.static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012492 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012493 res += join(" = ", to_expression(variable.static_expression));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010012494 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
12495 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012496 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010012497 else if (variable.initializer)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012498 {
12499 uint32_t expr = variable.initializer;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020012500 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +020012501 res += join(" = ", to_initializer_expression(variable));
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010012502 else if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
12503 res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable)));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010012504 }
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010012505
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012506 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012507}
12508
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012509const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012510{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010012511 auto &flags = ir.meta[variable.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012512 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012513 return "mediump ";
12514 else
12515 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012516}
12517
12518string CompilerGLSL::pls_decl(const PlsRemap &var)
12519{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012520 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012521
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012522 SPIRType type;
12523 type.vecsize = pls_format_to_components(var.format);
12524 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012525
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012526 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
12527 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012528}
12529
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +010012530uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type) const
12531{
12532 return to_array_size_literal(type, uint32_t(type.array.size() - 1));
12533}
12534
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020012535uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t index) const
12536{
12537 assert(type.array.size() == type.array_size_literal.size());
12538
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010012539 if (type.array_size_literal[index])
12540 {
12541 return type.array[index];
12542 }
12543 else
12544 {
12545 // Use the default spec constant value.
12546 // This is the best we can do.
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +020012547 return evaluate_constant_u32(type.array[index]);
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +010012548 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020012549}
12550
12551string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index)
12552{
12553 assert(type.array.size() == type.array_size_literal.size());
12554
12555 auto &size = type.array[index];
12556 if (!type.array_size_literal[index])
12557 return to_expression(size);
12558 else if (size)
12559 return convert_to_string(size);
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020012560 else if (!backend.unsized_array_supported)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +020012561 {
12562 // For runtime-sized arrays, we can work around
12563 // lack of standard support for this by simply having
12564 // a single element array.
12565 //
12566 // Runtime length arrays must always be the last element
12567 // in an interface block.
12568 return "1";
12569 }
12570 else
12571 return "";
12572}
12573
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012574string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
12575{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012576 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
12577 {
12578 // We are using a wrapped pointer type, and we should not emit any array declarations here.
12579 return "";
12580 }
12581
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +020012582 if (type.array.empty())
12583 return "";
12584
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020012585 if (options.flatten_multidimensional_arrays)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012586 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020012587 string res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012588 res += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020012589 for (auto i = uint32_t(type.array.size()); i; i--)
12590 {
12591 res += enclose_expression(to_array_size(type, i - 1));
12592 if (i > 1)
12593 res += " * ";
12594 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012595 res += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020012596 return res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012597 }
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020012598 else
12599 {
12600 if (type.array.size() > 1)
12601 {
12602 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012603 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020012604 else if (options.es && options.version < 310)
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020012605 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
12606 "Try using --flatten-multidimensional-arrays or set "
12607 "options.flatten_multidimensional_arrays to true.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +020012608 }
12609
12610 string res;
12611 for (auto i = uint32_t(type.array.size()); i; i--)
12612 {
12613 res += "[";
12614 res += to_array_size(type, i - 1);
12615 res += "]";
12616 }
12617 return res;
12618 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012619}
12620
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020012621string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012622{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012623 auto &imagetype = get<SPIRType>(type.image.type);
12624 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012626 switch (imagetype.basetype)
12627 {
12628 case SPIRType::Int:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020012629 case SPIRType::Short:
12630 case SPIRType::SByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012631 res = "i";
12632 break;
12633 case SPIRType::UInt:
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020012634 case SPIRType::UShort:
12635 case SPIRType::UByte:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012636 res = "u";
12637 break;
12638 default:
12639 break;
12640 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012641
Hans-Kristian Arntzenc76b99b2019-06-27 15:04:22 +020012642 // For half image types, we will force mediump for the sampler, and cast to f16 after any sampling operation.
12643 // We cannot express a true half texture type in GLSL. Neither for short integer formats for that matter.
12644
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020012645 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +020012646 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010012647 else if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
12648 subpass_input_is_framebuffer_fetch(id))
12649 {
12650 SPIRType sampled_type = get<SPIRType>(type.image.type);
12651 sampled_type.vecsize = 4;
12652 return type_to_glsl(sampled_type);
12653 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +020012654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012655 // If we're emulating subpassInput with samplers, force sampler2D
12656 // so we don't have to specify format.
12657 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +020012658 {
12659 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
12660 if (type.image.dim == DimBuffer && type.image.sampled == 1)
12661 res += "sampler";
12662 else
12663 res += type.image.sampled == 2 ? "image" : "texture";
12664 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012665 else
12666 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012667
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012668 switch (type.image.dim)
12669 {
12670 case Dim1D:
12671 res += "1D";
12672 break;
12673 case Dim2D:
12674 res += "2D";
12675 break;
12676 case Dim3D:
12677 res += "3D";
12678 break;
12679 case DimCube:
12680 res += "Cube";
12681 break;
Sidney Justfbb4df32019-01-06 12:21:59 -080012682 case DimRect:
12683 if (options.es)
12684 SPIRV_CROSS_THROW("Rectangle textures are not supported on OpenGL ES.");
12685
12686 if (is_legacy_desktop())
12687 require_extension_internal("GL_ARB_texture_rectangle");
12688
12689 res += "2DRect";
12690 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012691
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012692 case DimBuffer:
12693 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012694 require_extension_internal("GL_OES_texture_buffer");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012695 else if (!options.es && options.version < 300)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012696 require_extension_internal("GL_EXT_texture_buffer_object");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012697 res += "Buffer";
12698 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012699
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012700 case DimSubpassData:
12701 res += "2D";
12702 break;
12703 default:
Sidney Justfbb4df32019-01-06 12:21:59 -080012704 SPIRV_CROSS_THROW("Only 1D, 2D, 2DRect, 3D, Buffer, InputTarget and Cube textures supported.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012705 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012706
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +020012707 if (type.image.ms)
12708 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012709 if (type.image.arrayed)
Rob Fischer21990632016-09-17 17:01:50 +090012710 {
Lubos Lenco52158642016-09-17 15:56:23 +020012711 if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012712 require_extension_internal("GL_EXT_texture_array");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012713 res += "Array";
Rob Fischer21990632016-09-17 17:01:50 +090012714 }
Hans-Kristian Arntzena3ae8612018-02-09 12:37:17 +010012715
12716 // "Shadow" state in GLSL only exists for samplers and combined image samplers.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020012717 if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) &&
12718 image_is_comparison(type, id))
12719 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012720 res += "Shadow";
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020012721 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012723 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012724}
12725
12726string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
12727{
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020012728 if (backend.use_array_constructor && type.array.size() > 1)
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020012729 {
12730 if (options.flatten_multidimensional_arrays)
crissdb52e272020-10-08 12:14:52 +020012731 SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, "
12732 "e.g. float[][]().");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020012733 else if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012734 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +020012735 else if (options.es && options.version < 310)
12736 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
12737 }
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +020012738
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012739 auto e = type_to_glsl(type);
Hans-Kristian Arntzenfa011f82019-10-26 17:57:34 +020012740 if (backend.use_array_constructor)
12741 {
12742 for (uint32_t i = 0; i < type.array.size(); i++)
12743 e += "[]";
12744 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012745 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012746}
12747
Bill Hollingsb41e1482017-05-29 20:45:05 -040012748// The optional id parameter indicates the object whose type we are trying
12749// to find the description for. It is optional. Most type descriptions do not
12750// depend on a specific object's use of that type.
12751string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012752{
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020012753 if (type.pointer && type.storage == StorageClassPhysicalStorageBufferEXT && type.basetype != SPIRType::Struct)
12754 {
12755 // Need to create a magic type name which compacts the entire type information.
12756 string name = type_to_glsl(get_pointee_type(type));
12757 for (size_t i = 0; i < type.array.size(); i++)
12758 {
12759 if (type.array_size_literal[i])
12760 name += join(type.array[i], "_");
12761 else
12762 name += join("id", type.array[i], "_");
12763 }
12764 name += "Pointer";
12765 return name;
12766 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012767
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012768 switch (type.basetype)
12769 {
12770 case SPIRType::Struct:
12771 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012772 if (backend.explicit_struct_type)
12773 return join("struct ", to_name(type.self));
12774 else
12775 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012776
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012777 case SPIRType::Image:
12778 case SPIRType::SampledImage:
Bill Hollingsb41e1482017-05-29 20:45:05 -040012779 return image_type_glsl(type, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012780
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012781 case SPIRType::Sampler:
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +020012782 // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
12783 // this distinction into the type system.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +020012784 return comparison_ids.count(id) ? "samplerShadow" : "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012785
Hans-Kristian Arntzen6b0e5582020-04-21 14:25:18 +020012786 case SPIRType::AccelerationStructure:
Patrick Moursda39a7b2019-02-26 15:43:03 +010012787 return "accelerationStructureNV";
12788
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012789 case SPIRType::Void:
12790 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012791
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012792 default:
12793 break;
12794 }
12795
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020012796 if (type.basetype == SPIRType::UInt && is_legacy())
12797 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
12798
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012799 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
12800 {
12801 switch (type.basetype)
12802 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020012803 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012804 return "bool";
Chip Davis117ccf42018-11-01 17:20:07 -050012805 case SPIRType::SByte:
12806 return backend.basic_int8_type;
12807 case SPIRType::UByte:
12808 return backend.basic_uint8_type;
12809 case SPIRType::Short:
12810 return backend.basic_int16_type;
12811 case SPIRType::UShort:
12812 return backend.basic_uint16_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012813 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050012814 return backend.basic_int_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012815 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050012816 return backend.basic_uint_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012817 case SPIRType::AtomicCounter:
12818 return "atomic_uint";
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010012819 case SPIRType::Half:
12820 return "float16_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012821 case SPIRType::Float:
12822 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020012823 case SPIRType::Double:
12824 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020012825 case SPIRType::Int64:
12826 return "int64_t";
12827 case SPIRType::UInt64:
12828 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012829 default:
12830 return "???";
12831 }
12832 }
12833 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
12834 {
12835 switch (type.basetype)
12836 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020012837 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012838 return join("bvec", type.vecsize);
Chip Davis117ccf42018-11-01 17:20:07 -050012839 case SPIRType::SByte:
12840 return join("i8vec", type.vecsize);
12841 case SPIRType::UByte:
12842 return join("u8vec", type.vecsize);
12843 case SPIRType::Short:
12844 return join("i16vec", type.vecsize);
12845 case SPIRType::UShort:
12846 return join("u16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012847 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -050012848 return join("ivec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012849 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -050012850 return join("uvec", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010012851 case SPIRType::Half:
12852 return join("f16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012853 case SPIRType::Float:
12854 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020012855 case SPIRType::Double:
12856 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020012857 case SPIRType::Int64:
12858 return join("i64vec", type.vecsize);
12859 case SPIRType::UInt64:
12860 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012861 default:
12862 return "???";
12863 }
12864 }
12865 else if (type.vecsize == type.columns) // Simple Matrix builtin
12866 {
12867 switch (type.basetype)
12868 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020012869 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012870 return join("bmat", type.vecsize);
12871 case SPIRType::Int:
12872 return join("imat", type.vecsize);
12873 case SPIRType::UInt:
12874 return join("umat", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010012875 case SPIRType::Half:
12876 return join("f16mat", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012877 case SPIRType::Float:
12878 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020012879 case SPIRType::Double:
12880 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020012881 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012882 default:
12883 return "???";
12884 }
12885 }
12886 else
12887 {
12888 switch (type.basetype)
12889 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +020012890 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012891 return join("bmat", type.columns, "x", type.vecsize);
12892 case SPIRType::Int:
12893 return join("imat", type.columns, "x", type.vecsize);
12894 case SPIRType::UInt:
12895 return join("umat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +010012896 case SPIRType::Half:
12897 return join("f16mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012898 case SPIRType::Float:
12899 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +020012900 case SPIRType::Double:
12901 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +020012902 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012903 default:
12904 return "???";
12905 }
12906 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012907}
12908
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010012909void CompilerGLSL::add_variable(unordered_set<string> &variables_primary,
12910 const unordered_set<string> &variables_secondary, string &name)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012911{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012912 if (name.empty())
12913 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012914
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020012915 ParsedIR::sanitize_underscores(name);
12916 if (ParsedIR::is_globally_reserved_identifier(name, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012917 {
12918 name.clear();
12919 return;
12920 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012921
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010012922 update_name_cache(variables_primary, variables_secondary, name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +010012923}
12924
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012925void CompilerGLSL::add_local_variable_name(uint32_t id)
12926{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010012927 add_variable(local_variable_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020012928}
12929
12930void CompilerGLSL::add_resource_name(uint32_t id)
12931{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +010012932 add_variable(resource_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012933}
12934
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +020012935void CompilerGLSL::add_header_line(const std::string &line)
12936{
12937 header_lines.push_back(line);
12938}
12939
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012940bool CompilerGLSL::has_extension(const std::string &ext) const
12941{
12942 auto itr = find(begin(forced_extensions), end(forced_extensions), ext);
12943 return itr != end(forced_extensions);
12944}
12945
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012946void CompilerGLSL::require_extension(const std::string &ext)
12947{
12948 if (!has_extension(ext))
12949 forced_extensions.push_back(ext);
12950}
12951
12952void CompilerGLSL::require_extension_internal(const string &ext)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012953{
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010012954 if (backend.supports_extensions && !has_extension(ext))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012955 {
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +010012956 forced_extensions.push_back(ext);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020012957 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012958 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012959}
12960
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020012961void CompilerGLSL::flatten_buffer_block(VariableID id)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012962{
12963 auto &var = get<SPIRVariable>(id);
12964 auto &type = get<SPIRType>(var.basetype);
12965 auto name = to_name(type.self, false);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010012966 auto &flags = ir.meta[type.self].decoration.decoration_flags;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012967
12968 if (!type.array.empty())
12969 SPIRV_CROSS_THROW(name + " is an array of UBOs.");
12970 if (type.basetype != SPIRType::Struct)
12971 SPIRV_CROSS_THROW(name + " is not a struct.");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012972 if (!flags.get(DecorationBlock))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012973 SPIRV_CROSS_THROW(name + " is not a block.");
12974 if (type.member_types.empty())
12975 SPIRV_CROSS_THROW(name + " is an empty struct.");
12976
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -080012977 flattened_buffer_blocks.insert(id);
12978}
12979
Lukas Hermanns6673a672019-10-22 11:06:16 -040012980bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) const
12981{
12982 return false; // GLSL itself does not need to translate array builtin types to non-array builtin types
12983}
12984
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012985bool CompilerGLSL::check_atomic_image(uint32_t id)
12986{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012987 auto &type = expression_type(id);
12988 if (type.storage == StorageClassImage)
12989 {
12990 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +020012991 require_extension_internal("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010012992
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012993 auto *var = maybe_get_backing_variable(id);
12994 if (var)
12995 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010012996 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012997 if (flags.get(DecorationNonWritable) || flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020012998 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010012999 flags.clear(DecorationNonWritable);
13000 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013001 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013002 }
13003 }
13004 return true;
13005 }
13006 else
13007 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013008}
13009
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013010void CompilerGLSL::add_function_overload(const SPIRFunction &func)
13011{
13012 Hasher hasher;
13013 for (auto &arg : func.arguments)
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010013014 {
13015 // Parameters can vary with pointer type or not,
13016 // but that will not change the signature in GLSL/HLSL,
13017 // so strip the pointer type before hashing.
Chip Davisfc02b3d2019-01-08 12:54:40 -060013018 uint32_t type_id = get_pointee_type_id(arg.type);
Bill Hollingse0910312018-06-24 15:06:12 -040013019 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020013020
13021 if (!combined_image_samplers.empty())
13022 {
13023 // If we have combined image samplers, we cannot really trust the image and sampler arguments
13024 // we pass down to callees, because they may be shuffled around.
13025 // Ignore these arguments, to make sure that functions need to differ in some other way
13026 // to be considered different overloads.
Bill Hollingse0910312018-06-24 15:06:12 -040013027 if (type.basetype == SPIRType::SampledImage ||
13028 (type.basetype == SPIRType::Image && type.image.sampled == 1) || type.basetype == SPIRType::Sampler)
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +020013029 {
13030 continue;
13031 }
13032 }
13033
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010013034 hasher.u32(type_id);
13035 }
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013036 uint64_t types_hash = hasher.get();
13037
13038 auto function_name = to_name(func.self);
13039 auto itr = function_overloads.find(function_name);
13040 if (itr != end(function_overloads))
13041 {
13042 // There exists a function with this name already.
13043 auto &overloads = itr->second;
13044 if (overloads.count(types_hash) != 0)
13045 {
13046 // Overload conflict, assign a new name.
13047 add_resource_name(func.self);
13048 function_overloads[to_name(func.self)].insert(types_hash);
13049 }
13050 else
13051 {
13052 // Can reuse the name.
13053 overloads.insert(types_hash);
13054 }
13055 }
13056 else
13057 {
13058 // First time we see this function name.
13059 add_resource_name(func.self);
13060 function_overloads[to_name(func.self)].insert(types_hash);
13061 }
13062}
13063
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013064void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013065{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013066 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010013067 add_function_overload(func);
13068
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013069 // Avoid shadow declarations.
13070 local_variable_names = resource_names;
13071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013072 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013073
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013074 auto &type = get<SPIRType>(func.return_type);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020013075 decl += flags_to_qualifiers_glsl(type, return_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013076 decl += type_to_glsl(type);
Hans-Kristian Arntzen9fa91f72018-02-05 09:34:54 +010013077 decl += type_to_array_glsl(type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013078 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013079
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013080 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013081 {
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +020013082 // If we need complex fallback in GLSL, we just wrap main() in a function
13083 // and interlock the entire shader ...
13084 if (interlocked_is_complex)
13085 decl += "spvMainInterlockedBody";
13086 else
13087 decl += "main";
13088
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013089 processing_entry_point = true;
13090 }
13091 else
Bill Hollings1c180782017-11-05 21:34:42 -050013092 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013094 decl += "(";
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020013095 SmallVector<string> arglist;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013096 for (auto &arg : func.arguments)
13097 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013098 // Do not pass in separate images or samplers if we're remapping
13099 // to combined image samplers.
13100 if (skip_argument(arg.id))
13101 continue;
13102
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013103 // Might change the variable name if it already exists in this function.
13104 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
13105 // to use same name for variables.
13106 // 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 +020013107 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013108
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013109 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013110
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013111 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
13112 auto *var = maybe_get<SPIRVariable>(arg.id);
13113 if (var)
13114 var->parameter = &arg;
13115 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013116
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +020013117 for (auto &arg : func.shadow_arguments)
13118 {
13119 // Might change the variable name if it already exists in this function.
13120 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
13121 // to use same name for variables.
13122 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
13123 add_local_variable_name(arg.id);
13124
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013125 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013126
13127 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
13128 auto *var = maybe_get<SPIRVariable>(arg.id);
13129 if (var)
13130 var->parameter = &arg;
13131 }
13132
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020013133 decl += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013134 decl += ")";
13135 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013136}
13137
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013138void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013139{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013140 // Avoid potential cycles.
13141 if (func.active)
13142 return;
13143 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013144
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013145 // If we depend on a function, emit that function before we emit our own function.
13146 for (auto block : func.blocks)
13147 {
13148 auto &b = get<SPIRBlock>(block);
13149 for (auto &i : b.ops)
13150 {
13151 auto ops = stream(i);
13152 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013153
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013154 if (op == OpFunctionCall)
13155 {
13156 // Recursively emit functions which are called.
13157 uint32_t id = ops[2];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013158 emit_function(get<SPIRFunction>(id), ir.meta[ops[1]].decoration.decoration_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013159 }
13160 }
13161 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013162
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020013163 if (func.entry_line.file_id != 0)
13164 emit_line_directive(func.entry_line.file_id, func.entry_line.line_literal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013165 emit_function_prototype(func, return_flags);
13166 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013167
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013168 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +020013169 emit_entry_point_declarations();
13170
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013171 current_function = &func;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013172 auto &entry_block = get<SPIRBlock>(func.entry_block);
13173
Hans-Kristian Arntzen30343f32020-02-24 13:22:52 +010013174 sort(begin(func.constant_arrays_needed_on_stack), end(func.constant_arrays_needed_on_stack));
13175 for (auto &array : func.constant_arrays_needed_on_stack)
13176 {
13177 auto &c = get<SPIRConstant>(array);
13178 auto &type = get<SPIRType>(c.constant_type);
13179 statement(variable_decl(type, join("_", array, "_array_copy")), " = ", constant_expression(c), ";");
13180 }
13181
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013182 for (auto &v : func.local_variables)
13183 {
13184 auto &var = get<SPIRVariable>(v);
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020013185 var.deferred_declaration = false;
13186
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020013187 if (var.storage == StorageClassWorkgroup)
13188 {
13189 // Special variable type which cannot have initializer,
13190 // need to be declared as standalone variables.
13191 // Comes from MSL which can push global variables as local variables in main function.
13192 add_local_variable_name(var.self);
13193 statement(variable_decl(var), ";");
13194 var.deferred_declaration = false;
13195 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020013196 else if (var.storage == StorageClassPrivate)
13197 {
13198 // These variables will not have had their CFG usage analyzed, so move it to the entry block.
13199 // Comes from MSL which can push global variables as local variables in main function.
13200 // We could just declare them right now, but we would miss out on an important initialization case which is
13201 // LUT declaration in MSL.
13202 // If we don't declare the variable when it is assigned we're forced to go through a helper function
13203 // which copies elements one by one.
13204 add_local_variable_name(var.self);
Hans-Kristian Arntzenf8592ec2020-04-21 11:20:49 +020013205
13206 if (var.initializer)
13207 {
13208 statement(variable_decl(var), ";");
13209 var.deferred_declaration = false;
13210 }
13211 else
13212 {
13213 auto &dominated = entry_block.dominated_variables;
13214 if (find(begin(dominated), end(dominated), var.self) == end(dominated))
13215 entry_block.dominated_variables.push_back(var.self);
13216 var.deferred_declaration = true;
13217 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020013218 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020013219 else if (var.storage == StorageClassFunction && var.remapped_variable && var.static_expression)
13220 {
13221 // No need to declare this variable, it has a static expression.
13222 var.deferred_declaration = false;
13223 }
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020013224 else if (expression_is_lvalue(v))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013225 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020013226 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013227
Hans-Kristian Arntzenf1415212020-06-19 10:51:00 +020013228 // Loop variables should never be declared early, they are explicitly emitted in a loop.
13229 if (var.initializer && !var.loop_variable)
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +010013230 statement(variable_decl_function_local(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013231 else
13232 {
13233 // Don't declare variable until first use to declutter the GLSL output quite a lot.
13234 // If we don't touch the variable before first branch,
13235 // declare it then since we need variable declaration to be in top scope.
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020013236 var.deferred_declaration = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013237 }
13238 }
13239 else
13240 {
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020013241 // 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 +010013242 // For these types (non-lvalue), we enforce forwarding through a shadowed variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013243 // This means that when we OpStore to these variables, we just write in the expression ID directly.
13244 // This breaks any kind of branching, since the variable must be statically assigned.
13245 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
13246 var.statically_assigned = true;
13247 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013248
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013249 var.loop_variable_enable = false;
Hans-Kristian Arntzenb847c882016-11-18 17:06:49 +010013250
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013251 // Loop variables are never declared outside their for-loop, so block any implicit declaration.
13252 if (var.loop_variable)
13253 var.deferred_declaration = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013254 }
13255
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020013256 // Enforce declaration order for regression testing purposes.
13257 for (auto &block_id : func.blocks)
13258 {
13259 auto &block = get<SPIRBlock>(block_id);
13260 sort(begin(block.dominated_variables), end(block.dominated_variables));
13261 }
13262
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020013263 for (auto &line : current_function->fixup_hooks_in)
13264 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040013265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013266 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013268 end_scope();
13269 processing_entry_point = false;
13270 statement("");
Hans-Kristian Arntzend81bfc52019-06-13 10:31:37 +020013271
13272 // Make sure deferred declaration state for local variables is cleared when we are done with function.
13273 // We risk declaring Private/Workgroup variables in places we are not supposed to otherwise.
13274 for (auto &v : func.local_variables)
13275 {
13276 auto &var = get<SPIRVariable>(v);
13277 var.deferred_declaration = false;
13278 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013279}
13280
13281void CompilerGLSL::emit_fixup()
13282{
Hans-Kristian Arntzen5ea576e2020-09-28 14:09:39 +020013283 if (is_vertex_like_shader())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013284 {
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020013285 if (options.vertex.fixup_clipspace)
13286 {
13287 const char *suffix = backend.float_literal_suffix ? "f" : "";
13288 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
13289 }
13290
13291 if (options.vertex.flip_vert_y)
13292 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013293 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013294}
13295
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013296void CompilerGLSL::flush_phi(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013297{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013298 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020013299 if (child.ignore_phi_from_block == from)
13300 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013301
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013302 unordered_set<uint32_t> temporary_phi_variables;
13303
13304 for (auto itr = begin(child.phi_variables); itr != end(child.phi_variables); ++itr)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020013305 {
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013306 auto &phi = *itr;
13307
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013308 if (phi.parent == from)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020013309 {
13310 auto &var = get<SPIRVariable>(phi.function_variable);
13311
13312 // A Phi variable might be a loop variable, so flush to static expression.
13313 if (var.loop_variable && !var.loop_variable_enable)
13314 var.static_expression = phi.local_variable;
13315 else
13316 {
13317 flush_variable_declaration(phi.function_variable);
13318
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013319 // Check if we are going to write to a Phi variable that another statement will read from
13320 // as part of another Phi node in our target block.
13321 // For this case, we will need to copy phi.function_variable to a temporary, and use that for future reads.
13322 // This is judged to be extremely rare, so deal with it here using a simple, but suboptimal algorithm.
13323 bool need_saved_temporary =
13324 find_if(itr + 1, end(child.phi_variables), [&](const SPIRBlock::Phi &future_phi) -> bool {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013325 return future_phi.local_variable == ID(phi.function_variable) && future_phi.parent == from;
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013326 }) != end(child.phi_variables);
13327
13328 if (need_saved_temporary)
13329 {
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010013330 // Need to make sure we declare the phi variable with a copy at the right scope.
13331 // We cannot safely declare a temporary here since we might be inside a continue block.
13332 if (!var.allocate_temporary_copy)
13333 {
13334 var.allocate_temporary_copy = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013335 force_recompile();
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010013336 }
13337 statement("_", phi.function_variable, "_copy", " = ", to_name(phi.function_variable), ";");
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013338 temporary_phi_variables.insert(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013339 }
13340
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020013341 // This might be called in continue block, so make sure we
Hans-Kristian Arntzen91753632017-09-25 10:16:45 +020013342 // use this to emit ESSL 1.0 compliant increments/decrements.
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020013343 auto lhs = to_expression(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013344
13345 string rhs;
13346 if (temporary_phi_variables.count(phi.local_variable))
13347 rhs = join("_", phi.local_variable, "_copy");
13348 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060013349 rhs = to_pointer_expression(phi.local_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013350
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020013351 if (!optimize_read_modify_write(get<SPIRType>(var.basetype), lhs, rhs))
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020013352 statement(lhs, " = ", rhs, ";");
13353 }
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010013354
13355 register_write(phi.function_variable);
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020013356 }
13357 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013358}
13359
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013360void CompilerGLSL::branch_to_continue(BlockID from, BlockID to)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013361{
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013362 auto &to_block = get<SPIRBlock>(to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010013363 if (from == to)
13364 return;
13365
13366 assert(is_continue(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013367 if (to_block.complex_continue)
13368 {
13369 // Just emit the whole block chain as is.
13370 auto usage_counts = expression_usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013371
13372 emit_block_chain(to_block);
13373
Hans-Kristian Arntzen461f1502019-07-24 11:10:18 +020013374 // Expression usage counts are moot after returning from the continue block.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013375 expression_usage_counts = usage_counts;
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013376 }
13377 else
13378 {
13379 auto &from_block = get<SPIRBlock>(from);
13380 bool outside_control_flow = false;
13381 uint32_t loop_dominator = 0;
13382
13383 // FIXME: Refactor this to not use the old loop_dominator tracking.
13384 if (from_block.merge_block)
13385 {
13386 // If we are a loop header, we don't set the loop dominator,
13387 // so just use "self" here.
13388 loop_dominator = from;
13389 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013390 else if (from_block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013391 {
13392 loop_dominator = from_block.loop_dominator;
13393 }
13394
13395 if (loop_dominator != 0)
13396 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013397 auto &cfg = get_cfg_for_current_function();
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013398
13399 // For non-complex continue blocks, we implicitly branch to the continue block
13400 // by having the continue block be part of the loop header in for (; ; continue-block).
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020013401 outside_control_flow = cfg.node_terminates_control_flow_in_sub_graph(loop_dominator, from);
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013402 }
13403
13404 // Some simplification for for-loops. We always end up with a useless continue;
13405 // statement since we branch to a loop block.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020013406 // 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 +010013407 // we can avoid writing out an explicit continue statement.
13408 // Similar optimization to return statements if we know we're outside flow control.
13409 if (!outside_control_flow)
13410 statement("continue;");
13411 }
13412}
13413
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013414void CompilerGLSL::branch(BlockID from, BlockID to)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013415{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013416 flush_phi(from, to);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010013417 flush_control_dependent_expressions(from);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013418
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020013419 bool to_is_continue = is_continue(to);
13420
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013421 // This is only a continue if we branch to our loop dominator.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013422 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 +020013423 {
13424 // This can happen if we had a complex continue block which was emitted.
13425 // Once the continue block tries to branch to the loop header, just emit continue;
13426 // and end the chain here.
13427 statement("continue;");
13428 }
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010013429 else if (from != to && is_break(to))
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020013430 {
Hans-Kristian Arntzen542d4602020-10-27 12:29:08 +010013431 // We cannot break to ourselves, so check explicitly for from != to.
13432 // This case can trigger if a loop header is all three of these things:
13433 // - Continue block
13434 // - Loop header
13435 // - Break merge target all at once ...
13436
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020013437 // Very dirty workaround.
13438 // Switch constructs are able to break, but they cannot break out of a loop at the same time.
13439 // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block,
13440 // write to the ladder here, and defer the break.
13441 // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013442 if (current_emitting_switch && is_loop_break(to) &&
13443 current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) &&
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020013444 get<SPIRBlock>(current_emitting_switch->loop_dominator).merge_block == to)
13445 {
13446 if (!current_emitting_switch->need_ladder_break)
13447 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013448 force_recompile();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020013449 current_emitting_switch->need_ladder_break = true;
13450 }
13451
13452 statement("_", current_emitting_switch->self, "_ladder_break = true;");
13453 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013454 statement("break;");
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020013455 }
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020013456 else if (to_is_continue || from == to)
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010013457 {
13458 // For from == to case can happen for a do-while loop which branches into itself.
13459 // We don't mark these cases as continue blocks, but the only possible way to branch into
13460 // ourselves is through means of continue blocks.
Hans-Kristian Arntzen55c2ca92019-08-26 14:21:35 +020013461
13462 // If we are merging to a continue block, there is no need to emit the block chain for continue here.
13463 // We can branch to the continue block after we merge execution.
13464
13465 // Here we make use of structured control flow rules from spec:
13466 // 2.11: - the merge block declared by a header block cannot be a merge block declared by any other header block
13467 // - each header block must strictly dominate its merge block, unless the merge block is unreachable in the CFG
13468 // If we are branching to a merge block, we must be inside a construct which dominates the merge block.
13469 auto &block_meta = ir.block_meta[to];
13470 bool branching_to_merge =
13471 (block_meta & (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT |
13472 ParsedIR::BLOCK_META_LOOP_MERGE_BIT)) != 0;
13473 if (!to_is_continue || !branching_to_merge)
13474 branch_to_continue(from, to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010013475 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013476 else if (!is_conditional(to))
13477 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013478
13479 // It is important that we check for break before continue.
13480 // A block might serve two purposes, a break block for the inner scope, and
13481 // a continue block in the outer scope.
13482 // Inner scope always takes precedence.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013483}
13484
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013485void CompilerGLSL::branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013486{
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020013487 auto &from_block = get<SPIRBlock>(from);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013488 BlockID merge_block = from_block.merge == SPIRBlock::MergeSelection ? from_block.next_block : BlockID(0);
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020013489
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020013490 // If we branch directly to our selection merge target, we don't need a code path.
13491 bool true_block_needs_code = true_block != merge_block || flush_phi_required(from, true_block);
13492 bool false_block_needs_code = false_block != merge_block || flush_phi_required(from, false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013493
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020013494 if (!true_block_needs_code && !false_block_needs_code)
13495 return;
Hans-Kristian Arntzene06efb72019-07-25 12:30:50 +020013496
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020013497 emit_block_hints(get<SPIRBlock>(from));
13498
13499 if (true_block_needs_code)
Hans-Kristian Arntzen54cc0b02020-09-17 12:02:43 +020013500 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013501 statement("if (", to_expression(cond), ")");
13502 begin_scope();
13503 branch(from, true_block);
13504 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013505
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020013506 if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013507 {
13508 statement("else");
13509 begin_scope();
13510 branch(from, false_block);
13511 end_scope();
13512 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013513 }
Hans-Kristian Arntzen21442742020-09-17 12:12:37 +020013514 else if (false_block_needs_code)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013515 {
13516 // Only need false path, use negative conditional.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010013517 statement("if (!", to_enclosed_expression(cond), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013518 begin_scope();
13519 branch(from, false_block);
13520 end_scope();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013521 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013522}
13523
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013524// FIXME: This currently cannot handle complex continue blocks
13525// as in do-while.
13526// This should be seen as a "trivial" continue block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013527string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013528{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013529 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013530
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013531 // While emitting the continue block, declare_temporary will check this
13532 // if we have to emit temporaries.
13533 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013534
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020013535 SmallVector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013536
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013537 // Capture all statements into our list.
13538 auto *old = redirect_statement;
13539 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013540
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013541 // Stamp out all blocks one after each other.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013542 while ((ir.block_meta[block->self] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) == 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013543 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013544 // Write out all instructions we have in this block.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020013545 emit_block_instructions(*block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013547 // For plain branchless for/while continue blocks.
13548 if (block->next_block)
13549 {
13550 flush_phi(continue_block, block->next_block);
13551 block = &get<SPIRBlock>(block->next_block);
13552 }
13553 // For do while blocks. The last block will be a select block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013554 else if (block->true_block && follow_true_block)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013555 {
13556 flush_phi(continue_block, block->true_block);
13557 block = &get<SPIRBlock>(block->true_block);
13558 }
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013559 else if (block->false_block && follow_false_block)
13560 {
13561 flush_phi(continue_block, block->false_block);
13562 block = &get<SPIRBlock>(block->false_block);
13563 }
13564 else
13565 {
13566 SPIRV_CROSS_THROW("Invalid continue block detected!");
13567 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013568 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013569
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013570 // Restore old pointer.
13571 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013572
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013573 // Somewhat ugly, strip off the last ';' since we use ',' instead.
13574 // Ideally, we should select this behavior in statement().
13575 for (auto &s : statements)
13576 {
13577 if (!s.empty() && s.back() == ';')
Corentin Wallezef9ee492016-10-05 13:01:31 -040013578 s.erase(s.size() - 1, 1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013579 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013580
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013581 current_continue_block = nullptr;
13582 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013583}
13584
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013585void CompilerGLSL::emit_while_loop_initializers(const SPIRBlock &block)
13586{
13587 // While loops do not take initializers, so declare all of them outside.
13588 for (auto &loop_var : block.loop_variables)
13589 {
13590 auto &var = get<SPIRVariable>(loop_var);
13591 statement(variable_decl(var), ";");
13592 }
13593}
13594
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013595string CompilerGLSL::emit_for_loop_initializers(const SPIRBlock &block)
13596{
13597 if (block.loop_variables.empty())
13598 return "";
13599
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010013600 bool same_types = for_loop_initializers_are_same_type(block);
13601 // We can only declare for loop initializers if all variables are of same type.
13602 // If we cannot do this, declare individual variables before the loop header.
13603
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010013604 // We might have a loop variable candidate which was not assigned to for some reason.
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013605 uint32_t missing_initializers = 0;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010013606 for (auto &variable : block.loop_variables)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013607 {
13608 uint32_t expr = get<SPIRVariable>(variable).static_expression;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010013609
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013610 // Sometimes loop variables are initialized with OpUndef, but we can just declare
13611 // a plain variable without initializer in this case.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013612 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013613 missing_initializers++;
13614 }
13615
13616 if (block.loop_variables.size() == 1 && missing_initializers == 0)
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013617 {
13618 return variable_decl(get<SPIRVariable>(block.loop_variables.front()));
13619 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013620 else if (!same_types || missing_initializers == uint32_t(block.loop_variables.size()))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010013621 {
13622 for (auto &loop_var : block.loop_variables)
13623 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
13624 return "";
13625 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013626 else
13627 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013628 // We have a mix of loop variables, either ones with a clear initializer, or ones without.
13629 // Separate the two streams.
13630 string expr;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013631
13632 for (auto &loop_var : block.loop_variables)
13633 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013634 uint32_t static_expr = get<SPIRVariable>(loop_var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013635 if (static_expr == 0 || ir.ids[static_expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013636 {
13637 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
13638 }
13639 else
13640 {
Chip Davis3bfb2f92018-12-03 02:06:33 -060013641 auto &var = get<SPIRVariable>(loop_var);
13642 auto &type = get_variable_data_type(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013643 if (expr.empty())
13644 {
13645 // For loop initializers are of the form <type id = value, id = value, id = value, etc ...
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013646 expr = join(to_qualifiers_glsl(var.self), type_to_glsl(type), " ");
13647 }
13648 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060013649 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013650 expr += ", ";
Chip Davis3bfb2f92018-12-03 02:06:33 -060013651 // In MSL, being based on C++, the asterisk marking a pointer
13652 // binds to the identifier, not the type.
13653 if (type.pointer)
13654 expr += "* ";
13655 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013656
Chip Davis3bfb2f92018-12-03 02:06:33 -060013657 expr += join(to_name(loop_var), " = ", to_pointer_expression(var.static_expression));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013658 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013659 }
13660 return expr;
13661 }
13662}
13663
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010013664bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
13665{
13666 if (block.loop_variables.size() <= 1)
13667 return true;
13668
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013669 uint32_t expected = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013670 Bitset expected_flags;
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010013671 for (auto &var : block.loop_variables)
13672 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013673 // Don't care about uninitialized variables as they will not be part of the initializers.
13674 uint32_t expr = get<SPIRVariable>(var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020013675 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013676 continue;
13677
13678 if (expected == 0)
13679 {
13680 expected = get<SPIRVariable>(var).basetype;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013681 expected_flags = get_decoration_bitset(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010013682 }
13683 else if (expected != get<SPIRVariable>(var).basetype)
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010013684 return false;
13685
13686 // Precision flags and things like that must also match.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010013687 if (expected_flags != get_decoration_bitset(var))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010013688 return false;
13689 }
13690
13691 return true;
13692}
13693
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013694bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
13695{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013696 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013697
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013698 if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013699 {
13700 uint32_t current_count = statement_count;
13701 // If we're trying to create a true for loop,
13702 // we need to make sure that all opcodes before branch statement do not actually emit any code.
13703 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020013704 emit_block_instructions(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013705
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013706 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013707
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013708 // This can work! We only did trivial things which could be forwarded in block body!
13709 if (current_count == statement_count && condition_is_temporary)
13710 {
13711 switch (continue_type)
13712 {
13713 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010013714 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010013715 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
13716 flush_undeclared_variables(block);
13717
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010013718 // Important that we do this in this order because
13719 // emitting the continue block can invalidate the condition expression.
13720 auto initializer = emit_for_loop_initializers(block);
13721 auto condition = to_expression(block.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013722
13723 // Condition might have to be inverted.
13724 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
13725 condition = join("!", enclose_expression(condition));
13726
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013727 emit_block_hints(block);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013728 if (method != SPIRBlock::MergeToSelectContinueForLoop)
13729 {
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013730 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013731 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
13732 }
13733 else
13734 statement("for (", initializer, "; ", condition, "; )");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013735 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010013736 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013738 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013739 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010013740 // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
13741 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013742 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020013743 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013744
13745 auto condition = to_expression(block.condition);
13746 // Condition might have to be inverted.
13747 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
13748 condition = join("!", enclose_expression(condition));
13749
13750 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013751 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013752 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013753
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013754 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020013755 block.disable_block_optimization = true;
13756 force_recompile();
13757 begin_scope(); // We'll see an end_scope() later.
13758 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013759 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013760
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013761 begin_scope();
13762 return true;
13763 }
13764 else
13765 {
13766 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013767 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013768 begin_scope(); // We'll see an end_scope() later.
13769 return false;
13770 }
13771 }
13772 else if (method == SPIRBlock::MergeToDirectForLoop)
13773 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013774 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013775
Hans-Kristian Arntzen5ff11cc2016-11-18 16:45:11 +010013776 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
13777 flush_undeclared_variables(child);
13778
13779 uint32_t current_count = statement_count;
13780
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013781 // If we're trying to create a true for loop,
13782 // we need to make sure that all opcodes before branch statement do not actually emit any code.
13783 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020013784 emit_block_instructions(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013785
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013786 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013787
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013788 if (current_count == statement_count && condition_is_temporary)
13789 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013790 uint32_t target_block = child.true_block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013791
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013792 switch (continue_type)
13793 {
13794 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010013795 {
13796 // Important that we do this in this order because
13797 // emitting the continue block can invalidate the condition expression.
13798 auto initializer = emit_for_loop_initializers(block);
13799 auto condition = to_expression(child.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013800
13801 // Condition might have to be inverted.
13802 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
13803 {
13804 condition = join("!", enclose_expression(condition));
13805 target_block = child.false_block;
13806 }
13807
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010013808 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020013809 emit_block_hints(block);
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010013810 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013811 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010013812 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013814 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013815 {
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013816 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020013817 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013818
13819 auto condition = to_expression(child.condition);
13820 // Condition might have to be inverted.
13821 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
13822 {
13823 condition = join("!", enclose_expression(condition));
13824 target_block = child.false_block;
13825 }
13826
13827 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013828 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013829 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013830
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013831 default:
Hans-Kristian Arntzen50342962019-07-08 11:48:44 +020013832 block.disable_block_optimization = true;
13833 force_recompile();
13834 begin_scope(); // We'll see an end_scope() later.
13835 return false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013836 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013837
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013838 begin_scope();
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013839 branch(child.self, target_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013840 return true;
13841 }
13842 else
13843 {
13844 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020013845 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013846 begin_scope(); // We'll see an end_scope() later.
13847 return false;
13848 }
13849 }
13850 else
13851 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013852}
13853
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013854void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013855{
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013856 for (auto &v : block.dominated_variables)
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010013857 flush_variable_declaration(v);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013858}
13859
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013860void CompilerGLSL::emit_hoisted_temporaries(SmallVector<pair<TypeID, ID>> &temporaries)
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013861{
13862 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
13863 // Need to sort these to ensure that reference output is stable.
13864 sort(begin(temporaries), end(temporaries),
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020013865 [](const pair<TypeID, ID> &a, const pair<TypeID, ID> &b) { return a.second < b.second; });
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013866
13867 for (auto &tmp : temporaries)
13868 {
13869 add_local_variable_name(tmp.second);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010013870 auto &flags = ir.meta[tmp.second].decoration.decoration_flags;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013871 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +010013872
13873 // Not all targets support pointer literals, so don't bother with that case.
13874 string initializer;
13875 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
13876 initializer = join(" = ", to_zero_initialized_expression(tmp.first));
13877
13878 statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), initializer, ";");
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013879
13880 hoisted_temporaries.insert(tmp.second);
13881 forced_temporaries.insert(tmp.second);
13882
13883 // The temporary might be read from before it's assigned, set up the expression now.
13884 set<SPIRExpression>(tmp.second, to_name(tmp.second), tmp.first, true);
13885 }
13886}
13887
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013888void CompilerGLSL::emit_block_chain(SPIRBlock &block)
13889{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013890 bool select_branch_to_true_block = false;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013891 bool select_branch_to_false_block = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013892 bool skip_direct_branch = false;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013893 bool emitted_loop_header_variables = false;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013894 bool force_complex_continue_block = false;
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020013895 ValueSaver<uint32_t> loop_level_saver(current_loop_level);
13896
13897 if (block.merge == SPIRBlock::MergeLoop)
13898 add_loop_level();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013899
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013900 emit_hoisted_temporaries(block.declare_temporary);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013901
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013902 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
13903 if (block.continue_block)
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010013904 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013905 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzenf5cb08c2019-11-26 11:01:39 +010013906 // If we know we cannot emit a loop, mark the block early as a complex loop so we don't force unnecessary recompiles.
13907 if (continue_type == SPIRBlock::ComplexLoop)
13908 block.complex_continue = true;
13909 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013910
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010013911 // If we have loop variables, stop masking out access to the variable now.
Hans-Kristian Arntzenbcef66f2019-06-25 10:45:15 +020013912 for (auto var_id : block.loop_variables)
13913 {
13914 auto &var = get<SPIRVariable>(var_id);
13915 var.loop_variable_enable = true;
13916 // We're not going to declare the variable directly, so emit a copy here.
13917 emit_variable_temporary_copies(var);
13918 }
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010013919
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020013920 // Remember deferred declaration state. We will restore it before returning.
13921 SmallVector<bool, 64> rearm_dominated_variables(block.dominated_variables.size());
13922 for (size_t i = 0; i < block.dominated_variables.size(); i++)
13923 {
13924 uint32_t var_id = block.dominated_variables[i];
13925 auto &var = get<SPIRVariable>(var_id);
13926 rearm_dominated_variables[i] = var.deferred_declaration;
13927 }
13928
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013929 // This is the method often used by spirv-opt to implement loops.
13930 // The loop header goes straight into the continue block.
13931 // However, don't attempt this on ESSL 1.0, because if a loop variable is used in a continue block,
13932 // it *MUST* be used in the continue block. This loop method will not work.
13933 if (!is_legacy_es() && block_is_loop_candidate(block, SPIRBlock::MergeToSelectContinueForLoop))
13934 {
13935 flush_undeclared_variables(block);
13936 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
13937 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013938 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
13939 select_branch_to_false_block = true;
13940 else
13941 select_branch_to_true_block = true;
13942
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013943 emitted_loop_header_variables = true;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010013944 force_complex_continue_block = true;
13945 }
13946 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013947 // 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 +010013948 else if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013949 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013950 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013951 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
13952 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010013953 // The body of while, is actually just the true (or false) block, so always branch there unconditionally.
13954 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
13955 select_branch_to_false_block = true;
13956 else
13957 select_branch_to_true_block = true;
13958
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013959 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013960 }
13961 }
13962 // This is the newer loop behavior in glslang which branches from Loop header directly to
13963 // a new block, which in turn has a OpBranchSelection without a selection merge.
13964 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
13965 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013966 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013967 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013968 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013969 skip_direct_branch = true;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013970 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010013971 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013972 }
13973 else if (continue_type == SPIRBlock::DoWhileLoop)
13974 {
Hans-Kristian Arntzenb3f6e3d2018-01-24 19:46:53 +010013975 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013976 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013977 emitted_loop_header_variables = true;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013978 // We have some temporaries where the loop header is the dominator.
13979 // We risk a case where we have code like:
13980 // for (;;) { create-temporary; break; } consume-temporary;
13981 // so force-declare temporaries here.
13982 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013983 statement("do");
13984 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020013985
13986 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013987 }
13988 else if (block.merge == SPIRBlock::MergeLoop)
13989 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010013990 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020013991 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010013992 emitted_loop_header_variables = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013993
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020013994 // We have a generic loop without any distinguishable pattern like for, while or do while.
13995 get<SPIRBlock>(block.continue_block).complex_continue = true;
13996 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010013997
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010013998 // We have some temporaries where the loop header is the dominator.
13999 // We risk a case where we have code like:
14000 // for (;;) { create-temporary; break; } consume-temporary;
14001 // so force-declare temporaries here.
14002 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014003 statement("for (;;)");
14004 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014005
14006 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014007 }
14008 else
14009 {
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020014010 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014011 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014012
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014013 // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
14014 // as writes to said loop variables might have been masked out, we need a recompile.
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010014015 if (!emitted_loop_header_variables && !block.loop_variables.empty())
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014016 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014017 force_recompile();
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010014018 for (auto var : block.loop_variables)
14019 get<SPIRVariable>(var).loop_variable = false;
14020 block.loop_variables.clear();
14021 }
14022
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010014023 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014024 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014025
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014026 // Handle end of block.
14027 switch (block.terminator)
14028 {
14029 case SPIRBlock::Direct:
14030 // True when emitting complex continue block.
14031 if (block.loop_dominator == block.next_block)
14032 {
14033 branch(block.self, block.next_block);
14034 emit_next_block = false;
14035 }
14036 // True if MergeToDirectForLoop succeeded.
14037 else if (skip_direct_branch)
14038 emit_next_block = false;
14039 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
14040 {
14041 branch(block.self, block.next_block);
14042 emit_next_block = false;
14043 }
14044 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014045
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014046 case SPIRBlock::Select:
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014047 // True if MergeToSelectForLoop or MergeToSelectContinueForLoop succeeded.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014048 if (select_branch_to_true_block)
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010014049 {
14050 if (force_complex_continue_block)
14051 {
14052 assert(block.true_block == block.continue_block);
14053
14054 // We're going to emit a continue block directly here, so make sure it's marked as complex.
14055 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
14056 bool old_complex = complex_continue;
14057 complex_continue = true;
14058 branch(block.self, block.true_block);
14059 complex_continue = old_complex;
14060 }
14061 else
14062 branch(block.self, block.true_block);
14063 }
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010014064 else if (select_branch_to_false_block)
14065 {
14066 if (force_complex_continue_block)
14067 {
14068 assert(block.false_block == block.continue_block);
14069
14070 // We're going to emit a continue block directly here, so make sure it's marked as complex.
14071 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
14072 bool old_complex = complex_continue;
14073 complex_continue = true;
14074 branch(block.self, block.false_block);
14075 complex_continue = old_complex;
14076 }
14077 else
14078 branch(block.self, block.false_block);
14079 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014080 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014081 branch(block.self, block.condition, block.true_block, block.false_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014082 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014083
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014084 case SPIRBlock::MultiSelect:
14085 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014086 auto &type = expression_type(block.condition);
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020014087 bool unsigned_case =
14088 type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort || type.basetype == SPIRType::UByte;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014089
Hans-Kristian Arntzen45baf242019-03-20 10:42:38 +010014090 if (block.merge == SPIRBlock::MergeNone)
14091 SPIRV_CROSS_THROW("Switch statement is not structured");
14092
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010014093 if (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64)
14094 {
14095 // SPIR-V spec suggests this is allowed, but we cannot support it in higher level languages.
14096 SPIRV_CROSS_THROW("Cannot use 64-bit switch selectors.");
14097 }
14098
14099 const char *label_suffix = "";
14100 if (type.basetype == SPIRType::UInt && backend.uint32_t_literal_suffix)
14101 label_suffix = "u";
14102 else if (type.basetype == SPIRType::UShort)
14103 label_suffix = backend.uint16_t_literal_suffix;
14104 else if (type.basetype == SPIRType::Short)
14105 label_suffix = backend.int16_t_literal_suffix;
14106
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014107 SPIRBlock *old_emitting_switch = current_emitting_switch;
14108 current_emitting_switch = &block;
14109
14110 if (block.need_ladder_break)
14111 statement("bool _", block.self, "_ladder_break = false;");
14112
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014113 // Find all unique case constructs.
14114 unordered_map<uint32_t, SmallVector<uint32_t>> case_constructs;
14115 SmallVector<uint32_t> block_declaration_order;
14116 SmallVector<uint32_t> literals_to_merge;
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014117
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014118 // If a switch case branches to the default block for some reason, we can just remove that literal from consideration
14119 // and let the default: block handle it.
14120 // 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.
14121 // We only need to consider possible fallthrough if order[i] branches to order[i + 1].
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014122 for (auto &c : block.cases)
14123 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014124 if (c.block != block.next_block && c.block != block.default_block)
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014125 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014126 if (!case_constructs.count(c.block))
14127 block_declaration_order.push_back(c.block);
14128 case_constructs[c.block].push_back(c.value);
14129 }
14130 else if (c.block == block.next_block && block.default_block != block.next_block)
14131 {
14132 // We might have to flush phi inside specific case labels.
14133 // If we can piggyback on default:, do so instead.
14134 literals_to_merge.push_back(c.value);
14135 }
14136 }
14137
14138 // Empty literal array -> default.
14139 if (block.default_block != block.next_block)
14140 {
14141 auto &default_block = get<SPIRBlock>(block.default_block);
14142
14143 // We need to slide in the default block somewhere in this chain
14144 // if there are fall-through scenarios since the default is declared separately in OpSwitch.
14145 // Only consider trivial fall-through cases here.
14146 size_t num_blocks = block_declaration_order.size();
14147 bool injected_block = false;
14148
14149 for (size_t i = 0; i < num_blocks; i++)
14150 {
14151 auto &case_block = get<SPIRBlock>(block_declaration_order[i]);
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014152 if (execution_is_direct_branch(case_block, default_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014153 {
14154 // Fallthrough to default block, we must inject the default block here.
14155 block_declaration_order.insert(begin(block_declaration_order) + i + 1, block.default_block);
14156 injected_block = true;
14157 break;
14158 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014159 else if (execution_is_direct_branch(default_block, case_block))
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014160 {
14161 // Default case is falling through to another case label, we must inject the default block here.
14162 block_declaration_order.insert(begin(block_declaration_order) + i, block.default_block);
14163 injected_block = true;
14164 break;
14165 }
14166 }
14167
14168 // Order does not matter.
14169 if (!injected_block)
14170 block_declaration_order.push_back(block.default_block);
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014171 else if (is_legacy_es())
14172 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 +020014173
14174 case_constructs[block.default_block] = {};
14175 }
14176
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014177 size_t num_blocks = block_declaration_order.size();
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014178
Hans-Kristian Arntzenbcec5cb2019-06-21 14:59:51 +020014179 const auto to_case_label = [](uint32_t literal, bool is_unsigned_case) -> string {
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014180 return is_unsigned_case ? convert_to_string(literal) : convert_to_string(int32_t(literal));
14181 };
14182
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020014183 const auto to_legacy_case_label = [&](uint32_t condition, const SmallVector<uint32_t> &labels,
14184 const char *suffix) -> string {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014185 string ret;
14186 size_t count = labels.size();
14187 for (size_t i = 0; i < count; i++)
14188 {
14189 if (i)
14190 ret += " || ";
14191 ret += join(count > 1 ? "(" : "", to_enclosed_expression(condition), " == ", labels[i], suffix,
14192 count > 1 ? ")" : "");
14193 }
14194 return ret;
14195 };
14196
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014197 // We need to deal with a complex scenario for OpPhi. If we have case-fallthrough and Phi in the picture,
14198 // we need to flush phi nodes outside the switch block in a branch,
14199 // and skip any Phi handling inside the case label to make fall-through work as expected.
14200 // This kind of code-gen is super awkward and it's a last resort. Normally we would want to handle this
14201 // inside the case label if at all possible.
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014202 for (size_t i = 1; backend.support_case_fallthrough && i < num_blocks; i++)
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014203 {
14204 if (flush_phi_required(block.self, block_declaration_order[i]) &&
14205 flush_phi_required(block_declaration_order[i - 1], block_declaration_order[i]))
14206 {
14207 uint32_t target_block = block_declaration_order[i];
14208
14209 // Make sure we flush Phi, it might have been marked to be ignored earlier.
14210 get<SPIRBlock>(target_block).ignore_phi_from_block = 0;
14211
14212 auto &literals = case_constructs[target_block];
14213
14214 if (literals.empty())
14215 {
14216 // Oh boy, gotta make a complete negative test instead! o.o
14217 // Find all possible literals that would *not* make us enter the default block.
14218 // If none of those literals match, we flush Phi ...
14219 SmallVector<string> conditions;
14220 for (size_t j = 0; j < num_blocks; j++)
14221 {
14222 auto &negative_literals = case_constructs[block_declaration_order[j]];
14223 for (auto &case_label : negative_literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020014224 conditions.push_back(join(to_enclosed_expression(block.condition),
14225 " != ", to_case_label(case_label, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014226 }
14227
14228 statement("if (", merge(conditions, " && "), ")");
14229 begin_scope();
14230 flush_phi(block.self, target_block);
14231 end_scope();
14232 }
14233 else
14234 {
14235 SmallVector<string> conditions;
14236 conditions.reserve(literals.size());
14237 for (auto &case_label : literals)
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020014238 conditions.push_back(join(to_enclosed_expression(block.condition),
14239 " == ", to_case_label(case_label, unsigned_case)));
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014240 statement("if (", merge(conditions, " || "), ")");
14241 begin_scope();
14242 flush_phi(block.self, target_block);
14243 end_scope();
14244 }
14245
14246 // Mark the block so that we don't flush Phi from header to case label.
14247 get<SPIRBlock>(target_block).ignore_phi_from_block = block.self;
14248 }
14249 }
14250
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020014251 // If there is only one default block, and no cases, this is a case where SPIRV-opt decided to emulate
14252 // non-structured exits with the help of a switch block.
14253 // This is buggy on FXC, so just emit the logical equivalent of a do { } while(false), which is more idiomatic.
14254 bool degenerate_switch = block.default_block != block.merge_block && block.cases.empty();
14255
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014256 if (degenerate_switch || is_legacy_es())
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020014257 {
14258 // ESSL 1.0 is not guaranteed to support do/while.
14259 if (is_legacy_es())
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020014260 {
14261 uint32_t counter = statement_count;
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010014262 statement("for (int spvDummy", counter, " = 0; spvDummy", counter,
14263 " < 1; spvDummy", counter, "++)");
Hans-Kristian Arntzen70f17142020-06-30 12:02:24 +020014264 }
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020014265 else
14266 statement("do");
14267 }
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020014268 else
14269 {
14270 emit_block_hints(block);
14271 statement("switch (", to_expression(block.condition), ")");
14272 }
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014273 begin_scope();
14274
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014275 for (size_t i = 0; i < num_blocks; i++)
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014276 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014277 uint32_t target_block = block_declaration_order[i];
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014278 auto &literals = case_constructs[target_block];
14279
14280 if (literals.empty())
14281 {
14282 // Default case.
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020014283 if (!degenerate_switch)
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014284 {
14285 if (is_legacy_es())
14286 statement("else");
14287 else
14288 statement("default:");
14289 }
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014290 }
14291 else
14292 {
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014293 if (is_legacy_es())
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014294 {
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +020014295 statement((i ? "else " : ""), "if (", to_legacy_case_label(block.condition, literals, label_suffix),
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014296 ")");
14297 }
14298 else
14299 {
14300 for (auto &case_literal : literals)
14301 {
14302 // The case label value must be sign-extended properly in SPIR-V, so we can assume 32-bit values here.
14303 statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
14304 }
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014305 }
14306 }
14307
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014308 auto &case_block = get<SPIRBlock>(target_block);
Hans-Kristian Arntzen581ed0f2019-06-27 15:10:17 +020014309 if (backend.support_case_fallthrough && i + 1 < num_blocks &&
Hans-Kristian Arntzenb4e01632019-06-21 16:02:22 +020014310 execution_is_direct_branch(case_block, get<SPIRBlock>(block_declaration_order[i + 1])))
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014311 {
14312 // We will fall through here, so just terminate the block chain early.
14313 // We still need to deal with Phi potentially.
14314 // No need for a stack-like thing here since we only do fall-through when there is a
14315 // single trivial branch to fall-through target..
14316 current_emitting_switch_fallthrough = true;
14317 }
14318 else
14319 current_emitting_switch_fallthrough = false;
14320
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020014321 if (!degenerate_switch)
14322 begin_scope();
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014323 branch(block.self, target_block);
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020014324 if (!degenerate_switch)
14325 end_scope();
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014326
14327 current_emitting_switch_fallthrough = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014328 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014329
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014330 // Might still have to flush phi variables if we branch from loop header directly to merge target.
14331 if (flush_phi_required(block.self, block.next_block))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014332 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014333 if (block.default_block == block.next_block || !literals_to_merge.empty())
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014334 {
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014335 for (auto &case_literal : literals_to_merge)
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +020014336 statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014337
14338 if (block.default_block == block.next_block)
Hans-Kristian Arntzen4d79d632020-06-29 13:23:13 +020014339 {
14340 if (is_legacy_es())
14341 statement("else");
14342 else
14343 statement("default:");
14344 }
Hans-Kristian Arntzenbc3bf472019-06-20 11:20:06 +020014345
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020014346 begin_scope();
14347 flush_phi(block.self, block.next_block);
14348 statement("break;");
14349 end_scope();
14350 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014351 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014352
Hans-Kristian Arntzenbae76d72020-06-29 12:50:31 +020014353 if (degenerate_switch && !is_legacy_es())
Hans-Kristian Arntzeneb0f0322020-06-23 15:39:04 +020014354 end_scope_decl("while(false)");
14355 else
14356 end_scope();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020014357
14358 if (block.need_ladder_break)
14359 {
14360 statement("if (_", block.self, "_ladder_break)");
14361 begin_scope();
14362 statement("break;");
14363 end_scope();
14364 }
14365
14366 current_emitting_switch = old_emitting_switch;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014367 break;
14368 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014369
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014370 case SPIRBlock::Return:
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014371 {
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020014372 for (auto &line : current_function->fixup_hooks_out)
14373 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040014374
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014375 if (processing_entry_point)
14376 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014377
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014378 auto &cfg = get_cfg_for_current_function();
14379
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014380 if (block.return_value)
14381 {
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014382 auto &type = expression_type(block.return_value);
14383 if (!type.array.empty() && !backend.can_return_array)
14384 {
14385 // If we cannot return arrays, we will have a special out argument we can write to instead.
14386 // The backend is responsible for setting this up, and redirection the return values as appropriate.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010014387 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020014388 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010014389 emit_array_copy("spvReturnValue", block.return_value, StorageClassFunction,
Hans-Kristian Arntzen7314f512020-06-18 12:46:39 +020014390 get_expression_effective_storage_class(block.return_value));
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020014391 }
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014392
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014393 if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014394 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014395 {
14396 statement("return;");
14397 }
14398 }
14399 else
14400 {
14401 // OpReturnValue can return Undef, so don't emit anything for this case.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010014402 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014403 statement("return ", to_expression(block.return_value), ";");
14404 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014405 }
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014406 else if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) ||
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014407 block.loop_dominator != BlockID(SPIRBlock::NoDominator))
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014408 {
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014409 // If this block is the very final block and not called from control flow,
14410 // we do not need an explicit return which looks out of place. Just end the function here.
14411 // In the very weird case of for(;;) { return; } executing return is unconditional,
14412 // but we actually need a return here ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014413 statement("return;");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014414 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014415 break;
Hans-Kristian Arntzen5d97dae2019-08-26 15:36:23 +020014416 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014417
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014418 case SPIRBlock::Kill:
Bill Hollings943191a2016-10-27 10:20:01 -040014419 statement(backend.discard_literal, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014420 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014421
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010014422 case SPIRBlock::Unreachable:
14423 emit_next_block = false;
14424 break;
14425
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014426 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010014427 SPIRV_CROSS_THROW("Unimplemented block terminator.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014428 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014429
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014430 if (block.next_block && emit_next_block)
14431 {
14432 // If we hit this case, we're dealing with an unconditional branch, which means we will output
14433 // that block after this. If we had selection merge, we already flushed phi variables.
14434 if (block.merge != SPIRBlock::MergeSelection)
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020014435 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014436 flush_phi(block.self, block.next_block);
Hans-Kristian Arntzen05188ac2020-06-29 10:55:50 +020014437 // For a direct branch, need to remember to invalidate expressions in the next linear block instead.
14438 get<SPIRBlock>(block.next_block).invalidate_expressions = block.invalidate_expressions;
14439 }
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014440
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014441 // For switch fallthrough cases, we terminate the chain here, but we still need to handle Phi.
14442 if (!current_emitting_switch_fallthrough)
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014443 {
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014444 // For merge selects we might have ignored the fact that a merge target
14445 // could have been a break; or continue;
14446 // We will need to deal with it here.
14447 if (is_loop_break(block.next_block))
14448 {
14449 // Cannot check for just break, because switch statements will also use break.
14450 assert(block.merge == SPIRBlock::MergeSelection);
14451 statement("break;");
14452 }
14453 else if (is_continue(block.next_block))
14454 {
14455 assert(block.merge == SPIRBlock::MergeSelection);
14456 branch_to_continue(block.self, block.next_block);
14457 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014458 else if (BlockID(block.self) != block.next_block)
Hans-Kristian Arntzen22e3bea2019-06-20 12:14:19 +020014459 emit_block_chain(get<SPIRBlock>(block.next_block));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014460 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014461 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014462
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014463 if (block.merge == SPIRBlock::MergeLoop)
14464 {
14465 if (continue_type == SPIRBlock::DoWhileLoop)
14466 {
14467 // Make sure that we run the continue block to get the expressions set, but this
14468 // should become an empty string.
14469 // We have no fallbacks if we cannot forward everything to temporaries ...
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014470 const auto &continue_block = get<SPIRBlock>(block.continue_block);
Hans-Kristian Arntzen8bfb04d2019-03-06 12:20:13 +010014471 bool positive_test = execution_is_noop(get<SPIRBlock>(continue_block.true_block),
14472 get<SPIRBlock>(continue_block.loop_dominator));
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014473
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014474 uint32_t current_count = statement_count;
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014475 auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014476 if (statement_count != current_count)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014477 {
14478 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
14479 get<SPIRBlock>(block.continue_block).complex_continue = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020014480 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014481 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014482
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010014483 // Might have to invert the do-while test here.
14484 auto condition = to_expression(continue_block.condition);
14485 if (!positive_test)
14486 condition = join("!", enclose_expression(condition));
14487
14488 end_scope_decl(join("while (", condition, ")"));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014489 }
14490 else
14491 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014492
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +020014493 loop_level_saver.release();
14494
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010014495 // We cannot break out of two loops at once, so don't check for break; here.
14496 // Using block.self as the "from" block isn't quite right, but it has the same scope
14497 // and dominance structure, so it's fine.
14498 if (is_continue(block.merge_block))
14499 branch_to_continue(block.self, block.merge_block);
14500 else
14501 emit_block_chain(get<SPIRBlock>(block.merge_block));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014502 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020014503
14504 // Forget about control dependent expressions now.
14505 block.invalidate_expressions.clear();
Hans-Kristian Arntzenc09ca742019-06-05 12:35:30 +020014506
14507 // After we return, we must be out of scope, so if we somehow have to re-emit this function,
14508 // re-declare variables if necessary.
14509 assert(rearm_dominated_variables.size() == block.dominated_variables.size());
14510 for (size_t i = 0; i < block.dominated_variables.size(); i++)
14511 {
14512 uint32_t var = block.dominated_variables[i];
14513 get<SPIRVariable>(var).deferred_declaration = rearm_dominated_variables[i];
14514 }
Hans-Kristian Arntzen25c74b32019-07-10 12:57:12 +020014515
14516 // Just like for deferred declaration, we need to forget about loop variable enable
14517 // if our block chain is reinstantiated later.
14518 for (auto &var_id : block.loop_variables)
14519 get<SPIRVariable>(var_id).loop_variable_enable = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014520}
14521
14522void CompilerGLSL::begin_scope()
14523{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014524 statement("{");
14525 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014526}
14527
14528void CompilerGLSL::end_scope()
14529{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014530 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010014531 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014532 indent--;
14533 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014534}
14535
Chip Daviscb359342019-09-05 23:14:12 -050014536void CompilerGLSL::end_scope(const string &trailer)
14537{
14538 if (!indent)
14539 SPIRV_CROSS_THROW("Popping empty indent stack.");
14540 indent--;
14541 statement("}", trailer);
14542}
14543
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014544void CompilerGLSL::end_scope_decl()
14545{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014546 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010014547 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014548 indent--;
14549 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014550}
14551
14552void CompilerGLSL::end_scope_decl(const string &decl)
14553{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014554 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010014555 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020014556 indent--;
14557 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010014558}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020014559
14560void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
14561{
14562 // If our variable is remapped, and we rely on type-remapping information as
14563 // well, then we cannot pass the variable as a function parameter.
14564 // Fixing this is non-trivial without stamping out variants of the same function,
14565 // so for now warn about this and suggest workarounds instead.
14566 for (uint32_t i = 0; i < length; i++)
14567 {
14568 auto *var = maybe_get<SPIRVariable>(args[i]);
14569 if (!var || !var->remapped_variable)
14570 continue;
14571
14572 auto &type = get<SPIRType>(var->basetype);
14573 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
14574 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010014575 SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
14576 "This will not work correctly because type-remapping information is lost. "
14577 "To workaround, please consider not passing the subpass input as a function parameter, "
14578 "or use in/out variables instead which do not need type remapping information.");
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020014579 }
14580 }
14581}
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010014582
14583const Instruction *CompilerGLSL::get_next_instruction_in_block(const Instruction &instr)
14584{
14585 // FIXME: This is kind of hacky. There should be a cleaner way.
14586 auto offset = uint32_t(&instr - current_emitting_block->ops.data());
14587 if ((offset + 1) < current_emitting_block->ops.size())
14588 return &current_emitting_block->ops[offset + 1];
14589 else
14590 return nullptr;
14591}
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010014592
14593uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
14594{
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010014595 return semantics & (MemorySemanticsAtomicCounterMemoryMask | MemorySemanticsImageMemoryMask |
14596 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask |
14597 MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010014598}
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014599
Hans-Kristian Arntzen9436cd32019-08-27 13:16:16 +020014600void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageClass, StorageClass)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010014601{
14602 statement(lhs, " = ", to_expression(rhs_id), ";");
14603}
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020014604
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014605void 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 +010014606{
14607 if (!backend.force_gl_in_out_block)
14608 return;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014609 // This path is only relevant for GL backends.
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014610
14611 auto *var = maybe_get<SPIRVariable>(source_id);
14612 if (!var)
14613 return;
14614
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014615 if (var->storage != StorageClassInput)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014616 return;
14617
14618 auto &type = get_variable_data_type(*var);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014619 if (type.array.empty())
14620 return;
14621
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014622 auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014623 bool is_builtin = is_builtin_variable(*var) && (builtin == BuiltInPointSize || builtin == BuiltInPosition);
14624 bool is_tess = is_tessellation_shader();
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010014625 bool is_patch = has_decoration(var->self, DecorationPatch);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014626
14627 // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
14628 // We must unroll the array load.
14629 // For builtins, we couldn't catch this case normally,
14630 // because this is resolved in the OpAccessChain in most cases.
14631 // If we load the entire array, we have no choice but to unroll here.
Hans-Kristian Arntzen7c1e34f2019-12-10 12:00:55 +010014632 if (!is_patch && (is_builtin || is_tess))
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014633 {
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014634 auto new_expr = join("_", target_id, "_unrolled");
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014635 statement(variable_decl(type, new_expr, target_id), ";");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014636 string array_expr;
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010014637 if (type.array_size_literal.back())
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014638 {
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010014639 array_expr = convert_to_string(type.array.back());
14640 if (type.array.back() == 0)
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014641 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
14642 }
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014643 else
Hans-Kristian Arntzena8d676f2019-11-04 10:33:52 +010014644 array_expr = to_expression(type.array.back());
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014645
14646 // The array size might be a specialization constant, so use a for-loop instead.
14647 statement("for (int i = 0; i < int(", array_expr, "); i++)");
14648 begin_scope();
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010014649 if (is_builtin)
14650 statement(new_expr, "[i] = gl_in[i].", expr, ";");
14651 else
14652 statement(new_expr, "[i] = ", expr, "[i];");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010014653 end_scope();
14654
14655 expr = move(new_expr);
14656 }
14657}
14658
Chip Davis3e6010d2020-10-14 15:04:03 -050014659void CompilerGLSL::cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020014660{
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020014661 auto *var = maybe_get_backing_variable(source_id);
14662 if (var)
14663 source_id = var->self;
14664
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020014665 // Only interested in standalone builtin variables.
14666 if (!has_decoration(source_id, DecorationBuiltIn))
14667 return;
14668
14669 auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
14670 auto expected_type = expr_type.basetype;
14671
14672 // TODO: Fill in for more builtins.
14673 switch (builtin)
14674 {
14675 case BuiltInLayer:
14676 case BuiltInPrimitiveId:
14677 case BuiltInViewportIndex:
14678 case BuiltInInstanceId:
14679 case BuiltInInstanceIndex:
14680 case BuiltInVertexId:
14681 case BuiltInVertexIndex:
14682 case BuiltInSampleId:
Chip Davisfcad0192018-08-28 13:47:29 -050014683 case BuiltInBaseVertex:
14684 case BuiltInBaseInstance:
14685 case BuiltInDrawIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020014686 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020014687 case BuiltInInstanceCustomIndexNV:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020014688 expected_type = SPIRType::Int;
14689 break;
14690
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020014691 case BuiltInGlobalInvocationId:
14692 case BuiltInLocalInvocationId:
14693 case BuiltInWorkgroupId:
14694 case BuiltInLocalInvocationIndex:
14695 case BuiltInWorkgroupSize:
14696 case BuiltInNumWorkgroups:
Hans-Kristian Arntzen271ad332020-05-20 13:14:23 +020014697 case BuiltInIncomingRayFlagsNV:
14698 case BuiltInLaunchIdNV:
14699 case BuiltInLaunchSizeNV:
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020014700 expected_type = SPIRType::UInt;
14701 break;
14702
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020014703 default:
14704 break;
14705 }
14706
14707 if (expected_type != expr_type.basetype)
14708 expr = bitcast_expression(expr_type, expected_type, expr);
14709}
14710
Chip Davis3e6010d2020-10-14 15:04:03 -050014711void CompilerGLSL::cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020014712{
14713 // Only interested in standalone builtin variables.
14714 if (!has_decoration(target_id, DecorationBuiltIn))
14715 return;
14716
14717 auto builtin = static_cast<BuiltIn>(get_decoration(target_id, DecorationBuiltIn));
14718 auto expected_type = expr_type.basetype;
14719
14720 // TODO: Fill in for more builtins.
14721 switch (builtin)
14722 {
14723 case BuiltInLayer:
14724 case BuiltInPrimitiveId:
14725 case BuiltInViewportIndex:
Hans-Kristian Arntzena9da59b2019-06-12 09:57:32 +020014726 case BuiltInFragStencilRefEXT:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020014727 expected_type = SPIRType::Int;
14728 break;
14729
14730 default:
14731 break;
14732 }
14733
14734 if (expected_type != expr_type.basetype)
14735 {
14736 auto type = expr_type;
14737 type.basetype = expected_type;
14738 expr = bitcast_expression(type, expr_type.basetype, expr);
14739 }
14740}
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014741
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020014742void CompilerGLSL::convert_non_uniform_expression(const SPIRType &type, std::string &expr)
14743{
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +020014744 if (*backend.nonuniform_qualifier == '\0')
14745 return;
14746
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020014747 // Handle SPV_EXT_descriptor_indexing.
14748 if (type.basetype == SPIRType::Sampler || type.basetype == SPIRType::SampledImage ||
14749 type.basetype == SPIRType::Image)
14750 {
14751 // The image/sampler ID must be declared as non-uniform.
14752 // However, it is not legal GLSL to have
14753 // nonuniformEXT(samplers[index]), so we must move the nonuniform qualifier
14754 // to the array indexing, like
14755 // samplers[nonuniformEXT(index)].
14756 // While the access chain will generally be nonuniformEXT, it's not necessarily so,
14757 // so we might have to fixup the OpLoad-ed expression late.
14758
14759 auto start_array_index = expr.find_first_of('[');
Hans-Kristian Arntzen439b6662020-10-30 13:45:15 +010014760
14761 if (start_array_index == string::npos)
14762 return;
14763
14764 // Check for the edge case that a non-arrayed resource was marked to be nonuniform,
14765 // and the bracket we found is actually part of non-resource related data.
14766 if (expr.find_first_of(',') < start_array_index)
14767 return;
14768
14769 // We've opened a bracket, track expressions until we can close the bracket.
14770 // This must be our image index.
14771 size_t end_array_index = string::npos;
14772 unsigned bracket_count = 1;
14773 for (size_t index = start_array_index + 1; index < expr.size(); index++)
14774 {
14775 if (expr[index] == ']')
14776 {
14777 if (--bracket_count == 0)
14778 {
14779 end_array_index = index;
14780 break;
14781 }
14782 }
14783 else if (expr[index] == '[')
14784 bracket_count++;
14785 }
14786
14787 assert(bracket_count == 0);
14788
Hans-Kristian Arntzen31867012019-05-02 10:54:34 +020014789 // Doesn't really make sense to declare a non-arrayed image with nonuniformEXT, but there's
14790 // nothing we can do here to express that.
14791 if (start_array_index == string::npos || end_array_index == string::npos || end_array_index < start_array_index)
14792 return;
14793
14794 start_array_index++;
14795
14796 expr = join(expr.substr(0, start_array_index), backend.nonuniform_qualifier, "(",
14797 expr.substr(start_array_index, end_array_index - start_array_index), ")",
14798 expr.substr(end_array_index, string::npos));
14799 }
14800}
14801
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020014802void CompilerGLSL::emit_block_hints(const SPIRBlock &)
14803{
14804}
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +010014805
14806void CompilerGLSL::preserve_alias_on_reset(uint32_t id)
14807{
14808 preserved_aliases[id] = get_name(id);
14809}
14810
14811void CompilerGLSL::reset_name_caches()
14812{
14813 for (auto &preserved : preserved_aliases)
14814 set_name(preserved.first, preserved.second);
14815
14816 preserved_aliases.clear();
14817 resource_names.clear();
14818 block_input_names.clear();
14819 block_output_names.clear();
14820 block_ubo_names.clear();
14821 block_ssbo_names.clear();
14822 block_names.clear();
14823 function_overloads.clear();
14824}
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014825
14826void CompilerGLSL::fixup_type_alias()
14827{
14828 // 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 +020014829 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020014830 if (!type.type_alias)
14831 return;
14832
14833 if (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014834 {
Hans-Kristian Arntzenaac68852020-07-29 11:58:32 +020014835 // Top-level block types should never alias anything else.
14836 type.type_alias = 0;
14837 }
14838 else if (type_is_block_like(type) && type.self == ID(self))
14839 {
14840 // A block-like type is any type which contains Offset decoration, but not top-level blocks,
14841 // i.e. blocks which are placed inside buffers.
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014842 // Become the master.
14843 ir.for_each_typed_id<SPIRType>([&](uint32_t other_id, SPIRType &other_type) {
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020014844 if (other_id == self)
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014845 return;
14846
14847 if (other_type.type_alias == type.type_alias)
Hans-Kristian Arntzen038b0bf2020-07-29 11:21:13 +020014848 other_type.type_alias = self;
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014849 });
14850
14851 this->get<SPIRType>(type.type_alias).type_alias = self;
14852 type.type_alias = 0;
14853 }
14854 });
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014855}
14856
14857void CompilerGLSL::reorder_type_alias()
14858{
14859 // Reorder declaration of types so that the master of the type alias is always emitted first.
14860 // 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
14861 // 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 +020014862 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +020014863
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014864 auto &type_ids = ir.ids_for_type[TypeType];
14865 for (auto alias_itr = begin(type_ids); alias_itr != end(type_ids); ++alias_itr)
14866 {
14867 auto &type = get<SPIRType>(*alias_itr);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014868 if (type.type_alias != TypeID(0) &&
14869 !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked))
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014870 {
14871 // We will skip declaring this type, so make sure the type_alias type comes before.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020014872 auto master_itr = find(begin(type_ids), end(type_ids), ID(type.type_alias));
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +020014873 assert(master_itr != end(type_ids));
14874
14875 if (alias_itr < master_itr)
14876 {
14877 // Must also swap the type order for the constant-type joined array.
14878 auto &joined_types = ir.ids_for_constant_or_type;
14879 auto alt_alias_itr = find(begin(joined_types), end(joined_types), *alias_itr);
14880 auto alt_master_itr = find(begin(joined_types), end(joined_types), *master_itr);
14881 assert(alt_alias_itr != end(joined_types));
14882 assert(alt_master_itr != end(joined_types));
14883
14884 swap(*alias_itr, *master_itr);
14885 swap(*alt_alias_itr, *alt_master_itr);
14886 }
14887 }
14888 }
14889}
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020014890
14891void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
14892{
14893 // If we are redirecting statements, ignore the line directive.
14894 // Common case here is continue blocks.
14895 if (redirect_statement)
14896 return;
14897
14898 if (options.emit_line_directives)
14899 {
14900 require_extension_internal("GL_GOOGLE_cpp_style_line_directive");
14901 statement_no_indent("#line ", line_literal, " \"", get<SPIRString>(file_id).str, "\"");
14902 }
14903}
Hans-Kristian Arntzend12b54b2019-07-08 11:19:38 +020014904
14905void CompilerGLSL::propagate_nonuniform_qualifier(uint32_t id)
14906{
14907 // SPIR-V might only tag the very last ID with NonUniformEXT, but for codegen,
14908 // we need to know NonUniformEXT a little earlier, when the resource is actually loaded.
14909 // Back-propagate the qualifier based on the expression dependency chain.
14910
14911 if (!has_decoration(id, DecorationNonUniformEXT))
14912 {
14913 set_decoration(id, DecorationNonUniformEXT);
14914 force_recompile();
14915 }
14916
14917 auto *e = maybe_get<SPIRExpression>(id);
14918 auto *combined = maybe_get<SPIRCombinedImageSampler>(id);
14919 auto *chain = maybe_get<SPIRAccessChain>(id);
14920 if (e)
14921 {
14922 for (auto &expr : e->expression_dependencies)
14923 propagate_nonuniform_qualifier(expr);
14924 for (auto &expr : e->implied_read_expressions)
14925 propagate_nonuniform_qualifier(expr);
14926 }
14927 else if (combined)
14928 {
14929 propagate_nonuniform_qualifier(combined->image);
14930 propagate_nonuniform_qualifier(combined->sampler);
14931 }
14932 else if (chain)
14933 {
14934 for (auto &expr : chain->implied_read_expressions)
14935 propagate_nonuniform_qualifier(expr);
14936 }
14937}
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010014938
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010014939void 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 +010014940 SmallVector<uint32_t> chain)
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010014941{
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010014942 // Fully unroll all member/array indices one by one.
14943
14944 auto &lhs_type = get<SPIRType>(lhs_type_id);
14945 auto &rhs_type = get<SPIRType>(rhs_type_id);
14946
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010014947 if (!lhs_type.array.empty())
14948 {
14949 // Could use a loop here to support specialization constants, but it gets rather complicated with nested array types,
14950 // and this is a rather obscure opcode anyways, keep it simple unless we are forced to.
14951 uint32_t array_size = to_array_size_literal(lhs_type);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010014952 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010014953
14954 for (uint32_t i = 0; i < array_size; i++)
14955 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010014956 chain.back() = i;
14957 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 +010014958 }
14959 }
14960 else if (lhs_type.basetype == SPIRType::Struct)
14961 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010014962 chain.push_back(0);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010014963 uint32_t member_count = uint32_t(lhs_type.member_types.size());
14964 for (uint32_t i = 0; i < member_count; i++)
14965 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010014966 chain.back() = i;
14967 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 +010014968 }
14969 }
14970 else
14971 {
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010014972 // Need to handle unpack/packing fixups since this can differ wildly between the logical types,
14973 // particularly in MSL.
14974 // To deal with this, we emit access chains and go through emit_store_statement
14975 // to deal with all the special cases we can encounter.
14976
14977 AccessChainMeta lhs_meta, rhs_meta;
Hans-Kristian Arntzenb522b402020-01-08 10:48:30 +010014978 auto lhs = access_chain_internal(lhs_id, chain.data(), uint32_t(chain.size()),
14979 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &lhs_meta);
14980 auto rhs = access_chain_internal(rhs_id, chain.data(), uint32_t(chain.size()),
14981 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &rhs_meta);
Hans-Kristian Arntzencf725b42020-01-06 12:29:44 +010014982
14983 uint32_t id = ir.increase_bound_by(2);
14984 lhs_id = id;
14985 rhs_id = id + 1;
14986
14987 {
14988 auto &lhs_expr = set<SPIRExpression>(lhs_id, move(lhs), lhs_type_id, true);
14989 lhs_expr.need_transpose = lhs_meta.need_transpose;
14990
14991 if (lhs_meta.storage_is_packed)
14992 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypePacked);
14993 if (lhs_meta.storage_physical_type != 0)
14994 set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID, lhs_meta.storage_physical_type);
14995
14996 forwarded_temporaries.insert(lhs_id);
14997 suppressed_usage_tracking.insert(lhs_id);
14998 }
14999
15000 {
15001 auto &rhs_expr = set<SPIRExpression>(rhs_id, move(rhs), rhs_type_id, true);
15002 rhs_expr.need_transpose = rhs_meta.need_transpose;
15003
15004 if (rhs_meta.storage_is_packed)
15005 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypePacked);
15006 if (rhs_meta.storage_physical_type != 0)
15007 set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID, rhs_meta.storage_physical_type);
15008
15009 forwarded_temporaries.insert(rhs_id);
15010 suppressed_usage_tracking.insert(rhs_id);
15011 }
15012
15013 emit_store_statement(lhs_id, rhs_id);
Hans-Kristian Arntzen9012a392020-01-06 11:47:26 +010015014 }
15015}
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010015016
15017bool CompilerGLSL::subpass_input_is_framebuffer_fetch(uint32_t id) const
15018{
15019 if (!has_decoration(id, DecorationInputAttachmentIndex))
15020 return false;
15021
15022 uint32_t input_attachment_index = get_decoration(id, DecorationInputAttachmentIndex);
15023 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
15024 if (remap.first == input_attachment_index)
15025 return true;
15026
15027 return false;
15028}
15029
15030const SPIRVariable *CompilerGLSL::find_subpass_input_by_attachment_index(uint32_t index) const
15031{
15032 const SPIRVariable *ret = nullptr;
15033 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
15034 if (has_decoration(var.self, DecorationInputAttachmentIndex) &&
15035 get_decoration(var.self, DecorationInputAttachmentIndex) == index)
15036 {
15037 ret = &var;
15038 }
15039 });
15040 return ret;
15041}
15042
15043const SPIRVariable *CompilerGLSL::find_color_output_by_location(uint32_t location) const
15044{
15045 const SPIRVariable *ret = nullptr;
15046 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
15047 if (var.storage == StorageClassOutput && get_decoration(var.self, DecorationLocation) == location)
15048 ret = &var;
15049 });
15050 return ret;
15051}
15052
15053void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs()
15054{
15055 for (auto &remap : subpass_to_framebuffer_fetch_attachment)
15056 {
15057 auto *subpass_var = find_subpass_input_by_attachment_index(remap.first);
15058 auto *output_var = find_color_output_by_location(remap.second);
15059 if (!subpass_var)
15060 continue;
15061 if (!output_var)
crissdb52e272020-10-08 12:14:52 +020015062 SPIRV_CROSS_THROW("Need to declare the corresponding fragment output variable to be able "
15063 "to read from it.");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +010015064 if (is_array(get<SPIRType>(output_var->basetype)))
15065 SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs.");
15066
15067 auto &func = get<SPIRFunction>(get_entry_point().self);
15068 func.fixup_hooks_in.push_back([=]() {
15069 if (is_legacy())
15070 {
15071 statement(to_expression(subpass_var->self), " = ", "gl_LastFragData[",
15072 get_decoration(output_var->self, DecorationLocation), "];");
15073 }
15074 else
15075 {
15076 uint32_t num_rt_components = this->get<SPIRType>(output_var->basetype).vecsize;
15077 statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ",
15078 to_expression(output_var->self), ";");
15079 }
15080 });
15081 }
15082}
Hans-Kristian Arntzen941ccee2020-04-03 12:26:42 +020015083
15084bool CompilerGLSL::variable_is_depth_or_compare(VariableID id) const
15085{
15086 return image_is_comparison(get<SPIRType>(get<SPIRVariable>(id).basetype), id);
15087}
crissdb52e272020-10-08 12:14:52 +020015088
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015089const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extension_name(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015090{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015091 static const char *const retval[CandidateCount] = { "GL_KHR_shader_subgroup_ballot",
15092 "GL_KHR_shader_subgroup_basic",
15093 "GL_KHR_shader_subgroup_vote",
15094 "GL_NV_gpu_shader_5",
15095 "GL_NV_shader_thread_group",
15096 "GL_NV_shader_thread_shuffle",
15097 "GL_ARB_shader_ballot",
15098 "GL_ARB_shader_group_vote",
15099 "GL_AMD_gcn_shader" };
crissdb52e272020-10-08 12:14:52 +020015100 return retval[c];
15101}
15102
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015103SmallVector<std::string> CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_names(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015104{
15105 switch (c)
15106 {
15107 case ARB_shader_ballot:
15108 return { "GL_ARB_shader_int64" };
15109 case AMD_gcn_shader:
15110 return { "GL_AMD_gpu_shader_int64", "GL_NV_gpu_shader5" };
15111 default:
15112 return {};
15113 }
15114}
15115
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015116const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extra_required_extension_predicate(Candidate c)
crissdb52e272020-10-08 12:14:52 +020015117{
15118 switch (c)
15119 {
15120 case ARB_shader_ballot:
15121 return "defined(GL_ARB_shader_int64)";
15122 case AMD_gcn_shader:
15123 return "(defined(GL_AMD_gpu_shader_int64) || defined(GL_NV_gpu_shader5))";
15124 default:
15125 return "";
15126 }
15127}
15128
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015129CompilerGLSL::ShaderSubgroupSupportHelper::FeatureVector CompilerGLSL::ShaderSubgroupSupportHelper::
15130 get_feature_dependencies(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015131{
15132 switch (feature)
15133 {
15134 case SubgroupAllEqualT:
15135 return { SubgroupBrodcast_First, SubgroupAll_Any_AllEqualBool };
15136 case SubgroupElect:
15137 return { SubgroupBallotFindLSB_MSB, SubgroupBallot, SubgroupInvocationID };
15138 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
15139 return { SubgroupMask };
15140 case SubgroupBallotBitCount:
15141 return { SubgroupBallot };
15142 default:
15143 return {};
15144 }
15145}
15146
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015147CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::
15148 get_feature_dependency_mask(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015149{
15150 return build_mask(get_feature_dependencies(feature));
15151}
15152
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015153bool CompilerGLSL::ShaderSubgroupSupportHelper::can_feature_be_implemented_without_extensions(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015154{
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015155 static const bool retval[FeatureCount] = { false, false, false, false, false, false,
15156 true, // SubgroupBalloFindLSB_MSB
15157 false, false, false, false,
15158 true, // SubgroupMemBarrier - replaced with workgroup memory barriers
15159 false, false, true, false };
crissdb52e272020-10-08 12:14:52 +020015160
15161 return retval[feature];
15162}
15163
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015164CompilerGLSL::ShaderSubgroupSupportHelper::Candidate CompilerGLSL::ShaderSubgroupSupportHelper::
15165 get_KHR_extension_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015166{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015167 static const Candidate extensions[FeatureCount] = {
crissdb52e272020-10-08 12:14:52 +020015168 KHR_shader_subgroup_ballot, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic,
15169 KHR_shader_subgroup_basic, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_vote,
15170 KHR_shader_subgroup_vote, KHR_shader_subgroup_basic, KHR_shader_subgroup_ballot, KHR_shader_subgroup_basic,
15171 KHR_shader_subgroup_basic, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot
15172 };
15173
15174 return extensions[feature];
15175}
15176
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015177void CompilerGLSL::ShaderSubgroupSupportHelper::request_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015178{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015179 feature_mask |= (FeatureMask(1) << feature) | get_feature_dependency_mask(feature);
crissdb52e272020-10-08 12:14:52 +020015180}
15181
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015182bool CompilerGLSL::ShaderSubgroupSupportHelper::is_feature_requested(Feature feature) const
crissdb52e272020-10-08 12:14:52 +020015183{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015184 return (feature_mask & (1u << feature)) != 0;
crissdb52e272020-10-08 12:14:52 +020015185}
15186
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015187CompilerGLSL::ShaderSubgroupSupportHelper::Result CompilerGLSL::ShaderSubgroupSupportHelper::resolve() const
crissdb52e272020-10-08 12:14:52 +020015188{
15189 Result res;
15190
15191 for (uint32_t i = 0u; i < FeatureCount; ++i)
15192 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015193 if (feature_mask & (1u << i))
crissdb52e272020-10-08 12:14:52 +020015194 {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015195 auto feature = static_cast<Feature>(i);
15196 std::unordered_set<uint32_t> unique_candidates;
crissdb52e272020-10-08 12:14:52 +020015197
15198 auto candidates = get_candidates_for_feature(feature);
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015199 unique_candidates.insert(candidates.begin(), candidates.end());
crissdb52e272020-10-08 12:14:52 +020015200
15201 auto deps = get_feature_dependencies(feature);
15202 for (Feature d : deps)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015203 {
15204 candidates = get_candidates_for_feature(d);
15205 if (!candidates.empty())
15206 unique_candidates.insert(candidates.begin(), candidates.end());
15207 }
crissdb52e272020-10-08 12:14:52 +020015208
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015209 for (uint32_t c : unique_candidates)
15210 ++res.weights[static_cast<Candidate>(c)];
crissdb52e272020-10-08 12:14:52 +020015211 }
15212 }
15213
15214 return res;
15215}
15216
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015217CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
15218 get_candidates_for_feature(Feature ft, const Result &r)
crissdb52e272020-10-08 12:14:52 +020015219{
15220 auto c = get_candidates_for_feature(ft);
15221 auto cmp = [&r](Candidate a, Candidate b) {
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015222 if (r.weights[a] == r.weights[b])
15223 return a < b; // Prefer candidates with lower enum value
15224 return r.weights[a] > r.weights[b];
crissdb52e272020-10-08 12:14:52 +020015225 };
15226 std::sort(c.begin(), c.end(), cmp);
crissdb52e272020-10-08 12:14:52 +020015227 return c;
15228}
15229
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015230CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderSubgroupSupportHelper::
15231 get_candidates_for_feature(Feature feature)
crissdb52e272020-10-08 12:14:52 +020015232{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015233 switch (feature)
crissdb52e272020-10-08 12:14:52 +020015234 {
15235 case SubgroupMask:
15236 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
15237 case SubgroupSize:
15238 return { KHR_shader_subgroup_basic, NV_shader_thread_group, AMD_gcn_shader, ARB_shader_ballot };
15239 case SubgroupInvocationID:
15240 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot };
15241 case SubgroupID:
15242 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
15243 case NumSubgroups:
15244 return { KHR_shader_subgroup_basic, NV_shader_thread_group };
15245 case SubgroupBrodcast_First:
15246 return { KHR_shader_subgroup_ballot, NV_shader_thread_shuffle, ARB_shader_ballot };
15247 case SubgroupBallotFindLSB_MSB:
15248 return { KHR_shader_subgroup_ballot, NV_shader_thread_group };
15249 case SubgroupAll_Any_AllEqualBool:
15250 return { KHR_shader_subgroup_vote, NV_gpu_shader_5, ARB_shader_group_vote, AMD_gcn_shader };
15251 case SubgroupAllEqualT:
15252 return {}; // depends on other features only
15253 case SubgroupElect:
15254 return {}; // depends on other features only
15255 case SubgroupBallot:
15256 return { KHR_shader_subgroup_ballot, NV_shader_thread_group, ARB_shader_ballot };
15257 case SubgroupBarrier:
15258 return { KHR_shader_subgroup_basic, NV_shader_thread_group, ARB_shader_ballot, AMD_gcn_shader };
15259 case SubgroupMemBarrier:
15260 return { KHR_shader_subgroup_basic };
15261 case SubgroupInverseBallot_InclBitCount_ExclBitCout:
15262 return {};
15263 case SubgroupBallotBitExtract:
15264 return { NV_shader_thread_group };
15265 case SubgroupBallotBitCount:
15266 return {};
15267 default:
15268 return {};
15269 }
15270}
15271
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015272CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgroupSupportHelper::build_mask(
15273 const SmallVector<Feature> &features)
crissdb52e272020-10-08 12:14:52 +020015274{
15275 FeatureMask mask = 0;
crissdb52e272020-10-08 12:14:52 +020015276 for (Feature f : features)
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015277 mask |= FeatureMask(1) << f;
crissdb52e272020-10-08 12:14:52 +020015278 return mask;
15279}
15280
15281CompilerGLSL::ShaderSubgroupSupportHelper::Result::Result()
15282{
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015283 for (auto &weight : weights)
15284 weight = 0;
crissdb52e272020-10-08 12:14:52 +020015285
Hans-Kristian Arntzen56193292020-10-08 12:41:01 +020015286 // Make sure KHR_shader_subgroup extensions are always prefered.
15287 const uint32_t big_num = FeatureCount;
15288 weights[KHR_shader_subgroup_ballot] = big_num;
15289 weights[KHR_shader_subgroup_basic] = big_num;
15290 weights[KHR_shader_subgroup_vote] = big_num;
crissdb52e272020-10-08 12:14:52 +020015291}
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020015292
15293void CompilerGLSL::request_workaround_wrapper_overload(TypeID id)
15294{
15295 // Must be ordered to maintain deterministic output, so vector is appropriate.
15296 if (find(begin(workaround_ubo_load_overload_types), end(workaround_ubo_load_overload_types), id) ==
15297 end(workaround_ubo_load_overload_types))
15298 {
15299 force_recompile();
15300 workaround_ubo_load_overload_types.push_back(id);
15301 }
15302}
15303
15304void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID loaded_type, ID ptr)
15305{
15306 // Loading row-major matrices from UBOs on older AMD Windows OpenGL drivers is problematic.
15307 // To load these types correctly, we must first wrap them in a dummy function which only purpose is to
15308 // ensure row_major decoration is actually respected.
15309 auto *var = maybe_get_backing_variable(ptr);
15310 if (!var)
15311 return;
15312
15313 auto &backing_type = get<SPIRType>(var->basetype);
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +010015314 bool is_ubo = backing_type.basetype == SPIRType::Struct && backing_type.storage == StorageClassUniform &&
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020015315 has_decoration(backing_type.self, DecorationBlock);
15316 if (!is_ubo)
15317 return;
15318
15319 auto *type = &get<SPIRType>(loaded_type);
15320 bool rewrite = false;
15321
15322 if (is_matrix(*type))
15323 {
15324 // To avoid adding a lot of unnecessary meta tracking to forward the row_major state,
15325 // we will simply look at the base struct itself. It is exceptionally rare to mix and match row-major/col-major state.
15326 // If there is any row-major action going on, we apply the workaround.
15327 // It is harmless to apply the workaround to column-major matrices, so this is still a valid solution.
15328 // If an access chain occurred, the workaround is not required, so loading vectors or scalars don't need workaround.
15329 type = &backing_type;
15330 }
15331
15332 if (type->basetype == SPIRType::Struct)
15333 {
15334 // If we're loading a struct where any member is a row-major matrix, apply the workaround.
15335 for (uint32_t i = 0; i < uint32_t(type->member_types.size()); i++)
15336 {
15337 if (combined_decoration_for_member(*type, i).get(DecorationRowMajor))
15338 {
15339 rewrite = true;
15340 break;
15341 }
15342 }
15343 }
15344
15345 if (rewrite)
15346 {
15347 request_workaround_wrapper_overload(loaded_type);
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +010015348 expr = join("spvWorkaroundRowMajor(", expr, ")");
Hans-Kristian Arntzene47561a2020-10-14 15:51:49 +020015349 }
15350}