blob: 6d43582996578e4414b70b5efcd6c00fe30cee46 [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +01002 * Copyright 2015-2019 Arm Limited
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020017#include "spirv_glsl.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010018#include "GLSL.std.450.h"
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +020019#include "spirv_common.hpp"
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010020#include <algorithm>
21#include <assert.h>
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +010022#include <cmath>
Hans-Kristian Arntzencc7679e2018-07-17 00:10:12 +020023#include <limits>
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +010024#include <locale.h>
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +010025#include <utility>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010026
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +010027#ifndef _WIN32
28#include <langinfo.h>
29#endif
30#include <locale.h>
31
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010032using namespace spv;
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010033using namespace SPIRV_CROSS_NAMESPACE;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010034using namespace std;
35
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +020036static bool is_unsigned_opcode(Op op)
37{
38 // Don't have to be exhaustive, only relevant for legacy target checking ...
39 switch (op)
40 {
41 case OpShiftRightLogical:
42 case OpUGreaterThan:
43 case OpUGreaterThanEqual:
44 case OpULessThan:
45 case OpULessThanEqual:
46 case OpUConvert:
47 case OpUDiv:
48 case OpUMod:
49 case OpUMulExtended:
50 case OpConvertUToF:
51 case OpConvertFToU:
52 return true;
53
54 default:
55 return false;
56 }
57}
58
59static bool is_unsigned_glsl_opcode(GLSLstd450 op)
60{
61 // Don't have to be exhaustive, only relevant for legacy target checking ...
62 switch (op)
63 {
64 case GLSLstd450UClamp:
65 case GLSLstd450UMin:
66 case GLSLstd450UMax:
67 case GLSLstd450FindUMsb:
68 return true;
69
70 default:
71 return false;
72 }
73}
74
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +020075static bool packing_is_vec4_padded(BufferPackingStandard packing)
76{
77 switch (packing)
78 {
79 case BufferPackingHLSLCbuffer:
80 case BufferPackingHLSLCbufferPackOffset:
81 case BufferPackingStd140:
82 case BufferPackingStd140EnhancedLayout:
83 return true;
84
85 default:
86 return false;
87 }
88}
89
90static bool packing_is_hlsl(BufferPackingStandard packing)
91{
92 switch (packing)
93 {
94 case BufferPackingHLSLCbuffer:
95 case BufferPackingHLSLCbufferPackOffset:
96 return true;
97
98 default:
99 return false;
100 }
101}
102
103static bool packing_has_flexible_offset(BufferPackingStandard packing)
104{
105 switch (packing)
106 {
107 case BufferPackingStd140:
108 case BufferPackingStd430:
109 case BufferPackingHLSLCbuffer:
110 return false;
111
112 default:
113 return true;
114 }
115}
116
117static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard packing)
118{
119 switch (packing)
120 {
121 case BufferPackingStd140EnhancedLayout:
122 return BufferPackingStd140;
123 case BufferPackingStd430EnhancedLayout:
124 return BufferPackingStd430;
125 case BufferPackingHLSLCbufferPackOffset:
126 return BufferPackingHLSLCbuffer;
127 default:
128 return packing;
129 }
130}
131
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +0100132// Sanitizes underscores for GLSL where multiple underscores in a row are not allowed.
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +0200133string CompilerGLSL::sanitize_underscores(const string &str)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +0100134{
135 string res;
136 res.reserve(str.size());
137
138 bool last_underscore = false;
139 for (auto c : str)
140 {
141 if (c == '_')
142 {
143 if (last_underscore)
144 continue;
145
146 res += c;
147 last_underscore = true;
148 }
149 else
150 {
151 res += c;
152 last_underscore = false;
153 }
154 }
155 return res;
156}
157
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100158void CompilerGLSL::init()
159{
160 if (ir.source.known)
161 {
162 options.es = ir.source.es;
163 options.version = ir.source.version;
164 }
165
166 // Query the locale to see what the decimal point is.
167 // We'll rely on fixing it up ourselves in the rare case we have a comma-as-decimal locale
168 // rather than setting locales ourselves. Settings locales in a safe and isolated way is rather
169 // tricky.
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100170#ifdef _WIN32
171 // On Windows, localeconv uses thread-local storage, so it should be fine.
172 const struct lconv *conv = localeconv();
173 if (conv && conv->decimal_point)
174 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen73102742019-03-18 10:13:33 +0100175#elif defined(__ANDROID__) && __ANDROID_API__ < 26
176 // nl_langinfo is not supported on this platform, fall back to the worse alternative.
177 const struct lconv *conv = localeconv();
178 if (conv && conv->decimal_point)
179 current_locale_radix_character = *conv->decimal_point;
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100180#else
181 // localeconv, the portable function is not MT safe ...
Hans-Kristian Arntzen40965522019-02-28 12:32:52 +0100182 const char *decimal_point = nl_langinfo(RADIXCHAR);
Hans-Kristian Arntzen8255dd32019-02-28 11:51:08 +0100183 if (decimal_point && *decimal_point != '\0')
184 current_locale_radix_character = *decimal_point;
185#endif
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100186}
187
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200188static const char *to_pls_layout(PlsFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100189{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200190 switch (format)
191 {
192 case PlsR11FG11FB10F:
193 return "layout(r11f_g11f_b10f) ";
194 case PlsR32F:
195 return "layout(r32f) ";
196 case PlsRG16F:
197 return "layout(rg16f) ";
198 case PlsRGB10A2:
199 return "layout(rgb10_a2) ";
200 case PlsRGBA8:
201 return "layout(rgba8) ";
202 case PlsRG16:
203 return "layout(rg16) ";
204 case PlsRGBA8I:
205 return "layout(rgba8i)";
206 case PlsRG16I:
207 return "layout(rg16i) ";
208 case PlsRGB10A2UI:
209 return "layout(rgb10_a2ui) ";
210 case PlsRGBA8UI:
211 return "layout(rgba8ui) ";
212 case PlsRG16UI:
213 return "layout(rg16ui) ";
214 case PlsR32UI:
215 return "layout(r32ui) ";
216 default:
217 return "";
218 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100219}
220
221static SPIRType::BaseType pls_format_to_basetype(PlsFormat format)
222{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200223 switch (format)
224 {
225 default:
226 case PlsR11FG11FB10F:
227 case PlsR32F:
228 case PlsRG16F:
229 case PlsRGB10A2:
230 case PlsRGBA8:
231 case PlsRG16:
232 return SPIRType::Float;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100233
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200234 case PlsRGBA8I:
235 case PlsRG16I:
236 return SPIRType::Int;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200238 case PlsRGB10A2UI:
239 case PlsRGBA8UI:
240 case PlsRG16UI:
241 case PlsR32UI:
242 return SPIRType::UInt;
243 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100244}
245
246static uint32_t pls_format_to_components(PlsFormat format)
247{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200248 switch (format)
249 {
250 default:
251 case PlsR32F:
252 case PlsR32UI:
253 return 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100254
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200255 case PlsRG16F:
256 case PlsRG16:
257 case PlsRG16UI:
258 case PlsRG16I:
259 return 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200261 case PlsR11FG11FB10F:
262 return 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100263
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200264 case PlsRGB10A2:
265 case PlsRGBA8:
266 case PlsRGBA8I:
267 case PlsRGB10A2UI:
268 case PlsRGBA8UI:
269 return 4;
270 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100271}
272
Bill Hollings2d0d3282017-01-20 11:33:59 -0500273static const char *vector_swizzle(int vecsize, int index)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800274{
Bill Hollings2d0d3282017-01-20 11:33:59 -0500275 static const char *swizzle[4][4] = {
276 { ".x", ".y", ".z", ".w" }, { ".xy", ".yz", ".zw" }, { ".xyz", ".yzw" }, { "" }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800277 };
278
279 assert(vecsize >= 1 && vecsize <= 4);
280 assert(index >= 0 && index < 4);
281 assert(swizzle[vecsize - 1][index]);
282
283 return swizzle[vecsize - 1][index];
284}
285
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100286void CompilerGLSL::reset()
287{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200288 // We do some speculative optimizations which should pretty much always work out,
289 // but just in case the SPIR-V is rather weird, recompile until it's happy.
290 // This typically only means one extra pass.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200291 clear_force_recompile();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100292
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200293 // Clear invalid expression tracking.
294 invalid_expressions.clear();
295 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200297 // Clear temporary usage tracking.
298 expression_usage_counts.clear();
299 forwarded_temporaries.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100300
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +0100301 reset_name_caches();
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200302
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100303 ir.for_each_typed_id<SPIRFunction>([&](uint32_t, SPIRFunction &func) {
304 func.active = false;
305 func.flush_undeclared = true;
306 });
307
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +0100308 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) { var.dependees.clear(); });
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100309
310 ir.reset_all_of_type<SPIRExpression>();
311 ir.reset_all_of_type<SPIRAccessChain>();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100312
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200313 statement_count = 0;
314 indent = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100315}
316
317void CompilerGLSL::remap_pls_variables()
318{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200319 for (auto &input : pls_inputs)
320 {
321 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200323 bool input_is_target = false;
324 if (var.storage == StorageClassUniformConstant)
325 {
326 auto &type = get<SPIRType>(var.basetype);
327 input_is_target = type.image.dim == DimSubpassData;
328 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100329
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200330 if (var.storage != StorageClassInput && !input_is_target)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100331 SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200332 var.remapped_variable = true;
333 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200335 for (auto &output : pls_outputs)
336 {
337 auto &var = get<SPIRVariable>(output.id);
338 if (var.storage != StorageClassOutput)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100339 SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200340 var.remapped_variable = true;
341 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100342}
343
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200344void CompilerGLSL::find_static_extensions()
345{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100346 ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
347 if (type.basetype == SPIRType::Double)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200348 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100349 if (options.es)
350 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
351 if (!options.es && options.version < 400)
352 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200353 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100354 else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100355 {
356 if (options.es)
357 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
358 if (!options.es)
359 require_extension_internal("GL_ARB_gpu_shader_int64");
360 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100361 else if (type.basetype == SPIRType::Half)
362 {
363 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_float16");
364 if (options.vulkan_semantics)
365 require_extension_internal("GL_EXT_shader_16bit_storage");
366 }
367 else if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
368 {
369 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int8");
370 if (options.vulkan_semantics)
371 require_extension_internal("GL_EXT_shader_8bit_storage");
372 }
373 else if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
374 {
375 require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int16");
376 if (options.vulkan_semantics)
377 require_extension_internal("GL_EXT_shader_16bit_storage");
378 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100379 });
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200380
381 auto &execution = get_entry_point();
382 switch (execution.model)
383 {
384 case ExecutionModelGLCompute:
385 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200386 require_extension_internal("GL_ARB_compute_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200387 if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100388 SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200389 break;
390
391 case ExecutionModelGeometry:
392 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200393 require_extension_internal("GL_EXT_geometry_shader");
robfb1820e2017-06-17 10:06:46 +0900394 if (!options.es && options.version < 150)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200395 require_extension_internal("GL_ARB_geometry_shader4");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200396
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100397 if (execution.flags.get(ExecutionModeInvocations) && execution.invocations != 1)
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200398 {
399 // Instanced GS is part of 400 core or this extension.
400 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200401 require_extension_internal("GL_ARB_gpu_shader5");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200402 }
403 break;
404
405 case ExecutionModelTessellationEvaluation:
406 case ExecutionModelTessellationControl:
407 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200408 require_extension_internal("GL_EXT_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200409 if (!options.es && options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200410 require_extension_internal("GL_ARB_tessellation_shader");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200411 break;
412
Patrick Moursc74d7a42019-03-25 15:06:01 +0100413 case ExecutionModelRayGenerationNV:
414 case ExecutionModelIntersectionNV:
415 case ExecutionModelAnyHitNV:
416 case ExecutionModelClosestHitNV:
417 case ExecutionModelMissNV:
418 case ExecutionModelCallableNV:
419 if (options.es || options.version < 460)
420 SPIRV_CROSS_THROW("Ray tracing shaders require non-es profile with version 460 or above.");
Patrick Moursc96bab02019-03-26 14:04:39 +0100421 require_extension_internal("GL_NV_ray_tracing");
Patrick Moursc74d7a42019-03-25 15:06:01 +0100422 break;
423
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200424 default:
425 break;
426 }
427
428 if (!pls_inputs.empty() || !pls_outputs.empty())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200429 require_extension_internal("GL_EXT_shader_pixel_local_storage");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +0200430
431 if (options.separate_shader_objects && !options.es && options.version < 410)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200432 require_extension_internal("GL_ARB_separate_shader_objects");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200433}
434
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100435string CompilerGLSL::compile()
436{
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100437 if (options.vulkan_semantics)
438 backend.allow_precision_qualifiers = true;
Hans-Kristian Arntzenf708b492018-01-09 09:16:33 +0100439 backend.force_gl_in_out_block = true;
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +0100440 backend.supports_extensions = true;
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +0100441
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200442 // Scan the SPIR-V to find trivial uses of extensions.
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +0200443 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200444 find_static_extensions();
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +0100445 fixup_image_load_store_access();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100446 update_active_builtins();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +0100447 analyze_image_and_sampler_usage();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200448
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200449 uint32_t pass_count = 0;
450 do
451 {
452 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100453 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200455 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200457 // Move constructor for this type is broken on GCC 4.9 ...
458 buffer = unique_ptr<ostringstream>(new ostringstream());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100459
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200460 emit_header();
461 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100462
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200463 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100464
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200465 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +0200466 } while (is_forcing_recompilation());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100467
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100468 // Entry point in GLSL is always main().
469 get_entry_point().name = "main";
470
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200471 return buffer->str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100472}
473
Bill Hollingsc5c07362016-11-27 12:34:04 -0500474std::string CompilerGLSL::get_partial_source()
475{
Bill Hollingsf591bc02017-06-30 19:10:46 -0400476 return buffer ? buffer->str() : "No compiled source available yet.";
Bill Hollingsc5c07362016-11-27 12:34:04 -0500477}
478
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +0100479void CompilerGLSL::build_workgroup_size(vector<string> &arguments, const SpecializationConstant &wg_x,
480 const SpecializationConstant &wg_y, const SpecializationConstant &wg_z)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100481{
482 auto &execution = get_entry_point();
483
484 if (wg_x.id)
485 {
486 if (options.vulkan_semantics)
487 arguments.push_back(join("local_size_x_id = ", wg_x.constant_id));
488 else
489 arguments.push_back(join("local_size_x = ", get<SPIRConstant>(wg_x.id).specialization_constant_macro_name));
490 }
491 else
492 arguments.push_back(join("local_size_x = ", execution.workgroup_size.x));
493
494 if (wg_y.id)
495 {
496 if (options.vulkan_semantics)
497 arguments.push_back(join("local_size_y_id = ", wg_y.constant_id));
498 else
499 arguments.push_back(join("local_size_y = ", get<SPIRConstant>(wg_y.id).specialization_constant_macro_name));
500 }
501 else
502 arguments.push_back(join("local_size_y = ", execution.workgroup_size.y));
503
504 if (wg_z.id)
505 {
506 if (options.vulkan_semantics)
507 arguments.push_back(join("local_size_z_id = ", wg_z.constant_id));
508 else
509 arguments.push_back(join("local_size_z = ", get<SPIRConstant>(wg_z.id).specialization_constant_macro_name));
510 }
511 else
512 arguments.push_back(join("local_size_z = ", execution.workgroup_size.z));
513}
514
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100515void CompilerGLSL::emit_header()
516{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200517 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200518 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100519
Ben Claytone9621822017-10-09 10:33:42 +0100520 if (!options.es && options.version < 420)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200521 {
Ben Claytone9621822017-10-09 10:33:42 +0100522 // Needed for binding = # on UBOs, etc.
523 if (options.enable_420pack_extension)
524 {
525 statement("#ifdef GL_ARB_shading_language_420pack");
526 statement("#extension GL_ARB_shading_language_420pack : require");
527 statement("#endif");
528 }
529 // Needed for: layout(early_fragment_tests) in;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100530 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +0200531 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200532 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200534 for (auto &ext : forced_extensions)
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200535 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100536 if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16")
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200537 {
538 // Special case, this extension has a potential fallback to another vendor extension in normal GLSL.
539 // GL_AMD_gpu_shader_half_float is a superset, so try that first.
540 statement("#if defined(GL_AMD_gpu_shader_half_float)");
541 statement("#extension GL_AMD_gpu_shader_half_float : require");
Chip Davis1fb27b42018-10-31 09:43:03 -0500542 if (!options.vulkan_semantics)
543 {
544 statement("#elif defined(GL_NV_gpu_shader5)");
545 statement("#extension GL_NV_gpu_shader5 : require");
546 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100547 else
548 {
549 statement("#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)");
550 statement("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
551 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200552 statement("#else");
553 statement("#error No extension available for FP16.");
554 statement("#endif");
555 }
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100556 else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16")
Chip Davis1fb27b42018-10-31 09:43:03 -0500557 {
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +0100558 if (options.vulkan_semantics)
559 statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
560 else
561 {
562 statement("#if defined(GL_AMD_gpu_shader_int16)");
563 statement("#extension GL_AMD_gpu_shader_int16 : require");
564 statement("#else");
565 statement("#error No extension available for Int16.");
566 statement("#endif");
567 }
Chip Davis1fb27b42018-10-31 09:43:03 -0500568 }
Hans-Kristian Arntzenae859932018-08-23 15:37:09 +0200569 else
570 statement("#extension ", ext, " : require");
571 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100572
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200573 for (auto &header : header_lines)
574 statement(header);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200576 vector<string> inputs;
577 vector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100578
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200579 switch (execution.model)
580 {
581 case ExecutionModelGeometry:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200582 outputs.push_back(join("max_vertices = ", execution.output_vertices));
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100583 if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200584 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100585 if (execution.flags.get(ExecutionModeInputPoints))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200586 inputs.push_back("points");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100587 if (execution.flags.get(ExecutionModeInputLines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200588 inputs.push_back("lines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100589 if (execution.flags.get(ExecutionModeInputLinesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200590 inputs.push_back("lines_adjacency");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100591 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200592 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100593 if (execution.flags.get(ExecutionModeInputTrianglesAdjacency))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200594 inputs.push_back("triangles_adjacency");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100595 if (execution.flags.get(ExecutionModeOutputTriangleStrip))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200596 outputs.push_back("triangle_strip");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100597 if (execution.flags.get(ExecutionModeOutputPoints))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200598 outputs.push_back("points");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100599 if (execution.flags.get(ExecutionModeOutputLineStrip))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200600 outputs.push_back("line_strip");
601 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100602
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200603 case ExecutionModelTessellationControl:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100604 if (execution.flags.get(ExecutionModeOutputVertices))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200605 outputs.push_back(join("vertices = ", execution.output_vertices));
606 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100607
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200608 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100609 if (execution.flags.get(ExecutionModeQuads))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200610 inputs.push_back("quads");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100611 if (execution.flags.get(ExecutionModeTriangles))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200612 inputs.push_back("triangles");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100613 if (execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200614 inputs.push_back("isolines");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100615 if (execution.flags.get(ExecutionModePointMode))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200616 inputs.push_back("point_mode");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200617
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100618 if (!execution.flags.get(ExecutionModeIsolines))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200619 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100620 if (execution.flags.get(ExecutionModeVertexOrderCw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200621 inputs.push_back("cw");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100622 if (execution.flags.get(ExecutionModeVertexOrderCcw))
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200623 inputs.push_back("ccw");
624 }
625
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100626 if (execution.flags.get(ExecutionModeSpacingFractionalEven))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200627 inputs.push_back("fractional_even_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100628 if (execution.flags.get(ExecutionModeSpacingFractionalOdd))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200629 inputs.push_back("fractional_odd_spacing");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100630 if (execution.flags.get(ExecutionModeSpacingEqual))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200631 inputs.push_back("equal_spacing");
632 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100633
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200634 case ExecutionModelGLCompute:
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200635 {
636 if (execution.workgroup_size.constant != 0)
637 {
638 SpecializationConstant wg_x, wg_y, wg_z;
639 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
640
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +0100641 // If there are any spec constants on legacy GLSL, defer declaration, we need to set up macro
642 // declarations before we can emit the work group size.
643 if (options.vulkan_semantics || ((wg_x.id == 0) && (wg_y.id == 0) && (wg_z.id == 0)))
644 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200645 }
646 else
647 {
648 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
649 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
650 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
651 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200652 break;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200653 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200655 case ExecutionModelFragment:
656 if (options.es)
657 {
658 switch (options.fragment.default_float_precision)
659 {
660 case Options::Lowp:
661 statement("precision lowp float;");
662 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100663
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200664 case Options::Mediump:
665 statement("precision mediump float;");
666 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100667
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200668 case Options::Highp:
669 statement("precision highp float;");
670 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100671
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200672 default:
673 break;
674 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100675
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200676 switch (options.fragment.default_int_precision)
677 {
678 case Options::Lowp:
679 statement("precision lowp int;");
680 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100681
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200682 case Options::Mediump:
683 statement("precision mediump int;");
684 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200686 case Options::Highp:
687 statement("precision highp int;");
688 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100689
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200690 default:
691 break;
692 }
693 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100694
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100695 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200696 inputs.push_back("early_fragment_tests");
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +0100697
698 if (!options.es && execution.flags.get(ExecutionModeDepthGreater))
699 statement("layout(depth_greater) out float gl_FragDepth;");
700 else if (!options.es && execution.flags.get(ExecutionModeDepthLess))
701 statement("layout(depth_less) out float gl_FragDepth;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100702
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200703 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200705 default:
706 break;
707 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200709 if (!inputs.empty())
710 statement("layout(", merge(inputs), ") in;");
711 if (!outputs.empty())
712 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100713
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200714 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100715}
716
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +0100717bool CompilerGLSL::type_is_empty(const SPIRType &type)
718{
719 return type.basetype == SPIRType::Struct && type.member_types.empty();
720}
721
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200722void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100723{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200724 // Struct types can be stamped out multiple times
725 // with just different offsets, matrix layouts, etc ...
726 // Type-punning with these types is legal, which complicates things
727 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzen294259e2018-03-05 16:27:04 +0100728 // If the type master is packed however, we can no longer assume that the struct declaration will be redundant.
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +0100729 if (type.type_alias != 0 && !has_extended_decoration(type.type_alias, SPIRVCrossDecorationPacked))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200730 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200731
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200732 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200733 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100734
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200735 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200736 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100737
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200738 type.member_name_cache.clear();
739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200740 uint32_t i = 0;
741 bool emitted = false;
742 for (auto &member : type.member_types)
743 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200744 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -0500745 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200746 i++;
747 emitted = true;
748 }
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +0200749
750 // Don't declare empty structs in GLSL, this is not allowed.
751 if (type_is_empty(type) && !backend.supports_empty_struct)
752 {
753 statement("int empty_struct_member;");
754 emitted = true;
755 }
756
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200757 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100758
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200759 if (emitted)
760 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100761}
762
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100763string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200764{
765 string res;
766 //if (flags & (1ull << DecorationSmooth))
767 // res += "smooth ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100768 if (flags.get(DecorationFlat))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200769 res += "flat ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100770 if (flags.get(DecorationNoPerspective))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200771 res += "noperspective ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100772 if (flags.get(DecorationCentroid))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200773 res += "centroid ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100774 if (flags.get(DecorationPatch))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200775 res += "patch ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100776 if (flags.get(DecorationSample))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200777 res += "sample ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100778 if (flags.get(DecorationInvariant))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200779 res += "invariant ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100780 if (flags.get(DecorationExplicitInterpAMD))
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +0100781 res += "__explicitInterpAMD ";
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200782
783 return res;
784}
785
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100786string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
787{
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +0100788 if (is_legacy())
789 return "";
790
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200791 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
792 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200793 if (!is_block)
794 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100795
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200796 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200797 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +0200798 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200799 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100800
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200801 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100802
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200803 // We can only apply layouts on members in block interfaces.
804 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
805 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
806 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
807 //
808 // We would like to go from (SPIR-V style):
809 //
810 // struct Foo { layout(row_major) mat4 matrix; };
811 // buffer UBO { Foo foo; };
812 //
813 // to
814 //
815 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
816 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
817 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100818
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100819 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200820 attr.push_back("row_major");
821 // We don't emit any global layouts, so column_major is default.
822 //if (flags & (1ull << DecorationColMajor))
823 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100824
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +0200825 if (dec.decoration_flags.get(DecorationLocation) && can_use_io_location(type.storage, true))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200826 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100827
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +0200828 // Can only declare component if we can declare location.
829 if (dec.decoration_flags.get(DecorationComponent) && can_use_io_location(type.storage, true))
830 {
831 if (!options.es)
832 {
833 if (options.version < 440 && options.version >= 140)
834 require_extension_internal("GL_ARB_enhanced_layouts");
835 else if (options.version < 140)
836 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
837 attr.push_back(join("component = ", dec.component));
838 }
839 else
840 SPIRV_CROSS_THROW("Component decoration is not supported in ES targets.");
841 }
842
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +0100843 // 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 +0200844 // This is only done selectively in GLSL as needed.
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +0100845 if (has_extended_decoration(type.self, SPIRVCrossDecorationPacked) && dec.decoration_flags.get(DecorationOffset))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +0200846 attr.push_back(join("offset = ", dec.offset));
847
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200848 if (attr.empty())
849 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100850
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200851 string res = "layout(";
852 res += merge(attr);
853 res += ") ";
854 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100855}
856
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200857const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100858{
Brad Davis76204002018-06-20 10:25:38 -0700859 if (options.es && is_desktop_only_format(format))
860 SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200861
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200862 switch (format)
863 {
864 case ImageFormatRgba32f:
865 return "rgba32f";
866 case ImageFormatRgba16f:
867 return "rgba16f";
868 case ImageFormatR32f:
869 return "r32f";
870 case ImageFormatRgba8:
871 return "rgba8";
872 case ImageFormatRgba8Snorm:
873 return "rgba8_snorm";
874 case ImageFormatRg32f:
875 return "rg32f";
876 case ImageFormatRg16f:
877 return "rg16f";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200878 case ImageFormatRgba32i:
879 return "rgba32i";
880 case ImageFormatRgba16i:
881 return "rgba16i";
882 case ImageFormatR32i:
883 return "r32i";
884 case ImageFormatRgba8i:
885 return "rgba8i";
886 case ImageFormatRg32i:
887 return "rg32i";
888 case ImageFormatRg16i:
889 return "rg16i";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200890 case ImageFormatRgba32ui:
891 return "rgba32ui";
892 case ImageFormatRgba16ui:
893 return "rgba16ui";
894 case ImageFormatR32ui:
895 return "r32ui";
896 case ImageFormatRgba8ui:
897 return "rgba8ui";
898 case ImageFormatRg32ui:
899 return "rg32ui";
900 case ImageFormatRg16ui:
901 return "rg16ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200902 case ImageFormatR11fG11fB10f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200903 return "r11f_g11f_b10f";
904 case ImageFormatR16f:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200905 return "r16f";
906 case ImageFormatRgb10A2:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200907 return "rgb10_a2";
908 case ImageFormatR8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200909 return "r8";
910 case ImageFormatRg8:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200911 return "rg8";
912 case ImageFormatR16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200913 return "r16";
914 case ImageFormatRg16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200915 return "rg16";
916 case ImageFormatRgba16:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200917 return "rgba16";
918 case ImageFormatR16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200919 return "r16_snorm";
920 case ImageFormatRg16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200921 return "rg16_snorm";
922 case ImageFormatRgba16Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200923 return "rgba16_snorm";
924 case ImageFormatR8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200925 return "r8_snorm";
926 case ImageFormatRg8Snorm:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200927 return "rg8_snorm";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200928 case ImageFormatR8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200929 return "r8ui";
930 case ImageFormatRg8ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200931 return "rg8ui";
932 case ImageFormatR16ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200933 return "r16ui";
934 case ImageFormatRgb10a2ui:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200935 return "rgb10_a2ui";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200936 case ImageFormatR8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200937 return "r8i";
938 case ImageFormatRg8i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200939 return "rg8i";
940 case ImageFormatR16i:
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200941 return "r16i";
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200942 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200943 case ImageFormatUnknown:
944 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200945 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100946}
947
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200948uint32_t CompilerGLSL::type_to_packed_base_size(const SPIRType &type, BufferPackingStandard)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200949{
950 switch (type.basetype)
951 {
952 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200953 case SPIRType::Int64:
954 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200955 return 8;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +0100956 case SPIRType::Float:
957 case SPIRType::Int:
958 case SPIRType::UInt:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200959 return 4;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +0100960 case SPIRType::Half:
Chip Davis117ccf42018-11-01 17:20:07 -0500961 case SPIRType::Short:
962 case SPIRType::UShort:
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +0100963 return 2;
Chip Davis117ccf42018-11-01 17:20:07 -0500964 case SPIRType::SByte:
965 case SPIRType::UByte:
966 return 1;
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +0100967
968 default:
969 SPIRV_CROSS_THROW("Unrecognized type in type_to_packed_base_size.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200970 }
971}
972
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +0100973uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bitset &flags,
974 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100975{
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200976 if (!type.array.empty())
977 {
978 uint32_t minimum_alignment = 1;
979 if (packing_is_vec4_padded(packing))
980 minimum_alignment = 16;
981
982 auto *tmp = &get<SPIRType>(type.parent_type);
983 while (!tmp->array.empty())
984 tmp = &get<SPIRType>(tmp->parent_type);
985
986 // Get the alignment of the base type, then maybe round up.
987 return max(minimum_alignment, type_to_packed_alignment(*tmp, flags, packing));
988 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100989
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200990 if (type.basetype == SPIRType::Struct)
991 {
992 // Rule 9. Structs alignments are maximum alignment of its members.
Hans-Kristian Arntzen8c632da2019-01-28 11:02:28 +0100993 uint32_t alignment = 1;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200994 for (uint32_t i = 0; i < type.member_types.size(); i++)
995 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100996 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +0200997 alignment =
998 max(alignment, type_to_packed_alignment(get<SPIRType>(type.member_types[i]), member_flags, packing));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200999 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001000
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001001 // In std140, struct alignment is rounded up to 16.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001002 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001003 alignment = max(alignment, 16u);
1004
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001005 return alignment;
1006 }
1007 else
1008 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001009 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1010
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001011 // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle
1012 // a vec4, this is handled outside since that part knows our current offset.
1013 if (type.columns == 1 && packing_is_hlsl(packing))
1014 return base_alignment;
1015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001016 // From 7.6.2.2 in GL 4.5 core spec.
1017 // Rule 1
1018 if (type.vecsize == 1 && type.columns == 1)
1019 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001020
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001021 // Rule 2
1022 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
1023 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001025 // Rule 3
1026 if (type.vecsize == 3 && type.columns == 1)
1027 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001028
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001029 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001030
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001031 // Rule 5. Column-major matrices are stored as arrays of
1032 // vectors.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001033 if (flags.get(DecorationColMajor) && type.columns > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001034 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001035 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001036 return 4 * base_alignment;
1037 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001038 return 4 * base_alignment;
1039 else
1040 return type.vecsize * base_alignment;
1041 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001043 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001044
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001045 // Rule 7.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001046 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001047 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001048 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001049 return 4 * base_alignment;
1050 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001051 return 4 * base_alignment;
1052 else
1053 return type.columns * base_alignment;
1054 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001055
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001056 // Rule 8 implied.
1057 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001058
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001059 SPIRV_CROSS_THROW("Did not find suitable rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001060}
1061
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01001062uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, const Bitset &flags,
1063 BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001064{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001065 // Array stride is equal to aligned size of the underlying type.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001066 uint32_t parent = type.parent_type;
1067 assert(parent);
1068
1069 auto &tmp = get<SPIRType>(parent);
1070
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001071 uint32_t size = type_to_packed_size(tmp, flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001072 if (tmp.array.empty())
1073 {
1074 uint32_t alignment = type_to_packed_alignment(type, flags, packing);
1075 return (size + alignment - 1) & ~(alignment - 1);
1076 }
1077 else
1078 {
1079 // For multidimensional arrays, array stride always matches size of subtype.
1080 // The alignment cannot change because multidimensional arrays are basically N * M array elements.
1081 return size;
1082 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001083}
1084
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001085uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001086{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001087 if (!type.array.empty())
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001088 {
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001089 return to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001090 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001091
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001092 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001094 if (type.basetype == SPIRType::Struct)
1095 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001096 uint32_t pad_alignment = 1;
1097
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001098 for (uint32_t i = 0; i < type.member_types.size(); i++)
1099 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001100 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001101 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001102
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001103 uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
1104 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001105
1106 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1107 // GL 4.5 spec, 7.6.2.2.
1108 if (member_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001109 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001110 else
1111 pad_alignment = 1;
1112
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001113 size = (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001114 size += type_to_packed_size(member_type, member_flags, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001115 }
1116 }
1117 else
1118 {
Hans-Kristian Arntzenbc0f6982018-03-06 15:39:12 +01001119 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
1120
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001121 if (type.columns == 1)
1122 size = type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001123
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001124 if (flags.get(DecorationColMajor) && type.columns > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001125 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001126 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001127 size = type.columns * 4 * base_alignment;
1128 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001129 size = type.columns * 4 * base_alignment;
1130 else
1131 size = type.columns * type.vecsize * base_alignment;
1132 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001133
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001134 if (flags.get(DecorationRowMajor) && type.vecsize > 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001135 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001136 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001137 size = type.vecsize * 4 * base_alignment;
1138 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001139 size = type.vecsize * 4 * base_alignment;
1140 else
1141 size = type.vecsize * type.columns * base_alignment;
1142 }
1143 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001144
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001145 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001146}
1147
msiglreithd096f5c2017-11-27 16:00:56 +01001148bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
1149 uint32_t start_offset, uint32_t end_offset)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001150{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001151 // This is very tricky and error prone, but try to be exhaustive and correct here.
1152 // SPIR-V doesn't directly say if we're using std430 or std140.
1153 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
1154 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
1155 // 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).
1156 //
1157 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
1158 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
1159 //
1160 // The only two differences between std140 and std430 are related to padding alignment/array stride
1161 // in arrays and structs. In std140 they take minimum vec4 alignment.
1162 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001163
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001164 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001165 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001166
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001167 bool is_top_level_block =
1168 has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
1169
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001170 for (uint32_t i = 0; i < type.member_types.size(); i++)
1171 {
1172 auto &memb_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01001173 auto member_flags = ir.meta[type.self].members[i].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001174
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001175 // Verify alignment rules.
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001176 uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001177
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01001178 // This is a rather dirty workaround to deal with some cases of OpSpecConstantOp used as array size, e.g:
1179 // layout(constant_id = 0) const int s = 10;
1180 // const int S = s + 5; // SpecConstantOp
1181 // buffer Foo { int data[S]; }; // <-- Very hard for us to deduce a fixed value here,
1182 // we would need full implementation of compile-time constant folding. :(
1183 // If we are the last member of a struct, there might be cases where the actual size of that member is irrelevant
1184 // for our analysis (e.g. unsized arrays).
1185 // This lets us simply ignore that there are spec constant op sized arrays in our buffers.
1186 // Querying size of this member will fail, so just don't call it unless we have to.
1187 //
1188 // This is likely "best effort" we can support without going into unacceptably complicated workarounds.
1189 bool member_can_be_unsized =
1190 is_top_level_block && size_t(i + 1) == type.member_types.size() && !memb_type.array.empty();
1191
1192 uint32_t packed_size = 0;
1193 if (!member_can_be_unsized)
1194 packed_size = type_to_packed_size(memb_type, member_flags, packing);
1195
1196 // 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 +02001197 if (packing_is_hlsl(packing))
1198 {
1199 // If a member straddles across a vec4 boundary, alignment is actually vec4.
1200 uint32_t begin_word = offset / 16;
1201 uint32_t end_word = (offset + packed_size - 1) / 16;
1202 if (begin_word != end_word)
1203 packed_alignment = max(packed_alignment, 16u);
1204 }
1205
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001206 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001207 offset = (offset + alignment - 1) & ~(alignment - 1);
1208
msiglreithd096f5c2017-11-27 16:00:56 +01001209 // Field is not in the specified range anymore and we can ignore any further fields.
1210 if (offset >= end_offset)
1211 break;
1212
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001213 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1214 // GL 4.5 spec, 7.6.2.2.
1215 if (memb_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001216 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001217 else
1218 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001219
msiglreithd096f5c2017-11-27 16:00:56 +01001220 // Only care about packing if we are in the given range
1221 if (offset >= start_offset)
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001222 {
msiglreithd096f5c2017-11-27 16:00:56 +01001223 // We only care about offsets in std140, std430, etc ...
1224 // For EnhancedLayout variants, we have the flexibility to choose our own offsets.
1225 if (!packing_has_flexible_offset(packing))
1226 {
1227 uint32_t actual_offset = type_struct_member_offset(type, i);
1228 if (actual_offset != offset) // This cannot be the packing we're looking for.
1229 return false;
1230 }
1231
1232 // Verify array stride rules.
1233 if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
1234 type_struct_member_array_stride(type, i))
1235 return false;
1236
1237 // Verify that sub-structs also follow packing rules.
1238 // We cannot use enhanced layouts on substructs, so they better be up to spec.
1239 auto substruct_packing = packing_to_substruct_packing(packing);
1240
1241 if (!memb_type.member_types.empty() && !buffer_is_packing_standard(memb_type, substruct_packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001242 return false;
1243 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001244
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001245 // Bump size.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001246 offset += packed_size;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001247 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001248
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001249 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001250}
1251
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001252bool CompilerGLSL::can_use_io_location(StorageClass storage, bool block)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001253{
1254 // Location specifiers are must have in SPIR-V, but they aren't really supported in earlier versions of GLSL.
1255 // Be very explicit here about how to solve the issue.
1256 if ((get_execution_model() != ExecutionModelVertex && storage == StorageClassInput) ||
1257 (get_execution_model() != ExecutionModelFragment && storage == StorageClassOutput))
1258 {
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001259 uint32_t minimum_desktop_version = block ? 440 : 410;
1260 // ARB_enhanced_layouts vs ARB_separate_shader_objects ...
1261
1262 if (!options.es && options.version < minimum_desktop_version && !options.separate_shader_objects)
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001263 return false;
1264 else if (options.es && options.version < 310)
1265 return false;
1266 }
1267
1268 if ((get_execution_model() == ExecutionModelVertex && storage == StorageClassInput) ||
1269 (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput))
1270 {
1271 if (options.es && options.version < 300)
1272 return false;
1273 else if (!options.es && options.version < 330)
1274 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001275 }
1276
Hans-Kristian Arntzen1389aa32019-03-19 11:20:25 +01001277 if (storage == StorageClassUniform || storage == StorageClassUniformConstant || storage == StorageClassPushConstant)
Andrei Alexeyev4a430242018-04-07 22:14:35 +03001278 {
1279 if (options.es && options.version < 310)
1280 return false;
1281 else if (!options.es && options.version < 430)
1282 return false;
1283 }
1284
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001285 return true;
1286}
1287
1288string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
1289{
Hans-Kristian Arntzen62d223a2016-09-21 08:20:04 +02001290 // FIXME: Come up with a better solution for when to disable layouts.
1291 // Having layouts depend on extensions as well as which types
1292 // of layouts are used. For now, the simple solution is to just disable
1293 // layouts for legacy versions.
1294 if (is_legacy())
rob42fe8c32016-09-18 13:18:33 +09001295 return "";
1296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001297 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001298
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001299 auto &dec = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001300 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01001301 auto &flags = dec.decoration_flags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001302 auto typeflags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001303
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001304 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
1305 attr.push_back("push_constant");
1306
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001307 if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001308 attr.push_back("row_major");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001309 if (flags.get(DecorationColMajor))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001310 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001311
1312 if (options.vulkan_semantics)
1313 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001314 if (flags.get(DecorationInputAttachmentIndex))
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001315 attr.push_back(join("input_attachment_index = ", dec.input_attachment));
1316 }
1317
Hans-Kristian Arntzenb06c1af2018-04-17 14:16:27 +02001318 bool is_block = has_decoration(type.self, DecorationBlock);
1319 if (flags.get(DecorationLocation) && can_use_io_location(var.storage, is_block))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001320 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001321 Bitset combined_decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001322 for (uint32_t i = 0; i < ir.meta[type.self].members.size(); i++)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001323 combined_decoration.merge_or(combined_decoration_for_member(type, i));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001324
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001325 // If our members have location decorations, we don't need to
1326 // emit location decorations at the top as well (looks weird).
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001327 if (!combined_decoration.get(DecorationLocation))
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001328 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001329 }
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001330
Hans-Kristian Arntzen63f64662018-09-10 12:13:26 +02001331 // Can only declare Component if we can declare location.
1332 if (flags.get(DecorationComponent) && can_use_io_location(var.storage, is_block))
1333 {
1334 if (!options.es)
1335 {
1336 if (options.version < 440 && options.version >= 140)
1337 require_extension_internal("GL_ARB_enhanced_layouts");
1338 else if (options.version < 140)
1339 SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40.");
1340 attr.push_back(join("component = ", dec.component));
1341 }
1342 else
1343 SPIRV_CROSS_THROW("Component decoration is not supported in ES targets.");
1344 }
1345
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001346 if (flags.get(DecorationIndex))
1347 attr.push_back(join("index = ", dec.index));
1348
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001349 // Do not emit set = decoration in regular GLSL output, but
1350 // we need to preserve it in Vulkan GLSL mode.
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001351 if (var.storage != StorageClassPushConstant)
1352 {
Hans-Kristian Arntzen3a9b0452018-06-03 12:00:22 +02001353 if (flags.get(DecorationDescriptorSet) && options.vulkan_semantics)
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001354 attr.push_back(join("set = ", dec.set));
1355 }
1356
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001357 // GL 3.0/GLSL 1.30 is not considered legacy, but it doesn't have UBOs ...
1358 bool can_use_buffer_blocks = (options.es && options.version >= 300) || (!options.es && options.version >= 140);
1359
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001360 bool can_use_binding;
1361 if (options.es)
1362 can_use_binding = options.version >= 310;
1363 else
1364 can_use_binding = options.enable_420pack_extension || (options.version >= 420);
1365
Hans-Kristian Arntzen938040b2018-04-03 16:58:05 +02001366 // Make sure we don't emit binding layout for a classic uniform on GLSL 1.30.
1367 if (!can_use_buffer_blocks && var.storage == StorageClassUniform)
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001368 can_use_binding = false;
1369
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001370 if (can_use_binding && flags.get(DecorationBinding))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001371 attr.push_back(join("binding = ", dec.binding));
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001372
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001373 if (flags.get(DecorationOffset))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001374 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001375
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001376 bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
1377 bool ssbo_block = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001378 (var.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001379 bool emulated_ubo = var.storage == StorageClassPushConstant && options.emit_push_constant_as_uniform_buffer;
1380 bool ubo_block = var.storage == StorageClassUniform && typeflags.get(DecorationBlock);
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001381
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001382 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
1383 // If SPIR-V does not comply with either layout, we cannot really work around it.
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001384 if (can_use_buffer_blocks && (ubo_block || emulated_ubo))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001385 {
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001386 if (buffer_is_packing_standard(type, BufferPackingStd140))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001387 attr.push_back("std140");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001388 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001389 {
Hans-Kristian Arntzen4d112202017-10-10 11:30:29 +02001390 attr.push_back("std140");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001391 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
1392 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
1393 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
1394 if (options.es && !options.vulkan_semantics)
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001395 SPIRV_CROSS_THROW("Uniform buffer block cannot be expressed as std140. ES-targets do "
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001396 "not support GL_ARB_enhanced_layouts.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001397 if (!options.es && !options.vulkan_semantics && options.version < 440)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02001398 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001399
1400 // This is a very last minute to check for this, but use this unused decoration to mark that we should emit
1401 // explicit offsets for this block type.
1402 // layout_for_variable() will be called before the actual buffer emit.
1403 // The alternative is a full pass before codegen where we deduce this decoration,
1404 // but then we are just doing the exact same work twice, and more complexity.
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001405 set_extended_decoration(type.self, SPIRVCrossDecorationPacked);
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001406 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001407 else
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001408 {
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001409 SPIRV_CROSS_THROW("Uniform buffer cannot be expressed as std140, even with enhanced layouts. You can try "
1410 "flattening this block to "
1411 "support a more flexible layout.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001412 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001413 }
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001414 else if (can_use_buffer_blocks && (push_constant_block || ssbo_block))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001415 {
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001416 if (buffer_is_packing_standard(type, BufferPackingStd430))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001417 attr.push_back("std430");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001418 else if (buffer_is_packing_standard(type, BufferPackingStd140))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001419 attr.push_back("std140");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001420 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001421 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001422 attr.push_back("std140");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001423
1424 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
1425 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
1426 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
1427 if (options.es && !options.vulkan_semantics)
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001428 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1429 "not support GL_ARB_enhanced_layouts.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001430 if (!options.es && !options.vulkan_semantics && options.version < 440)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02001431 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001432
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001433 set_extended_decoration(type.self, SPIRVCrossDecorationPacked);
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001434 }
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001435 else if (buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001436 {
1437 attr.push_back("std430");
1438 if (options.es && !options.vulkan_semantics)
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001439 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1440 "not support GL_ARB_enhanced_layouts.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001441 if (!options.es && !options.vulkan_semantics && options.version < 440)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02001442 require_extension_internal("GL_ARB_enhanced_layouts");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001443
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001444 set_extended_decoration(type.self, SPIRVCrossDecorationPacked);
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001445 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001446 else
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001447 {
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001448 SPIRV_CROSS_THROW("Buffer block cannot be expressed as neither std430 nor std140, even with enhanced "
1449 "layouts. You can try flattening this block to support a more flexible layout.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001450 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001451 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001453 // For images, the type itself adds a layout qualifer.
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02001454 // Only emit the format for storage images.
1455 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001456 {
1457 const char *fmt = format_to_glsl(type.image.format);
1458 if (fmt)
1459 attr.push_back(fmt);
1460 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001461
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001462 if (attr.empty())
1463 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001464
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001465 string res = "layout(";
1466 res += merge(attr);
1467 res += ") ";
1468 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001469}
1470
1471void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
1472{
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01001473 if (flattened_buffer_blocks.count(var.self))
1474 emit_buffer_block_flattened(var);
1475 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001476 emit_push_constant_block_vulkan(var);
Hans-Kristian Arntzen04748482019-03-19 10:58:37 +01001477 else if (options.emit_push_constant_as_uniform_buffer)
1478 emit_buffer_block_native(var);
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001479 else
1480 emit_push_constant_block_glsl(var);
1481}
1482
1483void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
1484{
1485 emit_buffer_block(var);
1486}
1487
1488void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
1489{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001490 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
1491 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001492
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001493 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001494 flags.clear(DecorationBinding);
1495 flags.clear(DecorationDescriptorSet);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001496
1497#if 0
1498 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001499 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001500 "Remap to location with reflection API first or disable these decorations.");
1501#endif
1502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001503 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1504 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001505 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001506 bool block_flag = block_flags.get(DecorationBlock);
1507 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001508
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001509 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001510
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001511 if (block_flag)
1512 block_flags.set(DecorationBlock);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001513
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001514 emit_uniform(var);
1515 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001516}
1517
1518void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
1519{
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001520 if (flattened_buffer_blocks.count(var.self))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001521 emit_buffer_block_flattened(var);
Hans-Kristian Arntzenfe697a82018-04-03 16:46:58 +02001522 else if (is_legacy() || (!options.es && options.version == 130))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001523 emit_buffer_block_legacy(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001524 else
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001525 emit_buffer_block_native(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001526}
1527
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001528void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
1529{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001530 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001531 bool ssbo = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001532 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001533 if (ssbo)
1534 SPIRV_CROSS_THROW("SSBOs not supported in legacy targets.");
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001535
1536 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1537 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001538 auto &block_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001539 bool block_flag = block_flags.get(DecorationBlock);
1540 block_flags.clear(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001541 emit_struct(type);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001542 if (block_flag)
1543 block_flags.set(DecorationBlock);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001544 emit_uniform(var);
1545 statement("");
1546}
1547
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001548void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001549{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001550 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01001551
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001552 Bitset flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001553 bool ssbo = var.storage == StorageClassStorageBuffer ||
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001554 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001555 bool is_restrict = ssbo && flags.get(DecorationRestrict);
1556 bool is_writeonly = ssbo && flags.get(DecorationNonReadable);
1557 bool is_readonly = ssbo && flags.get(DecorationNonWritable);
1558 bool is_coherent = ssbo && flags.get(DecorationCoherent);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001559
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001560 // 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 +02001561 auto buffer_name = to_name(type.self, false);
1562
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02001563 auto &block_namespace = ssbo ? block_ssbo_names : block_ubo_names;
1564
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001565 // Shaders never use the block by interface name, so we don't
1566 // have to track this other than updating name caches.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01001567 // If we have a collision for any reason, just fallback immediately.
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01001568 if (ir.meta[type.self].decoration.alias.empty() || block_namespace.find(buffer_name) != end(block_namespace) ||
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01001569 resource_names.find(buffer_name) != end(resource_names))
1570 {
Hans-Kristian Arntzenaab31072017-09-29 12:16:53 +02001571 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01001572 }
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001573
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01001574 // Make sure we get something unique for both global name scope and block name scope.
1575 // See GLSL 4.5 spec: section 4.3.9 for details.
1576 add_variable(block_namespace, resource_names, buffer_name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001577
1578 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
1579 // This cannot conflict with anything else, so we're safe now.
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01001580 // 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 +01001581 if (buffer_name.empty())
1582 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
1583
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01001584 block_names.insert(buffer_name);
1585 block_namespace.insert(buffer_name);
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02001586
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001587 // Save for post-reflection later.
1588 declared_block_names[var.self] = buffer_name;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001589
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02001590 statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
1591 is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
1592 buffer_name);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01001593
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001594 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001595
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001596 type.member_name_cache.clear();
1597
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001598 uint32_t i = 0;
1599 for (auto &member : type.member_types)
1600 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001601 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05001602 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001603 i++;
1604 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001605
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +01001606 // var.self can be used as a backup name for the block name,
1607 // so we need to make sure we don't disturb the name here on a recompile.
1608 // It will need to be reset if we have to recompile.
1609 preserve_alias_on_reset(var.self);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001610 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001611 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
1612 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001613}
1614
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001615void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08001616{
1617 auto &type = get<SPIRType>(var.basetype);
1618
1619 // Block names should never alias.
1620 auto buffer_name = to_name(type.self, false);
1621 size_t buffer_size = (get_declared_struct_size(type) + 15) / 16;
1622
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001623 SPIRType::BaseType basic_type;
1624 if (get_common_basic_type(type, basic_type))
1625 {
1626 SPIRType tmp;
1627 tmp.basetype = basic_type;
Hans-Kristian Arntzenefba6102017-01-22 08:53:52 +01001628 tmp.vecsize = 4;
1629 if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt)
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001630 SPIRV_CROSS_THROW("Basic types in a flattened UBO must be float, int or uint.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001631
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001632 auto flags = ir.get_buffer_block_flags(var);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01001633 statement("uniform ", flags_to_precision_qualifiers_glsl(tmp, flags), type_to_glsl(tmp), " ", buffer_name, "[",
1634 buffer_size, "];");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001635 }
1636 else
1637 SPIRV_CROSS_THROW("All basic types in a flattened block must be the same.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08001638}
1639
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001640const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001641{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001642 auto &execution = get_entry_point();
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001643
1644 if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
1645 {
1646 if (is_legacy() && execution.model == ExecutionModelVertex)
1647 return var.storage == StorageClassInput ? "attribute " : "varying ";
1648 else if (is_legacy() && execution.model == ExecutionModelFragment)
1649 return "varying "; // Fragment outputs are renamed so they never hit this case.
1650 else
1651 return var.storage == StorageClassInput ? "in " : "out ";
1652 }
1653 else if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
1654 var.storage == StorageClassPushConstant)
1655 {
1656 return "uniform ";
1657 }
Patrick Moursda39a7b2019-02-26 15:43:03 +01001658 else if (var.storage == StorageClassRayPayloadNV)
1659 {
1660 return "rayPayloadNV ";
1661 }
1662 else if (var.storage == StorageClassIncomingRayPayloadNV)
1663 {
1664 return "rayPayloadInNV ";
1665 }
1666 else if (var.storage == StorageClassHitAttributeNV)
1667 {
1668 return "hitAttributeNV ";
1669 }
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001670
1671 return "";
1672}
1673
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001674void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual)
1675{
1676 auto &type = get<SPIRType>(var.basetype);
1677 if (!type.array.empty())
1678 SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings.");
1679
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001680 auto old_flags = ir.meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001681 // Emit the members as if they are part of a block to get all qualifiers.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001682 ir.meta[type.self].decoration.decoration_flags.set(DecorationBlock);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001683
Hans-Kristian Arntzena8df0802017-11-22 11:19:54 +01001684 type.member_name_cache.clear();
1685
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001686 uint32_t i = 0;
1687 for (auto &member : type.member_types)
1688 {
1689 add_member_name(type, i);
1690 auto &membertype = get<SPIRType>(member);
1691
1692 if (membertype.basetype == SPIRType::Struct)
1693 SPIRV_CROSS_THROW("Cannot flatten struct inside structs in I/O variables.");
1694
1695 // Pass in the varying qualifier here so it will appear in the correct declaration order.
1696 // Replace member name while emitting it so it encodes both struct name and member name.
1697 // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row,
1698 // which is not allowed.
Hans-Kristian Arntzen94ff3552017-10-10 17:32:26 +02001699 auto backup_name = get_member_name(type.self, i);
1700 auto member_name = to_member_name(type, i);
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01001701 set_member_name(type.self, i, sanitize_underscores(join(to_name(var.self), "_", member_name)));
Bill Hollingsdc694272017-03-11 12:17:22 -05001702 emit_struct_member(type, member, i, qual);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001703 // Restore member name.
1704 set_member_name(type.self, i, member_name);
1705 i++;
1706 }
1707
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001708 ir.meta[type.self].decoration.decoration_flags = old_flags;
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001709
1710 // Treat this variable as flattened from now on.
1711 flattened_structs.insert(var.self);
1712}
1713
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001714void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
1715{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001716 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001717
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001718 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001719 bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001720 const char *qual = to_storage_qualifiers_glsl(var);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001721
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001722 if (block)
1723 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001724 // ESSL earlier than 310 and GLSL earlier than 150 did not support
1725 // I/O variables which are struct types.
1726 // To support this, flatten the struct into separate varyings instead.
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001727 if ((options.es && options.version < 310) || (!options.es && options.version < 150))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001728 {
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001729 // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320.
1730 // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150).
1731 emit_flattened_io_block(var, qual);
1732 }
1733 else
1734 {
1735 if (options.es && options.version < 320)
1736 {
1737 // Geometry and tessellation extensions imply this extension.
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01001738 if (!has_extension("GL_EXT_geometry_shader") && !has_extension("GL_EXT_tessellation_shader"))
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02001739 require_extension_internal("GL_EXT_shader_io_blocks");
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001740 }
1741
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001742 // Block names should never alias.
1743 auto block_name = to_name(type.self, false);
1744
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02001745 // The namespace for I/O blocks is separate from other variables in GLSL.
1746 auto &block_namespace = type.storage == StorageClassInput ? block_input_names : block_output_names;
1747
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001748 // Shaders never use the block by interface name, so we don't
1749 // have to track this other than updating name caches.
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02001750 if (block_name.empty() || block_namespace.find(block_name) != end(block_namespace))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001751 block_name = get_fallback_name(type.self);
1752 else
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02001753 block_namespace.insert(block_name);
1754
Hans-Kristian Arntzen20c8e672018-08-21 12:17:40 +02001755 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
1756 // This cannot conflict with anything else, so we're safe now.
1757 if (block_name.empty())
1758 block_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
1759
Hans-Kristian Arntzenf6ec83e2018-08-21 11:29:08 +02001760 // Instance names cannot alias block names.
1761 resource_names.insert(block_name);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001762
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001763 statement(layout_for_variable(var), qual, block_name);
1764 begin_scope();
1765
1766 type.member_name_cache.clear();
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001767
1768 uint32_t i = 0;
1769 for (auto &member : type.member_types)
1770 {
1771 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05001772 emit_struct_member(type, member, i);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001773 i++;
1774 }
1775
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001776 add_resource_name(var.self);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001777 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
1778 statement("");
1779 }
1780 }
1781 else
1782 {
1783 // ESSL earlier than 310 and GLSL earlier than 150 did not support
1784 // I/O variables which are struct types.
1785 // To support this, flatten the struct into separate varyings instead.
1786 if (type.basetype == SPIRType::Struct &&
1787 ((options.es && options.version < 310) || (!options.es && options.version < 150)))
1788 {
1789 emit_flattened_io_block(var, qual);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001790 }
1791 else
1792 {
1793 add_resource_name(var.self);
Chip Davis3bfb2f92018-12-03 02:06:33 -06001794 statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
1795 variable_decl(type, to_name(var.self), var.self), ";");
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01001796
1797 // If a StorageClassOutput variable has an initializer, we need to initialize it in main().
1798 if (var.storage == StorageClassOutput && var.initializer)
1799 {
1800 auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
Hans-Kristian Arntzen2edee352019-01-30 13:42:50 +01001801 entry_func.fixup_hooks_in.push_back(
1802 [&]() { statement(to_name(var.self), " = ", to_expression(var.initializer), ";"); });
Hans-Kristian Arntzen3e098792019-01-30 10:29:08 +01001803 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001804 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001805 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001806}
1807
1808void CompilerGLSL::emit_uniform(const SPIRVariable &var)
1809{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001810 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen32b463f2016-09-10 13:00:07 +02001811 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001812 {
1813 if (!options.es && options.version < 420)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02001814 require_extension_internal("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001815 else if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001816 SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001817 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001818
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001819 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001820 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001821}
1822
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07001823string CompilerGLSL::constant_value_macro_name(uint32_t id)
1824{
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001825 return join("SPIRV_CROSS_CONSTANT_ID_", id);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07001826}
1827
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02001828void CompilerGLSL::emit_specialization_constant_op(const SPIRConstantOp &constant)
1829{
1830 auto &type = get<SPIRType>(constant.basetype);
1831 auto name = to_name(constant.self);
1832 statement("const ", variable_decl(type, name), " = ", constant_op_expression(constant), ";");
1833}
1834
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02001835void CompilerGLSL::emit_constant(const SPIRConstant &constant)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02001836{
1837 auto &type = get<SPIRType>(constant.constant_type);
1838 auto name = to_name(constant.self);
1839
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001840 SpecializationConstant wg_x, wg_y, wg_z;
1841 uint32_t workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
1842
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001843 // This specialization constant is implicitly declared by emitting layout() in;
1844 if (constant.self == workgroup_size_id)
1845 return;
1846
1847 // These specialization constants are implicitly declared by emitting layout() in;
1848 // In legacy GLSL, we will still need to emit macros for these, so a layout() in; declaration
1849 // later can use macro overrides for work group size.
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01001850 bool is_workgroup_size_constant = constant.self == wg_x.id || constant.self == wg_y.id || constant.self == wg_z.id;
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001851
1852 if (options.vulkan_semantics && is_workgroup_size_constant)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001853 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001854 // Vulkan GLSL does not need to declare workgroup spec constants explicitly, it is handled in layout().
1855 return;
1856 }
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01001857 else if (!options.vulkan_semantics && is_workgroup_size_constant &&
1858 !has_decoration(constant.self, DecorationSpecId))
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001859 {
1860 // 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 +02001861 return;
1862 }
1863
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001864 // Only scalars have constant IDs.
1865 if (has_decoration(constant.self, DecorationSpecId))
1866 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07001867 if (options.vulkan_semantics)
1868 {
1869 statement("layout(constant_id = ", get_decoration(constant.self, DecorationSpecId), ") const ",
1870 variable_decl(type, name), " = ", constant_expression(constant), ";");
1871 }
1872 else
1873 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001874 const string &macro_name = constant.specialization_constant_macro_name;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07001875 statement("#ifndef ", macro_name);
1876 statement("#define ", macro_name, " ", constant_expression(constant));
1877 statement("#endif");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001878
1879 // For workgroup size constants, only emit the macros.
1880 if (!is_workgroup_size_constant)
1881 statement("const ", variable_decl(type, name), " = ", macro_name, ";");
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07001882 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001883 }
1884 else
1885 {
1886 statement("const ", variable_decl(type, name), " = ", constant_expression(constant), ";");
1887 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02001888}
1889
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +02001890void CompilerGLSL::emit_entry_point_declarations()
1891{
1892}
1893
Robert Konrad76936562016-08-13 00:14:52 +02001894void CompilerGLSL::replace_illegal_names()
1895{
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02001896 // clang-format off
1897 static const unordered_set<string> keywords = {
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01001898 "abs", "acos", "acosh", "all", "any", "asin", "asinh", "atan", "atanh",
1899 "atomicAdd", "atomicCompSwap", "atomicCounter", "atomicCounterDecrement", "atomicCounterIncrement",
1900 "atomicExchange", "atomicMax", "atomicMin", "atomicOr", "atomicXor",
1901 "bitCount", "bitfieldExtract", "bitfieldInsert", "bitfieldReverse",
1902 "ceil", "cos", "cosh", "cross", "degrees",
1903 "dFdx", "dFdxCoarse", "dFdxFine",
1904 "dFdy", "dFdyCoarse", "dFdyFine",
1905 "distance", "dot", "EmitStreamVertex", "EmitVertex", "EndPrimitive", "EndStreamPrimitive", "equal", "exp", "exp2",
Chip Davis0d949e12018-11-05 14:55:56 -06001906 "faceforward", "findLSB", "findMSB", "float16BitsToInt16", "float16BitsToUint16", "floatBitsToInt", "floatBitsToUint", "floor", "fma", "fract",
1907 "frexp", "fwidth", "fwidthCoarse", "fwidthFine",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01001908 "greaterThan", "greaterThanEqual", "groupMemoryBarrier",
1909 "imageAtomicAdd", "imageAtomicAnd", "imageAtomicCompSwap", "imageAtomicExchange", "imageAtomicMax", "imageAtomicMin", "imageAtomicOr", "imageAtomicXor",
Chip Davis0d949e12018-11-05 14:55:56 -06001910 "imageLoad", "imageSamples", "imageSize", "imageStore", "imulExtended", "int16BitsToFloat16", "intBitsToFloat", "interpolateAtOffset", "interpolateAtCentroid", "interpolateAtSample",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01001911 "inverse", "inversesqrt", "isinf", "isnan", "ldexp", "length", "lessThan", "lessThanEqual", "log", "log2",
1912 "matrixCompMult", "max", "memoryBarrier", "memoryBarrierAtomicCounter", "memoryBarrierBuffer", "memoryBarrierImage", "memoryBarrierShared",
1913 "min", "mix", "mod", "modf", "noise", "noise1", "noise2", "noise3", "noise4", "normalize", "not", "notEqual",
Chip Davis0d949e12018-11-05 14:55:56 -06001914 "outerProduct", "packDouble2x32", "packHalf2x16", "packInt2x16", "packInt4x16", "packSnorm2x16", "packSnorm4x8",
1915 "packUint2x16", "packUint4x16", "packUnorm2x16", "packUnorm4x8", "pow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01001916 "radians", "reflect", "refract", "round", "roundEven", "sign", "sin", "sinh", "smoothstep", "sqrt", "step",
Pascal Muetschardaced6052018-05-04 14:53:32 -07001917 "tan", "tanh", "texelFetch", "texelFetchOffset", "texture", "textureGather", "textureGatherOffset", "textureGatherOffsets",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01001918 "textureGrad", "textureGradOffset", "textureLod", "textureLodOffset", "textureOffset", "textureProj", "textureProjGrad",
1919 "textureProjGradOffset", "textureProjLod", "textureProjLodOffset", "textureProjOffset", "textureQueryLevels", "textureQueryLod", "textureSamples", "textureSize",
Chip Davis0d949e12018-11-05 14:55:56 -06001920 "transpose", "trunc", "uaddCarry", "uint16BitsToFloat16", "uintBitsToFloat", "umulExtended", "unpackDouble2x32", "unpackHalf2x16", "unpackInt2x16", "unpackInt4x16",
1921 "unpackSnorm2x16", "unpackSnorm4x8", "unpackUint2x16", "unpackUint4x16", "unpackUnorm2x16", "unpackUnorm4x8", "usubBorrow",
Hans-Kristian Arntzen15a941c2018-03-06 17:37:47 +01001922
Pascal Muetschardaced6052018-05-04 14:53:32 -07001923 "active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer",
David Srbeckyedec5ea2017-06-27 15:35:47 +01001924 "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard",
1925 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4",
1926 "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float",
1927 "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray",
1928 "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
1929 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect",
1930 "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant",
1931 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
Pascal Muetschardaced6052018-05-04 14:53:32 -07001932 "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp",
1933 "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump",
1934 "namespace", "noinline", "noperspective", "out", "output", "packed", "partition", "patch", "precise", "precision", "public", "readonly",
1935 "resource", "restrict", "return", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
David Srbeckyedec5ea2017-06-27 15:35:47 +01001936 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
1937 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer",
Pascal Muetschardaced6052018-05-04 14:53:32 -07001938 "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "shared", "short", "sizeof", "smooth", "static",
David Srbeckyedec5ea2017-06-27 15:35:47 +01001939 "struct", "subroutine", "superp", "switch", "template", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D",
1940 "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube",
1941 "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
1942 "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube",
Pascal Muetschardaced6052018-05-04 14:53:32 -07001943 "usamplerCubeArray", "using", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile",
1944 "while", "writeonly",
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02001945 };
1946 // clang-format on
Bas Zalmstraf537adf2016-10-27 12:51:22 +02001947
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001948 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
1949 if (!is_hidden_variable(var))
Robert Konrad76936562016-08-13 00:14:52 +02001950 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001951 auto &m = ir.meta[var.self].decoration;
1952 if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords))
1953 m.alias = join("_", m.alias);
Robert Konrad76936562016-08-13 00:14:52 +02001954 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001955 });
Robert Konrad76936562016-08-13 00:14:52 +02001956}
1957
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001958void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
1959{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001960 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001961 uint32_t location = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001962 if (m.decoration_flags.get(DecorationLocation))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001963 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001964
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001965 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
1966 // do the access chain part of this for us.
1967 auto &type = get<SPIRType>(var.basetype);
1968
1969 if (type.array.empty())
1970 {
1971 // Redirect the write to a specific render target in legacy GLSL.
1972 m.alias = join("gl_FragData[", location, "]");
Lubos Lenco52158642016-09-17 15:56:23 +02001973
1974 if (is_legacy_es() && location != 0)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02001975 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001976 }
1977 else if (type.array.size() == 1)
1978 {
1979 // If location is non-zero, we probably have to add an offset.
1980 // This gets really tricky since we'd have to inject an offset in the access chain.
1981 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
1982 m.alias = "gl_FragData";
1983 if (location != 0)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001984 SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
1985 "This is unimplemented in SPIRV-Cross.");
Hans-Kristian Arntzen6cc96242016-09-17 18:46:10 +02001986
Lubos Lenco80c39412016-09-17 14:33:16 +02001987 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02001988 require_extension_internal("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001989 }
1990 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001991 SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001992
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001993 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 +01001994}
1995
1996void CompilerGLSL::replace_fragment_outputs()
1997{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001998 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01001999 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002000
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +01002001 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer && var.storage == StorageClassOutput)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002002 replace_fragment_output(var);
2003 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002004}
2005
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002006string CompilerGLSL::remap_swizzle(const SPIRType &out_type, uint32_t input_components, const string &expr)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002007{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002008 if (out_type.vecsize == input_components)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002009 return expr;
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01002010 else if (input_components == 1 && !backend.can_swizzle_scalar)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002011 return join(type_to_glsl(out_type), "(", expr, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002012 else
2013 {
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02002014 // FIXME: This will not work with packed expressions.
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02002015 auto e = enclose_expression(expr) + ".";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002016 // Just clamp the swizzle index if we have more outputs than inputs.
2017 for (uint32_t c = 0; c < out_type.vecsize; c++)
2018 e += index_to_swizzle(min(c, input_components - 1));
2019 if (backend.swizzle_is_function && out_type.vecsize > 1)
2020 e += "()";
Hans-Kristian Arntzenffad50b2017-12-12 13:01:10 +01002021
2022 remove_duplicate_swizzle(e);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002023 return e;
2024 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002025}
2026
2027void CompilerGLSL::emit_pls()
2028{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002029 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002030 if (execution.model != ExecutionModelFragment)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002031 SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002032
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002033 if (!options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002034 SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002036 if (options.version < 300)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002037 SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002038
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002039 if (!pls_inputs.empty())
2040 {
2041 statement("__pixel_local_inEXT _PLSIn");
2042 begin_scope();
2043 for (auto &input : pls_inputs)
2044 statement(pls_decl(input), ";");
2045 end_scope_decl();
2046 statement("");
2047 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002048
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002049 if (!pls_outputs.empty())
2050 {
2051 statement("__pixel_local_outEXT _PLSOut");
2052 begin_scope();
2053 for (auto &output : pls_outputs)
2054 statement(pls_decl(output), ";");
2055 end_scope_decl();
2056 statement("");
2057 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002058}
2059
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002060void CompilerGLSL::fixup_image_load_store_access()
2061{
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002062 ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002063 auto &vartype = expression_type(var);
2064 if (vartype.basetype == SPIRType::Image)
2065 {
2066 // Older glslangValidator does not emit required qualifiers here.
2067 // Solve this by making the image access as restricted as possible and loosen up if we need to.
2068 // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
2069
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01002070 auto &flags = ir.meta[var].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002071 if (!flags.get(DecorationNonWritable) && !flags.get(DecorationNonReadable))
2072 {
2073 flags.set(DecorationNonWritable);
2074 flags.set(DecorationNonReadable);
2075 }
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002076 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002077 });
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01002078}
2079
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002080void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
2081{
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002082 Bitset emitted_builtins;
2083 Bitset global_builtins;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002084 const SPIRVariable *block_var = nullptr;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002085 bool emitted_block = false;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002086 bool builtin_array = false;
2087
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002088 // Need to use declared size in the type.
2089 // These variables might have been declared, but not statically used, so we haven't deduced their size yet.
2090 uint32_t cull_distance_size = 0;
2091 uint32_t clip_distance_size = 0;
2092
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002093 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002094 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002095 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002096 Bitset builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002097
2098 if (var.storage == storage && block && is_builtin_variable(var))
2099 {
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002100 uint32_t index = 0;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002101 for (auto &m : ir.meta[type.self].members)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002102 {
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002103 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002104 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002105 builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002106 if (m.builtin_type == BuiltInCullDistance)
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002107 cull_distance_size = this->get<SPIRType>(type.member_types[index]).array.front();
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002108 else if (m.builtin_type == BuiltInClipDistance)
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002109 clip_distance_size = this->get<SPIRType>(type.member_types[index]).array.front();
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002110 }
2111 index++;
2112 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002113 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002114 else if (var.storage == storage && !block && is_builtin_variable(var))
2115 {
2116 // While we're at it, collect all declared global builtins (HLSL mostly ...).
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002117 auto &m = ir.meta[var.self].decoration;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002118 if (m.builtin)
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002119 {
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002120 global_builtins.set(m.builtin_type);
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002121 if (m.builtin_type == BuiltInCullDistance)
2122 cull_distance_size = type.array.front();
2123 else if (m.builtin_type == BuiltInClipDistance)
2124 clip_distance_size = type.array.front();
2125 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002126 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002127
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002128 if (builtins.empty())
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002129 return;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002130
2131 if (emitted_block)
2132 SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
2133
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002134 emitted_builtins = builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002135 emitted_block = true;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002136 builtin_array = !type.array.empty();
2137 block_var = &var;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002138 });
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002139
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +01002140 global_builtins =
2141 Bitset(global_builtins.get_lower() & ((1ull << BuiltInPosition) | (1ull << BuiltInPointSize) |
2142 (1ull << BuiltInClipDistance) | (1ull << BuiltInCullDistance)));
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002143
2144 // Try to collect all other declared builtins.
2145 if (!emitted_block)
2146 emitted_builtins = global_builtins;
2147
2148 // Can't declare an empty interface block.
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002149 if (emitted_builtins.empty())
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002150 return;
2151
2152 if (storage == StorageClassOutput)
2153 statement("out gl_PerVertex");
2154 else
2155 statement("in gl_PerVertex");
2156
2157 begin_scope();
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002158 if (emitted_builtins.get(BuiltInPosition))
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002159 statement("vec4 gl_Position;");
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002160 if (emitted_builtins.get(BuiltInPointSize))
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002161 statement("float gl_PointSize;");
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002162 if (emitted_builtins.get(BuiltInClipDistance))
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002163 statement("float gl_ClipDistance[", clip_distance_size, "];");
Hans-Kristian Arntzen012377f2018-03-12 15:59:34 +01002164 if (emitted_builtins.get(BuiltInCullDistance))
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002165 statement("float gl_CullDistance[", cull_distance_size, "];");
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01002166
2167 bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl;
2168 if (builtin_array)
2169 {
2170 // Make sure the array has a supported name in the code.
2171 if (storage == StorageClassOutput)
2172 set_name(block_var->self, "gl_out");
2173 else if (storage == StorageClassInput)
2174 set_name(block_var->self, "gl_in");
2175
2176 if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
2177 end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]"));
2178 else
2179 end_scope_decl(join(to_name(block_var->self), tessellation ? "[gl_MaxPatchVertices]" : "[]"));
2180 }
2181 else
2182 end_scope_decl();
2183 statement("");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002184}
2185
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002186void CompilerGLSL::declare_undefined_values()
2187{
2188 bool emitted = false;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002189 ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002190 statement(variable_decl(this->get<SPIRType>(undef.basetype), to_name(undef.self), undef.self), ";");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002191 emitted = true;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002192 });
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002193
2194 if (emitted)
2195 statement("");
2196}
2197
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01002198bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const
2199{
2200 bool statically_assigned = var.statically_assigned && var.static_expression != 0 && var.remapped_variable;
2201
2202 if (statically_assigned)
2203 {
2204 auto *constant = maybe_get<SPIRConstant>(var.static_expression);
2205 if (constant && constant->is_used_as_lut)
2206 return true;
2207 }
2208
2209 return false;
2210}
2211
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002212void CompilerGLSL::emit_resources()
2213{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02002214 auto &execution = get_entry_point();
2215
Robert Konrad76936562016-08-13 00:14:52 +02002216 replace_illegal_names();
2217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002218 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
2219 // with builtins.
2220 if (execution.model == ExecutionModelFragment && is_legacy())
2221 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002222
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002223 // Emit PLS blocks if we have such variables.
2224 if (!pls_inputs.empty() || !pls_outputs.empty())
2225 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002226
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002227 // Emit custom gl_PerVertex for SSO compatibility.
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01002228 if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment)
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002229 {
2230 switch (execution.model)
2231 {
2232 case ExecutionModelGeometry:
2233 case ExecutionModelTessellationControl:
2234 case ExecutionModelTessellationEvaluation:
2235 emit_declared_builtin_block(StorageClassInput, execution.model);
2236 emit_declared_builtin_block(StorageClassOutput, execution.model);
2237 break;
2238
2239 case ExecutionModelVertex:
2240 emit_declared_builtin_block(StorageClassOutput, execution.model);
2241 break;
2242
2243 default:
2244 break;
2245 }
2246 }
Hans-Kristian Arntzenfb3f92a2018-02-22 14:36:50 +01002247 else
2248 {
2249 // Need to redeclare clip/cull distance with explicit size to use them.
2250 // SPIR-V mandates these builtins have a size declared.
2251 const char *storage = execution.model == ExecutionModelFragment ? "in" : "out";
2252 if (clip_distance_count != 0)
2253 statement(storage, " float gl_ClipDistance[", clip_distance_count, "];");
2254 if (cull_distance_count != 0)
2255 statement(storage, " float gl_CullDistance[", cull_distance_count, "];");
2256 if (clip_distance_count != 0 || cull_distance_count != 0)
2257 statement("");
2258 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02002259
Hans-Kristian Arntzen3c1b1472018-03-01 12:30:55 +01002260 if (position_invariant)
2261 {
2262 statement("invariant gl_Position;");
2263 statement("");
2264 }
2265
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002266 bool emitted = false;
2267
2268 // If emitted Vulkan GLSL,
2269 // emit specialization constants as actual floats,
2270 // spec op expressions will redirect to the constant name.
2271 //
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002272 for (auto &id_ : ir.ids_for_constant_or_type)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002273 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002274 auto &id = ir.ids[id_];
2275
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002276 if (id.get_type() == TypeConstant)
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002277 {
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002278 auto &c = id.get<SPIRConstant>();
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002279
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002280 bool needs_declaration = c.specialization || c.is_used_as_lut;
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002281
2282 if (needs_declaration)
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002283 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002284 if (!options.vulkan_semantics && c.specialization)
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002285 {
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002286 c.specialization_constant_macro_name =
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002287 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002288 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002289 emit_constant(c);
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02002290 emitted = true;
2291 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002292 }
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002293 else if (id.get_type() == TypeConstantOp)
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002294 {
2295 emit_specialization_constant_op(id.get<SPIRConstantOp>());
2296 emitted = true;
2297 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002298 else if (id.get_type() == TypeType)
2299 {
2300 auto &type = id.get<SPIRType>();
2301 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
2302 (!ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) &&
2303 !ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
2304 {
2305 if (emitted)
2306 statement("");
2307 emitted = false;
2308
2309 emit_struct(type);
2310 }
2311 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002312 }
2313
2314 if (emitted)
2315 statement("");
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002316
2317 // If we needed to declare work group size late, check here.
2318 // If the work group size depends on a specialization constant, we need to declare the layout() block
2319 // after constants (and their macros) have been declared.
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002320 if (execution.model == ExecutionModelGLCompute && !options.vulkan_semantics &&
2321 execution.workgroup_size.constant != 0)
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002322 {
2323 SpecializationConstant wg_x, wg_y, wg_z;
2324 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
2325
2326 if ((wg_x.id != 0) || (wg_y.id != 0) || (wg_z.id != 0))
2327 {
2328 vector<string> inputs;
2329 build_workgroup_size(inputs, wg_x, wg_y, wg_z);
2330 statement("layout(", merge(inputs), ") in;");
2331 statement("");
2332 }
2333 }
2334
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02002335 emitted = false;
2336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002337 // Output UBOs and SSBOs
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002338 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002339 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002340
2341 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform;
2342 bool has_block_flags = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
2343 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
2344
2345 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
2346 has_block_flags)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002347 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002348 emit_buffer_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002349 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002350 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002352 // Output push constant blocks
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002353 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002354 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002355 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
2356 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002357 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002358 emit_push_constant_block(var);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002359 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002360 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002361
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02002362 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002364 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002365 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002366 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002367
2368 // If we're remapping separate samplers and images, only emit the combined samplers.
2369 if (skip_separate_image_sampler)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002370 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002371 // Sampler buffers are always used without a sampler, and they will also work in regular GL.
2372 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
2373 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
2374 bool separate_sampler = type.basetype == SPIRType::Sampler;
2375 if (!sampler_buffer && (separate_image || separate_sampler))
2376 return;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002377 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002378
2379 if (var.storage != StorageClassFunction && type.pointer &&
Patrick Moursda39a7b2019-02-26 15:43:03 +01002380 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter ||
2381 type.storage == StorageClassRayPayloadNV || type.storage == StorageClassHitAttributeNV ||
2382 type.storage == StorageClassIncomingRayPayloadNV) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002383 !is_hidden_variable(var))
2384 {
2385 emit_uniform(var);
2386 emitted = true;
2387 }
2388 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002390 if (emitted)
2391 statement("");
2392 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002393
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002394 // Output in/out interfaces.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002395 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002396 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002397
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002398 if (var.storage != StorageClassFunction && type.pointer &&
2399 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
2400 interface_variable_exists_in_entry_point(var.self) && !is_hidden_variable(var))
2401 {
2402 emit_interface_block(var);
2403 emitted = true;
2404 }
2405 else if (is_builtin_variable(var))
2406 {
2407 // For gl_InstanceIndex emulation on GLES, the API user needs to
2408 // supply this uniform.
2409 if (options.vertex.support_nonzero_base_instance &&
2410 ir.meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002411 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002412 statement("uniform int SPIRV_Cross_BaseInstance;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002413 emitted = true;
2414 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002415 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002416 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002417
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002418 // Global variables.
2419 for (auto global : global_variables)
2420 {
2421 auto &var = get<SPIRVariable>(global);
2422 if (var.storage != StorageClassOutput)
2423 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01002424 if (!variable_is_lut(var))
2425 {
2426 add_resource_name(var.self);
2427 statement(variable_decl(var), ";");
2428 emitted = true;
2429 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002430 }
2431 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002432
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002433 if (emitted)
2434 statement("");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002435
2436 declare_undefined_values();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002437}
2438
Bill Hollingsb321b832016-07-06 20:30:47 -04002439// Returns a string representation of the ID, usable as a function arg.
2440// Default is to simply return the expression representation fo the arg ID.
2441// Subclasses may override to modify the return value.
2442string CompilerGLSL::to_func_call_arg(uint32_t id)
2443{
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +02002444 // Make sure that we use the name of the original variable, and not the parameter alias.
2445 uint32_t name_id = id;
2446 auto *var = maybe_get<SPIRVariable>(id);
2447 if (var && var->basevariable)
2448 name_id = var->basevariable;
2449 return to_expression(name_id);
Bill Hollingsb321b832016-07-06 20:30:47 -04002450}
2451
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002452void CompilerGLSL::handle_invalid_expression(uint32_t id)
2453{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002454 // We tried to read an invalidated expression.
2455 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
2456 forced_temporaries.insert(id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02002457 force_recompile();
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002458}
2459
Bill Hollingsb332bae2017-03-01 13:07:40 -05002460// Converts the format of the current expression from packed to unpacked,
2461// by wrapping the expression in a constructor of the appropriate type.
2462// GLSL does not support packed formats, so simply return the expression.
2463// Subclasses that do will override
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01002464string CompilerGLSL::unpack_expression_type(string expr_str, const SPIRType &, uint32_t)
Bill Hollingsb332bae2017-03-01 13:07:40 -05002465{
2466 return expr_str;
2467}
2468
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01002469// Sometimes we proactively enclosed an expression where it turns out we might have not needed it after all.
2470void CompilerGLSL::strip_enclosed_expression(string &expr)
2471{
2472 if (expr.size() < 2 || expr.front() != '(' || expr.back() != ')')
2473 return;
2474
2475 // Have to make sure that our first and last parens actually enclose everything inside it.
2476 uint32_t paren_count = 0;
2477 for (auto &c : expr)
2478 {
2479 if (c == '(')
2480 paren_count++;
2481 else if (c == ')')
2482 {
2483 paren_count--;
2484
2485 // If we hit 0 and this is not the final char, our first and final parens actually don't
2486 // enclose the expression, and we cannot strip, e.g.: (a + b) * (c + d).
2487 if (paren_count == 0 && &c != &expr.back())
2488 return;
2489 }
2490 }
Corentin Walleze88c88c2017-01-18 17:22:19 -05002491 expr.erase(expr.size() - 1, 1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01002492 expr.erase(begin(expr));
2493}
2494
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02002495string CompilerGLSL::enclose_expression(const string &expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002496{
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002497 bool need_parens = false;
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02002498
2499 // If the expression starts with a unary we need to enclose to deal with cases where we have back-to-back
2500 // unary expressions.
2501 if (!expr.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002502 {
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02002503 auto c = expr.front();
Chip Davis3bfb2f92018-12-03 02:06:33 -06002504 if (c == '-' || c == '+' || c == '!' || c == '~' || c == '&' || c == '*')
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002505 need_parens = true;
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002506 }
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02002507
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002508 if (!need_parens)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002509 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002510 uint32_t paren_count = 0;
2511 for (auto c : expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002512 {
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02002513 if (c == '(' || c == '[')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002514 paren_count++;
Hans-Kristian Arntzen51436952018-07-05 14:09:25 +02002515 else if (c == ')' || c == ']')
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002516 {
2517 assert(paren_count);
2518 paren_count--;
2519 }
2520 else if (c == ' ' && paren_count == 0)
2521 {
2522 need_parens = true;
2523 break;
2524 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002525 }
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002526 assert(paren_count == 0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002527 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002528
2529 // If this expression contains any spaces which are not enclosed by parentheses,
2530 // we need to enclose it so we can treat the whole string as an expression.
2531 // This happens when two expressions have been part of a binary op earlier.
2532 if (need_parens)
2533 return join('(', expr, ')');
2534 else
2535 return expr;
2536}
2537
Chip Davis3bfb2f92018-12-03 02:06:33 -06002538string CompilerGLSL::dereference_expression(const std::string &expr)
2539{
2540 // If this expression starts with an address-of operator ('&'), then
2541 // just return the part after the operator.
2542 // TODO: Strip parens if unnecessary?
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01002543 if (expr.front() == '&')
Chip Davis3bfb2f92018-12-03 02:06:33 -06002544 return expr.substr(1);
2545 else
2546 return join('*', expr);
2547}
2548
2549string CompilerGLSL::address_of_expression(const std::string &expr)
2550{
2551 // If this expression starts with a dereference operator ('*'), then
2552 // just return the part after the operator.
2553 // TODO: Strip parens if unnecessary?
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01002554 if (expr.front() == '*')
Chip Davis3bfb2f92018-12-03 02:06:33 -06002555 return expr.substr(1);
2556 else
2557 return join('&', expr);
2558}
2559
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02002560// Just like to_expression except that we enclose the expression inside parentheses if needed.
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01002561string CompilerGLSL::to_enclosed_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02002562{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01002563 return enclose_expression(to_expression(id, register_expression_read));
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02002564}
2565
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002566string CompilerGLSL::to_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02002567{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02002568 // If we need to transpose, it will also take care of unpacking rules.
2569 auto *e = maybe_get<SPIRExpression>(id);
2570 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01002571 if (!need_transpose && has_extended_decoration(id, SPIRVCrossDecorationPacked))
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01002572 return unpack_expression_type(to_expression(id, register_expression_read), expression_type(id),
2573 get_extended_decoration(id, SPIRVCrossDecorationPackedType));
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02002574 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002575 return to_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02002576}
2577
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002578string CompilerGLSL::to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02002579{
Hans-Kristian Arntzen58fab582018-06-12 09:36:13 +02002580 // If we need to transpose, it will also take care of unpacking rules.
2581 auto *e = maybe_get<SPIRExpression>(id);
2582 bool need_transpose = e && e->need_transpose;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01002583 if (!need_transpose && has_extended_decoration(id, SPIRVCrossDecorationPacked))
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01002584 return unpack_expression_type(to_expression(id, register_expression_read), expression_type(id),
2585 get_extended_decoration(id, SPIRVCrossDecorationPackedType));
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02002586 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002587 return to_enclosed_expression(id, register_expression_read);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02002588}
2589
Chip Davis3bfb2f92018-12-03 02:06:33 -06002590string CompilerGLSL::to_dereferenced_expression(uint32_t id, bool register_expression_read)
2591{
2592 auto &type = expression_type(id);
2593 if (type.pointer && should_dereference(id))
2594 return dereference_expression(to_enclosed_expression(id, register_expression_read));
2595 else
2596 return to_expression(id, register_expression_read);
2597}
2598
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002599string CompilerGLSL::to_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06002600{
2601 auto &type = expression_type(id);
2602 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002603 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06002604 else
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002605 return to_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06002606}
2607
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002608string CompilerGLSL::to_enclosed_pointer_expression(uint32_t id, bool register_expression_read)
Chip Davis3bfb2f92018-12-03 02:06:33 -06002609{
2610 auto &type = expression_type(id);
2611 if (type.pointer && expression_is_lvalue(id) && !should_dereference(id))
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01002612 return address_of_expression(to_enclosed_expression(id, register_expression_read));
Chip Davis3bfb2f92018-12-03 02:06:33 -06002613 else
Hans-Kristian Arntzen432aaed2019-01-17 11:39:16 +01002614 return to_enclosed_unpacked_expression(id, register_expression_read);
Chip Davis3bfb2f92018-12-03 02:06:33 -06002615}
2616
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02002617string CompilerGLSL::to_extract_component_expression(uint32_t id, uint32_t index)
2618{
2619 auto expr = to_enclosed_expression(id);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01002620 if (has_extended_decoration(id, SPIRVCrossDecorationPacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02002621 return join(expr, "[", index, "]");
2622 else
2623 return join(expr, ".", index_to_swizzle(index));
2624}
2625
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01002626string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002627{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002628 auto itr = invalid_expressions.find(id);
2629 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002630 handle_invalid_expression(id);
2631
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002632 if (ir.ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002633 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002634 // We might have a more complex chain of dependencies.
2635 // A possible scenario is that we
2636 //
2637 // %1 = OpLoad
2638 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
2639 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
2640 // 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.
2641 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
2642 //
2643 // 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,
2644 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002645 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002646 for (uint32_t dep : expr.expression_dependencies)
2647 if (invalid_expressions.find(dep) != end(invalid_expressions))
2648 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002649 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002650
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01002651 if (register_expression_read)
2652 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002653
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002654 switch (ir.ids[id].get_type())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002655 {
2656 case TypeExpression:
2657 {
2658 auto &e = get<SPIRExpression>(id);
2659 if (e.base_expression)
Hans-Kristian Arntzenea781e62016-12-06 17:19:34 +01002660 return to_enclosed_expression(e.base_expression) + e.expression;
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002661 else if (e.need_transpose)
Bill Hollings607b0d62018-02-11 16:52:57 -05002662 {
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01002663 bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPacked);
Bill Hollings607b0d62018-02-11 16:52:57 -05002664 return convert_row_major_matrix(e.expression, get<SPIRType>(e.expression_type), is_packed);
2665 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002666 else
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01002667 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02002668 if (is_forcing_recompilation())
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01002669 {
2670 // During first compilation phase, certain expression patterns can trigger exponential growth of memory.
2671 // Avoid this by returning dummy expressions during this phase.
2672 // Do not use empty expressions here, because those are sentinels for other cases.
2673 return "_";
2674 }
2675 else
2676 return e.expression;
2677 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002678 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002680 case TypeConstant:
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002681 {
2682 auto &c = get<SPIRConstant>(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01002683 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02002684
2685 // WorkGroupSize may be a constant.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002686 auto &dec = ir.meta[c.self].decoration;
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02002687 if (dec.builtin)
2688 return builtin_to_glsl(dec.builtin_type, StorageClassGeneric);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002689 else if (c.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002690 return to_name(id);
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02002691 else if (c.is_used_as_lut)
2692 return to_name(id);
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01002693 else if (type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
2694 return to_name(id);
2695 else if (!type.array.empty() && !backend.can_declare_arrays_inline)
2696 return to_name(id);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002697 else
2698 return constant_expression(c);
2699 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002700
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002701 case TypeConstantOp:
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01002702 return to_name(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002703
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002704 case TypeVariable:
2705 {
2706 auto &var = get<SPIRVariable>(id);
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01002707 // If we try to use a loop variable before the loop header, we have to redirect it to the static expression,
2708 // the variable has not been declared yet.
2709 if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002710 return to_expression(var.static_expression);
2711 else if (var.deferred_declaration)
2712 {
2713 var.deferred_declaration = false;
2714 return variable_decl(var);
2715 }
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01002716 else if (flattened_structs.count(id))
2717 {
2718 return load_flattened_struct(var);
2719 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002720 else
2721 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002722 auto &dec = ir.meta[var.self].decoration;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002723 if (dec.builtin)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02002724 return builtin_to_glsl(dec.builtin_type, var.storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002725 else
2726 return to_name(id);
2727 }
2728 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002729
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02002730 case TypeCombinedImageSampler:
2731 // This type should never be taken the expression of directly.
2732 // The intention is that texture sampling functions will extract the image and samplers
2733 // separately and take their expressions as needed.
2734 // GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
2735 // expression ala sampler2D(texture, sampler).
2736 SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
2737
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02002738 case TypeAccessChain:
2739 // We cannot express this type. They only have meaning in other OpAccessChains, OpStore or OpLoad.
2740 SPIRV_CROSS_THROW("Access chains have no default expression representation.");
2741
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002742 default:
2743 return to_name(id);
2744 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002745}
2746
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002747string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
2748{
2749 auto &type = get<SPIRType>(cop.basetype);
2750 bool binary = false;
2751 bool unary = false;
2752 string op;
2753
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02002754 if (is_legacy() && is_unsigned_opcode(cop.opcode))
2755 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
2756
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002757 // TODO: Find a clean way to reuse emit_instruction.
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002758 switch (cop.opcode)
2759 {
2760 case OpSConvert:
2761 case OpUConvert:
2762 case OpFConvert:
2763 op = type_to_glsl_constructor(type);
2764 break;
2765
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02002766#define GLSL_BOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02002767 case Op##opname: \
2768 binary = true; \
2769 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002770 break
2771
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02002772#define GLSL_UOP(opname, x) \
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02002773 case Op##opname: \
2774 unary = true; \
2775 op = x; \
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002776 break
2777
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02002778 GLSL_UOP(SNegate, "-");
2779 GLSL_UOP(Not, "~");
2780 GLSL_BOP(IAdd, "+");
2781 GLSL_BOP(ISub, "-");
2782 GLSL_BOP(IMul, "*");
2783 GLSL_BOP(SDiv, "/");
2784 GLSL_BOP(UDiv, "/");
2785 GLSL_BOP(UMod, "%");
2786 GLSL_BOP(SMod, "%");
2787 GLSL_BOP(ShiftRightLogical, ">>");
2788 GLSL_BOP(ShiftRightArithmetic, ">>");
2789 GLSL_BOP(ShiftLeftLogical, "<<");
2790 GLSL_BOP(BitwiseOr, "|");
2791 GLSL_BOP(BitwiseXor, "^");
2792 GLSL_BOP(BitwiseAnd, "&");
2793 GLSL_BOP(LogicalOr, "||");
2794 GLSL_BOP(LogicalAnd, "&&");
2795 GLSL_UOP(LogicalNot, "!");
2796 GLSL_BOP(LogicalEqual, "==");
2797 GLSL_BOP(LogicalNotEqual, "!=");
2798 GLSL_BOP(IEqual, "==");
2799 GLSL_BOP(INotEqual, "!=");
2800 GLSL_BOP(ULessThan, "<");
2801 GLSL_BOP(SLessThan, "<");
2802 GLSL_BOP(ULessThanEqual, "<=");
2803 GLSL_BOP(SLessThanEqual, "<=");
2804 GLSL_BOP(UGreaterThan, ">");
2805 GLSL_BOP(SGreaterThan, ">");
2806 GLSL_BOP(UGreaterThanEqual, ">=");
2807 GLSL_BOP(SGreaterThanEqual, ">=");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002808
2809 case OpSelect:
2810 {
2811 if (cop.arguments.size() < 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002812 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002813
2814 // This one is pretty annoying. It's triggered from
2815 // uint(bool), int(bool) from spec constants.
2816 // In order to preserve its compile-time constness in Vulkan GLSL,
2817 // we need to reduce the OpSelect expression back to this simplified model.
2818 // If we cannot, fail.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02002819 if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002820 {
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02002821 // Implement as a simple cast down below.
2822 }
2823 else
2824 {
2825 // Implement a ternary and pray the compiler understands it :)
2826 return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002827 }
2828 break;
2829 }
2830
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02002831 case OpVectorShuffle:
2832 {
2833 string expr = type_to_glsl_constructor(type);
2834 expr += "(";
2835
2836 uint32_t left_components = expression_type(cop.arguments[0]).vecsize;
2837 string left_arg = to_enclosed_expression(cop.arguments[0]);
2838 string right_arg = to_enclosed_expression(cop.arguments[1]);
2839
2840 for (uint32_t i = 2; i < uint32_t(cop.arguments.size()); i++)
2841 {
2842 uint32_t index = cop.arguments[i];
2843 if (index >= left_components)
2844 expr += right_arg + "." + "xyzw"[index - left_components];
2845 else
2846 expr += left_arg + "." + "xyzw"[index];
2847
2848 if (i + 1 < uint32_t(cop.arguments.size()))
2849 expr += ", ";
2850 }
2851
2852 expr += ")";
2853 return expr;
2854 }
2855
2856 case OpCompositeExtract:
2857 {
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01002858 auto expr = access_chain_internal(cop.arguments[0], &cop.arguments[1], uint32_t(cop.arguments.size() - 1),
2859 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02002860 return expr;
2861 }
2862
2863 case OpCompositeInsert:
2864 SPIRV_CROSS_THROW("OpCompositeInsert spec constant op is not supported.");
2865
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002866 default:
2867 // Some opcodes are unimplemented here, these are currently not possible to test from glslang.
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002868 SPIRV_CROSS_THROW("Unimplemented spec constant op.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002869 }
2870
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01002871 uint32_t bit_width = 0;
2872 if (unary || binary)
2873 bit_width = expression_type(cop.arguments[0]).width;
2874
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002875 SPIRType::BaseType input_type;
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01002876 bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002877
2878 switch (cop.opcode)
2879 {
2880 case OpIEqual:
2881 case OpINotEqual:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01002882 input_type = to_signed_basetype(bit_width);
2883 break;
2884
2885 case OpSLessThan:
2886 case OpSLessThanEqual:
2887 case OpSGreaterThan:
2888 case OpSGreaterThanEqual:
2889 case OpSMod:
2890 case OpSDiv:
2891 case OpShiftRightArithmetic:
2892 input_type = to_signed_basetype(bit_width);
2893 break;
2894
2895 case OpULessThan:
2896 case OpULessThanEqual:
2897 case OpUGreaterThan:
2898 case OpUGreaterThanEqual:
2899 case OpUMod:
2900 case OpUDiv:
2901 case OpShiftRightLogical:
2902 input_type = to_unsigned_basetype(bit_width);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002903 break;
2904
2905 default:
2906 input_type = type.basetype;
2907 break;
2908 }
2909
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02002910#undef GLSL_BOP
2911#undef GLSL_UOP
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002912 if (binary)
2913 {
2914 if (cop.arguments.size() < 2)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002915 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002916
2917 string cast_op0;
2918 string cast_op1;
2919 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, cop.arguments[0],
2920 cop.arguments[1], skip_cast_if_equal_type);
2921
2922 if (type.basetype != input_type && type.basetype != SPIRType::Boolean)
2923 {
2924 expected_type.basetype = input_type;
2925 auto expr = bitcast_glsl_op(type, expected_type);
2926 expr += '(';
2927 expr += join(cast_op0, " ", op, " ", cast_op1);
2928 expr += ')';
2929 return expr;
2930 }
2931 else
2932 return join("(", cast_op0, " ", op, " ", cast_op1, ")");
2933 }
2934 else if (unary)
2935 {
2936 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002937 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002938
2939 // Auto-bitcast to result type as needed.
2940 // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
2941 return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")");
2942 }
2943 else
2944 {
2945 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002946 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002947 return join(op, "(", to_expression(cop.arguments[0]), ")");
2948 }
2949}
2950
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002951string CompilerGLSL::constant_expression(const SPIRConstant &c)
2952{
Chip Davis3bfb2f92018-12-03 02:06:33 -06002953 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02002954
Chip Davis3bfb2f92018-12-03 02:06:33 -06002955 if (type.pointer)
2956 {
2957 return backend.null_pointer_literal;
2958 }
2959 else if (!c.subconstants.empty())
2960 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002961 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002962 string res;
Hans-Kristian Arntzen57a15df2018-09-10 10:08:02 +02002963 if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02002964 type.array.empty())
2965 {
2966 res = type_to_glsl_constructor(type) + "{ ";
2967 }
2968 else if (backend.use_initializer_list)
2969 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002970 res = "{ ";
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02002971 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002972 else
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02002973 {
2974 res = type_to_glsl_constructor(type) + "(";
2975 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002976
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002977 for (auto &elem : c.subconstants)
2978 {
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002979 auto &subc = get<SPIRConstant>(elem);
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07002980 if (subc.specialization)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002981 res += to_name(elem);
2982 else
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02002983 res += constant_expression(subc);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002985 if (&elem != &c.subconstants.back())
2986 res += ", ";
2987 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002988
2989 res += backend.use_initializer_list ? " }" : ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002990 return res;
2991 }
2992 else if (c.columns() == 1)
2993 {
2994 return constant_expression_vector(c, 0);
2995 }
2996 else
2997 {
2998 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
2999 for (uint32_t col = 0; col < c.columns(); col++)
3000 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003001 if (c.specialization_constant_id(col) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003002 res += to_name(c.specialization_constant_id(col));
3003 else
3004 res += constant_expression_vector(c, col);
3005
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003006 if (col + 1 < c.columns())
3007 res += ", ";
3008 }
3009 res += ")";
3010 return res;
3011 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003012}
3013
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003014#ifdef _MSC_VER
3015// sprintf warning.
3016// We cannot rely on snprintf existing because, ..., MSVC.
3017#pragma warning(push)
3018#pragma warning(disable : 4996)
3019#endif
3020
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003021string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
3022{
3023 string res;
3024 float float_value = c.scalar_f16(col, row);
3025
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003026 // There is no literal "hf" in GL_NV_gpu_shader5, so to avoid lots
3027 // of complicated workarounds, just value-cast to the half type always.
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003028 if (std::isnan(float_value) || std::isinf(float_value))
3029 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003030 SPIRType type;
3031 type.basetype = SPIRType::Half;
3032 type.vecsize = 1;
3033 type.columns = 1;
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003034
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003035 if (float_value == numeric_limits<float>::infinity())
3036 res = join(type_to_glsl(type), "(1.0 / 0.0)");
3037 else if (float_value == -numeric_limits<float>::infinity())
3038 res = join(type_to_glsl(type), "(-1.0 / 0.0)");
3039 else if (std::isnan(float_value))
3040 res = join(type_to_glsl(type), "(0.0 / 0.0)");
3041 else
3042 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003043 }
3044 else
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003045 {
Hans-Kristian Arntzen4ef51332019-02-20 12:30:01 +01003046 SPIRType type;
3047 type.basetype = SPIRType::Half;
3048 type.vecsize = 1;
3049 type.columns = 1;
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01003050 res = join(type_to_glsl(type), "(", convert_to_string(float_value, current_locale_radix_character), ")");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003051 }
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003052
3053 return res;
3054}
3055
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003056string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
3057{
3058 string res;
3059 float float_value = c.scalar_f32(col, row);
3060
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003061 if (std::isnan(float_value) || std::isinf(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003062 {
3063 // Use special representation.
3064 if (!is_legacy())
3065 {
3066 SPIRType out_type;
3067 SPIRType in_type;
3068 out_type.basetype = SPIRType::Float;
3069 in_type.basetype = SPIRType::UInt;
3070 out_type.vecsize = 1;
3071 in_type.vecsize = 1;
3072 out_type.width = 32;
3073 in_type.width = 32;
3074
3075 char print_buffer[32];
3076 sprintf(print_buffer, "0x%xu", c.scalar(col, row));
3077 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
3078 }
3079 else
3080 {
3081 if (float_value == numeric_limits<float>::infinity())
3082 {
3083 if (backend.float_literal_suffix)
3084 res = "(1.0f / 0.0f)";
3085 else
3086 res = "(1.0 / 0.0)";
3087 }
3088 else if (float_value == -numeric_limits<float>::infinity())
3089 {
3090 if (backend.float_literal_suffix)
3091 res = "(-1.0f / 0.0f)";
3092 else
3093 res = "(-1.0 / 0.0)";
3094 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003095 else if (std::isnan(float_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003096 {
3097 if (backend.float_literal_suffix)
3098 res = "(0.0f / 0.0f)";
3099 else
3100 res = "(0.0 / 0.0)";
3101 }
3102 else
3103 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
3104 }
3105 }
3106 else
3107 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01003108 res = convert_to_string(float_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003109 if (backend.float_literal_suffix)
3110 res += "f";
3111 }
3112
3113 return res;
3114}
3115
3116std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
3117{
3118 string res;
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003119 double double_value = c.scalar_f64(col, row);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003120
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003121 if (std::isnan(double_value) || std::isinf(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003122 {
3123 // Use special representation.
3124 if (!is_legacy())
3125 {
3126 SPIRType out_type;
3127 SPIRType in_type;
3128 out_type.basetype = SPIRType::Double;
3129 in_type.basetype = SPIRType::UInt64;
3130 out_type.vecsize = 1;
3131 in_type.vecsize = 1;
3132 out_type.width = 64;
3133 in_type.width = 64;
3134
3135 uint64_t u64_value = c.scalar_u64(col, row);
3136
3137 if (options.es)
3138 SPIRV_CROSS_THROW("64-bit integers/float not supported in ES profile.");
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02003139 require_extension_internal("GL_ARB_gpu_shader_int64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003140
3141 char print_buffer[64];
3142 sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
3143 backend.long_long_literal_suffix ? "ull" : "ul");
3144 res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
3145 }
3146 else
3147 {
3148 if (options.es)
3149 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
3150 if (options.version < 400)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02003151 require_extension_internal("GL_ARB_gpu_shader_fp64");
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003152
3153 if (double_value == numeric_limits<double>::infinity())
3154 {
3155 if (backend.double_literal_suffix)
3156 res = "(1.0lf / 0.0lf)";
3157 else
3158 res = "(1.0 / 0.0)";
3159 }
3160 else if (double_value == -numeric_limits<double>::infinity())
3161 {
3162 if (backend.double_literal_suffix)
3163 res = "(-1.0lf / 0.0lf)";
3164 else
3165 res = "(-1.0 / 0.0)";
3166 }
Hans-Kristian Arntzene69b1ae2018-02-26 09:15:52 +01003167 else if (std::isnan(double_value))
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003168 {
3169 if (backend.double_literal_suffix)
3170 res = "(0.0lf / 0.0lf)";
3171 else
3172 res = "(0.0 / 0.0)";
3173 }
3174 else
3175 SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
3176 }
3177 }
3178 else
3179 {
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +01003180 res = convert_to_string(double_value, current_locale_radix_character);
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003181 if (backend.double_literal_suffix)
3182 res += "lf";
3183 }
3184
3185 return res;
3186}
3187
3188#ifdef _MSC_VER
3189#pragma warning(pop)
3190#endif
3191
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003192string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
3193{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003194 auto type = get<SPIRType>(c.constant_type);
3195 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003196
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003197 auto scalar_type = type;
3198 scalar_type.vecsize = 1;
3199
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003200 string res;
Robert Konradea24ee82016-09-23 18:57:18 +02003201 bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003202 bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003203
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003204 if (!type_is_floating_point(type))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003205 {
3206 // Cannot swizzle literal integers as a special case.
3207 swizzle_splat = false;
3208 }
3209
3210 if (splat || swizzle_splat)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003211 {
3212 // Cannot use constant splatting if we have specialization constants somewhere in the vector.
3213 for (uint32_t i = 0; i < c.vector_size(); i++)
3214 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003215 if (c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003216 {
3217 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003218 swizzle_splat = false;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003219 break;
3220 }
3221 }
3222 }
3223
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003224 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003225 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02003226 if (type.width == 64)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003227 {
3228 uint64_t ident = c.scalar_u64(vector, 0);
3229 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003230 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003231 if (ident != c.scalar_u64(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003232 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003233 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003234 swizzle_splat = false;
3235 break;
3236 }
3237 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003238 }
3239 else
3240 {
3241 uint32_t ident = c.scalar(vector, 0);
3242 for (uint32_t i = 1; i < c.vector_size(); i++)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003243 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003244 if (ident != c.scalar(vector, i))
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003245 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003246 splat = false;
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003247 swizzle_splat = false;
3248 }
3249 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003250 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003251 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003252
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003253 if (c.vector_size() > 1 && !swizzle_splat)
3254 res += type_to_glsl(type) + "(";
3255
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003256 switch (type.basetype)
3257 {
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003258 case SPIRType::Half:
3259 if (splat || swizzle_splat)
3260 {
3261 res += convert_half_to_string(c, vector, 0);
3262 if (swizzle_splat)
3263 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
3264 }
3265 else
3266 {
3267 for (uint32_t i = 0; i < c.vector_size(); i++)
3268 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003269 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01003270 res += to_name(c.specialization_constant_id(vector, i));
3271 else
3272 res += convert_half_to_string(c, vector, i);
3273
3274 if (i + 1 < c.vector_size())
3275 res += ", ";
3276 }
3277 }
3278 break;
3279
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003280 case SPIRType::Float:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003281 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003282 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003283 res += convert_float_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003284 if (swizzle_splat)
3285 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003286 }
3287 else
3288 {
3289 for (uint32_t i = 0; i < c.vector_size(); i++)
3290 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003291 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003292 res += to_name(c.specialization_constant_id(vector, i));
3293 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003294 res += convert_float_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003295
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003296 if (i + 1 < c.vector_size())
3297 res += ", ";
3298 }
3299 }
3300 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003301
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003302 case SPIRType::Double:
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003303 if (splat || swizzle_splat)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003304 {
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003305 res += convert_double_to_string(c, vector, 0);
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003306 if (swizzle_splat)
3307 res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003308 }
3309 else
3310 {
3311 for (uint32_t i = 0; i < c.vector_size(); i++)
3312 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003313 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003314 res += to_name(c.specialization_constant_id(vector, i));
3315 else
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01003316 res += convert_double_to_string(c, vector, i);
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003317
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003318 if (i + 1 < c.vector_size())
3319 res += ", ";
3320 }
3321 }
3322 break;
3323
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02003324 case SPIRType::Int64:
3325 if (splat)
3326 {
3327 res += convert_to_string(c.scalar_i64(vector, 0));
3328 if (backend.long_long_literal_suffix)
3329 res += "ll";
3330 else
3331 res += "l";
3332 }
3333 else
3334 {
3335 for (uint32_t i = 0; i < c.vector_size(); i++)
3336 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003337 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003338 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02003339 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003340 {
3341 res += convert_to_string(c.scalar_i64(vector, i));
3342 if (backend.long_long_literal_suffix)
3343 res += "ll";
3344 else
3345 res += "l";
3346 }
3347
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02003348 if (i + 1 < c.vector_size())
3349 res += ", ";
3350 }
3351 }
3352 break;
3353
3354 case SPIRType::UInt64:
3355 if (splat)
3356 {
3357 res += convert_to_string(c.scalar_u64(vector, 0));
3358 if (backend.long_long_literal_suffix)
3359 res += "ull";
3360 else
3361 res += "ul";
3362 }
3363 else
3364 {
3365 for (uint32_t i = 0; i < c.vector_size(); i++)
3366 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003367 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003368 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02003369 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003370 {
3371 res += convert_to_string(c.scalar_u64(vector, i));
3372 if (backend.long_long_literal_suffix)
3373 res += "ull";
3374 else
3375 res += "ul";
3376 }
3377
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02003378 if (i + 1 < c.vector_size())
3379 res += ", ";
3380 }
3381 }
3382 break;
3383
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003384 case SPIRType::UInt:
3385 if (splat)
3386 {
3387 res += convert_to_string(c.scalar(vector, 0));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02003388 if (is_legacy())
3389 {
3390 // Fake unsigned constant literals with signed ones if possible.
3391 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
3392 if (c.scalar_i32(vector, 0) < 0)
3393 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative.");
3394 }
3395 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003396 res += "u";
3397 }
3398 else
3399 {
3400 for (uint32_t i = 0; i < c.vector_size(); i++)
3401 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003402 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003403 res += to_name(c.specialization_constant_id(vector, i));
3404 else
3405 {
3406 res += convert_to_string(c.scalar(vector, i));
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02003407 if (is_legacy())
3408 {
3409 // Fake unsigned constant literals with signed ones if possible.
3410 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
3411 if (c.scalar_i32(vector, i) < 0)
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02003412 SPIRV_CROSS_THROW(
3413 "Tried to convert uint literal into int, but this made the literal negative.");
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02003414 }
3415 else if (backend.uint32_t_literal_suffix)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003416 res += "u";
3417 }
3418
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003419 if (i + 1 < c.vector_size())
3420 res += ", ";
3421 }
3422 }
3423 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003424
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003425 case SPIRType::Int:
3426 if (splat)
3427 res += convert_to_string(c.scalar_i32(vector, 0));
3428 else
3429 {
3430 for (uint32_t i = 0; i < c.vector_size(); i++)
3431 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003432 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003433 res += to_name(c.specialization_constant_id(vector, i));
3434 else
3435 res += convert_to_string(c.scalar_i32(vector, i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003436 if (i + 1 < c.vector_size())
3437 res += ", ";
3438 }
3439 }
3440 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003441
Chip Davisca4744a2018-11-02 14:39:55 -05003442 case SPIRType::UShort:
3443 if (splat)
3444 {
3445 res += convert_to_string(c.scalar(vector, 0));
3446 if (is_legacy())
3447 {
3448 // Fake unsigned constant literals with signed ones if possible.
3449 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
3450 if (c.scalar_i16(vector, 0) < 0)
3451 SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative.");
3452 }
Bill Hollingsc48702d2019-03-28 14:23:32 -04003453 else
Chip Davisca4744a2018-11-02 14:39:55 -05003454 res += backend.uint16_t_literal_suffix;
3455 }
3456 else
3457 {
3458 for (uint32_t i = 0; i < c.vector_size(); i++)
3459 {
3460 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
3461 res += to_name(c.specialization_constant_id(vector, i));
3462 else
3463 {
3464 res += convert_to_string(c.scalar(vector, i));
3465 if (is_legacy())
3466 {
3467 // Fake unsigned constant literals with signed ones if possible.
3468 // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
3469 if (c.scalar_i16(vector, i) < 0)
3470 SPIRV_CROSS_THROW(
3471 "Tried to convert uint literal into int, but this made the literal negative.");
3472 }
Bill Hollingsc48702d2019-03-28 14:23:32 -04003473 else
Chip Davisca4744a2018-11-02 14:39:55 -05003474 res += backend.uint16_t_literal_suffix;
3475 }
3476
3477 if (i + 1 < c.vector_size())
3478 res += ", ";
3479 }
3480 }
3481 break;
3482
3483 case SPIRType::Short:
3484 if (splat)
3485 {
3486 res += convert_to_string(c.scalar_i16(vector, 0));
Bill Hollingsc48702d2019-03-28 14:23:32 -04003487 res += backend.int16_t_literal_suffix;
Chip Davisca4744a2018-11-02 14:39:55 -05003488 }
3489 else
3490 {
3491 for (uint32_t i = 0; i < c.vector_size(); i++)
3492 {
3493 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
3494 res += to_name(c.specialization_constant_id(vector, i));
3495 else
3496 {
3497 res += convert_to_string(c.scalar_i16(vector, i));
Bill Hollingsc48702d2019-03-28 14:23:32 -04003498 res += backend.int16_t_literal_suffix;
Chip Davisca4744a2018-11-02 14:39:55 -05003499 }
3500 if (i + 1 < c.vector_size())
3501 res += ", ";
3502 }
3503 }
3504 break;
3505
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01003506 case SPIRType::UByte:
3507 if (splat)
3508 {
3509 res += convert_to_string(c.scalar_u8(vector, 0));
3510 }
3511 else
3512 {
3513 for (uint32_t i = 0; i < c.vector_size(); i++)
3514 {
3515 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
3516 res += to_name(c.specialization_constant_id(vector, i));
3517 else
3518 {
3519 res += type_to_glsl(scalar_type);
3520 res += "(";
3521 res += convert_to_string(c.scalar_u8(vector, i));
3522 res += ")";
3523 }
3524
3525 if (i + 1 < c.vector_size())
3526 res += ", ";
3527 }
3528 }
3529 break;
3530
3531 case SPIRType::SByte:
3532 if (splat)
3533 {
3534 res += convert_to_string(c.scalar_i8(vector, 0));
3535 }
3536 else
3537 {
3538 for (uint32_t i = 0; i < c.vector_size(); i++)
3539 {
3540 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
3541 res += to_name(c.specialization_constant_id(vector, i));
3542 else
3543 {
3544 res += type_to_glsl(scalar_type);
3545 res += "(";
3546 res += convert_to_string(c.scalar_i8(vector, i));
3547 res += ")";
3548 }
3549
3550 if (i + 1 < c.vector_size())
3551 res += ", ";
3552 }
3553 }
3554 break;
3555
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02003556 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003557 if (splat)
3558 res += c.scalar(vector, 0) ? "true" : "false";
3559 else
3560 {
3561 for (uint32_t i = 0; i < c.vector_size(); i++)
3562 {
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07003563 if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02003564 res += to_name(c.specialization_constant_id(vector, i));
3565 else
3566 res += c.scalar(vector, i) ? "true" : "false";
3567
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003568 if (i + 1 < c.vector_size())
3569 res += ", ";
3570 }
3571 }
3572 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003574 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003575 SPIRV_CROSS_THROW("Invalid constant expression basetype.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003576 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003577
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01003578 if (c.vector_size() > 1 && !swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003579 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003580
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003581 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003582}
3583
3584string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
3585{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003586 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01003587 auto &flags = ir.meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003588
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003589 // If we're declaring temporaries inside continue blocks,
3590 // 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 +01003591 if (current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003592 {
3593 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
3594 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003595 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003596 return tmp.first == result_type && tmp.second == result_id;
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01003597 }) == end(header.declare_temporary))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003598 {
3599 header.declare_temporary.emplace_back(result_type, result_id);
Hans-Kristian Arntzen7d223b82018-01-18 12:07:10 +01003600 hoisted_temporaries.insert(result_id);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003601 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003602 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003603
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003604 return join(to_name(result_id), " = ");
3605 }
Hans-Kristian Arntzenb629ca12017-11-21 09:27:49 +01003606 else if (hoisted_temporaries.count(result_id))
3607 {
3608 // The temporary has already been declared earlier, so just "declare" the temporary by writing to it.
3609 return join(to_name(result_id), " = ");
3610 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003611 else
3612 {
3613 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen35f64d02018-03-24 01:53:08 +01003614 add_local_variable_name(result_id);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003615 return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003616 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003617}
3618
3619bool CompilerGLSL::expression_is_forwarded(uint32_t id)
3620{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003621 return forwarded_temporaries.find(id) != end(forwarded_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003622}
3623
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003624SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003625 bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003626{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003627 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
3628 {
3629 // Just forward it without temporary.
3630 // If the forward is trivial, we do not force flushing to temporary for this expression.
3631 if (!suppress_usage_tracking)
3632 forwarded_temporaries.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003633
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003634 return set<SPIRExpression>(result_id, rhs, result_type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003635 }
3636 else
3637 {
3638 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
3639 statement(declare_temporary(result_type, result_id), rhs, ";");
3640 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
3641 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003642}
3643
3644void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
3645{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003646 bool forward = should_forward(op0);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02003647 emit_op(result_type, result_id, join(op, to_enclosed_unpacked_expression(op0)), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003648 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003649}
3650
3651void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
3652{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003653 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen192a8822018-06-11 16:21:38 +02003654 emit_op(result_type, result_id,
3655 join(to_enclosed_unpacked_expression(op0), " ", op, " ", to_enclosed_unpacked_expression(op1)), forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003656
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003657 inherit_expression_dependencies(result_id, op0);
3658 inherit_expression_dependencies(result_id, op1);
3659}
3660
Robert Konradf3a82772017-03-24 15:00:48 +01003661void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
3662{
3663 auto &type = get<SPIRType>(result_type);
3664 auto expr = type_to_glsl_constructor(type);
3665 expr += '(';
3666 for (uint32_t i = 0; i < type.vecsize; i++)
3667 {
3668 // Make sure to call to_expression multiple times to ensure
3669 // that these expressions are properly flushed to temporaries if needed.
3670 expr += op;
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02003671 expr += to_extract_component_expression(operand, i);
Robert Konradf3a82772017-03-24 15:00:48 +01003672
3673 if (i + 1 < type.vecsize)
3674 expr += ", ";
3675 }
3676 expr += ')';
3677 emit_op(result_type, result_id, expr, should_forward(operand));
3678
3679 inherit_expression_dependencies(result_id, operand);
3680}
3681
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003682void CompilerGLSL::emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
3683 const char *op)
3684{
3685 auto &type = get<SPIRType>(result_type);
3686 auto expr = type_to_glsl_constructor(type);
3687 expr += '(';
3688 for (uint32_t i = 0; i < type.vecsize; i++)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003689 {
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003690 // Make sure to call to_expression multiple times to ensure
3691 // that these expressions are properly flushed to temporaries if needed.
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02003692 expr += to_extract_component_expression(op0, i);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003693 expr += ' ';
3694 expr += op;
3695 expr += ' ';
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02003696 expr += to_extract_component_expression(op1, i);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003697
3698 if (i + 1 < type.vecsize)
3699 expr += ", ";
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003700 }
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003701 expr += ')';
3702 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
3703
3704 inherit_expression_dependencies(result_id, op0);
3705 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003706}
3707
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003708SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
3709 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
3710{
3711 auto &type0 = expression_type(op0);
3712 auto &type1 = expression_type(op1);
3713
3714 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
3715 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
3716 // since equality test is exactly the same.
3717 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
3718
3719 // Create a fake type so we can bitcast to it.
3720 // We only deal with regular arithmetic types here like int, uints and so on.
3721 SPIRType expected_type;
3722 expected_type.basetype = input_type;
3723 expected_type.vecsize = type0.vecsize;
3724 expected_type.columns = type0.columns;
3725 expected_type.width = type0.width;
3726
3727 if (cast)
3728 {
3729 cast_op0 = bitcast_glsl(expected_type, op0);
3730 cast_op1 = bitcast_glsl(expected_type, op1);
3731 }
3732 else
3733 {
3734 // 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 +02003735 cast_op0 = to_enclosed_unpacked_expression(op0);
3736 cast_op1 = to_enclosed_unpacked_expression(op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003737 input_type = type0.basetype;
3738 }
3739
3740 return expected_type;
3741}
3742
3743void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
3744 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
3745{
3746 string cast_op0, cast_op1;
3747 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
3748 auto &out_type = get<SPIRType>(result_type);
3749
3750 // We might have casted away from the result type, so bitcast again.
3751 // For example, arithmetic right shift with uint inputs.
3752 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003753 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02003754 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003755 {
3756 expected_type.basetype = input_type;
3757 expr = bitcast_glsl_op(out_type, expected_type);
3758 expr += '(';
3759 expr += join(cast_op0, " ", op, " ", cast_op1);
3760 expr += ')';
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003761 }
3762 else
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003763 expr += join(cast_op0, " ", op, " ", cast_op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003764
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003765 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01003766 inherit_expression_dependencies(result_id, op0);
3767 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003768}
3769
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003770void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
3771{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003772 bool forward = should_forward(op0);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003773 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003774 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003775}
3776
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003777void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
3778 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003779{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003780 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003781 emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ")"),
3782 forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003783 inherit_expression_dependencies(result_id, op0);
3784 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003785}
3786
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01003787void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op,
3788 SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type)
3789{
3790 auto &out_type = get<SPIRType>(result_type);
3791 auto expected_type = out_type;
3792 expected_type.basetype = input_type;
3793 string cast_op = expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0);
3794
3795 string expr;
3796 if (out_type.basetype != expected_result_type)
3797 {
3798 expected_type.basetype = expected_result_type;
3799 expr = bitcast_glsl_op(out_type, expected_type);
3800 expr += '(';
3801 expr += join(op, "(", cast_op, ")");
3802 expr += ')';
3803 }
3804 else
3805 {
3806 expr += join(op, "(", cast_op, ")");
3807 }
3808
3809 emit_op(result_type, result_id, expr, should_forward(op0));
3810 inherit_expression_dependencies(result_id, op0);
3811}
3812
3813void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id,
3814 uint32_t op0, uint32_t op1, uint32_t op2,
3815 const char *op,
3816 SPIRType::BaseType input_type)
3817{
3818 auto &out_type = get<SPIRType>(result_type);
3819 auto expected_type = out_type;
3820 expected_type.basetype = input_type;
3821 string cast_op0 = expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0);
3822 string cast_op1 = expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_expression(op1);
3823 string cast_op2 = expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_expression(op2);
3824
3825 string expr;
3826 if (out_type.basetype != input_type)
3827 {
3828 expr = bitcast_glsl_op(out_type, expected_type);
3829 expr += '(';
3830 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
3831 expr += ')';
3832 }
3833 else
3834 {
3835 expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")");
3836 }
3837
3838 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2));
3839 inherit_expression_dependencies(result_id, op0);
3840 inherit_expression_dependencies(result_id, op1);
3841 inherit_expression_dependencies(result_id, op2);
3842}
3843
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003844void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
3845 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
3846{
3847 string cast_op0, cast_op1;
3848 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
3849 auto &out_type = get<SPIRType>(result_type);
3850
3851 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
3852 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02003853 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003854 {
3855 expected_type.basetype = input_type;
3856 expr = bitcast_glsl_op(out_type, expected_type);
3857 expr += '(';
3858 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
3859 expr += ')';
3860 }
3861 else
3862 {
3863 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
3864 }
3865
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003866 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01003867 inherit_expression_dependencies(result_id, op0);
3868 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003869}
3870
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003871void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
3872 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003873{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003874 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003875 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003876 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
3877 to_unpacked_expression(op2), ")"),
3878 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003879
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003880 inherit_expression_dependencies(result_id, op0);
3881 inherit_expression_dependencies(result_id, op1);
3882 inherit_expression_dependencies(result_id, op2);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003883}
3884
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003885void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
3886 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003887{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003888 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01003889 emit_op(result_type, result_id,
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02003890 join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ", ",
3891 to_unpacked_expression(op2), ", ", to_unpacked_expression(op3), ")"),
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003892 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02003893
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01003894 inherit_expression_dependencies(result_id, op0);
3895 inherit_expression_dependencies(result_id, op1);
3896 inherit_expression_dependencies(result_id, op2);
3897 inherit_expression_dependencies(result_id, op3);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003898}
3899
Robert Konradedfc2972017-03-23 13:25:24 +01003900// EXT_shader_texture_lod only concerns fragment shaders so lod tex functions
3901// are not allowed in ES 2 vertex shaders. But SPIR-V only supports lod tex
3902// functions in vertex shaders so we revert those back to plain calls when
3903// the lod is a constant value of zero.
Robert Konrad9760f152017-03-23 14:43:54 +01003904bool CompilerGLSL::check_explicit_lod_allowed(uint32_t lod)
Robert Konradedfc2972017-03-23 13:25:24 +01003905{
3906 auto &execution = get_entry_point();
Robert Konrad9760f152017-03-23 14:43:54 +01003907 bool allowed = !is_legacy_es() || execution.model == ExecutionModelFragment;
Robert Konradec396472017-03-24 09:26:02 +01003908 if (!allowed && lod != 0)
Robert Konrad9760f152017-03-23 14:43:54 +01003909 {
3910 auto *lod_constant = maybe_get<SPIRConstant>(lod);
3911 if (!lod_constant || lod_constant->scalar_f32() != 0.0f)
3912 {
3913 SPIRV_CROSS_THROW("Explicit lod not allowed in legacy ES non-fragment shaders.");
3914 }
3915 }
3916 return allowed;
Robert Konradedfc2972017-03-23 13:25:24 +01003917}
3918
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02003919string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t tex)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003920{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003921 const char *type;
3922 switch (imgtype.image.dim)
3923 {
3924 case spv::Dim1D:
Rob Fischer21990632016-09-17 17:01:50 +09003925 type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003926 break;
3927 case spv::Dim2D:
Rob Fischer21990632016-09-17 17:01:50 +09003928 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003929 break;
3930 case spv::Dim3D:
3931 type = "3D";
3932 break;
3933 case spv::DimCube:
3934 type = "Cube";
3935 break;
Sidney Justfbb4df32019-01-06 12:21:59 -08003936 case spv::DimRect:
3937 type = "2DRect";
3938 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003939 case spv::DimBuffer:
3940 type = "Buffer";
3941 break;
3942 case spv::DimSubpassData:
3943 type = "2D";
3944 break;
3945 default:
3946 type = "";
3947 break;
3948 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003949
Robert Konrad9760f152017-03-23 14:43:54 +01003950 bool use_explicit_lod = check_explicit_lod_allowed(lod);
Robert Konrad3f745032017-03-23 09:55:32 +01003951
Sidney Just5ac55ee2018-06-25 02:11:46 -07003952 if (op == "textureLod" || op == "textureProjLod" || op == "textureGrad" || op == "textureProjGrad")
Lubos Lenco0028b4f2016-11-21 22:37:20 +01003953 {
Robert Konradedfc2972017-03-23 13:25:24 +01003954 if (is_legacy_es())
3955 {
Robert Konrad9760f152017-03-23 14:43:54 +01003956 if (use_explicit_lod)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02003957 require_extension_internal("GL_EXT_shader_texture_lod");
Robert Konradedfc2972017-03-23 13:25:24 +01003958 }
3959 else if (is_legacy())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02003960 require_extension_internal("GL_ARB_shader_texture_lod");
Lubos Lenco0028b4f2016-11-21 22:37:20 +01003961 }
Lubos Lenco52158642016-09-17 15:56:23 +02003962
Sidney Just5ac55ee2018-06-25 02:11:46 -07003963 if (op == "textureLodOffset" || op == "textureProjLodOffset")
3964 {
3965 if (is_legacy_es())
3966 SPIRV_CROSS_THROW(join(op, " not allowed in legacy ES"));
3967
3968 require_extension_internal("GL_EXT_gpu_shader4");
3969 }
3970
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02003971 // GLES has very limited support for shadow samplers.
Sidney Just5ac55ee2018-06-25 02:11:46 -07003972 // Basically shadow2D and shadow2DProj work through EXT_shadow_samplers,
3973 // everything else can just throw
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02003974 if (image_is_comparison(imgtype, tex) && is_legacy_es())
Sidney Just5ac55ee2018-06-25 02:11:46 -07003975 {
3976 if (op == "texture" || op == "textureProj")
3977 require_extension_internal("GL_EXT_shadow_samplers");
3978 else
3979 SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
3980 }
3981
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02003982 bool is_es_and_depth = is_legacy_es() && image_is_comparison(imgtype, tex);
3983 std::string type_prefix = image_is_comparison(imgtype, tex) ? "shadow" : "texture";
Sidney Just0f62b5d2018-06-22 01:40:01 -07003984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003985 if (op == "texture")
Sidney Just5ac55ee2018-06-25 02:11:46 -07003986 return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
Robert Konradedfc2972017-03-23 13:25:24 +01003987 else if (op == "textureLod")
3988 {
Robert Konrad9760f152017-03-23 14:43:54 +01003989 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07003990 return join(type_prefix, type, is_legacy_es() ? "LodEXT" : "Lod");
Robert Konrad9760f152017-03-23 14:43:54 +01003991 else
Sidney Just0f62b5d2018-06-22 01:40:01 -07003992 return join(type_prefix, type);
Robert Konrad3f745032017-03-23 09:55:32 +01003993 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003994 else if (op == "textureProj")
Sidney Just5ac55ee2018-06-25 02:11:46 -07003995 return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
Sidney Juste66fd6c2018-03-12 00:59:06 +10003996 else if (op == "textureGrad")
Sidney Just0f62b5d2018-06-22 01:40:01 -07003997 return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003998 else if (op == "textureProjLod")
Robert Konrad9760f152017-03-23 14:43:54 +01003999 {
4000 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07004001 return join(type_prefix, type, is_legacy_es() ? "ProjLodEXT" : "ProjLod");
Robert Konrad9760f152017-03-23 14:43:54 +01004002 else
Sidney Justceec7082018-06-25 02:06:45 -07004003 return join(type_prefix, type, "Proj");
Robert Konrad9760f152017-03-23 14:43:54 +01004004 }
Sidney Just0f62b5d2018-06-22 01:40:01 -07004005 else if (op == "textureLodOffset")
Sidney Justf6dad782018-06-22 00:28:40 -07004006 {
4007 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07004008 return join(type_prefix, type, "LodOffset");
Sidney Justf6dad782018-06-22 00:28:40 -07004009 else
Sidney Just0f62b5d2018-06-22 01:40:01 -07004010 return join(type_prefix, type);
Sidney Justf6dad782018-06-22 00:28:40 -07004011 }
Sidney Just0f62b5d2018-06-22 01:40:01 -07004012 else if (op == "textureProjGrad")
Hans-Kristian Arntzen9ddbd5a2018-06-28 23:00:26 +02004013 return join(type_prefix, type,
4014 is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
Sidney Just0f62b5d2018-06-22 01:40:01 -07004015 else if (op == "textureProjLodOffset")
Sidney Justf6dad782018-06-22 00:28:40 -07004016 {
4017 if (use_explicit_lod)
Sidney Just0f62b5d2018-06-22 01:40:01 -07004018 return join(type_prefix, type, "ProjLodOffset");
Sidney Justf6dad782018-06-22 00:28:40 -07004019 else
Sidney Justceec7082018-06-25 02:06:45 -07004020 return join(type_prefix, type, "ProjOffset");
Robert Konrad3f745032017-03-23 09:55:32 +01004021 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004022 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004023 {
4024 SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
4025 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004026}
4027
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004028bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
4029{
4030 auto *cleft = maybe_get<SPIRConstant>(left);
4031 auto *cright = maybe_get<SPIRConstant>(right);
4032 auto &lerptype = expression_type(lerp);
4033
4034 // If our targets aren't constants, we cannot use construction.
4035 if (!cleft || !cright)
4036 return false;
4037
4038 // If our targets are spec constants, we cannot use construction.
4039 if (cleft->specialization || cright->specialization)
4040 return false;
4041
4042 // We can only use trivial construction if we have a scalar
4043 // (should be possible to do it for vectors as well, but that is overkill for now).
4044 if (lerptype.basetype != SPIRType::Boolean || lerptype.vecsize > 1)
4045 return false;
4046
4047 // If our bool selects between 0 and 1, we can cast from bool instead, making our trivial constructor.
4048 bool ret = false;
4049 switch (type.basetype)
4050 {
Chip Davis117ccf42018-11-01 17:20:07 -05004051 case SPIRType::Short:
4052 case SPIRType::UShort:
4053 ret = cleft->scalar_u16() == 0 && cright->scalar_u16() == 1;
4054 break;
4055
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004056 case SPIRType::Int:
4057 case SPIRType::UInt:
4058 ret = cleft->scalar() == 0 && cright->scalar() == 1;
4059 break;
4060
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01004061 case SPIRType::Half:
4062 ret = cleft->scalar_f16() == 0.0f && cright->scalar_f16() == 1.0f;
4063 break;
4064
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004065 case SPIRType::Float:
4066 ret = cleft->scalar_f32() == 0.0f && cright->scalar_f32() == 1.0f;
4067 break;
4068
4069 case SPIRType::Double:
4070 ret = cleft->scalar_f64() == 0.0 && cright->scalar_f64() == 1.0;
4071 break;
4072
4073 case SPIRType::Int64:
4074 case SPIRType::UInt64:
4075 ret = cleft->scalar_u64() == 0 && cright->scalar_u64() == 1;
4076 break;
4077
4078 default:
4079 break;
4080 }
4081
4082 if (ret)
4083 op = type_to_glsl_constructor(type);
4084 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004085}
4086
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004087string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
4088 uint32_t false_value)
4089{
4090 string expr;
4091 auto &lerptype = expression_type(select);
4092
4093 if (lerptype.vecsize == 1)
Chip Davis3bfb2f92018-12-03 02:06:33 -06004094 expr = join(to_enclosed_expression(select), " ? ", to_enclosed_pointer_expression(true_value), " : ",
4095 to_enclosed_pointer_expression(false_value));
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004096 else
4097 {
4098 auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
4099
4100 expr = type_to_glsl_constructor(restype);
4101 expr += "(";
4102 for (uint32_t i = 0; i < restype.vecsize; i++)
4103 {
4104 expr += swiz(select, i);
4105 expr += " ? ";
4106 expr += swiz(true_value, i);
4107 expr += " : ";
4108 expr += swiz(false_value, i);
4109 if (i + 1 < restype.vecsize)
4110 expr += ", ";
4111 }
4112 expr += ")";
4113 }
4114
4115 return expr;
4116}
4117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004118void 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 +01004119{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004120 auto &lerptype = expression_type(lerp);
4121 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004122
Chip Davis3bfb2f92018-12-03 02:06:33 -06004123 // If this results in a variable pointer, assume it may be written through.
4124 if (restype.pointer)
4125 {
4126 register_write(left);
4127 register_write(right);
4128 }
4129
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004130 string mix_op;
Hans-Kristian Arntzen851acf32017-05-04 10:28:30 +02004131 bool has_boolean_mix = backend.boolean_mix_support &&
4132 ((options.es && options.version >= 310) || (!options.es && options.version >= 450));
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004133 bool trivial_mix = to_trivial_mix_op(restype, mix_op, left, right, lerp);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004134
Hans-Kristian Arntzen0e7c33f2017-02-11 10:52:34 +01004135 // Cannot use boolean mix when the lerp argument is just one boolean,
4136 // fall back to regular trinary statements.
4137 if (lerptype.vecsize == 1)
4138 has_boolean_mix = false;
4139
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004140 // If we can reduce the mix to a simple cast, do so.
4141 // This helps for cases like int(bool), uint(bool) which is implemented with
4142 // OpSelect bool 1 0.
4143 if (trivial_mix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004144 {
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02004145 emit_unary_func_op(result_type, id, lerp, mix_op.c_str());
4146 }
4147 else if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
4148 {
4149 // Boolean mix not supported on desktop without extension.
4150 // Was added in OpenGL 4.5 with ES 3.1 compat.
4151 //
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004152 // Could use GL_EXT_shader_integer_mix on desktop at least,
4153 // but Apple doesn't support it. :(
4154 // Just implement it as ternary expressions.
Hans-Kristian Arntzenffa91332018-06-25 09:48:17 +02004155 auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004156 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004157 inherit_expression_dependencies(id, left);
4158 inherit_expression_dependencies(id, right);
4159 inherit_expression_dependencies(id, lerp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004160 }
4161 else
4162 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004163}
4164
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004165string CompilerGLSL::to_combined_image_sampler(uint32_t image_id, uint32_t samp_id)
4166{
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02004167 // Keep track of the array indices we have used to load the image.
4168 // We'll need to use the same array index into the combined image sampler array.
4169 auto image_expr = to_expression(image_id);
4170 string array_expr;
4171 auto array_index = image_expr.find_first_of('[');
4172 if (array_index != string::npos)
4173 array_expr = image_expr.substr(array_index, string::npos);
4174
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004175 auto &args = current_function->arguments;
4176
4177 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
4178 // all possible combinations into new sampler2D uniforms.
4179 auto *image = maybe_get_backing_variable(image_id);
4180 auto *samp = maybe_get_backing_variable(samp_id);
4181 if (image)
4182 image_id = image->self;
4183 if (samp)
4184 samp_id = samp->self;
4185
4186 auto image_itr = find_if(begin(args), end(args),
4187 [image_id](const SPIRFunction::Parameter &param) { return param.id == image_id; });
4188
4189 auto sampler_itr = find_if(begin(args), end(args),
4190 [samp_id](const SPIRFunction::Parameter &param) { return param.id == samp_id; });
4191
4192 if (image_itr != end(args) || sampler_itr != end(args))
4193 {
4194 // If any parameter originates from a parameter, we will find it in our argument list.
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02004195 bool global_image = image_itr == end(args);
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004196 bool global_sampler = sampler_itr == end(args);
Hans-Kristian Arntzen7630d3c2016-11-21 12:14:02 +01004197 uint32_t iid = global_image ? image_id : uint32_t(image_itr - begin(args));
4198 uint32_t sid = global_sampler ? samp_id : uint32_t(sampler_itr - begin(args));
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004199
4200 auto &combined = current_function->combined_parameters;
4201 auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02004202 return p.global_image == global_image && p.global_sampler == global_sampler && p.image_id == iid &&
4203 p.sampler_id == sid;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004204 });
4205
4206 if (itr != end(combined))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02004207 return to_expression(itr->id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004208 else
4209 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004210 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004211 "Cannot find mapping for combined sampler parameter, was build_combined_image_samplers() used "
4212 "before compile() was called?");
4213 }
4214 }
4215 else
4216 {
4217 // For global sampler2D, look directly at the global remapping table.
4218 auto &mapping = combined_image_samplers;
4219 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
4220 return combined.image_id == image_id && combined.sampler_id == samp_id;
4221 });
4222
4223 if (itr != end(combined_image_samplers))
Hans-Kristian Arntzena39eb482018-04-23 11:52:05 +02004224 return to_expression(itr->combined_id) + array_expr;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004225 else
4226 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004227 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
4228 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02004229 }
4230 }
4231}
4232
Bill Hollings5aafb282016-04-23 21:47:41 -04004233void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
4234{
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02004235 if (options.vulkan_semantics && combined_image_samplers.empty())
4236 {
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02004237 emit_binary_func_op(result_type, result_id, image_id, samp_id,
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02004238 type_to_glsl(get<SPIRType>(result_type), result_id).c_str());
Hans-Kristian Arntzen02808002018-04-27 09:34:13 +02004239
4240 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
4241 forwarded_temporaries.erase(result_id);
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02004242 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02004243 else
Hans-Kristian Arntzen02808002018-04-27 09:34:13 +02004244 {
4245 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
4246 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true);
4247 }
Bill Hollings5aafb282016-04-23 21:47:41 -04004248}
4249
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01004250static inline bool image_opcode_is_sample_no_dref(Op op)
4251{
4252 switch (op)
4253 {
4254 case OpImageSampleExplicitLod:
4255 case OpImageSampleImplicitLod:
4256 case OpImageSampleProjExplicitLod:
4257 case OpImageSampleProjImplicitLod:
4258 case OpImageFetch:
4259 case OpImageRead:
4260 case OpImageSparseSampleExplicitLod:
4261 case OpImageSparseSampleImplicitLod:
4262 case OpImageSparseSampleProjExplicitLod:
4263 case OpImageSparseSampleProjImplicitLod:
4264 case OpImageSparseFetch:
4265 case OpImageSparseRead:
4266 return true;
4267
4268 default:
4269 return false;
4270 }
4271}
4272
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004273void CompilerGLSL::emit_texture_op(const Instruction &i)
4274{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004275 auto *ops = stream(i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004276 auto op = static_cast<Op>(i.op);
4277 uint32_t length = i.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004278
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004279 vector<uint32_t> inherited_expressions;
4280
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004281 uint32_t result_type = ops[0];
4282 uint32_t id = ops[1];
4283 uint32_t img = ops[2];
4284 uint32_t coord = ops[3];
4285 uint32_t dref = 0;
4286 uint32_t comp = 0;
4287 bool gather = false;
4288 bool proj = false;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004289 bool fetch = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004290 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004291
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004292 inherited_expressions.push_back(coord);
4293
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004294 switch (op)
4295 {
4296 case OpImageSampleDrefImplicitLod:
4297 case OpImageSampleDrefExplicitLod:
4298 dref = ops[4];
4299 opt = &ops[5];
4300 length -= 5;
4301 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004303 case OpImageSampleProjDrefImplicitLod:
4304 case OpImageSampleProjDrefExplicitLod:
4305 dref = ops[4];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004306 opt = &ops[5];
4307 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004308 proj = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004309 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004311 case OpImageDrefGather:
4312 dref = ops[4];
4313 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004314 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004315 gather = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004316 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004318 case OpImageGather:
4319 comp = ops[4];
4320 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004321 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004322 gather = true;
4323 break;
4324
4325 case OpImageFetch:
Bill Hollings8f6df772017-05-19 18:14:08 -04004326 case OpImageRead: // Reads == fetches in Metal (other langs will not get here)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004327 opt = &ops[4];
4328 length -= 4;
4329 fetch = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004330 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004332 case OpImageSampleProjImplicitLod:
4333 case OpImageSampleProjExplicitLod:
4334 opt = &ops[4];
4335 length -= 4;
4336 proj = true;
4337 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004338
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004339 default:
4340 opt = &ops[4];
4341 length -= 4;
4342 break;
4343 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004344
Bill Hollings8f6df772017-05-19 18:14:08 -04004345 // Bypass pointers because we need the real image struct
4346 auto &type = expression_type(img);
4347 auto &imgtype = get<SPIRType>(type.self);
4348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004349 uint32_t coord_components = 0;
4350 switch (imgtype.image.dim)
4351 {
4352 case spv::Dim1D:
4353 coord_components = 1;
4354 break;
4355 case spv::Dim2D:
4356 coord_components = 2;
4357 break;
4358 case spv::Dim3D:
4359 coord_components = 3;
4360 break;
4361 case spv::DimCube:
4362 coord_components = 3;
4363 break;
4364 case spv::DimBuffer:
4365 coord_components = 1;
4366 break;
4367 default:
4368 coord_components = 2;
4369 break;
4370 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004371
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004372 if (dref)
4373 inherited_expressions.push_back(dref);
4374
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004375 if (proj)
4376 coord_components++;
4377 if (imgtype.image.arrayed)
4378 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004379
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004380 uint32_t bias = 0;
4381 uint32_t lod = 0;
4382 uint32_t grad_x = 0;
4383 uint32_t grad_y = 0;
4384 uint32_t coffset = 0;
4385 uint32_t offset = 0;
4386 uint32_t coffsets = 0;
4387 uint32_t sample = 0;
4388 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004390 if (length)
4391 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004392 flags = *opt++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004393 length--;
4394 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004395
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02004396 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004397 if (length && (flags & flag))
4398 {
4399 v = *opt++;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004400 inherited_expressions.push_back(v);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004401 length--;
4402 }
4403 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004404
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004405 test(bias, ImageOperandsBiasMask);
4406 test(lod, ImageOperandsLodMask);
4407 test(grad_x, ImageOperandsGradMask);
4408 test(grad_y, ImageOperandsGradMask);
4409 test(coffset, ImageOperandsConstOffsetMask);
4410 test(offset, ImageOperandsOffsetMask);
4411 test(coffsets, ImageOperandsConstOffsetsMask);
4412 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004413
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004414 string expr;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004415 bool forward = false;
Hans-Kristian Arntzen27f4f752017-01-13 16:32:54 +01004416 expr += to_function_name(img, imgtype, !!fetch, !!gather, !!proj, !!coffsets, (!!coffset || !!offset),
Robert Konradec396472017-03-24 09:26:02 +01004417 (!!grad_x || !!grad_y), !!dref, lod);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004418 expr += "(";
4419 expr += to_function_args(img, imgtype, fetch, gather, proj, coord, coord_components, dref, grad_x, grad_y, lod,
4420 coffset, offset, bias, comp, sample, &forward);
4421 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004422
Sidney Justf6dad782018-06-22 00:28:40 -07004423 // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02004424 if (is_legacy() && image_is_comparison(imgtype, img))
Sidney Justf6dad782018-06-22 00:28:40 -07004425 expr += ".r";
4426
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01004427 // Sampling from a texture which was deduced to be a depth image, might actually return 1 component here.
4428 // Remap back to 4 components as sampling opcodes expect.
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02004429 if (backend.comparison_image_samples_scalar && image_opcode_is_sample_no_dref(op))
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01004430 {
Hans-Kristian Arntzen7e376232019-04-03 10:24:22 +02004431 bool image_is_depth = false;
4432 const auto *combined = maybe_get<SPIRCombinedImageSampler>(img);
4433 uint32_t image_id = combined ? combined->image : img;
4434
4435 if (combined && image_is_comparison(imgtype, combined->image))
4436 image_is_depth = true;
4437 else if (image_is_comparison(imgtype, img))
4438 image_is_depth = true;
4439
4440 // We must also check the backing variable for the image.
4441 // We might have loaded an OpImage, and used that handle for two different purposes.
4442 // Once with comparison, once without.
4443 auto *image_variable = maybe_get_backing_variable(image_id);
4444 if (image_variable && image_is_comparison(get<SPIRType>(image_variable->basetype), image_variable->self))
4445 image_is_depth = true;
4446
4447 if (image_is_depth)
4448 expr = remap_swizzle(get<SPIRType>(result_type), 1, expr);
Hans-Kristian Arntzena4ac2752019-02-22 12:02:11 +01004449 }
4450
Hans-Kristian Arntzen3aa08f72019-01-17 14:53:42 +01004451 // Deals with reads from MSL. We might need to downconvert to fewer components.
4452 if (op == OpImageRead)
4453 expr = remap_swizzle(get<SPIRType>(result_type), 4, expr);
4454
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004455 emit_op(result_type, id, expr, forward);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01004456 for (auto &inherit : inherited_expressions)
4457 inherit_expression_dependencies(id, inherit);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01004458
4459 switch (op)
4460 {
4461 case OpImageSampleDrefImplicitLod:
4462 case OpImageSampleImplicitLod:
4463 case OpImageSampleProjImplicitLod:
4464 case OpImageSampleProjDrefImplicitLod:
4465 register_control_dependent_expression(id);
4466 break;
4467
4468 default:
4469 break;
4470 }
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004471}
4472
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01004473bool CompilerGLSL::expression_is_constant_null(uint32_t id) const
4474{
4475 auto *c = maybe_get<SPIRConstant>(id);
4476 if (!c)
4477 return false;
4478 return c->constant_is_null();
4479}
4480
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004481// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
4482// For some subclasses, the function is a method on the specified image.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02004483string CompilerGLSL::to_function_name(uint32_t tex, const SPIRType &imgtype, bool is_fetch, bool is_gather,
4484 bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, bool,
4485 uint32_t lod)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004486{
4487 string fname;
4488
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02004489 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004490 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
4491 // 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 +02004492 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004493 bool workaround_lod_array_shadow_as_grad = false;
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02004494 if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02004495 image_is_comparison(imgtype, tex) && lod)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004496 {
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01004497 if (!expression_is_constant_null(lod))
4498 {
Hans-Kristian Arntzen7bb74912017-06-23 09:46:15 +02004499 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen5b876222019-01-07 10:01:28 +01004500 "textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be expressed in GLSL.");
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01004501 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004502 workaround_lod_array_shadow_as_grad = true;
4503 }
4504
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004505 if (is_fetch)
4506 fname += "texelFetch";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004507 else
4508 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004509 fname += "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004510
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004511 if (is_gather)
4512 fname += "Gather";
4513 if (has_array_offsets)
4514 fname += "Offsets";
4515 if (is_proj)
4516 fname += "Proj";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004517 if (has_grad || workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004518 fname += "Grad";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004519 if (!!lod && !workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004520 fname += "Lod";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004521 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004522
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004523 if (has_offset)
4524 fname += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004525
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02004526 return is_legacy() ? legacy_tex_op(fname, imgtype, lod, tex) : fname;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004527}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004528
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02004529std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id)
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004530{
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004531 auto *var = maybe_get_backing_variable(id);
4532
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02004533 // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler in GLSL.
4534 // In Vulkan GLSL, we can make use of the newer GL_EXT_samplerless_texture_functions.
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004535 if (var)
4536 {
4537 auto &type = get<SPIRType>(var->basetype);
4538 if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer)
4539 {
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004540 if (options.vulkan_semantics)
4541 {
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02004542 // Newer glslang supports this extension to deal with texture2D as argument to texture functions.
4543 if (dummy_sampler_id)
4544 SPIRV_CROSS_THROW("Vulkan GLSL should not have a dummy sampler for combining.");
4545 require_extension_internal("GL_EXT_samplerless_texture_functions");
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004546 }
4547 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02004548 {
4549 if (!dummy_sampler_id)
4550 SPIRV_CROSS_THROW(
4551 "Cannot find dummy sampler ID. Was build_dummy_sampler_for_combined_images() called?");
4552
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004553 return to_combined_image_sampler(id, dummy_sampler_id);
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02004554 }
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004555 }
4556 }
4557
4558 return to_expression(id);
4559}
4560
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004561// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
Hans-Kristian Arntzen7e23e692018-04-30 12:46:21 +02004562string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather,
4563 bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref,
4564 uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset,
4565 uint32_t bias, uint32_t comp, uint32_t sample, bool *p_forward)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004566{
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004567 string farg_str;
Hans-Kristian Arntzen1a2e4de2018-02-21 13:43:16 +01004568 if (is_fetch)
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02004569 farg_str = convert_separate_image_to_expression(img);
Hans-Kristian Arntzen40bbf6b2018-04-30 11:18:18 +02004570 else
4571 farg_str = to_expression(img);
Hans-Kristian Arntzen1a2e4de2018-02-21 13:43:16 +01004572
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004573 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02004574 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004575 if (comps == in_comps)
4576 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004577
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004578 switch (comps)
4579 {
4580 case 1:
4581 return ".x";
4582 case 2:
4583 return swizz_func ? ".xy()" : ".xy";
4584 case 3:
4585 return swizz_func ? ".xyz()" : ".xyz";
4586 default:
4587 return "";
4588 }
4589 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004590
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004591 bool forward = should_forward(coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004592
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004593 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004594 auto swizzle_expr = swizzle(coord_components, expression_type(coord).vecsize);
4595 // Only enclose the UV expression if needed.
4596 auto coord_expr = (*swizzle_expr == '\0') ? to_expression(coord) : (to_enclosed_expression(coord) + swizzle_expr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004597
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01004598 // texelFetch only takes int, not uint.
4599 auto &coord_type = expression_type(coord);
4600 if (coord_type.basetype == SPIRType::UInt)
4601 {
4602 auto expected_type = coord_type;
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02004603 expected_type.vecsize = coord_components;
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01004604 expected_type.basetype = SPIRType::Int;
4605 coord_expr = bitcast_expression(expected_type, coord_type.basetype, coord_expr);
4606 }
4607
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02004608 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004609 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
4610 // 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 +02004611 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02004612 bool workaround_lod_array_shadow_as_grad =
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02004613 ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02004614 image_is_comparison(imgtype, img) && lod;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004615
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004616 if (dref)
4617 {
4618 forward = forward && should_forward(dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004619
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004620 // SPIR-V splits dref and coordinate.
Hans-Kristian Arntzen47081f82018-04-30 12:45:23 +02004621 if (is_gather || coord_components == 4) // GLSL also splits the arguments in two. Same for textureGather.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004622 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004623 farg_str += ", ";
4624 farg_str += to_expression(coord);
4625 farg_str += ", ";
4626 farg_str += to_expression(dref);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004627 }
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02004628 else if (is_proj)
4629 {
4630 // Have to reshuffle so we get vec4(coord, dref, proj), special case.
4631 // Other shading languages splits up the arguments for coord and compare value like SPIR-V.
4632 // The coordinate type for textureProj shadow is always vec4 even for sampler1DShadow.
4633 farg_str += ", vec4(";
4634
4635 if (imgtype.image.dim == Dim1D)
4636 {
4637 // Could reuse coord_expr, but we will mess up the temporary usage checking.
4638 farg_str += to_enclosed_expression(coord) + ".x";
4639 farg_str += ", ";
4640 farg_str += "0.0, ";
4641 farg_str += to_expression(dref);
4642 farg_str += ", ";
4643 farg_str += to_enclosed_expression(coord) + ".y)";
4644 }
4645 else if (imgtype.image.dim == Dim2D)
4646 {
4647 // Could reuse coord_expr, but we will mess up the temporary usage checking.
4648 farg_str += to_enclosed_expression(coord) + (swizz_func ? ".xy()" : ".xy");
4649 farg_str += ", ";
4650 farg_str += to_expression(dref);
4651 farg_str += ", ";
4652 farg_str += to_enclosed_expression(coord) + ".z)";
4653 }
4654 else
4655 SPIRV_CROSS_THROW("Invalid type for textureProj with shadow.");
4656 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004657 else
4658 {
4659 // Create a composite which merges coord/dref into a single vector.
4660 auto type = expression_type(coord);
4661 type.vecsize = coord_components + 1;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004662 farg_str += ", ";
4663 farg_str += type_to_glsl_constructor(type);
4664 farg_str += "(";
4665 farg_str += coord_expr;
4666 farg_str += ", ";
4667 farg_str += to_expression(dref);
4668 farg_str += ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004669 }
4670 }
4671 else
4672 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004673 farg_str += ", ";
4674 farg_str += coord_expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004675 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004676
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004677 if (grad_x || grad_y)
4678 {
4679 forward = forward && should_forward(grad_x);
4680 forward = forward && should_forward(grad_y);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004681 farg_str += ", ";
4682 farg_str += to_expression(grad_x);
4683 farg_str += ", ";
4684 farg_str += to_expression(grad_y);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004685 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004687 if (lod)
4688 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004689 if (workaround_lod_array_shadow_as_grad)
Robert Konrad3f745032017-03-23 09:55:32 +01004690 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004691 // Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
4692 // Implementing this as plain texture() is not safe on some implementations.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02004693 if (imgtype.image.dim == Dim2D)
4694 farg_str += ", vec2(0.0), vec2(0.0)";
4695 else if (imgtype.image.dim == DimCube)
4696 farg_str += ", vec3(0.0), vec3(0.0)";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004697 }
4698 else
4699 {
4700 if (check_explicit_lod_allowed(lod))
4701 {
4702 forward = forward && should_forward(lod);
4703 farg_str += ", ";
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02004704
4705 auto &lod_expr_type = expression_type(lod);
4706
4707 // Lod expression for TexelFetch in GLSL must be int, and only int.
4708 if (is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms &&
4709 lod_expr_type.basetype != SPIRType::Int)
4710 {
4711 farg_str += join("int(", to_expression(lod), ")");
4712 }
4713 else
4714 {
4715 farg_str += to_expression(lod);
4716 }
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02004717 }
Robert Konrad3f745032017-03-23 09:55:32 +01004718 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004719 }
Hans-Kristian Arntzend93807a2018-04-30 10:53:21 +02004720 else if (is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms)
4721 {
4722 // Lod argument is optional in OpImageFetch, but we require a LOD value, pick 0 as the default.
4723 farg_str += ", 0";
4724 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004725
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004726 if (coffset)
4727 {
4728 forward = forward && should_forward(coffset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004729 farg_str += ", ";
4730 farg_str += to_expression(coffset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004731 }
4732 else if (offset)
4733 {
4734 forward = forward && should_forward(offset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004735 farg_str += ", ";
4736 farg_str += to_expression(offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004737 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004738
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004739 if (bias)
4740 {
4741 forward = forward && should_forward(bias);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004742 farg_str += ", ";
4743 farg_str += to_expression(bias);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004744 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004745
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004746 if (comp)
4747 {
4748 forward = forward && should_forward(comp);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004749 farg_str += ", ";
4750 farg_str += to_expression(comp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004751 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004752
Hans-Kristian Arntzen9d4360f2016-06-22 12:35:58 +02004753 if (sample)
4754 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004755 farg_str += ", ";
4756 farg_str += to_expression(sample);
Hans-Kristian Arntzen9d4360f2016-06-22 12:35:58 +02004757 }
4758
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004759 *p_forward = forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004760
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05004761 return farg_str;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004762}
4763
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004764void 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 +01004765{
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02004766 auto op = static_cast<GLSLstd450>(eop);
4767
4768 if (is_legacy() && is_unsigned_glsl_opcode(op))
4769 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy GLSL targets.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004770
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004771 // If we need to do implicit bitcasts, make sure we do it with the correct type.
4772 uint32_t integer_width = get_integer_width_for_glsl_instruction(op, args, length);
4773 auto int_type = to_signed_basetype(integer_width);
4774 auto uint_type = to_unsigned_basetype(integer_width);
4775
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004776 switch (op)
4777 {
4778 // FP fiddling
4779 case GLSLstd450Round:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004780 emit_unary_func_op(result_type, id, args[0], "round");
4781 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004782
4783 case GLSLstd450RoundEven:
4784 if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
4785 emit_unary_func_op(result_type, id, args[0], "roundEven");
4786 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004787 SPIRV_CROSS_THROW("roundEven supported only in ESSL 300 and GLSL 130 and up.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004788 break;
4789
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004790 case GLSLstd450Trunc:
4791 emit_unary_func_op(result_type, id, args[0], "trunc");
4792 break;
4793 case GLSLstd450SAbs:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004794 emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type);
4795 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004796 case GLSLstd450FAbs:
4797 emit_unary_func_op(result_type, id, args[0], "abs");
4798 break;
4799 case GLSLstd450SSign:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004800 emit_unary_func_op_cast(result_type, id, args[0], "sign", int_type, int_type);
4801 break;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004802 case GLSLstd450FSign:
4803 emit_unary_func_op(result_type, id, args[0], "sign");
4804 break;
4805 case GLSLstd450Floor:
4806 emit_unary_func_op(result_type, id, args[0], "floor");
4807 break;
4808 case GLSLstd450Ceil:
4809 emit_unary_func_op(result_type, id, args[0], "ceil");
4810 break;
4811 case GLSLstd450Fract:
4812 emit_unary_func_op(result_type, id, args[0], "fract");
4813 break;
4814 case GLSLstd450Radians:
4815 emit_unary_func_op(result_type, id, args[0], "radians");
4816 break;
4817 case GLSLstd450Degrees:
4818 emit_unary_func_op(result_type, id, args[0], "degrees");
4819 break;
4820 case GLSLstd450Fma:
Hans-Kristian Arntzen3ca8bc52019-04-08 10:33:34 +02004821 if ((!options.es && options.version < 400) || (options.es && options.version < 320))
4822 {
4823 auto expr = join(to_enclosed_expression(args[0]), " * ", to_enclosed_expression(args[1]), " + ",
4824 to_enclosed_expression(args[2]));
4825
4826 emit_op(result_type, id, expr,
4827 should_forward(args[0]) && should_forward(args[1]) && should_forward(args[2]));
4828 for (uint32_t i = 0; i < 3; i++)
4829 inherit_expression_dependencies(id, args[i]);
4830 }
4831 else
4832 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004833 break;
4834 case GLSLstd450Modf:
4835 register_call_out_argument(args[1]);
4836 forced_temporaries.insert(id);
4837 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
4838 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004839
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02004840 case GLSLstd450ModfStruct:
4841 {
4842 forced_temporaries.insert(id);
4843 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01004844 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02004845 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(id)), ";");
4846 set<SPIRExpression>(id, to_name(id), result_type, true);
4847
4848 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
4849 to_expression(id), ".", to_member_name(type, 1), ");");
4850 break;
4851 }
4852
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004853 // Minmax
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004854 case GLSLstd450UMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004855 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", uint_type, false);
4856 break;
4857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004858 case GLSLstd450SMin:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004859 emit_binary_func_op_cast(result_type, id, args[0], args[1], "min", int_type, false);
4860 break;
4861
4862 case GLSLstd450FMin:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004863 emit_binary_func_op(result_type, id, args[0], args[1], "min");
4864 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004866 case GLSLstd450FMax:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004867 emit_binary_func_op(result_type, id, args[0], args[1], "max");
4868 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004869
4870 case GLSLstd450UMax:
4871 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", uint_type, false);
4872 break;
4873
4874 case GLSLstd450SMax:
4875 emit_binary_func_op_cast(result_type, id, args[0], args[1], "max", int_type, false);
4876 break;
4877
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004878 case GLSLstd450FClamp:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004879 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
4880 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004881
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01004882 case GLSLstd450UClamp:
4883 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", uint_type);
4884 break;
4885
4886 case GLSLstd450SClamp:
4887 emit_trinary_func_op_cast(result_type, id, args[0], args[1], args[2], "clamp", int_type);
4888 break;
4889
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004890 // Trig
4891 case GLSLstd450Sin:
4892 emit_unary_func_op(result_type, id, args[0], "sin");
4893 break;
4894 case GLSLstd450Cos:
4895 emit_unary_func_op(result_type, id, args[0], "cos");
4896 break;
4897 case GLSLstd450Tan:
4898 emit_unary_func_op(result_type, id, args[0], "tan");
4899 break;
4900 case GLSLstd450Asin:
4901 emit_unary_func_op(result_type, id, args[0], "asin");
4902 break;
4903 case GLSLstd450Acos:
4904 emit_unary_func_op(result_type, id, args[0], "acos");
4905 break;
4906 case GLSLstd450Atan:
4907 emit_unary_func_op(result_type, id, args[0], "atan");
4908 break;
4909 case GLSLstd450Sinh:
4910 emit_unary_func_op(result_type, id, args[0], "sinh");
4911 break;
4912 case GLSLstd450Cosh:
4913 emit_unary_func_op(result_type, id, args[0], "cosh");
4914 break;
4915 case GLSLstd450Tanh:
4916 emit_unary_func_op(result_type, id, args[0], "tanh");
4917 break;
4918 case GLSLstd450Asinh:
4919 emit_unary_func_op(result_type, id, args[0], "asinh");
4920 break;
4921 case GLSLstd450Acosh:
4922 emit_unary_func_op(result_type, id, args[0], "acosh");
4923 break;
4924 case GLSLstd450Atanh:
4925 emit_unary_func_op(result_type, id, args[0], "atanh");
4926 break;
4927 case GLSLstd450Atan2:
4928 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
4929 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004930
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004931 // Exponentials
4932 case GLSLstd450Pow:
4933 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
4934 break;
4935 case GLSLstd450Exp:
4936 emit_unary_func_op(result_type, id, args[0], "exp");
4937 break;
4938 case GLSLstd450Log:
4939 emit_unary_func_op(result_type, id, args[0], "log");
4940 break;
4941 case GLSLstd450Exp2:
4942 emit_unary_func_op(result_type, id, args[0], "exp2");
4943 break;
4944 case GLSLstd450Log2:
4945 emit_unary_func_op(result_type, id, args[0], "log2");
4946 break;
4947 case GLSLstd450Sqrt:
4948 emit_unary_func_op(result_type, id, args[0], "sqrt");
4949 break;
4950 case GLSLstd450InverseSqrt:
4951 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
4952 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004953
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004954 // Matrix math
4955 case GLSLstd450Determinant:
4956 emit_unary_func_op(result_type, id, args[0], "determinant");
4957 break;
4958 case GLSLstd450MatrixInverse:
4959 emit_unary_func_op(result_type, id, args[0], "inverse");
4960 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004961
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004962 // Lerping
4963 case GLSLstd450FMix:
4964 case GLSLstd450IMix:
4965 {
4966 emit_mix_op(result_type, id, args[0], args[1], args[2]);
4967 break;
4968 }
4969 case GLSLstd450Step:
4970 emit_binary_func_op(result_type, id, args[0], args[1], "step");
4971 break;
4972 case GLSLstd450SmoothStep:
4973 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
4974 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004975
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004976 // Packing
4977 case GLSLstd450Frexp:
4978 register_call_out_argument(args[1]);
4979 forced_temporaries.insert(id);
4980 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
4981 break;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02004982
4983 case GLSLstd450FrexpStruct:
4984 {
4985 forced_temporaries.insert(id);
4986 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01004987 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02004988 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(id)), ";");
4989 set<SPIRExpression>(id, to_name(id), result_type, true);
4990
4991 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
4992 to_expression(id), ".", to_member_name(type, 1), ");");
4993 break;
4994 }
4995
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004996 case GLSLstd450Ldexp:
4997 emit_binary_func_op(result_type, id, args[0], args[1], "ldexp");
4998 break;
4999 case GLSLstd450PackSnorm4x8:
5000 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
5001 break;
5002 case GLSLstd450PackUnorm4x8:
5003 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
5004 break;
5005 case GLSLstd450PackSnorm2x16:
5006 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
5007 break;
5008 case GLSLstd450PackUnorm2x16:
5009 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
5010 break;
5011 case GLSLstd450PackHalf2x16:
5012 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
5013 break;
5014 case GLSLstd450UnpackSnorm4x8:
5015 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
5016 break;
5017 case GLSLstd450UnpackUnorm4x8:
5018 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
5019 break;
5020 case GLSLstd450UnpackSnorm2x16:
5021 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
5022 break;
5023 case GLSLstd450UnpackUnorm2x16:
5024 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
5025 break;
5026 case GLSLstd450UnpackHalf2x16:
5027 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
5028 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005029
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005030 case GLSLstd450PackDouble2x32:
5031 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
5032 break;
5033 case GLSLstd450UnpackDouble2x32:
5034 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
5035 break;
5036
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005037 // Vector math
5038 case GLSLstd450Length:
5039 emit_unary_func_op(result_type, id, args[0], "length");
5040 break;
5041 case GLSLstd450Distance:
5042 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
5043 break;
5044 case GLSLstd450Cross:
5045 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
5046 break;
5047 case GLSLstd450Normalize:
5048 emit_unary_func_op(result_type, id, args[0], "normalize");
5049 break;
5050 case GLSLstd450FaceForward:
5051 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
5052 break;
5053 case GLSLstd450Reflect:
5054 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
5055 break;
5056 case GLSLstd450Refract:
5057 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
5058 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005059
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005060 // Bit-fiddling
5061 case GLSLstd450FindILsb:
5062 emit_unary_func_op(result_type, id, args[0], "findLSB");
5063 break;
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005065 case GLSLstd450FindSMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005066 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", int_type, int_type);
5067 break;
5068
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005069 case GLSLstd450FindUMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01005070 emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type, int_type); // findMSB always returns int.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005071 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005073 // Multisampled varying
5074 case GLSLstd450InterpolateAtCentroid:
5075 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
5076 break;
5077 case GLSLstd450InterpolateAtSample:
5078 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
5079 break;
5080 case GLSLstd450InterpolateAtOffset:
5081 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
5082 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005083
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02005084 case GLSLstd450NMin:
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02005085 case GLSLstd450NMax:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01005086 {
5087 emit_nminmax_op(result_type, id, args[0], args[1], op);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02005088 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01005089 }
5090
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02005091 case GLSLstd450NClamp:
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01005092 {
5093 // Make sure we have a unique ID here to avoid aliasing the extra sub-expressions between clamp and NMin sub-op.
5094 // IDs cannot exceed 24 bits, so we can make use of the higher bits for some unique flags.
5095 uint32_t &max_id = extra_sub_expressions[id | 0x80000000u];
5096 if (!max_id)
5097 max_id = ir.increase_bound_by(1);
5098
5099 // Inherit precision qualifiers.
5100 ir.meta[max_id] = ir.meta[id];
5101
5102 emit_nminmax_op(result_type, max_id, args[0], args[1], GLSLstd450NMax);
5103 emit_nminmax_op(result_type, id, max_id, args[2], GLSLstd450NMin);
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02005104 break;
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01005105 }
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02005106
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005107 default:
5108 statement("// unimplemented GLSL op ", eop);
5109 break;
5110 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005111}
5112
Hans-Kristian Arntzen2a0365c2019-03-21 15:26:46 +01005113void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op)
5114{
5115 // Need to emulate this call.
5116 uint32_t &ids = extra_sub_expressions[id];
5117 if (!ids)
5118 {
5119 ids = ir.increase_bound_by(5);
5120 auto btype = get<SPIRType>(result_type);
5121 btype.basetype = SPIRType::Boolean;
5122 set<SPIRType>(ids, btype);
5123 }
5124
5125 uint32_t btype_id = ids + 0;
5126 uint32_t left_nan_id = ids + 1;
5127 uint32_t right_nan_id = ids + 2;
5128 uint32_t tmp_id = ids + 3;
5129 uint32_t mixed_first_id = ids + 4;
5130
5131 // Inherit precision qualifiers.
5132 ir.meta[tmp_id] = ir.meta[id];
5133 ir.meta[mixed_first_id] = ir.meta[id];
5134
5135 emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
5136 emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
5137 emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max");
5138 emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id);
5139 emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id);
5140}
5141
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005142void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
5143 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01005144{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005145 require_extension_internal("GL_AMD_shader_ballot");
Lou Kramer6671f522017-11-21 14:04:57 +01005146
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005147 enum AMDShaderBallot
5148 {
Lou Kramer6671f522017-11-21 14:04:57 +01005149 SwizzleInvocationsAMD = 1,
5150 SwizzleInvocationsMaskedAMD = 2,
5151 WriteInvocationAMD = 3,
5152 MbcntAMD = 4
5153 };
5154
5155 auto op = static_cast<AMDShaderBallot>(eop);
5156
5157 switch (op)
5158 {
5159 case SwizzleInvocationsAMD:
5160 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005161 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01005162 break;
5163
5164 case SwizzleInvocationsMaskedAMD:
5165 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsMaskedAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005166 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01005167 break;
5168
5169 case WriteInvocationAMD:
5170 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "writeInvocationAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005171 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01005172 break;
5173
5174 case MbcntAMD:
5175 emit_unary_func_op(result_type, id, args[0], "mbcntAMD");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005176 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01005177 break;
5178
5179 default:
5180 statement("// unimplemented SPV AMD shader ballot op ", eop);
5181 break;
5182 }
5183}
5184
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005185void CompilerGLSL::emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t id, uint32_t eop,
5186 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01005187{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005188 require_extension_internal("GL_AMD_shader_explicit_vertex_parameter");
Lou Kramer6671f522017-11-21 14:04:57 +01005189
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005190 enum AMDShaderExplicitVertexParameter
5191 {
Lou Kramer6671f522017-11-21 14:04:57 +01005192 InterpolateAtVertexAMD = 1
5193 };
5194
5195 auto op = static_cast<AMDShaderExplicitVertexParameter>(eop);
5196
5197 switch (op)
5198 {
5199 case InterpolateAtVertexAMD:
5200 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtVertexAMD");
5201 break;
5202
5203 default:
5204 statement("// unimplemented SPV AMD shader explicit vertex parameter op ", eop);
5205 break;
5206 }
5207}
5208
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005209void CompilerGLSL::emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t id, uint32_t eop,
5210 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01005211{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005212 require_extension_internal("GL_AMD_shader_trinary_minmax");
Lou Kramer6671f522017-11-21 14:04:57 +01005213
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005214 enum AMDShaderTrinaryMinMax
5215 {
Lou Kramer6671f522017-11-21 14:04:57 +01005216 FMin3AMD = 1,
5217 UMin3AMD = 2,
5218 SMin3AMD = 3,
5219 FMax3AMD = 4,
5220 UMax3AMD = 5,
5221 SMax3AMD = 6,
5222 FMid3AMD = 7,
5223 UMid3AMD = 8,
5224 SMid3AMD = 9
5225 };
5226
5227 auto op = static_cast<AMDShaderTrinaryMinMax>(eop);
5228
5229 switch (op)
5230 {
5231 case FMin3AMD:
5232 case UMin3AMD:
5233 case SMin3AMD:
5234 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "min3");
5235 break;
5236
5237 case FMax3AMD:
5238 case UMax3AMD:
5239 case SMax3AMD:
5240 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "max3");
5241 break;
5242
5243 case FMid3AMD:
5244 case UMid3AMD:
5245 case SMid3AMD:
5246 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mid3");
5247 break;
5248
5249 default:
5250 statement("// unimplemented SPV AMD shader trinary minmax op ", eop);
5251 break;
5252 }
5253}
5254
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005255void CompilerGLSL::emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
5256 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01005257{
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005258 require_extension_internal("GL_AMD_gcn_shader");
Lou Kramer6671f522017-11-21 14:04:57 +01005259
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01005260 enum AMDGCNShader
5261 {
Lou Kramer6671f522017-11-21 14:04:57 +01005262 CubeFaceIndexAMD = 1,
5263 CubeFaceCoordAMD = 2,
5264 TimeAMD = 3
5265 };
5266
5267 auto op = static_cast<AMDGCNShader>(eop);
5268
5269 switch (op)
5270 {
5271 case CubeFaceIndexAMD:
5272 emit_unary_func_op(result_type, id, args[0], "cubeFaceIndexAMD");
5273 break;
5274 case CubeFaceCoordAMD:
5275 emit_unary_func_op(result_type, id, args[0], "cubeFaceCoordAMD");
5276 break;
5277 case TimeAMD:
5278 {
5279 string expr = "timeAMD()";
5280 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005281 register_control_dependent_expression(id);
Lou Kramer6671f522017-11-21 14:04:57 +01005282 break;
5283 }
5284
5285 default:
5286 statement("// unimplemented SPV AMD gcn shader op ", eop);
5287 break;
5288 }
5289}
5290
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005291void CompilerGLSL::emit_subgroup_op(const Instruction &i)
5292{
5293 const uint32_t *ops = stream(i);
5294 auto op = static_cast<Op>(i.op);
5295
5296 if (!options.vulkan_semantics)
5297 SPIRV_CROSS_THROW("Can only use subgroup operations in Vulkan semantics.");
5298
5299 switch (op)
5300 {
5301 case OpGroupNonUniformElect:
5302 require_extension_internal("GL_KHR_shader_subgroup_basic");
5303 break;
5304
5305 case OpGroupNonUniformBroadcast:
5306 case OpGroupNonUniformBroadcastFirst:
5307 case OpGroupNonUniformBallot:
5308 case OpGroupNonUniformInverseBallot:
5309 case OpGroupNonUniformBallotBitExtract:
5310 case OpGroupNonUniformBallotBitCount:
5311 case OpGroupNonUniformBallotFindLSB:
5312 case OpGroupNonUniformBallotFindMSB:
5313 require_extension_internal("GL_KHR_shader_subgroup_ballot");
5314 break;
5315
5316 case OpGroupNonUniformShuffle:
5317 case OpGroupNonUniformShuffleXor:
5318 require_extension_internal("GL_KHR_shader_subgroup_shuffle");
5319 break;
5320
5321 case OpGroupNonUniformShuffleUp:
5322 case OpGroupNonUniformShuffleDown:
5323 require_extension_internal("GL_KHR_shader_subgroup_shuffle_relative");
5324 break;
5325
5326 case OpGroupNonUniformAll:
5327 case OpGroupNonUniformAny:
5328 case OpGroupNonUniformAllEqual:
5329 require_extension_internal("GL_KHR_shader_subgroup_vote");
5330 break;
5331
5332 case OpGroupNonUniformFAdd:
5333 case OpGroupNonUniformFMul:
5334 case OpGroupNonUniformFMin:
5335 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005336 case OpGroupNonUniformIAdd:
5337 case OpGroupNonUniformIMul:
5338 case OpGroupNonUniformSMin:
5339 case OpGroupNonUniformSMax:
5340 case OpGroupNonUniformUMin:
5341 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005342 case OpGroupNonUniformBitwiseAnd:
5343 case OpGroupNonUniformBitwiseOr:
5344 case OpGroupNonUniformBitwiseXor:
5345 {
5346 auto operation = static_cast<GroupOperation>(ops[3]);
5347 if (operation == GroupOperationClusteredReduce)
5348 {
5349 require_extension_internal("GL_KHR_shader_subgroup_clustered");
5350 }
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02005351 else if (operation == GroupOperationExclusiveScan || operation == GroupOperationInclusiveScan ||
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005352 operation == GroupOperationReduce)
5353 {
5354 require_extension_internal("GL_KHR_shader_subgroup_arithmetic");
5355 }
5356 else
5357 SPIRV_CROSS_THROW("Invalid group operation.");
5358 break;
5359 }
5360
5361 case OpGroupNonUniformQuadSwap:
5362 case OpGroupNonUniformQuadBroadcast:
5363 require_extension_internal("GL_KHR_shader_subgroup_quad");
5364 break;
5365
5366 default:
5367 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
5368 }
5369
5370 uint32_t result_type = ops[0];
5371 uint32_t id = ops[1];
5372
5373 auto scope = static_cast<Scope>(get<SPIRConstant>(ops[2]).scalar());
5374 if (scope != ScopeSubgroup)
5375 SPIRV_CROSS_THROW("Only subgroup scope is supported.");
5376
5377 switch (op)
5378 {
5379 case OpGroupNonUniformElect:
5380 emit_op(result_type, id, "subgroupElect()", true);
5381 break;
5382
5383 case OpGroupNonUniformBroadcast:
5384 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBroadcast");
5385 break;
5386
5387 case OpGroupNonUniformBroadcastFirst:
5388 emit_unary_func_op(result_type, id, ops[3], "subgroupBroadcastFirst");
5389 break;
5390
5391 case OpGroupNonUniformBallot:
5392 emit_unary_func_op(result_type, id, ops[3], "subgroupBallot");
5393 break;
5394
5395 case OpGroupNonUniformInverseBallot:
5396 emit_unary_func_op(result_type, id, ops[3], "subgroupInverseBallot");
5397 break;
5398
5399 case OpGroupNonUniformBallotBitExtract:
5400 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupBallotBitExtract");
5401 break;
5402
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005403 case OpGroupNonUniformBallotFindLSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005404 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindLSB");
5405 break;
5406
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005407 case OpGroupNonUniformBallotFindMSB:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005408 emit_unary_func_op(result_type, id, ops[3], "subgroupBallotFindMSB");
5409 break;
5410
5411 case OpGroupNonUniformBallotBitCount:
5412 {
5413 auto operation = static_cast<GroupOperation>(ops[3]);
5414 if (operation == GroupOperationReduce)
5415 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotBitCount");
5416 else if (operation == GroupOperationInclusiveScan)
5417 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotInclusiveBitCount");
5418 else if (operation == GroupOperationExclusiveScan)
5419 emit_unary_func_op(result_type, id, ops[4], "subgroupBallotExclusiveBitCount");
5420 else
5421 SPIRV_CROSS_THROW("Invalid BitCount operation.");
5422 break;
5423 }
5424
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005425 case OpGroupNonUniformShuffle:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005426 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffle");
5427 break;
5428
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005429 case OpGroupNonUniformShuffleXor:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005430 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleXor");
5431 break;
5432
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005433 case OpGroupNonUniformShuffleUp:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005434 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleUp");
5435 break;
5436
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005437 case OpGroupNonUniformShuffleDown:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005438 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupShuffleDown");
5439 break;
5440
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005441 case OpGroupNonUniformAll:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005442 emit_unary_func_op(result_type, id, ops[3], "subgroupAll");
5443 break;
5444
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005445 case OpGroupNonUniformAny:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005446 emit_unary_func_op(result_type, id, ops[3], "subgroupAny");
5447 break;
5448
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005449 case OpGroupNonUniformAllEqual:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005450 emit_unary_func_op(result_type, id, ops[3], "subgroupAllEqual");
5451 break;
5452
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02005453 // clang-format off
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005454#define GLSL_GROUP_OP(op, glsl_op) \
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005455case OpGroupNonUniform##op: \
5456 { \
5457 auto operation = static_cast<GroupOperation>(ops[3]); \
5458 if (operation == GroupOperationReduce) \
5459 emit_unary_func_op(result_type, id, ops[4], "subgroup" #glsl_op); \
5460 else if (operation == GroupOperationInclusiveScan) \
5461 emit_unary_func_op(result_type, id, ops[4], "subgroupInclusive" #glsl_op); \
5462 else if (operation == GroupOperationExclusiveScan) \
5463 emit_unary_func_op(result_type, id, ops[4], "subgroupExclusive" #glsl_op); \
5464 else if (operation == GroupOperationClusteredReduce) \
5465 emit_binary_func_op(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op); \
5466 else \
5467 SPIRV_CROSS_THROW("Invalid group operation."); \
5468 break; \
5469 }
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005470 GLSL_GROUP_OP(FAdd, Add)
5471 GLSL_GROUP_OP(FMul, Mul)
5472 GLSL_GROUP_OP(FMin, Min)
5473 GLSL_GROUP_OP(FMax, Max)
5474 GLSL_GROUP_OP(IAdd, Add)
5475 GLSL_GROUP_OP(IMul, Mul)
5476 GLSL_GROUP_OP(SMin, Min)
5477 GLSL_GROUP_OP(SMax, Max)
5478 GLSL_GROUP_OP(UMin, Min)
5479 GLSL_GROUP_OP(UMax, Max)
5480 GLSL_GROUP_OP(BitwiseAnd, And)
5481 GLSL_GROUP_OP(BitwiseOr, Or)
5482 GLSL_GROUP_OP(BitwiseXor, Xor)
5483#undef GLSL_GROUP_OP
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02005484 // clang-format on
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005485
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005486 case OpGroupNonUniformQuadSwap:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005487 {
5488 uint32_t direction = get<SPIRConstant>(ops[4]).scalar();
5489 if (direction == 0)
5490 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapHorizontal");
5491 else if (direction == 1)
5492 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapVertical");
5493 else if (direction == 2)
5494 emit_unary_func_op(result_type, id, ops[3], "subgroupQuadSwapDiagonal");
5495 else
5496 SPIRV_CROSS_THROW("Invalid quad swap direction.");
5497 break;
5498 }
5499
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005500 case OpGroupNonUniformQuadBroadcast:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02005501 {
5502 emit_binary_func_op(result_type, id, ops[3], ops[4], "subgroupQuadBroadcast");
5503 break;
5504 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005505
5506 default:
5507 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
5508 }
5509
5510 register_control_dependent_expression(id);
5511}
5512
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005513string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005514{
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005515 if (out_type.basetype == in_type.basetype)
5516 return "";
5517
Chip Davisef0b1fc2019-01-30 20:19:05 -06005518 assert(out_type.basetype != SPIRType::Boolean);
5519 assert(in_type.basetype != SPIRType::Boolean);
5520
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005521 bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
5522 bool same_size_cast = out_type.width == in_type.width;
5523
5524 // Trivial bitcast case, casts between integers.
5525 if (integral_cast && same_size_cast)
Chip Davis0d949e12018-11-05 14:55:56 -06005526 return type_to_glsl(out_type);
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005527
5528 // Catch-all 8-bit arithmetic casts (GL_EXT_shader_explicit_arithmetic_types).
5529 if (out_type.width == 8 && in_type.width >= 16 && integral_cast && in_type.vecsize == 1)
5530 return "unpack8";
5531 else if (in_type.width == 8 && out_type.width == 16 && integral_cast && out_type.vecsize == 1)
5532 return "pack16";
5533 else if (in_type.width == 8 && out_type.width == 32 && integral_cast && out_type.vecsize == 1)
5534 return "pack32";
5535
5536 // Floating <-> Integer special casts. Just have to enumerate all cases. :(
5537 // 16-bit, 32-bit and 64-bit floats.
5538 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005539 return "floatBitsToUint";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005540 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
5541 return "floatBitsToInt";
5542 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
5543 return "uintBitsToFloat";
5544 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
5545 return "intBitsToFloat";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02005546 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
5547 return "doubleBitsToInt64";
5548 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
5549 return "doubleBitsToUint64";
5550 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
5551 return "int64BitsToDouble";
5552 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
5553 return "uint64BitsToDouble";
Chip Davis0d949e12018-11-05 14:55:56 -06005554 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Half)
5555 return "float16BitsToInt16";
5556 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half)
5557 return "float16BitsToUint16";
5558 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Short)
5559 return "int16BitsToFloat16";
5560 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
5561 return "uint16BitsToFloat16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005562
5563 // And finally, some even more special purpose casts.
5564 if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
Lou Kramer6671f522017-11-21 14:04:57 +01005565 return "packUint2x32";
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01005566 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
5567 return "unpackFloat2x16";
5568 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)
5569 return "packFloat2x16";
Chip Davis0d949e12018-11-05 14:55:56 -06005570 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Short && in_type.vecsize == 2)
5571 return "packInt2x16";
5572 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int && in_type.vecsize == 1)
5573 return "unpackInt2x16";
5574 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UShort && in_type.vecsize == 2)
5575 return "packUint2x16";
5576 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
5577 return "unpackUint2x16";
5578 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Short && in_type.vecsize == 4)
5579 return "packInt4x16";
5580 else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int64 && in_type.vecsize == 1)
5581 return "unpackInt4x16";
5582 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UShort && in_type.vecsize == 4)
5583 return "packUint4x16";
5584 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt64 && in_type.vecsize == 1)
5585 return "unpackUint4x16";
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005586
5587 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005588}
5589
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005590string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005591{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005592 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005593 if (op.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005594 return to_enclosed_expression(argument);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005595 else
5596 return join(op, "(", to_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005597}
5598
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02005599std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg)
5600{
5601 auto expr = to_expression(arg);
5602 auto &src_type = expression_type(arg);
5603 if (src_type.basetype != target_type)
5604 {
5605 auto target = src_type;
5606 target.basetype = target_type;
5607 expr = join(bitcast_glsl_op(target, src_type), "(", expr, ")");
5608 }
5609
5610 return expr;
5611}
5612
5613std::string CompilerGLSL::bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type,
5614 const std::string &expr)
5615{
5616 if (target_type.basetype == expr_type)
5617 return expr;
5618
5619 auto src_type = target_type;
5620 src_type.basetype = expr_type;
5621 return join(bitcast_glsl_op(target_type, src_type), "(", expr, ")");
5622}
5623
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02005624string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005625{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005626 switch (builtin)
5627 {
5628 case BuiltInPosition:
5629 return "gl_Position";
5630 case BuiltInPointSize:
5631 return "gl_PointSize";
Bill Hollingse73e8e42016-12-17 17:07:53 -05005632 case BuiltInClipDistance:
5633 return "gl_ClipDistance";
Hans-Kristian Arntzen7f2e1792017-03-05 12:44:29 +01005634 case BuiltInCullDistance:
5635 return "gl_CullDistance";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005636 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02005637 if (options.vulkan_semantics)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005638 SPIRV_CROSS_THROW(
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02005639 "Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005640 return "gl_VertexID";
5641 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02005642 if (options.vulkan_semantics)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005643 SPIRV_CROSS_THROW(
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02005644 "Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005645 return "gl_InstanceID";
5646 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02005647 if (options.vulkan_semantics)
5648 return "gl_VertexIndex";
5649 else
5650 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005651 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02005652 if (options.vulkan_semantics)
5653 return "gl_InstanceIndex";
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02005654 else if (options.vertex.support_nonzero_base_instance)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02005655 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzenb29629f2018-06-22 10:01:38 +02005656 else
5657 return "gl_InstanceID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005658 case BuiltInPrimitiveId:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02005659 if (storage == StorageClassInput && get_entry_point().model == ExecutionModelGeometry)
5660 return "gl_PrimitiveIDIn";
5661 else
5662 return "gl_PrimitiveID";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005663 case BuiltInInvocationId:
5664 return "gl_InvocationID";
5665 case BuiltInLayer:
5666 return "gl_Layer";
Hans-Kristian Arntzenf825bd92018-01-04 12:41:25 +01005667 case BuiltInViewportIndex:
5668 return "gl_ViewportIndex";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005669 case BuiltInTessLevelOuter:
5670 return "gl_TessLevelOuter";
5671 case BuiltInTessLevelInner:
5672 return "gl_TessLevelInner";
5673 case BuiltInTessCoord:
5674 return "gl_TessCoord";
5675 case BuiltInFragCoord:
5676 return "gl_FragCoord";
5677 case BuiltInPointCoord:
5678 return "gl_PointCoord";
5679 case BuiltInFrontFacing:
5680 return "gl_FrontFacing";
5681 case BuiltInFragDepth:
5682 return "gl_FragDepth";
5683 case BuiltInNumWorkgroups:
5684 return "gl_NumWorkGroups";
5685 case BuiltInWorkgroupSize:
5686 return "gl_WorkGroupSize";
5687 case BuiltInWorkgroupId:
5688 return "gl_WorkGroupID";
5689 case BuiltInLocalInvocationId:
5690 return "gl_LocalInvocationID";
5691 case BuiltInGlobalInvocationId:
5692 return "gl_GlobalInvocationID";
5693 case BuiltInLocalInvocationIndex:
5694 return "gl_LocalInvocationIndex";
Hans-Kristian Arntzen61f1d8b2018-11-28 15:18:43 +01005695 case BuiltInHelperInvocation:
5696 return "gl_HelperInvocation";
Chip Davisfcad0192018-08-28 13:47:29 -05005697 case BuiltInBaseVertex:
5698 if (options.es)
5699 SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
Chip Davis3dc23612018-08-29 10:08:33 -05005700 if (options.version < 460)
5701 {
Chip Davisfcad0192018-08-28 13:47:29 -05005702 require_extension_internal("GL_ARB_shader_draw_parameters");
5703 return "gl_BaseVertexARB";
5704 }
5705 return "gl_BaseVertex";
5706 case BuiltInBaseInstance:
5707 if (options.es)
5708 SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
Chip Davis3dc23612018-08-29 10:08:33 -05005709 if (options.version < 460)
5710 {
Chip Davisfcad0192018-08-28 13:47:29 -05005711 require_extension_internal("GL_ARB_shader_draw_parameters");
5712 return "gl_BaseInstanceARB";
5713 }
5714 return "gl_BaseInstance";
5715 case BuiltInDrawIndex:
5716 if (options.es)
5717 SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
Chip Davis3dc23612018-08-29 10:08:33 -05005718 if (options.version < 460)
5719 {
Chip Davisfcad0192018-08-28 13:47:29 -05005720 require_extension_internal("GL_ARB_shader_draw_parameters");
5721 return "gl_DrawIDARB";
5722 }
5723 return "gl_DrawID";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02005724
5725 case BuiltInSampleId:
5726 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005727 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02005728 if (!options.es && options.version < 400)
5729 SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
5730 return "gl_SampleID";
5731
5732 case BuiltInSampleMask:
5733 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005734 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02005735 if (!options.es && options.version < 400)
5736 SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
5737
5738 if (storage == StorageClassInput)
5739 return "gl_SampleMaskIn";
5740 else
5741 return "gl_SampleMask";
5742
5743 case BuiltInSamplePosition:
5744 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005745 require_extension_internal("GL_OES_sample_variables");
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02005746 if (!options.es && options.version < 400)
5747 SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
5748 return "gl_SamplePosition";
5749
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02005750 case BuiltInViewIndex:
5751 if (options.vulkan_semantics)
5752 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005753 require_extension_internal("GL_EXT_multiview");
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02005754 return "gl_ViewIndex";
5755 }
5756 else
5757 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02005758 require_extension_internal("GL_OVR_multiview2");
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02005759 return "gl_ViewID_OVR";
5760 }
5761
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02005762 case BuiltInNumSubgroups:
5763 if (!options.vulkan_semantics)
5764 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5765 require_extension_internal("GL_KHR_shader_subgroup_basic");
5766 return "gl_NumSubgroups";
5767
5768 case BuiltInSubgroupId:
5769 if (!options.vulkan_semantics)
5770 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5771 require_extension_internal("GL_KHR_shader_subgroup_basic");
5772 return "gl_SubgroupID";
5773
5774 case BuiltInSubgroupSize:
5775 if (!options.vulkan_semantics)
5776 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5777 require_extension_internal("GL_KHR_shader_subgroup_basic");
5778 return "gl_SubgroupSize";
5779
5780 case BuiltInSubgroupLocalInvocationId:
5781 if (!options.vulkan_semantics)
5782 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5783 require_extension_internal("GL_KHR_shader_subgroup_basic");
5784 return "gl_SubgroupInvocationID";
5785
5786 case BuiltInSubgroupEqMask:
5787 if (!options.vulkan_semantics)
5788 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5789 require_extension_internal("GL_KHR_shader_subgroup_ballot");
5790 return "gl_SubgroupEqMask";
5791
5792 case BuiltInSubgroupGeMask:
5793 if (!options.vulkan_semantics)
5794 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5795 require_extension_internal("GL_KHR_shader_subgroup_ballot");
5796 return "gl_SubgroupGeMask";
5797
5798 case BuiltInSubgroupGtMask:
5799 if (!options.vulkan_semantics)
5800 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5801 require_extension_internal("GL_KHR_shader_subgroup_ballot");
5802 return "gl_SubgroupGtMask";
5803
5804 case BuiltInSubgroupLeMask:
5805 if (!options.vulkan_semantics)
5806 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5807 require_extension_internal("GL_KHR_shader_subgroup_ballot");
5808 return "gl_SubgroupLeMask";
5809
5810 case BuiltInSubgroupLtMask:
5811 if (!options.vulkan_semantics)
5812 SPIRV_CROSS_THROW("Need Vulkan semantics for subgroup.");
5813 require_extension_internal("GL_KHR_shader_subgroup_ballot");
5814 return "gl_SubgroupLtMask";
5815
Patrick Moursda39a7b2019-02-26 15:43:03 +01005816 case BuiltInLaunchIdNV:
5817 return "gl_LaunchIDNV";
5818 case BuiltInLaunchSizeNV:
5819 return "gl_LaunchSizeNV";
5820 case BuiltInWorldRayOriginNV:
5821 return "gl_WorldRayOriginNV";
5822 case BuiltInWorldRayDirectionNV:
5823 return "gl_WorldRayDirectionNV";
5824 case BuiltInObjectRayOriginNV:
5825 return "gl_ObjectRayOriginNV";
5826 case BuiltInObjectRayDirectionNV:
5827 return "gl_ObjectRayDirectionNV";
5828 case BuiltInRayTminNV:
5829 return "gl_RayTminNV";
5830 case BuiltInRayTmaxNV:
5831 return "gl_RayTmaxNV";
5832 case BuiltInInstanceCustomIndexNV:
5833 return "gl_InstanceCustomIndexNV";
5834 case BuiltInObjectToWorldNV:
5835 return "gl_ObjectToWorldNV";
5836 case BuiltInWorldToObjectNV:
5837 return "gl_WorldToObjectNV";
5838 case BuiltInHitTNV:
5839 return "gl_HitTNV";
5840 case BuiltInHitKindNV:
5841 return "gl_HitKindNV";
5842 case BuiltInIncomingRayFlagsNV:
5843 return "gl_IncomingRayFlagsNV";
5844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005845 default:
Bill Hollingse73e8e42016-12-17 17:07:53 -05005846 return join("gl_BuiltIn_", convert_to_string(builtin));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005847 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005848}
5849
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005850const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005851{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005852 switch (index)
5853 {
5854 case 0:
5855 return "x";
5856 case 1:
5857 return "y";
5858 case 2:
5859 return "z";
5860 case 3:
5861 return "w";
5862 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005863 SPIRV_CROSS_THROW("Swizzle index out of range");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005864 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005865}
5866
Hans-Kristian Arntzeneb5e09f2017-02-23 19:33:14 +01005867string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01005868 AccessChainFlags flags, AccessChainMeta *meta)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005869{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005870 string expr;
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01005871
5872 bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0;
5873 bool chain_only = (flags & ACCESS_CHAIN_CHAIN_ONLY_BIT) != 0;
5874 bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0;
5875 bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0;
5876
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005877 if (!chain_only)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01005878 expr = to_enclosed_expression(base, register_expression_read);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005879
Bill Hollings1e84a372017-08-12 00:21:13 -04005880 // Start traversing type hierarchy at the proper non-pointer types,
5881 // but keep type_id referencing the original pointer for use below.
Bill Hollingse0910312018-06-24 15:06:12 -04005882 uint32_t type_id = expression_type_id(base);
Chip Davisfc02b3d2019-01-08 12:54:40 -06005883 const auto *type = &get_pointee_type(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005884
Hans-Kristian Arntzenb71f5df2018-05-08 15:33:51 +02005885 bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos;
Bill Hollings13583622016-12-14 02:12:52 -05005886 bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01005887 bool is_packed = has_extended_decoration(base, SPIRVCrossDecorationPacked);
5888 uint32_t packed_type = get_extended_decoration(base, SPIRVCrossDecorationPackedType);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01005889 bool is_invariant = has_decoration(base, DecorationInvariant);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02005890 bool pending_array_enclose = false;
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02005891 bool dimension_flatten = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005892
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005893 for (uint32_t i = 0; i < count; i++)
5894 {
5895 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005896
Chip Davis3bfb2f92018-12-03 02:06:33 -06005897 const auto append_index = [&]() {
5898 expr += "[";
5899 if (index_is_literal)
5900 expr += convert_to_string(index);
5901 else
5902 expr += to_expression(index, register_expression_read);
5903 expr += "]";
5904 };
5905
5906 // Pointer chains
5907 if (ptr_chain && i == 0)
5908 {
5909 // If we are flattening multidimensional arrays, only create opening bracket on first
5910 // array index.
5911 if (options.flatten_multidimensional_arrays)
5912 {
5913 dimension_flatten = type->array.size() >= 1;
5914 pending_array_enclose = dimension_flatten;
5915 if (pending_array_enclose)
5916 expr += "[";
5917 }
5918
5919 if (options.flatten_multidimensional_arrays && dimension_flatten)
5920 {
5921 // If we are flattening multidimensional arrays, do manual stride computation.
5922 if (index_is_literal)
5923 expr += convert_to_string(index);
5924 else
5925 expr += to_enclosed_expression(index, register_expression_read);
5926
5927 for (auto j = uint32_t(type->array.size()); j; j--)
5928 {
5929 expr += " * ";
5930 expr += enclose_expression(to_array_size(*type, j - 1));
5931 }
5932
5933 if (type->array.empty())
5934 pending_array_enclose = false;
5935 else
5936 expr += " + ";
5937
5938 if (!pending_array_enclose)
5939 expr += "]";
5940 }
5941 else
5942 {
5943 append_index();
5944 }
5945
Chip Davise75add42019-02-05 18:13:26 -06005946 if (type->basetype == SPIRType::ControlPointArray)
5947 {
5948 type_id = type->parent_type;
5949 type = &get<SPIRType>(type_id);
5950 }
5951
Chip Davis3bfb2f92018-12-03 02:06:33 -06005952 access_chain_is_arrayed = true;
5953 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005954 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06005955 else if (!type->array.empty())
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005956 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02005957 // If we are flattening multidimensional arrays, only create opening bracket on first
5958 // array index.
5959 if (options.flatten_multidimensional_arrays && !pending_array_enclose)
5960 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02005961 dimension_flatten = type->array.size() > 1;
5962 pending_array_enclose = dimension_flatten;
5963 if (pending_array_enclose)
5964 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02005965 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005966
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01005967 assert(type->parent_type);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005968
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005969 auto *var = maybe_get<SPIRVariable>(base);
Bill Hollings27d4af72018-01-08 16:18:34 -05005970 if (backend.force_gl_in_out_block && i == 0 && var && is_builtin_variable(*var) &&
5971 !has_decoration(type->self, DecorationBlock))
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02005972 {
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005973 // This deals with scenarios for tesc/geom where arrays of gl_Position[] are declared.
5974 // Normally, these variables live in blocks when compiled from GLSL,
5975 // but HLSL seems to just emit straight arrays here.
5976 // We must pretend this access goes through gl_in/gl_out arrays
5977 // to be able to access certain builtins as arrays.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02005978 auto builtin = ir.meta[base].decoration.builtin_type;
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005979 switch (builtin)
5980 {
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01005981 // case BuiltInCullDistance: // These are already arrays, need to figure out rules for these in tess/geom.
5982 // case BuiltInClipDistance:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005983 case BuiltInPosition:
5984 case BuiltInPointSize:
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005985 if (var->storage == StorageClassInput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01005986 expr = join("gl_in[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005987 else if (var->storage == StorageClassOutput)
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01005988 expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr);
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01005989 else
5990 append_index();
5991 break;
5992
5993 default:
5994 append_index();
5995 break;
5996 }
5997 }
5998 else if (options.flatten_multidimensional_arrays && dimension_flatten)
5999 {
6000 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02006001 auto &parent_type = get<SPIRType>(type->parent_type);
6002
6003 if (index_is_literal)
6004 expr += convert_to_string(index);
6005 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01006006 expr += to_enclosed_expression(index, register_expression_read);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02006007
6008 for (auto j = uint32_t(parent_type.array.size()); j; j--)
6009 {
6010 expr += " * ";
6011 expr += enclose_expression(to_array_size(parent_type, j - 1));
6012 }
6013
6014 if (parent_type.array.empty())
6015 pending_array_enclose = false;
6016 else
6017 expr += " + ";
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01006018
6019 if (!pending_array_enclose)
6020 expr += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02006021 }
6022 else
6023 {
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01006024 append_index();
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02006025 }
6026
Bill Hollings1e84a372017-08-12 00:21:13 -04006027 type_id = type->parent_type;
6028 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006030 access_chain_is_arrayed = true;
6031 }
6032 // For structs, the index refers to a constant, which indexes into the members.
6033 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
6034 else if (type->basetype == SPIRType::Struct)
6035 {
6036 if (!index_is_literal)
6037 index = get<SPIRConstant>(index).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006038
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006039 if (index >= type->member_types.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006040 SPIRV_CROSS_THROW("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006042 BuiltIn builtin;
6043 if (is_member_builtin(*type, index, &builtin))
6044 {
6045 // FIXME: We rely here on OpName on gl_in/gl_out to make this work properly.
6046 // To make this properly work by omitting all OpName opcodes,
6047 // we need to infer gl_in or gl_out based on the builtin, and stage.
6048 if (access_chain_is_arrayed)
6049 {
6050 expr += ".";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02006051 expr += builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006052 }
6053 else
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02006054 expr = builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006055 }
6056 else
6057 {
Bill Hollingsc1b81542017-05-22 21:41:19 -04006058 // If the member has a qualified name, use it as the entire chain
Bill Hollings1e84a372017-08-12 00:21:13 -04006059 string qual_mbr_name = get_member_qualified_name(type_id, index);
Bill Hollingsc1b81542017-05-22 21:41:19 -04006060 if (!qual_mbr_name.empty())
6061 expr = qual_mbr_name;
6062 else
Chip Davis3bfb2f92018-12-03 02:06:33 -06006063 expr += to_member_reference(base, *type, index, ptr_chain);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006064 }
Bill Hollingsb332bae2017-03-01 13:07:40 -05006065
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01006066 if (has_member_decoration(type->self, index, DecorationInvariant))
6067 is_invariant = true;
6068
Bill Hollings607b0d62018-02-11 16:52:57 -05006069 is_packed = member_is_packed_type(*type, index);
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01006070 if (is_packed)
6071 packed_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPackedType);
6072 else
6073 packed_type = 0;
6074
Bill Hollings13583622016-12-14 02:12:52 -05006075 row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006076 type = &get<SPIRType>(type->member_types[index]);
6077 }
6078 // Matrix -> Vector
6079 else if (type->columns > 1)
6080 {
Bill Hollings13583622016-12-14 02:12:52 -05006081 if (row_major_matrix_needs_conversion)
Bill Hollings343677e2016-12-11 11:01:08 -05006082 {
Bill Hollings607b0d62018-02-11 16:52:57 -05006083 expr = convert_row_major_matrix(expr, *type, is_packed);
Bill Hollings13583622016-12-14 02:12:52 -05006084 row_major_matrix_needs_conversion = false;
Bill Hollings607b0d62018-02-11 16:52:57 -05006085 is_packed = false;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01006086 packed_type = 0;
Bill Hollings343677e2016-12-11 11:01:08 -05006087 }
6088
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006089 expr += "[";
6090 if (index_is_literal)
6091 expr += convert_to_string(index);
6092 else
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01006093 expr += to_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006094 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006095
Bill Hollings1e84a372017-08-12 00:21:13 -04006096 type_id = type->parent_type;
6097 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006098 }
6099 // Vector -> Scalar
6100 else if (type->vecsize > 1)
6101 {
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01006102 if (index_is_literal && !is_packed)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006103 {
6104 expr += ".";
6105 expr += index_to_swizzle(index);
6106 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02006107 else if (ir.ids[index].get_type() == TypeConstant && !is_packed)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006108 {
6109 auto &c = get<SPIRConstant>(index);
6110 expr += ".";
6111 expr += index_to_swizzle(c.scalar());
6112 }
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01006113 else if (index_is_literal)
6114 {
6115 // For packed vectors, we can only access them as an array, not by swizzle.
6116 expr += join("[", index, "]");
6117 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006118 else
6119 {
6120 expr += "[";
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01006121 expr += to_expression(index, register_expression_read);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006122 expr += "]";
6123 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006124
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01006125 is_packed = false;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01006126 packed_type = 0;
Bill Hollings1e84a372017-08-12 00:21:13 -04006127 type_id = type->parent_type;
6128 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006129 }
Bill Hollings2964e322018-02-13 14:44:40 -05006130 else if (!backend.allow_truncated_access_chain)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006131 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006132 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006133
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02006134 if (pending_array_enclose)
6135 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02006136 SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
6137 "but the access chain was terminated in the middle of a multidimensional array. "
6138 "This is not supported.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02006139 }
6140
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01006141 if (meta)
6142 {
6143 meta->need_transpose = row_major_matrix_needs_conversion;
6144 meta->storage_is_packed = is_packed;
6145 meta->storage_is_invariant = is_invariant;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01006146 meta->storage_packed_type = packed_type;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01006147 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05006148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006149 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006150}
6151
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01006152string CompilerGLSL::to_flattened_struct_member(const SPIRVariable &var, uint32_t index)
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01006153{
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01006154 auto &type = get<SPIRType>(var.basetype);
6155 return sanitize_underscores(join(to_name(var.self), "_", to_member_name(type, index)));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01006156}
6157
Bill Hollings2d0d3282017-01-20 11:33:59 -05006158string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
Chip Davis3bfb2f92018-12-03 02:06:33 -06006159 AccessChainMeta *meta, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006160{
Arseny Kapoulkine24c66252017-01-16 14:19:49 -08006161 if (flattened_buffer_blocks.count(base))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006162 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02006163 uint32_t matrix_stride = 0;
6164 bool need_transpose = false;
Chip Davis3bfb2f92018-12-03 02:06:33 -06006165 flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride,
6166 ptr_chain);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006167
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01006168 if (meta)
6169 {
6170 meta->need_transpose = target_type.columns > 1 && need_transpose;
6171 meta->storage_is_packed = false;
6172 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006173
6174 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006175 }
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01006176 else if (flattened_structs.count(base) && count > 0)
6177 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01006178 AccessChainFlags flags = ACCESS_CHAIN_CHAIN_ONLY_BIT | ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
6179 if (ptr_chain)
6180 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
6181
6182 auto chain = access_chain_internal(base, indices, count, flags, nullptr).substr(1);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01006183 if (meta)
6184 {
6185 meta->need_transpose = false;
6186 meta->storage_is_packed = false;
6187 }
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01006188 return sanitize_underscores(join(to_name(base), "_", chain));
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01006189 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006190 else
6191 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01006192 AccessChainFlags flags = ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT;
6193 if (ptr_chain)
6194 flags |= ACCESS_CHAIN_PTR_CHAIN_BIT;
6195 return access_chain_internal(base, indices, count, flags, meta);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006196 }
6197}
6198
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01006199string CompilerGLSL::load_flattened_struct(SPIRVariable &var)
6200{
6201 auto expr = type_to_glsl_constructor(get<SPIRType>(var.basetype));
6202 expr += '(';
6203
6204 auto &type = get<SPIRType>(var.basetype);
6205 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
6206 {
6207 if (i)
6208 expr += ", ";
6209
6210 // Flatten the varyings.
6211 // Apply name transformation for flattened I/O blocks.
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01006212 expr += to_flattened_struct_member(var, i);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01006213 }
6214 expr += ')';
6215 return expr;
6216}
6217
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01006218void CompilerGLSL::store_flattened_struct(SPIRVariable &var, uint32_t value)
6219{
6220 // We're trying to store a structure which has been flattened.
6221 // Need to copy members one by one.
6222 auto rhs = to_expression(value);
6223
6224 // Store result locally.
6225 // Since we're declaring a variable potentially multiple times here,
6226 // store the variable in an isolated scope.
6227 begin_scope();
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01006228 statement(variable_decl_function_local(var), " = ", rhs, ";");
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01006229
6230 auto &type = get<SPIRType>(var.basetype);
6231 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
6232 {
6233 // Flatten the varyings.
6234 // Apply name transformation for flattened I/O blocks.
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01006235
Hans-Kristian Arntzen1a5a7552018-01-09 10:36:04 +01006236 auto lhs = sanitize_underscores(join(to_name(var.self), "_", to_member_name(type, i)));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01006237 rhs = join(to_name(var.self), ".", to_member_name(type, i));
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01006238 statement(lhs, " = ", rhs, ";");
6239 }
6240 end_scope();
6241}
6242
Bill Hollings2d0d3282017-01-20 11:33:59 -05006243std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006244 const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
6245 bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006246{
6247 if (!target_type.array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006248 SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006249 else if (target_type.basetype == SPIRType::Struct)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006250 return flattened_access_chain_struct(base, indices, count, target_type, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006251 else if (target_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006252 return flattened_access_chain_matrix(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006253 else
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006254 return flattened_access_chain_vector(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006255}
6256
Bill Hollings2d0d3282017-01-20 11:33:59 -05006257std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
6258 const SPIRType &target_type, uint32_t offset)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006259{
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006260 std::string expr;
6261
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01006262 expr += type_to_glsl_constructor(target_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006263 expr += "(";
6264
Henrik Rydgårdbfae0412017-03-07 09:59:26 +01006265 for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006266 {
6267 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08006268 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006269
6270 const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006271 uint32_t member_offset = type_struct_member_offset(target_type, i);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006272
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006273 // The access chain terminates at the struct, so we need to find matrix strides and row-major information
6274 // ahead of time.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006275 bool need_transpose = false;
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006276 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006277 if (member_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006278 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01006279 need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006280 matrix_stride = type_struct_member_matrix_stride(target_type, i);
6281 }
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006282
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006283 auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride,
6284 need_transpose);
6285
6286 // Cannot forward transpositions, so resolve them here.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006287 if (need_transpose)
Bill Hollings607b0d62018-02-11 16:52:57 -05006288 expr += convert_row_major_matrix(tmp, member_type, false);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006289 else
6290 expr += tmp;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006291 }
6292
6293 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006294
6295 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006296}
6297
Bill Hollings2d0d3282017-01-20 11:33:59 -05006298std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006299 const SPIRType &target_type, uint32_t offset,
6300 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006301{
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006302 assert(matrix_stride);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006303 SPIRType tmp_type = target_type;
6304 if (need_transpose)
6305 swap(tmp_type.vecsize, tmp_type.columns);
6306
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006307 std::string expr;
6308
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006309 expr += type_to_glsl_constructor(tmp_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006310 expr += "(";
6311
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006312 for (uint32_t i = 0; i < tmp_type.columns; i++)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006313 {
6314 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08006315 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006316
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006317 expr += flattened_access_chain_vector(base, indices, count, tmp_type, offset + i * matrix_stride, matrix_stride,
6318 /* need_transpose= */ false);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006319 }
6320
6321 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006322
6323 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006324}
6325
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006326std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
6327 const SPIRType &target_type, uint32_t offset,
6328 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006329{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02006330 auto result = flattened_access_chain_offset(expression_type(base), indices, count, offset, 16);
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006331
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006332 auto buffer_name = to_name(expression_type(base).self);
6333
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006334 if (need_transpose)
6335 {
6336 std::string expr;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006337
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08006338 if (target_type.vecsize > 1)
6339 {
6340 expr += type_to_glsl_constructor(target_type);
6341 expr += "(";
6342 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006343
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006344 for (uint32_t i = 0; i < target_type.vecsize; ++i)
6345 {
6346 if (i != 0)
6347 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006348
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006349 uint32_t component_offset = result.second + i * matrix_stride;
6350
6351 assert(component_offset % (target_type.width / 8) == 0);
6352 uint32_t index = component_offset / (target_type.width / 8);
6353
6354 expr += buffer_name;
6355 expr += "[";
6356 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
6357 expr += convert_to_string(index / 4);
6358 expr += "]";
6359
6360 expr += vector_swizzle(1, index % 4);
6361 }
6362
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08006363 if (target_type.vecsize > 1)
6364 {
6365 expr += ")";
6366 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08006367
6368 return expr;
6369 }
6370 else
6371 {
6372 assert(result.second % (target_type.width / 8) == 0);
6373 uint32_t index = result.second / (target_type.width / 8);
6374
6375 std::string expr;
6376
6377 expr += buffer_name;
6378 expr += "[";
6379 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
6380 expr += convert_to_string(index / 4);
6381 expr += "]";
6382
6383 expr += vector_swizzle(target_type.vecsize, index % 4);
6384
6385 return expr;
6386 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006387}
6388
Chip Davis3bfb2f92018-12-03 02:06:33 -06006389std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(
6390 const SPIRType &basetype, const uint32_t *indices, uint32_t count, uint32_t offset, uint32_t word_stride,
6391 bool *need_transpose, uint32_t *out_matrix_stride, bool ptr_chain)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006392{
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01006393 // Start traversing type hierarchy at the proper non-pointer types.
Chip Davisfc02b3d2019-01-08 12:54:40 -06006394 const auto *type = &get_pointee_type(basetype);
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01006395
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01006396 // This holds the type of the current pointer which we are traversing through.
6397 // We always start out from a struct type which is the block.
6398 // This is primarily used to reflect the array strides and matrix strides later.
6399 // For the first access chain index, type_id won't be needed, so just keep it as 0, it will be set
6400 // accordingly as members of structs are accessed.
6401 assert(type->basetype == SPIRType::Struct);
6402 uint32_t type_id = 0;
6403
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006404 std::string expr;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02006405
6406 // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout.
6407 bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false;
6408 uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006409
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006410 for (uint32_t i = 0; i < count; i++)
6411 {
6412 uint32_t index = indices[i];
6413
Chip Davis3bfb2f92018-12-03 02:06:33 -06006414 // Pointers
6415 if (ptr_chain && i == 0)
6416 {
6417 // Here, the pointer type will be decorated with an array stride.
6418 uint32_t array_stride = get_decoration(basetype.self, DecorationArrayStride);
6419 if (!array_stride)
6420 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
6421
6422 auto *constant = maybe_get<SPIRConstant>(index);
6423 if (constant)
6424 {
6425 // Constant array access.
6426 offset += constant->scalar() * array_stride;
6427 }
6428 else
6429 {
6430 // Dynamic array access.
6431 if (array_stride % word_stride)
6432 {
6433 SPIRV_CROSS_THROW(
6434 "Array stride for dynamic indexing must be divisible by the size of a 4-component vector. "
6435 "Likely culprit here is a float or vec2 array inside a push constant block which is std430. "
6436 "This cannot be flattened. Try using std140 layout instead.");
6437 }
6438
6439 expr += to_enclosed_expression(index);
6440 expr += " * ";
6441 expr += convert_to_string(array_stride / word_stride);
6442 expr += " + ";
6443 }
6444 // Type ID is unchanged.
6445 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006446 // Arrays
Chip Davis3bfb2f92018-12-03 02:06:33 -06006447 else if (!type->array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006448 {
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01006449 // Here, the type_id will be a type ID for the array type itself.
6450 uint32_t array_stride = get_decoration(type_id, DecorationArrayStride);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01006451 if (!array_stride)
6452 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006453
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01006454 auto *constant = maybe_get<SPIRConstant>(index);
6455 if (constant)
6456 {
6457 // Constant array access.
6458 offset += constant->scalar() * array_stride;
6459 }
6460 else
6461 {
6462 // Dynamic array access.
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01006463 if (array_stride % word_stride)
6464 {
Hans-Kristian Arntzen87f3c572017-01-21 12:47:26 +01006465 SPIRV_CROSS_THROW(
6466 "Array stride for dynamic indexing must be divisible by the size of a 4-component vector. "
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01006467 "Likely culprit here is a float or vec2 array inside a push constant block which is std430. "
6468 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01006469 }
6470
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01006471 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01006472 expr += " * ";
6473 expr += convert_to_string(array_stride / word_stride);
6474 expr += " + ";
6475 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006476
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01006477 uint32_t parent_type = type->parent_type;
6478 type = &get<SPIRType>(parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01006479 type_id = parent_type;
6480
6481 // Type ID now refers to the array type with one less dimension.
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006482 }
6483 // For structs, the index refers to a constant, which indexes into the members.
6484 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
6485 else if (type->basetype == SPIRType::Struct)
6486 {
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01006487 index = get<SPIRConstant>(index).scalar();
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006488
6489 if (index >= type->member_types.size())
6490 SPIRV_CROSS_THROW("Member index is out of bounds!");
6491
6492 offset += type_struct_member_offset(*type, index);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01006493 type_id = type->member_types[index];
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01006494
6495 auto &struct_type = *type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006496 type = &get<SPIRType>(type->member_types[index]);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01006497
6498 if (type->columns > 1)
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006499 {
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01006500 matrix_stride = type_struct_member_matrix_stride(struct_type, index);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006501 row_major_matrix_needs_conversion =
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01006502 combined_decoration_for_member(struct_type, index).get(DecorationRowMajor);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01006503 }
6504 else
6505 row_major_matrix_needs_conversion = false;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006506 }
6507 // Matrix -> Vector
6508 else if (type->columns > 1)
6509 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02006510 auto *constant = maybe_get<SPIRConstant>(index);
6511 if (constant)
6512 {
6513 index = get<SPIRConstant>(index).scalar();
6514 offset += index * (row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride);
6515 }
6516 else
6517 {
6518 uint32_t indexing_stride = row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride;
6519 // Dynamic array access.
6520 if (indexing_stride % word_stride)
6521 {
6522 SPIRV_CROSS_THROW(
6523 "Matrix stride for dynamic indexing must be divisible by the size of a 4-component vector. "
6524 "Likely culprit here is a row-major matrix being accessed dynamically. "
6525 "This cannot be flattened. Try using std140 layout instead.");
6526 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006527
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01006528 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02006529 expr += " * ";
6530 expr += convert_to_string(indexing_stride / word_stride);
6531 expr += " + ";
6532 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006533
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01006534 uint32_t parent_type = type->parent_type;
6535 type = &get<SPIRType>(type->parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01006536 type_id = parent_type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006537 }
6538 // Vector -> Scalar
6539 else if (type->vecsize > 1)
6540 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02006541 auto *constant = maybe_get<SPIRConstant>(index);
6542 if (constant)
6543 {
6544 index = get<SPIRConstant>(index).scalar();
6545 offset += index * (row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8));
6546 }
6547 else
6548 {
6549 uint32_t indexing_stride = row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006550
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02006551 // Dynamic array access.
6552 if (indexing_stride % word_stride)
6553 {
6554 SPIRV_CROSS_THROW(
6555 "Stride for dynamic vector indexing must be divisible by the size of a 4-component vector. "
6556 "This cannot be flattened in legacy targets.");
6557 }
6558
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01006559 expr += to_enclosed_expression(index, false);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02006560 expr += " * ";
6561 expr += convert_to_string(indexing_stride / word_stride);
6562 expr += " + ";
6563 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006564
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01006565 uint32_t parent_type = type->parent_type;
6566 type = &get<SPIRType>(type->parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01006567 type_id = parent_type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006568 }
6569 else
6570 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
6571 }
6572
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08006573 if (need_transpose)
6574 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01006575 if (out_matrix_stride)
6576 *out_matrix_stride = matrix_stride;
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08006577
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08006578 return std::make_pair(expr, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08006579}
6580
Chip Davis3bfb2f92018-12-03 02:06:33 -06006581bool CompilerGLSL::should_dereference(uint32_t id)
6582{
6583 const auto &type = expression_type(id);
6584 // Non-pointer expressions don't need to be dereferenced.
6585 if (!type.pointer)
6586 return false;
6587
6588 // Handles shouldn't be dereferenced either.
6589 if (!expression_is_lvalue(id))
6590 return false;
6591
6592 // If id is a variable but not a phi variable, we should not dereference it.
6593 if (auto *var = maybe_get<SPIRVariable>(id))
6594 return var->phi_variable;
6595
6596 // If id is an access chain, we should not dereference it.
6597 if (auto *expr = maybe_get<SPIRExpression>(id))
6598 return !expr->access_chain;
6599
6600 // Otherwise, we should dereference this pointer expression.
6601 return true;
6602}
6603
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006604bool CompilerGLSL::should_forward(uint32_t id)
6605{
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07006606 // If id is a variable we will try to forward it regardless of force_temporary check below
6607 // 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 +02006608 auto *var = maybe_get<SPIRVariable>(id);
Arseny Kapoulkine7f055e82018-10-30 10:45:41 -07006609 if (var && var->forwardable)
6610 return true;
6611
6612 // For debugging emit temporary variables for all expressions
6613 if (options.force_temporary)
6614 return false;
6615
6616 // Immutable expression can always be forwarded.
6617 if (is_immutable(id))
6618 return true;
6619
6620 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006621}
6622
6623void CompilerGLSL::track_expression_read(uint32_t id)
6624{
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01006625 switch (ir.ids[id].get_type())
6626 {
6627 case TypeExpression:
6628 {
6629 auto &e = get<SPIRExpression>(id);
6630 for (auto implied_read : e.implied_read_expressions)
6631 track_expression_read(implied_read);
6632 break;
6633 }
6634
6635 case TypeAccessChain:
6636 {
6637 auto &e = get<SPIRAccessChain>(id);
6638 for (auto implied_read : e.implied_read_expressions)
6639 track_expression_read(implied_read);
6640 break;
6641 }
6642
6643 default:
6644 break;
6645 }
6646
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006647 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
6648 // In this case, it's better to just bind the complex expression to the temporary and read that temporary twice.
6649 if (expression_is_forwarded(id))
6650 {
6651 auto &v = expression_usage_counts[id];
6652 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006653
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006654 if (v >= 2)
6655 {
6656 //if (v == 2)
6657 // 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 +01006658
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006659 forced_temporaries.insert(id);
6660 // Force a recompile after this pass to avoid forwarding this variable.
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02006661 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006662 }
6663 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006664}
6665
6666bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
6667{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006668 if (forced_temporaries.find(id) != end(forced_temporaries))
6669 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006671 for (uint32_t i = 0; i < num_args; i++)
6672 if (!should_forward(args[i]))
6673 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006675 // We need to forward globals as well.
6676 if (!pure)
6677 {
6678 for (auto global : global_variables)
6679 if (!should_forward(global))
6680 return false;
6681 for (auto aliased : aliased_variables)
6682 if (!should_forward(aliased))
6683 return false;
6684 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006686 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006687}
6688
6689void CompilerGLSL::register_impure_function_call()
6690{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006691 // Impure functions can modify globals and aliased variables, so invalidate them as well.
6692 for (auto global : global_variables)
6693 flush_dependees(get<SPIRVariable>(global));
6694 for (auto aliased : aliased_variables)
6695 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006696}
6697
6698void CompilerGLSL::register_call_out_argument(uint32_t id)
6699{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006700 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006701
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006702 auto *var = maybe_get<SPIRVariable>(id);
6703 if (var)
6704 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006705}
6706
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01006707string CompilerGLSL::variable_decl_function_local(SPIRVariable &var)
6708{
6709 // These variables are always function local,
6710 // so make sure we emit the variable without storage qualifiers.
6711 // Some backends will inject custom variables locally in a function
6712 // with a storage qualifier which is not function-local.
6713 auto old_storage = var.storage;
6714 var.storage = StorageClassFunction;
6715 auto expr = variable_decl(var);
6716 var.storage = old_storage;
6717 return expr;
6718}
6719
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006720void CompilerGLSL::flush_variable_declaration(uint32_t id)
6721{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006722 auto *var = maybe_get<SPIRVariable>(id);
6723 if (var && var->deferred_declaration)
6724 {
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01006725 statement(variable_decl_function_local(*var), ";");
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +01006726 if (var->allocate_temporary_copy)
6727 {
6728 auto &type = get<SPIRType>(var->basetype);
6729 auto &flags = ir.meta[id].decoration.decoration_flags;
6730 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, join("_", id, "_copy")),
6731 ";");
6732 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006733 var->deferred_declaration = false;
6734 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006735}
6736
6737bool CompilerGLSL::remove_duplicate_swizzle(string &op)
6738{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006739 auto pos = op.find_last_of('.');
6740 if (pos == string::npos || pos == 0)
6741 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006742
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006743 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006745 if (backend.swizzle_is_function)
6746 {
6747 if (final_swiz.size() < 2)
6748 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006749
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006750 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
6751 final_swiz.erase(final_swiz.size() - 2, string::npos);
6752 else
6753 return false;
6754 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006755
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006756 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
6757 // If so, and previous swizzle is of same length,
6758 // we can drop the final swizzle altogether.
6759 for (uint32_t i = 0; i < final_swiz.size(); i++)
6760 {
6761 static const char expected[] = { 'x', 'y', 'z', 'w' };
6762 if (i >= 4 || final_swiz[i] != expected[i])
6763 return false;
6764 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006765
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006766 auto prevpos = op.find_last_of('.', pos - 1);
6767 if (prevpos == string::npos)
6768 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006769
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006770 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006771
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006772 // Make sure there are only swizzles here ...
6773 for (auto i = prevpos; i < pos; i++)
6774 {
6775 if (op[i] < 'w' || op[i] > 'z')
6776 {
6777 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
6778 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
6779 break;
6780 return false;
6781 }
6782 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006783
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006784 // If original swizzle is large enough, just carve out the components we need.
6785 // E.g. foobar.wyx.xy will turn into foobar.wy.
6786 if (pos - prevpos >= final_swiz.size())
6787 {
6788 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006789
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006790 // Add back the function call ...
6791 if (backend.swizzle_is_function)
6792 op += "()";
6793 }
6794 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006795}
6796
6797// Optimizes away vector swizzles where we have something like
6798// vec3 foo;
6799// foo.xyz <-- swizzle expression does nothing.
6800// This is a very common pattern after OpCompositeCombine.
6801bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
6802{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006803 auto pos = op.find_last_of('.');
6804 if (pos == string::npos || pos == 0)
6805 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006806
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006807 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006808
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006809 if (backend.swizzle_is_function)
6810 {
6811 if (final_swiz.size() < 2)
6812 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006814 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
6815 final_swiz.erase(final_swiz.size() - 2, string::npos);
6816 else
6817 return false;
6818 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006819
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006820 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
6821 // If so, and previous swizzle is of same length,
6822 // we can drop the final swizzle altogether.
6823 for (uint32_t i = 0; i < final_swiz.size(); i++)
6824 {
6825 static const char expected[] = { 'x', 'y', 'z', 'w' };
6826 if (i >= 4 || final_swiz[i] != expected[i])
6827 return false;
6828 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006829
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006830 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006831
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006832 // Sanity checking ...
6833 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006835 if (type.vecsize == final_swiz.size())
6836 op.erase(pos, string::npos);
6837 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006838}
6839
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01006840string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006841{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006842 uint32_t base = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006843 string op;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006844 string subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006845
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01006846 // Can only merge swizzles for vectors.
6847 auto &type = get<SPIRType>(return_type);
6848 bool can_apply_swizzle_opt = type.basetype != SPIRType::Struct && type.array.empty() && type.columns == 1;
6849 bool swizzle_optimization = false;
6850
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006851 for (uint32_t i = 0; i < length; i++)
6852 {
6853 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006854
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006855 // If we're merging another scalar which belongs to the same base
6856 // 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 +01006857 if (can_apply_swizzle_opt && e && e->base_expression && e->base_expression == base)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006858 {
6859 // Only supposed to be used for vector swizzle -> scalar.
6860 assert(!e->expression.empty() && e->expression.front() == '.');
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006861 subop += e->expression.substr(1, string::npos);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006862 swizzle_optimization = true;
6863 }
6864 else
6865 {
6866 // We'll likely end up with duplicated swizzles, e.g.
6867 // foobar.xyz.xyz from patterns like
Bill Hollingsd8d2da92018-01-05 17:46:56 -05006868 // OpVectorShuffle
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006869 // OpCompositeExtract x 3
6870 // OpCompositeConstruct 3x + other scalar.
6871 // Just modify op in-place.
6872 if (swizzle_optimization)
6873 {
6874 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006875 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006876
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006877 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
6878 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
6879 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
6880 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
6881 // Case 1:
6882 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
6883 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
6884 // Case 2:
6885 // foo.xyz: Duplicate swizzle won't kick in.
6886 // If foo is vec3, we can remove xyz, giving just foo.
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006887 if (!remove_duplicate_swizzle(subop))
6888 remove_unity_swizzle(base, subop);
6889
6890 // Strips away redundant parens if we created them during component extraction.
6891 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006892 swizzle_optimization = false;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006893 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006894 }
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006895 else
6896 op += subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006897
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006898 if (i)
6899 op += ", ";
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006900 subop = to_expression(elems[i]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006901 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006902
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006903 base = e ? e->base_expression : 0;
6904 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006905
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006906 if (swizzle_optimization)
6907 {
6908 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006909 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006910
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006911 if (!remove_duplicate_swizzle(subop))
6912 remove_unity_swizzle(base, subop);
6913 // Strips away redundant parens if we created them during component extraction.
6914 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006915 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006916
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01006917 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006918 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006919}
6920
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02006921bool CompilerGLSL::skip_argument(uint32_t id) const
6922{
6923 if (!combined_image_samplers.empty() || !options.vulkan_semantics)
6924 {
6925 auto &type = expression_type(id);
6926 if (type.basetype == SPIRType::Sampler || (type.basetype == SPIRType::Image && type.image.sampled == 1))
6927 return true;
6928 }
6929 return false;
6930}
6931
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02006932bool CompilerGLSL::optimize_read_modify_write(const SPIRType &type, const string &lhs, const string &rhs)
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01006933{
6934 // Do this with strings because we have a very clear pattern we can check for and it avoids
6935 // adding lots of special cases to the code emission.
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01006936 if (rhs.size() < lhs.size() + 3)
6937 return false;
6938
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +02006939 // Do not optimize matrices. They are a bit awkward to reason about in general
6940 // (in which order does operation happen?), and it does not work on MSL anyways.
6941 if (type.vecsize > 1 && type.columns > 1)
6942 return false;
6943
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01006944 auto index = rhs.find(lhs);
6945 if (index != 0)
6946 return false;
6947
6948 // TODO: Shift operators, but it's not important for now.
6949 auto op = rhs.find_first_of("+-/*%|&^", lhs.size() + 1);
6950 if (op != lhs.size() + 1)
6951 return false;
6952
David Srbeckye596d402017-09-05 16:05:53 +01006953 // Check that the op is followed by space. This excludes && and ||.
Hans-Kristian Arntzen03db5c42017-09-06 09:15:27 +02006954 if (rhs[op + 1] != ' ')
David Srbeckye596d402017-09-05 16:05:53 +01006955 return false;
6956
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01006957 char bop = rhs[op];
6958 auto expr = rhs.substr(lhs.size() + 3);
6959 // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code.
6960 // Find some common patterns which are equivalent.
6961 if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)"))
6962 statement(lhs, bop, bop, ";");
6963 else
6964 statement(lhs, " ", bop, "= ", expr, ";");
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01006965 return true;
6966}
6967
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01006968void CompilerGLSL::register_control_dependent_expression(uint32_t expr)
6969{
6970 if (forwarded_temporaries.find(expr) == end(forwarded_temporaries))
6971 return;
6972
6973 assert(current_emitting_block);
6974 current_emitting_block->invalidate_expressions.push_back(expr);
6975}
6976
6977void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02006978{
6979 current_emitting_block = &block;
6980 for (auto &op : block.ops)
6981 emit_instruction(op);
6982 current_emitting_block = nullptr;
6983}
6984
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01006985void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression &expr)
6986{
6987 if (forwarded_temporaries.count(expr.self))
6988 {
6989 forced_temporaries.insert(expr.self);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02006990 force_recompile();
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01006991 }
6992
6993 for (auto &dependent : expr.expression_dependencies)
6994 disallow_forwarding_in_expression_chain(get<SPIRExpression>(dependent));
6995}
6996
6997void CompilerGLSL::handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id)
6998{
6999 // Variables or access chains marked invariant are complicated. We will need to make sure the code-gen leading up to
7000 // this variable is consistent. The failure case for SPIRV-Cross is when an expression is forced to a temporary
7001 // in one translation unit, but not another, e.g. due to multiple use of an expression.
7002 // This causes variance despite the output variable being marked invariant, so the solution here is to force all dependent
7003 // expressions to be temporaries.
7004 // It is uncertain if this is enough to support invariant in all possible cases, but it should be good enough
7005 // for all reasonable uses of invariant.
7006 if (!has_decoration(store_id, DecorationInvariant))
7007 return;
7008
7009 auto *expr = maybe_get<SPIRExpression>(value_id);
7010 if (!expr)
7011 return;
7012
7013 disallow_forwarding_in_expression_chain(*expr);
7014}
7015
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01007016void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01007017{
7018 auto rhs = to_pointer_expression(rhs_expression);
7019
7020 // Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
7021 if (!rhs.empty())
7022 {
7023 handle_store_to_invariant_variable(lhs_expression, rhs_expression);
7024
7025 auto lhs = to_dereferenced_expression(lhs_expression);
7026
7027 // We might need to bitcast in order to store to a builtin.
7028 bitcast_to_builtin_store(lhs_expression, rhs, expression_type(rhs_expression));
7029
7030 // Tries to optimize assignments like "<lhs> = <lhs> op expr".
7031 // While this is purely cosmetic, this is important for legacy ESSL where loop
7032 // variable increments must be in either i++ or i += const-expr.
7033 // Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
7034 if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
7035 statement(lhs, " = ", rhs, ";");
7036 register_write(lhs_expression);
7037 }
7038}
7039
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007040uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &instr) const
7041{
7042 if (instr.length < 3)
7043 return 32;
7044
7045 auto *ops = stream(instr);
7046
7047 switch (instr.op)
7048 {
7049 case OpIEqual:
7050 case OpINotEqual:
7051 case OpSLessThan:
7052 case OpSLessThanEqual:
7053 case OpSGreaterThan:
7054 case OpSGreaterThanEqual:
7055 return expression_type(ops[2]).width;
7056
7057 default:
7058 {
7059 // We can look at result type which is more robust.
7060 auto *type = maybe_get<SPIRType>(ops[0]);
7061 if (type && type_is_integral(*type))
7062 return type->width;
7063 else
7064 return 32;
7065 }
7066 }
7067}
7068
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01007069uint32_t CompilerGLSL::get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *ops, uint32_t length) const
7070{
7071 if (length < 1)
7072 return 32;
7073
7074 switch (op)
7075 {
7076 case GLSLstd450SAbs:
7077 case GLSLstd450SSign:
7078 case GLSLstd450UMin:
7079 case GLSLstd450SMin:
7080 case GLSLstd450UMax:
7081 case GLSLstd450SMax:
7082 case GLSLstd450UClamp:
7083 case GLSLstd450SClamp:
7084 case GLSLstd450FindSMsb:
7085 case GLSLstd450FindUMsb:
7086 return expression_type(ops[0]).width;
7087
7088 default:
7089 {
7090 // We don't need to care about other opcodes, just return 32.
7091 return 32;
7092 }
7093 }
7094}
7095
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02007096void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007097{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007098 auto ops = stream(instruction);
7099 auto opcode = static_cast<Op>(instruction.op);
7100 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007101
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007102#define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
7103#define GLSL_BOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007104 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 +02007105#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
7106#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
7107#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
7108#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
7109#define GLSL_BFOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007110 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 +02007111#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
7112#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007113
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007114 // If we need to do implicit bitcasts, make sure we do it with the correct type.
7115 uint32_t integer_width = get_integer_width_for_instruction(instruction);
7116 auto int_type = to_signed_basetype(integer_width);
7117 auto uint_type = to_unsigned_basetype(integer_width);
7118
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007119 switch (opcode)
7120 {
7121 // Dealing with memory
7122 case OpLoad:
7123 {
7124 uint32_t result_type = ops[0];
7125 uint32_t id = ops[1];
7126 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007128 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007129
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007130 // If we're loading from memory that cannot be changed by the shader,
7131 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02007132 // If an expression is mutable and forwardable, we speculate that it is immutable.
7133 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
7134
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01007135 // If loading a non-native row-major matrix, mark the expression as need_transpose.
7136 bool need_transpose = false;
7137 bool old_need_transpose = false;
7138
7139 auto *ptr_expression = maybe_get<SPIRExpression>(ptr);
7140 if (ptr_expression && ptr_expression->need_transpose)
7141 {
7142 old_need_transpose = true;
7143 ptr_expression->need_transpose = false;
7144 need_transpose = true;
7145 }
7146 else if (is_non_native_row_major_matrix(ptr))
7147 need_transpose = true;
7148
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007149 // If we are forwarding this load,
7150 // don't register the read to access chain here, defer that to when we actually use the expression,
7151 // using the add_implied_read_expression mechanism.
Chip Davis3bfb2f92018-12-03 02:06:33 -06007152 auto expr = to_dereferenced_expression(ptr, !forward);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01007153
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +02007154 // We might need to bitcast in order to load from a builtin.
7155 bitcast_from_builtin_load(ptr, expr, get<SPIRType>(result_type));
7156
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +01007157 // We might be trying to load a gl_Position[N], where we should be
7158 // doing float4[](gl_in[i].gl_Position, ...) instead.
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +01007159 // Similar workarounds are required for input arrays in tessellation.
7160 unroll_array_from_complex_load(id, ptr, expr);
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +01007161
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01007162 if (ptr_expression)
7163 ptr_expression->need_transpose = old_need_transpose;
Bill Hollings13583622016-12-14 02:12:52 -05007164
Hans-Kristian Arntzen18b82ca2018-07-09 14:02:50 +02007165 // 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 +02007166 // However, if we try to load a complex, composite object from a flattened buffer,
7167 // we should avoid emitting the same code over and over and lower the result to a temporary.
7168 auto &type = get<SPIRType>(result_type);
7169 bool usage_tracking = ptr_expression && flattened_buffer_blocks.count(ptr_expression->loaded_from) != 0 &&
7170 (type.basetype == SPIRType::Struct || (type.columns > 1));
7171
7172 auto &e = emit_op(result_type, id, expr, forward, !usage_tracking);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01007173 e.need_transpose = need_transpose;
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02007174 register_read(id, ptr, forward);
Bill Hollingsd8d2da92018-01-05 17:46:56 -05007175
7176 // Pass through whether the result is of a packed type.
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01007177 if (has_extended_decoration(ptr, SPIRVCrossDecorationPacked))
7178 {
7179 set_extended_decoration(id, SPIRVCrossDecorationPacked);
7180 set_extended_decoration(id, SPIRVCrossDecorationPackedType,
7181 get_extended_decoration(ptr, SPIRVCrossDecorationPackedType));
7182 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05007183
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007184 inherit_expression_dependencies(id, ptr);
7185 if (forward)
7186 add_implied_read_expression(e, ptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007187 break;
7188 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007189
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007190 case OpInBoundsAccessChain:
7191 case OpAccessChain:
Chip Davis3bfb2f92018-12-03 02:06:33 -06007192 case OpPtrAccessChain:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007193 {
7194 auto *var = maybe_get<SPIRVariable>(ops[2]);
7195 if (var)
7196 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007197
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007198 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02007199 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007200 AccessChainMeta meta;
Chip Davis3bfb2f92018-12-03 02:06:33 -06007201 bool ptr_chain = opcode == OpPtrAccessChain;
7202 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 +02007203
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02007204 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +02007205
7206 auto *backing_variable = maybe_get_backing_variable(ops[2]);
7207 expr.loaded_from = backing_variable ? backing_variable->self : ops[2];
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007208 expr.need_transpose = meta.need_transpose;
Chip Davis3bfb2f92018-12-03 02:06:33 -06007209 expr.access_chain = true;
Bill Hollingsd8d2da92018-01-05 17:46:56 -05007210
7211 // Mark the result as being packed. Some platforms handled packed vectors differently than non-packed.
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007212 if (meta.storage_is_packed)
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01007213 set_extended_decoration(ops[1], SPIRVCrossDecorationPacked);
7214 if (meta.storage_packed_type != 0)
7215 set_extended_decoration(ops[1], SPIRVCrossDecorationPackedType, meta.storage_packed_type);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007216 if (meta.storage_is_invariant)
7217 set_decoration(ops[1], DecorationInvariant);
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01007218
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01007219 for (uint32_t i = 2; i < length; i++)
7220 {
7221 inherit_expression_dependencies(ops[1], ops[i]);
7222 add_implied_read_expression(expr, ops[i]);
7223 }
7224
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007225 break;
7226 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007227
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007228 case OpStore:
7229 {
7230 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007232 if (var && var->statically_assigned)
7233 var->static_expression = ops[1];
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007234 else if (var && var->loop_variable && !var->loop_variable_enable)
7235 var->static_expression = ops[1];
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02007236 else if (var && var->remapped_variable)
7237 {
7238 // Skip the write.
7239 }
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01007240 else if (var && flattened_structs.count(ops[0]))
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01007241 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01007242 store_flattened_struct(*var, ops[1]);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01007243 register_write(ops[0]);
7244 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007245 else
7246 {
Hans-Kristian Arntzen73d9da72019-01-17 12:21:16 +01007247 emit_store_statement(ops[0], ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007248 }
Hans-Kristian Arntzen15b52be2019-01-17 10:06:23 +01007249
Chip Davis3bfb2f92018-12-03 02:06:33 -06007250 // Storing a pointer results in a variable pointer, so we must conservatively assume
7251 // we can write through it.
7252 if (expression_type(ops[1]).pointer)
7253 register_write(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007254 break;
7255 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007257 case OpArrayLength:
7258 {
7259 uint32_t result_type = ops[0];
7260 uint32_t id = ops[1];
Hans-Kristian Arntzen40e77232019-01-17 11:29:50 +01007261 auto e = access_chain_internal(ops[2], &ops[3], length - 3, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007262 set<SPIRExpression>(id, e + ".length()", result_type, true);
7263 break;
7264 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007266 // Function calls
7267 case OpFunctionCall:
7268 {
7269 uint32_t result_type = ops[0];
7270 uint32_t id = ops[1];
7271 uint32_t func = ops[2];
7272 const auto *arg = &ops[3];
7273 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007274
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007275 auto &callee = get<SPIRFunction>(func);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01007276 auto &return_type = get<SPIRType>(callee.return_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007277 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007278
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007279 bool callee_has_out_variables = false;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01007280 bool emit_return_value_as_argument = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007281
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007282 // Invalidate out variables passed to functions since they can be OpStore'd to.
7283 for (uint32_t i = 0; i < length; i++)
7284 {
7285 if (callee.arguments[i].write_count)
7286 {
7287 register_call_out_argument(arg[i]);
7288 callee_has_out_variables = true;
7289 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007290
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007291 flush_variable_declaration(arg[i]);
7292 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007293
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01007294 if (!return_type.array.empty() && !backend.can_return_array)
7295 {
7296 callee_has_out_variables = true;
7297 emit_return_value_as_argument = true;
7298 }
7299
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007300 if (!pure)
7301 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007303 string funexpr;
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007304 vector<string> arglist;
Bill Hollings1c180782017-11-05 21:34:42 -05007305 funexpr += to_name(func) + "(";
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01007306
7307 if (emit_return_value_as_argument)
7308 {
7309 statement(type_to_glsl(return_type), " ", to_name(id), type_to_array_glsl(return_type), ";");
7310 arglist.push_back(to_name(id));
7311 }
7312
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007313 for (uint32_t i = 0; i < length; i++)
7314 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007315 // Do not pass in separate images or samplers if we're remapping
7316 // to combined image samplers.
7317 if (skip_argument(arg[i]))
7318 continue;
7319
Bill Hollingsac00c602016-10-24 09:24:24 -04007320 arglist.push_back(to_func_call_arg(arg[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007321 }
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02007322
7323 for (auto &combined : callee.combined_parameters)
7324 {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02007325 uint32_t image_id = combined.global_image ? combined.image_id : arg[combined.image_id];
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02007326 uint32_t sampler_id = combined.global_sampler ? combined.sampler_id : arg[combined.sampler_id];
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02007327 arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02007328 }
Bill Hollingsa759e2c2016-10-19 14:09:51 -07007329
Bill Hollingsac00c602016-10-24 09:24:24 -04007330 append_global_func_args(callee, length, arglist);
Bill Hollingsa759e2c2016-10-19 14:09:51 -07007331
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007332 funexpr += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007333 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007334
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02007335 // Check for function call constraints.
7336 check_function_call_constraints(arg, length);
7337
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01007338 if (return_type.basetype != SPIRType::Void)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007339 {
7340 // If the function actually writes to an out variable,
7341 // take the conservative route and do not forward.
7342 // The problem is that we might not read the function
7343 // result (and emit the function) before an out variable
7344 // is read (common case when return value is ignored!
7345 // In order to avoid start tracking invalid variables,
7346 // just avoid the forwarding problem altogether.
7347 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
7348 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007349
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01007350 if (emit_return_value_as_argument)
7351 {
7352 statement(funexpr, ";");
7353 set<SPIRExpression>(id, to_name(id), result_type, true);
7354 }
7355 else
7356 emit_op(result_type, id, funexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007357
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007358 // Function calls are implicit loads from all variables in question.
7359 // Set dependencies for them.
7360 for (uint32_t i = 0; i < length; i++)
7361 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007362
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007363 // If we're going to forward the temporary result,
7364 // put dependencies on every variable that must not change.
7365 if (forward)
7366 register_global_read_dependencies(callee, id);
7367 }
7368 else
7369 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007370
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007371 break;
7372 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007373
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007374 // Composite munging
7375 case OpCompositeConstruct:
7376 {
7377 uint32_t result_type = ops[0];
7378 uint32_t id = ops[1];
Hans-Kristian Arntzen9a527132018-03-09 15:26:36 +01007379 const auto *const elems = &ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007380 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007381
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007382 bool forward = true;
7383 for (uint32_t i = 0; i < length; i++)
7384 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007385
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007386 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02007387 auto *in_type = length > 0 ? &expression_type(elems[0]) : nullptr;
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02007388
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007389 // Only splat if we have vector constructors.
7390 // Arrays and structs must be initialized properly in full.
7391 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007392
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02007393 bool splat = false;
7394 bool swizzle_splat = false;
7395
7396 if (in_type)
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01007397 {
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02007398 splat = in_type->vecsize == 1 && in_type->columns == 1 && !composite && backend.use_constructor_splatting;
7399 swizzle_splat = in_type->vecsize == 1 && in_type->columns == 1 && backend.can_swizzle_scalar;
7400
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02007401 if (ir.ids[elems[0]].get_type() == TypeConstant && !type_is_floating_point(*in_type))
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02007402 {
7403 // Cannot swizzle literal integers as a special case.
7404 swizzle_splat = false;
7405 }
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01007406 }
7407
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01007408 if (splat || swizzle_splat)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007409 {
7410 uint32_t input = elems[0];
7411 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01007412 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007413 if (input != elems[i])
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01007414 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007415 splat = false;
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01007416 swizzle_splat = false;
7417 }
7418 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007419 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007420
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01007421 if (out_type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline)
7422 forward = false;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01007423 if (!out_type.array.empty() && !backend.can_declare_arrays_inline)
7424 forward = false;
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02007425 if (type_is_empty(out_type) && !backend.supports_empty_struct)
7426 forward = false;
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01007427
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007428 string constructor_op;
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +02007429 if (!backend.array_is_value_type && out_type.array.size() > 1)
7430 {
7431 // We cannot construct array of arrays because we cannot treat the inputs
7432 // as value types. Need to declare the array-of-arrays, and copy in elements one by one.
7433 forced_temporaries.insert(id);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01007434 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen89e3b8f2018-09-12 10:53:50 +02007435 statement(flags_to_precision_qualifiers_glsl(out_type, flags), variable_decl(out_type, to_name(id)), ";");
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +02007436 set<SPIRExpression>(id, to_name(id), result_type, true);
7437 for (uint32_t i = 0; i < length; i++)
7438 emit_array_copy(join(to_expression(id), "[", i, "]"), elems[i]);
7439 }
7440 else if (backend.use_initializer_list && composite)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007441 {
7442 // Only use this path if we are building composites.
7443 // This path cannot be used for arithmetic.
Hans-Kristian Arntzenb1148892018-09-10 10:04:17 +02007444 if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01007445 constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007446 constructor_op += "{ ";
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02007447 if (type_is_empty(out_type) && !backend.supports_empty_struct)
7448 constructor_op += "0";
7449 else if (splat)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007450 constructor_op += to_expression(elems[0]);
7451 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01007452 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007453 constructor_op += " }";
7454 }
Hans-Kristian Arntzen1c7980a2017-12-12 12:52:45 +01007455 else if (swizzle_splat && !composite)
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01007456 {
7457 constructor_op = remap_swizzle(get<SPIRType>(result_type), 1, to_expression(elems[0]));
7458 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007459 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007460 {
7461 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +02007462 if (type_is_empty(out_type) && !backend.supports_empty_struct)
7463 constructor_op += "0";
7464 else if (splat)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007465 constructor_op += to_expression(elems[0]);
7466 else
Hans-Kristian Arntzend0ce9482018-01-22 09:52:57 +01007467 constructor_op += build_composite_combiner(result_type, elems, length);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007468 constructor_op += ")";
7469 }
7470
Hans-Kristian Arntzen2f65a152018-09-12 10:25:51 +02007471 if (!constructor_op.empty())
7472 {
7473 emit_op(result_type, id, constructor_op, forward);
7474 for (uint32_t i = 0; i < length; i++)
7475 inherit_expression_dependencies(id, elems[i]);
7476 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007477 break;
7478 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007479
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007480 case OpVectorInsertDynamic:
7481 {
7482 uint32_t result_type = ops[0];
7483 uint32_t id = ops[1];
7484 uint32_t vec = ops[2];
7485 uint32_t comp = ops[3];
7486 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007487
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007488 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007489
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007490 // Make a copy, then use access chain to store the variable.
7491 statement(declare_temporary(result_type, id), to_expression(vec), ";");
7492 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007493 auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007494 statement(chain, " = ", to_expression(comp), ";");
7495 break;
7496 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007497
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007498 case OpVectorExtractDynamic:
7499 {
7500 uint32_t result_type = ops[0];
7501 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007502
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007503 auto expr = access_chain_internal(ops[2], &ops[3], 1, 0, nullptr);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01007504 emit_op(result_type, id, expr, should_forward(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01007505 inherit_expression_dependencies(id, ops[2]);
7506 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007507 break;
7508 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007509
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007510 case OpCompositeExtract:
7511 {
7512 uint32_t result_type = ops[0];
7513 uint32_t id = ops[1];
7514 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007516 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007517
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02007518 // We can only split the expression here if our expression is forwarded as a temporary.
7519 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
7520
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01007521 // Do not allow base expression for struct members. We risk doing "swizzle" optimizations in this case.
7522 auto &composite_type = expression_type(ops[2]);
Hans-Kristian Arntzen3fac2892017-11-22 12:07:37 +01007523 if (composite_type.basetype == SPIRType::Struct || !composite_type.array.empty())
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01007524 allow_base_expression = false;
7525
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01007526 // Packed expressions cannot be split up.
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01007527 if (has_extended_decoration(ops[2], SPIRVCrossDecorationPacked))
Hans-Kristian Arntzenb46910e2018-03-13 12:13:01 +01007528 allow_base_expression = false;
7529
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01007530 AccessChainMeta meta;
7531 SPIRExpression *e = nullptr;
7532
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007533 // Only apply this optimization if result is scalar.
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02007534 if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007535 {
7536 // We want to split the access chain from the base.
7537 // This is so we can later combine different CompositeExtract results
7538 // with CompositeConstruct without emitting code like
7539 //
7540 // vec3 temp = texture(...).xyz
7541 // vec4(temp.x, temp.y, temp.z, 1.0).
7542 //
7543 // when we actually wanted to emit this
7544 // vec4(texture(...).xyz, 1.0).
7545 //
7546 // Including the base will prevent this and would trigger multiple reads
7547 // from expression causing it to be forced to an actual temporary in GLSL.
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007548 auto expr = access_chain_internal(ops[2], &ops[3], length,
7549 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_CHAIN_ONLY_BIT, &meta);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01007550 e = &emit_op(result_type, id, expr, true, !expression_is_forwarded(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01007551 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01007552 e->base_expression = ops[2];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007553 }
7554 else
7555 {
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007556 auto expr = access_chain_internal(ops[2], &ops[3], length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &meta);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01007557 e = &emit_op(result_type, id, expr, should_forward(ops[2]), !expression_is_forwarded(ops[2]));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01007558 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007559 }
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01007560
7561 // Pass through some meta information to the loaded expression.
7562 // We can still end up loading a buffer type to a variable, then CompositeExtract from it
7563 // instead of loading everything through an access chain.
7564 e->need_transpose = meta.need_transpose;
7565 if (meta.storage_is_packed)
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01007566 set_extended_decoration(id, SPIRVCrossDecorationPacked);
7567 if (meta.storage_packed_type != 0)
7568 set_extended_decoration(id, SPIRVCrossDecorationPackedType, meta.storage_packed_type);
Hans-Kristian Arntzen66263d42019-01-07 10:43:55 +01007569 if (meta.storage_is_invariant)
7570 set_decoration(id, DecorationInvariant);
7571
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007572 break;
7573 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007574
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007575 case OpCompositeInsert:
7576 {
7577 uint32_t result_type = ops[0];
7578 uint32_t id = ops[1];
7579 uint32_t obj = ops[2];
7580 uint32_t composite = ops[3];
7581 const auto *elems = &ops[4];
7582 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007584 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007585
David Srbecky77b5b442017-06-26 18:32:53 +01007586 // Make a copy, then use access chain to store the variable.
7587 statement(declare_temporary(result_type, id), to_expression(composite), ";");
7588 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzenf4026a52019-01-17 10:30:13 +01007589 auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
David Srbecky77b5b442017-06-26 18:32:53 +01007590 statement(chain, " = ", to_expression(obj), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007592 break;
7593 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007594
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01007595 case OpCopyMemory:
7596 {
7597 uint32_t lhs = ops[0];
7598 uint32_t rhs = ops[1];
7599 if (lhs != rhs)
7600 {
7601 flush_variable_declaration(lhs);
7602 flush_variable_declaration(rhs);
7603 statement(to_expression(lhs), " = ", to_expression(rhs), ";");
7604 register_write(lhs);
7605 }
7606 break;
7607 }
7608
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007609 case OpCopyObject:
7610 {
7611 uint32_t result_type = ops[0];
7612 uint32_t id = ops[1];
7613 uint32_t rhs = ops[2];
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01007614 bool pointer = get<SPIRType>(result_type).pointer;
7615
7616 if (expression_is_lvalue(rhs) && !pointer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007617 {
7618 // Need a copy.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01007619 // For pointer types, we copy the pointer itself.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007620 statement(declare_temporary(result_type, id), to_expression(rhs), ";");
7621 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01007622 inherit_expression_dependencies(id, rhs);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007623 }
7624 else
7625 {
7626 // RHS expression is immutable, so just forward it.
7627 // Copying these things really make no sense, but
7628 // seems to be allowed anyways.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01007629 auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
7630 if (pointer)
7631 {
7632 auto *var = maybe_get_backing_variable(rhs);
7633 e.loaded_from = var ? var->self : 0;
7634 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007635 }
7636 break;
7637 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007638
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007639 case OpVectorShuffle:
7640 {
7641 uint32_t result_type = ops[0];
7642 uint32_t id = ops[1];
7643 uint32_t vec0 = ops[2];
7644 uint32_t vec1 = ops[3];
7645 const auto *elems = &ops[4];
7646 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007647
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007648 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007649
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01007650 // If we have the undefined swizzle index -1, we need to swizzle in undefined data,
7651 // or in our case, T(0).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007652 bool shuffle = false;
7653 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01007654 if (elems[i] >= type0.vecsize || elems[i] == 0xffffffffu)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007655 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007656
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02007657 // Cannot use swizzles with packed expressions, force shuffle path.
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01007658 if (!shuffle && has_extended_decoration(vec0, SPIRVCrossDecorationPacked))
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02007659 shuffle = true;
7660
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007661 string expr;
Bill Hollings1845f312017-12-31 18:55:04 -05007662 bool should_fwd, trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007663
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007664 if (shuffle)
7665 {
Hans-Kristian Arntzen09f550f2018-01-15 10:26:12 +01007666 should_fwd = should_forward(vec0) && should_forward(vec1);
7667 trivial_forward = !expression_is_forwarded(vec0) && !expression_is_forwarded(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007668
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007669 // Constructor style and shuffling from two different vectors.
7670 vector<string> args;
7671 for (uint32_t i = 0; i < length; i++)
7672 {
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01007673 if (elems[i] == 0xffffffffu)
7674 {
7675 // Use a constant 0 here.
7676 // We could use the first component or similar, but then we risk propagating
7677 // a value we might not need, and bog down codegen.
7678 SPIRConstant c;
7679 c.constant_type = type0.parent_type;
7680 assert(type0.parent_type != 0);
7681 args.push_back(constant_expression(c));
7682 }
7683 else if (elems[i] >= type0.vecsize)
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02007684 args.push_back(to_extract_component_expression(vec1, elems[i] - type0.vecsize));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007685 else
Hans-Kristian Arntzenf65120c2018-05-25 10:56:27 +02007686 args.push_back(to_extract_component_expression(vec0, elems[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007687 }
7688 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
7689 }
7690 else
7691 {
Bill Hollings1845f312017-12-31 18:55:04 -05007692 should_fwd = should_forward(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007693 trivial_forward = !expression_is_forwarded(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007694
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007695 // We only source from first vector, so can use swizzle.
Bill Hollingsd8d2da92018-01-05 17:46:56 -05007696 // If the vector is packed, unpack it before applying a swizzle (needed for MSL)
Hans-Kristian Arntzenb86bd0a2018-06-11 10:48:12 +02007697 expr += to_enclosed_unpacked_expression(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007698 expr += ".";
7699 for (uint32_t i = 0; i < length; i++)
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01007700 {
7701 assert(elems[i] != 0xffffffffu);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007702 expr += index_to_swizzle(elems[i]);
Hans-Kristian Arntzen8eb33c82019-03-25 10:17:05 +01007703 }
Bill Hollingsd8d2da92018-01-05 17:46:56 -05007704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007705 if (backend.swizzle_is_function && length > 1)
7706 expr += "()";
7707 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007709 // A shuffle is trivial in that it doesn't actually *do* anything.
7710 // 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 +01007711
Bill Hollings1845f312017-12-31 18:55:04 -05007712 emit_op(result_type, id, expr, should_fwd, trivial_forward);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01007713 inherit_expression_dependencies(id, vec0);
7714 inherit_expression_dependencies(id, vec1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007715 break;
7716 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007717
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007718 // ALU
7719 case OpIsNan:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007720 GLSL_UFOP(isnan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007721 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007723 case OpIsInf:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007724 GLSL_UFOP(isinf);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007725 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007726
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007727 case OpSNegate:
7728 case OpFNegate:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007729 GLSL_UOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007730 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007731
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007732 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007733 {
7734 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
7735 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007736 GLSL_BOP_CAST(+, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007737 break;
7738 }
7739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007740 case OpFAdd:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007741 GLSL_BOP(+);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007742 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007743
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007744 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007745 {
7746 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007747 GLSL_BOP_CAST(-, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007748 break;
7749 }
7750
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007751 case OpFSub:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007752 GLSL_BOP(-);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007753 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007754
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007755 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007756 {
7757 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007758 GLSL_BOP_CAST(*, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007759 break;
7760 }
7761
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01007762 case OpVectorTimesMatrix:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007763 case OpMatrixTimesVector:
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01007764 {
7765 // If the matrix needs transpose, just flip the multiply order.
7766 auto *e = maybe_get<SPIRExpression>(ops[opcode == OpMatrixTimesVector ? 2 : 3]);
7767 if (e && e->need_transpose)
7768 {
7769 e->need_transpose = false;
7770 emit_binary_op(ops[0], ops[1], ops[3], ops[2], "*");
7771 e->need_transpose = true;
7772 }
7773 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007774 GLSL_BOP(*);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007775 break;
7776 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007777
7778 case OpFMul:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007779 case OpMatrixTimesScalar:
7780 case OpVectorTimesScalar:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007781 case OpMatrixTimesMatrix:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007782 GLSL_BOP(*);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007783 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007784
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007785 case OpOuterProduct:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007786 GLSL_BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007787 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007788
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007789 case OpDot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007790 GLSL_BFOP(dot);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007791 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007792
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007793 case OpTranspose:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007794 GLSL_UFOP(transpose);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007795 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007796
Jin Zhoue792cd62018-05-22 00:44:34 -04007797 case OpSRem:
Jin Zhou6b144cc2018-05-24 01:17:47 -04007798 {
7799 uint32_t result_type = ops[0];
7800 uint32_t result_id = ops[1];
7801 uint32_t op0 = ops[2];
7802 uint32_t op1 = ops[3];
7803
7804 // Needs special handling.
7805 bool forward = should_forward(op0) && should_forward(op1);
7806 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
7807 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
7808
7809 emit_op(result_type, result_id, expr, forward);
7810 inherit_expression_dependencies(result_id, op0);
7811 inherit_expression_dependencies(result_id, op1);
Jin Zhoue792cd62018-05-22 00:44:34 -04007812 break;
Jin Zhou6b144cc2018-05-24 01:17:47 -04007813 }
Jin Zhoue792cd62018-05-22 00:44:34 -04007814
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007815 case OpSDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007816 GLSL_BOP_CAST(/, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007817 break;
7818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007819 case OpUDiv:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007820 GLSL_BOP_CAST(/, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007821 break;
7822
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01007823 case OpIAddCarry:
7824 case OpISubBorrow:
7825 {
7826 if (options.es && options.version < 310)
7827 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
7828 else if (!options.es && options.version < 400)
7829 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 400.");
7830
7831 uint32_t result_type = ops[0];
7832 uint32_t result_id = ops[1];
7833 uint32_t op0 = ops[2];
7834 uint32_t op1 = ops[3];
7835 forced_temporaries.insert(result_id);
7836 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01007837 auto &flags = ir.meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01007838 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), ";");
7839 set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
7840
7841 const char *op = opcode == OpIAddCarry ? "uaddCarry" : "usubBorrow";
7842
7843 statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", op, "(", to_expression(op0), ", ",
7844 to_expression(op1), ", ", to_expression(result_id), ".", to_member_name(type, 1), ");");
7845 break;
7846 }
7847
7848 case OpUMulExtended:
7849 case OpSMulExtended:
7850 {
7851 if (options.es && options.version < 310)
7852 SPIRV_CROSS_THROW("Extended arithmetic is only available from ESSL 310.");
7853 else if (!options.es && options.version < 400)
7854 SPIRV_CROSS_THROW("Extended arithmetic is only available from GLSL 4000.");
7855
7856 uint32_t result_type = ops[0];
7857 uint32_t result_id = ops[1];
7858 uint32_t op0 = ops[2];
7859 uint32_t op1 = ops[3];
7860 forced_temporaries.insert(result_id);
7861 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01007862 auto &flags = ir.meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen2a8a4fe2018-11-13 14:50:17 +01007863 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), ";");
7864 set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
7865
7866 const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended";
7867
7868 statement(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(result_id), ".",
7869 to_member_name(type, 1), ", ", to_expression(result_id), ".", to_member_name(type, 0), ");");
7870 break;
7871 }
7872
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007873 case OpFDiv:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007874 GLSL_BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007875 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007876
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007877 case OpShiftRightLogical:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007878 GLSL_BOP_CAST(>>, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007879 break;
7880
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007881 case OpShiftRightArithmetic:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007882 GLSL_BOP_CAST(>>, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007883 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007884
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007885 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02007886 {
7887 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007888 GLSL_BOP_CAST(<<, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007889 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02007890 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007891
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007892 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007893 {
7894 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007895 GLSL_BOP_CAST(|, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007896 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007897 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007898
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007899 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007900 {
7901 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01007902 GLSL_BOP_CAST(^, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007903 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007904 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007905
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007906 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007907 {
7908 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007909 GLSL_BOP_CAST(&, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007910 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007911 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007912
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007913 case OpNot:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007914 GLSL_UOP(~);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007915 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007916
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007917 case OpUMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007918 GLSL_BOP_CAST(%, uint_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02007919 break;
7920
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007921 case OpSMod:
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01007922 GLSL_BOP_CAST(%, int_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007923 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007924
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007925 case OpFMod:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007926 GLSL_BFOP(mod);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007927 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +02007928
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +01007929 case OpFRem:
7930 {
7931 if (is_legacy())
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +01007932 SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is "
7933 "needed for legacy.");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +01007934
7935 uint32_t result_type = ops[0];
7936 uint32_t result_id = ops[1];
7937 uint32_t op0 = ops[2];
7938 uint32_t op1 = ops[3];
7939
7940 // Needs special handling.
7941 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen54a065b2018-02-15 13:32:49 +01007942 auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
7943 to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +01007944
7945 emit_op(result_type, result_id, expr, forward);
7946 inherit_expression_dependencies(result_id, op0);
7947 inherit_expression_dependencies(result_id, op1);
7948 break;
7949 }
7950
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007951 // Relational
7952 case OpAny:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007953 GLSL_UFOP(any);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007954 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007955
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007956 case OpAll:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007957 GLSL_UFOP(all);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007958 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007959
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007960 case OpSelect:
7961 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
7962 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007963
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007964 case OpLogicalOr:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01007965 {
7966 // No vector variant in GLSL for logical OR.
7967 auto result_type = ops[0];
7968 auto id = ops[1];
7969 auto &type = get<SPIRType>(result_type);
7970
7971 if (type.vecsize > 1)
7972 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||");
7973 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007974 GLSL_BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007975 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01007976 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007977
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007978 case OpLogicalAnd:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01007979 {
7980 // No vector variant in GLSL for logical AND.
7981 auto result_type = ops[0];
7982 auto id = ops[1];
7983 auto &type = get<SPIRType>(result_type);
7984
7985 if (type.vecsize > 1)
7986 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&");
7987 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007988 GLSL_BOP(&&);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007989 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01007990 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007991
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007992 case OpLogicalNot:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01007993 {
7994 auto &type = get<SPIRType>(ops[0]);
7995 if (type.vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007996 GLSL_UFOP(not);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01007997 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02007998 GLSL_UOP(!);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007999 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01008000 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008001
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008002 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008003 {
8004 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008005 GLSL_BFOP_CAST(equal, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008006 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008007 GLSL_BOP_CAST(==, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008008 break;
8009 }
8010
8011 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008012 case OpFOrdEqual:
8013 {
8014 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008015 GLSL_BFOP(equal);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008016 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008017 GLSL_BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008018 break;
8019 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008020
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008021 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008022 {
8023 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008024 GLSL_BFOP_CAST(notEqual, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008025 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01008026 GLSL_BOP_CAST(!=, int_type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008027 break;
8028 }
8029
8030 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008031 case OpFOrdNotEqual:
8032 {
8033 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008034 GLSL_BFOP(notEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008035 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008036 GLSL_BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008037 break;
8038 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008039
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008040 case OpUGreaterThan:
8041 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008042 {
8043 auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
8044 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008045 GLSL_BFOP_CAST(greaterThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008046 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008047 GLSL_BOP_CAST(>, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008048 break;
8049 }
8050
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008051 case OpFOrdGreaterThan:
8052 {
8053 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008054 GLSL_BFOP(greaterThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008055 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008056 GLSL_BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008057 break;
8058 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008059
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008060 case OpUGreaterThanEqual:
8061 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008062 {
8063 auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
8064 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008065 GLSL_BFOP_CAST(greaterThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008066 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008067 GLSL_BOP_CAST(>=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008068 break;
8069 }
8070
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008071 case OpFOrdGreaterThanEqual:
8072 {
8073 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008074 GLSL_BFOP(greaterThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008075 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008076 GLSL_BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008077 break;
8078 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008079
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008080 case OpULessThan:
8081 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008082 {
8083 auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
8084 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008085 GLSL_BFOP_CAST(lessThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008086 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008087 GLSL_BOP_CAST(<, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008088 break;
8089 }
8090
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008091 case OpFOrdLessThan:
8092 {
8093 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008094 GLSL_BFOP(lessThan);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008095 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008096 GLSL_BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008097 break;
8098 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008099
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008100 case OpULessThanEqual:
8101 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008102 {
8103 auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
8104 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008105 GLSL_BFOP_CAST(lessThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008106 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008107 GLSL_BOP_CAST(<=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008108 break;
8109 }
8110
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008111 case OpFOrdLessThanEqual:
8112 {
8113 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008114 GLSL_BFOP(lessThanEqual);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008115 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008116 GLSL_BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008117 break;
8118 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008119
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008120 // Conversion
8121 case OpConvertFToU:
8122 case OpConvertFToS:
8123 case OpConvertSToF:
8124 case OpConvertUToF:
8125 case OpUConvert:
8126 case OpSConvert:
8127 case OpFConvert:
8128 {
8129 uint32_t result_type = ops[0];
8130 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008131
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008132 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
8133 emit_unary_func_op(result_type, id, ops[2], func.c_str());
8134 break;
8135 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008136
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008137 case OpBitcast:
8138 {
8139 uint32_t result_type = ops[0];
8140 uint32_t id = ops[1];
8141 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008142
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02008143 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008144 emit_unary_func_op(result_type, id, arg, op.c_str());
8145 break;
8146 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008147
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02008148 case OpQuantizeToF16:
8149 {
8150 uint32_t result_type = ops[0];
8151 uint32_t id = ops[1];
8152 uint32_t arg = ops[2];
8153
8154 string op;
8155 auto &type = get<SPIRType>(result_type);
8156
8157 switch (type.vecsize)
8158 {
8159 case 1:
8160 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
8161 break;
8162 case 2:
8163 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
8164 break;
8165 case 3:
8166 {
8167 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
8168 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
8169 op = join("vec3(", op0, ", ", op1, ")");
8170 break;
8171 }
8172 case 4:
8173 {
8174 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
8175 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
8176 op = join("vec4(", op0, ", ", op1, ")");
8177 break;
8178 }
8179 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008180 SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02008181 }
8182
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01008183 emit_op(result_type, id, op, should_forward(arg));
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01008184 inherit_expression_dependencies(id, arg);
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02008185 break;
8186 }
8187
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008188 // Derivatives
8189 case OpDPdx:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008190 GLSL_UFOP(dFdx);
Lubos Lenco80c39412016-09-17 14:33:16 +02008191 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008192 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008193 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008194 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008195
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008196 case OpDPdy:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008197 GLSL_UFOP(dFdy);
Lubos Lenco80c39412016-09-17 14:33:16 +02008198 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008199 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008200 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008201 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008202
Robert Konrad9ec9dd02017-03-24 13:59:19 +01008203 case OpDPdxFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008204 GLSL_UFOP(dFdxFine);
Robert Konradcb637db2017-03-24 15:58:54 +01008205 if (options.es)
8206 {
8207 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
8208 }
8209 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008210 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008211 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01008212 break;
8213
8214 case OpDPdyFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008215 GLSL_UFOP(dFdyFine);
Robert Konradcb637db2017-03-24 15:58:54 +01008216 if (options.es)
8217 {
8218 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
8219 }
8220 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008221 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008222 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01008223 break;
8224
8225 case OpDPdxCoarse:
Robert Konradcb637db2017-03-24 15:58:54 +01008226 if (options.es)
8227 {
8228 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
8229 }
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008230 GLSL_UFOP(dFdxCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +01008231 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008232 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008233 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01008234 break;
8235
8236 case OpDPdyCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008237 GLSL_UFOP(dFdyCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +01008238 if (options.es)
8239 {
8240 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
8241 }
8242 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008243 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008244 register_control_dependent_expression(ops[1]);
Robert Konrad9ec9dd02017-03-24 13:59:19 +01008245 break;
8246
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008247 case OpFwidth:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008248 GLSL_UFOP(fwidth);
Lubos Lenco80c39412016-09-17 14:33:16 +02008249 if (is_legacy_es())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008250 require_extension_internal("GL_OES_standard_derivatives");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008251 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008252 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008253
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008254 case OpFwidthCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008255 GLSL_UFOP(fwidthCoarse);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008256 if (options.es)
8257 {
8258 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
8259 }
8260 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008261 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008262 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008263 break;
8264
8265 case OpFwidthFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008266 GLSL_UFOP(fwidthFine);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008267 if (options.es)
8268 {
8269 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
8270 }
8271 if (options.version < 450)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008272 require_extension_internal("GL_ARB_derivative_control");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008273 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen05348a62018-03-06 16:28:42 +01008274 break;
8275
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008276 // Bitfield
8277 case OpBitFieldInsert:
Hans-Kristian Arntzen6801af42017-03-25 15:38:20 +01008278 // TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008279 GLSL_QFOP(bitfieldInsert);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008280 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008281
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008282 case OpBitFieldSExtract:
8283 case OpBitFieldUExtract:
Hans-Kristian Arntzen6801af42017-03-25 15:38:20 +01008284 // TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008285 GLSL_TFOP(bitfieldExtract);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008286 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008287
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008288 case OpBitReverse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008289 GLSL_UFOP(bitfieldReverse);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008290 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008291
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008292 case OpBitCount:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008293 GLSL_UFOP(bitCount);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008294 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008295
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008296 // Atomics
8297 case OpAtomicExchange:
8298 {
8299 uint32_t result_type = ops[0];
8300 uint32_t id = ops[1];
8301 uint32_t ptr = ops[2];
8302 // Ignore semantics for now, probably only relevant to CL.
8303 uint32_t val = ops[5];
8304 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
8305 forced_temporaries.insert(id);
8306 emit_binary_func_op(result_type, id, ptr, val, op);
8307 flush_all_atomic_capable_variables();
8308 break;
8309 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008311 case OpAtomicCompareExchange:
8312 {
8313 uint32_t result_type = ops[0];
8314 uint32_t id = ops[1];
8315 uint32_t ptr = ops[2];
8316 uint32_t val = ops[6];
8317 uint32_t comp = ops[7];
8318 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008320 forced_temporaries.insert(id);
8321 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
8322 flush_all_atomic_capable_variables();
8323 break;
8324 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008325
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008326 case OpAtomicLoad:
8327 flush_all_atomic_capable_variables();
8328 // FIXME: Image?
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01008329 // OpAtomicLoad seems to only be relevant for atomic counters.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008330 GLSL_UFOP(atomicCounter);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008331 register_read(ops[1], ops[2], should_forward(ops[2]));
8332 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008333
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01008334 case OpAtomicStore:
8335 SPIRV_CROSS_THROW("Unsupported opcode OpAtomicStore.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008337 case OpAtomicIIncrement:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008338 case OpAtomicIDecrement:
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +02008339 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008340 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +02008341 auto &type = expression_type(ops[2]);
8342 if (type.storage == StorageClassAtomicCounter)
8343 {
8344 // Legacy GLSL stuff, not sure if this is relevant to support.
8345 if (opcode == OpAtomicIIncrement)
8346 GLSL_UFOP(atomicCounterIncrement);
8347 else
8348 GLSL_UFOP(atomicCounterDecrement);
8349 }
8350 else
8351 {
8352 bool atomic_image = check_atomic_image(ops[2]);
8353 bool unsigned_type = (type.basetype == SPIRType::UInt) ||
8354 (atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
8355 const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
8356
8357 const char *increment = nullptr;
8358 if (opcode == OpAtomicIIncrement && unsigned_type)
8359 increment = "1u";
8360 else if (opcode == OpAtomicIIncrement)
8361 increment = "1";
8362 else if (unsigned_type)
8363 increment = "uint(-1)";
8364 else
8365 increment = "-1";
8366
8367 emit_op(ops[0], ops[1], join(op, "(", to_expression(ops[2]), ", ", increment, ")"), false);
8368 }
8369
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008370 flush_all_atomic_capable_variables();
8371 register_read(ops[1], ops[2], should_forward(ops[2]));
8372 break;
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +02008373 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008374
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008375 case OpAtomicIAdd:
8376 {
8377 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
8378 forced_temporaries.insert(ops[1]);
8379 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
8380 flush_all_atomic_capable_variables();
8381 register_read(ops[1], ops[2], should_forward(ops[2]));
8382 break;
8383 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008385 case OpAtomicISub:
8386 {
8387 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
8388 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01008389 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_enclosed_expression(ops[5]), ")");
8390 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008391 flush_all_atomic_capable_variables();
8392 register_read(ops[1], ops[2], should_forward(ops[2]));
8393 break;
8394 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008395
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008396 case OpAtomicSMin:
8397 case OpAtomicUMin:
8398 {
8399 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
8400 forced_temporaries.insert(ops[1]);
8401 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
8402 flush_all_atomic_capable_variables();
8403 register_read(ops[1], ops[2], should_forward(ops[2]));
8404 break;
8405 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008406
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008407 case OpAtomicSMax:
8408 case OpAtomicUMax:
8409 {
8410 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
8411 forced_temporaries.insert(ops[1]);
8412 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
8413 flush_all_atomic_capable_variables();
8414 register_read(ops[1], ops[2], should_forward(ops[2]));
8415 break;
8416 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008417
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008418 case OpAtomicAnd:
8419 {
8420 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
8421 forced_temporaries.insert(ops[1]);
8422 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
8423 flush_all_atomic_capable_variables();
8424 register_read(ops[1], ops[2], should_forward(ops[2]));
8425 break;
8426 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008428 case OpAtomicOr:
8429 {
8430 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
8431 forced_temporaries.insert(ops[1]);
8432 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
8433 flush_all_atomic_capable_variables();
8434 register_read(ops[1], ops[2], should_forward(ops[2]));
8435 break;
8436 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008437
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008438 case OpAtomicXor:
8439 {
8440 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
8441 forced_temporaries.insert(ops[1]);
8442 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
8443 flush_all_atomic_capable_variables();
8444 register_read(ops[1], ops[2], should_forward(ops[2]));
8445 break;
8446 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008447
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008448 // Geometry shaders
8449 case OpEmitVertex:
8450 statement("EmitVertex();");
8451 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008453 case OpEndPrimitive:
8454 statement("EndPrimitive();");
8455 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008457 case OpEmitStreamVertex:
8458 statement("EmitStreamVertex();");
8459 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008460
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008461 case OpEndStreamPrimitive:
8462 statement("EndStreamPrimitive();");
8463 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008464
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008465 // Textures
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008466 case OpImageSampleExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008467 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008468 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008469 case OpImageSampleProjDrefExplicitLod:
Lubos Lenco80c39412016-09-17 14:33:16 +02008470 case OpImageSampleImplicitLod:
8471 case OpImageSampleProjImplicitLod:
8472 case OpImageSampleDrefImplicitLod:
8473 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008474 case OpImageFetch:
8475 case OpImageGather:
8476 case OpImageDrefGather:
8477 // Gets a bit hairy, so move this to a separate instruction.
8478 emit_texture_op(instruction);
8479 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008480
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008481 case OpImage:
8482 {
8483 uint32_t result_type = ops[0];
8484 uint32_t id = ops[1];
Hans-Kristian Arntzenaaf397c2018-04-27 11:10:10 +02008485
8486 // Suppress usage tracking.
8487 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02008488
8489 // When using the image, we need to know which variable it is actually loaded from.
8490 auto *var = maybe_get_backing_variable(ops[2]);
8491 e.loaded_from = var ? var->self : 0;
8492 break;
8493 }
8494
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02008495 case OpImageQueryLod:
8496 {
8497 if (!options.es && options.version < 400)
8498 {
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008499 require_extension_internal("GL_ARB_texture_query_lod");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02008500 // For some reason, the ARB spec is all-caps.
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008501 GLSL_BFOP(textureQueryLOD);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02008502 }
8503 else if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008504 SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02008505 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02008506 GLSL_BFOP(textureQueryLod);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008507 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02008508 break;
8509 }
8510
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02008511 case OpImageQueryLevels:
8512 {
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02008513 uint32_t result_type = ops[0];
8514 uint32_t id = ops[1];
8515
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02008516 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008517 require_extension_internal("GL_ARB_texture_query_levels");
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02008518 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008519 SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02008520
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02008521 auto expr = join("textureQueryLevels(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02008522 auto &restype = get<SPIRType>(ops[0]);
8523 expr = bitcast_expression(restype, SPIRType::Int, expr);
8524 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02008525 break;
8526 }
8527
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02008528 case OpImageQuerySamples:
8529 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008530 auto &type = expression_type(ops[2]);
8531 uint32_t result_type = ops[0];
8532 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02008533
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008534 string expr;
8535 if (type.image.sampled == 2)
8536 expr = join("imageSamples(", to_expression(ops[2]), ")");
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02008537 else
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02008538 expr = join("textureSamples(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008539
8540 auto &restype = get<SPIRType>(ops[0]);
8541 expr = bitcast_expression(restype, SPIRType::Int, expr);
8542 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008543 break;
8544 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008545
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008546 case OpSampledImage:
8547 {
8548 uint32_t result_type = ops[0];
8549 uint32_t id = ops[1];
8550 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
8551 break;
8552 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +02008553
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008554 case OpImageQuerySizeLod:
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008555 {
8556 uint32_t result_type = ops[0];
8557 uint32_t id = ops[1];
8558
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02008559 auto expr = join("textureSize(", convert_separate_image_to_expression(ops[2]), ", ",
Hans-Kristian Arntzen7e23e692018-04-30 12:46:21 +02008560 bitcast_expression(SPIRType::Int, ops[3]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008561 auto &restype = get<SPIRType>(ops[0]);
8562 expr = bitcast_expression(restype, SPIRType::Int, expr);
8563 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008564 break;
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008565 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008566
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008567 // Image load/store
8568 case OpImageRead:
8569 {
8570 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
8571 // not adding the proper qualifiers.
8572 // If it turns out we need to read the image after all, remove the qualifier and recompile.
8573 auto *var = maybe_get_backing_variable(ops[2]);
8574 if (var)
8575 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01008576 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01008577 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008578 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01008579 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02008580 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008581 }
8582 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008584 uint32_t result_type = ops[0];
8585 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008586
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008587 bool pure;
8588 string imgexpr;
8589 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008590
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02008591 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008592 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02008593 if (type.image.ms)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008594 SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02008595
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02008596 auto itr =
8597 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 +01008598
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008599 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02008600 {
8601 // For non-PLS inputs, we rely on subpass type remapping information to get it right
8602 // since ImageRead always returns 4-component vectors and the backing type is opaque.
8603 if (!var->remapped_components)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008604 SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02008605 imgexpr = remap_swizzle(get<SPIRType>(result_type), var->remapped_components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02008606 }
8607 else
8608 {
8609 // PLS input could have different number of components than what the SPIR expects, swizzle to
8610 // the appropriate vector size.
8611 uint32_t components = pls_format_to_components(itr->format);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02008612 imgexpr = remap_swizzle(get<SPIRType>(result_type), components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02008613 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008614 pure = true;
8615 }
8616 else if (type.image.dim == DimSubpassData)
8617 {
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008618 if (options.vulkan_semantics)
8619 {
8620 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02008621 if (type.image.ms)
8622 {
8623 uint32_t operands = ops[4];
8624 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008625 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02008626 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
8627
8628 uint32_t samples = ops[5];
8629 imgexpr = join("subpassLoad(", to_expression(ops[2]), ", ", to_expression(samples), ")");
8630 }
8631 else
8632 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008633 }
8634 else
8635 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02008636 if (type.image.ms)
8637 {
8638 uint32_t operands = ops[4];
8639 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008640 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02008641 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
8642
8643 uint32_t samples = ops[5];
8644 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
8645 to_expression(samples), ")");
8646 }
8647 else
8648 {
8649 // Implement subpass loads via texture barrier style sampling.
8650 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
8651 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02008652 }
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02008653 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008654 pure = true;
8655 }
8656 else
8657 {
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01008658 // imageLoad only accepts int coords, not uint.
8659 auto coord_expr = to_expression(ops[3]);
8660 auto target_coord_type = expression_type(ops[3]);
8661 target_coord_type.basetype = SPIRType::Int;
8662 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
8663
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008664 // Plain image load/store.
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02008665 if (type.image.ms)
8666 {
8667 uint32_t operands = ops[4];
8668 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008669 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02008670
8671 uint32_t samples = ops[5];
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01008672 imgexpr =
8673 join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ", ", to_expression(samples), ")");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02008674 }
8675 else
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01008676 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ")");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02008677
8678 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008679 pure = false;
8680 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008681
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008682 if (var && var->forwardable)
8683 {
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +01008684 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
8685 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008687 // We only need to track dependencies if we're reading from image load/store.
8688 if (!pure)
8689 {
8690 e.loaded_from = var->self;
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +01008691 if (forward)
8692 var->dependees.push_back(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008693 }
8694 }
8695 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01008696 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01008697
8698 inherit_expression_dependencies(id, ops[2]);
8699 if (type.image.ms)
8700 inherit_expression_dependencies(id, ops[5]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008701 break;
8702 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008703
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008704 case OpImageTexelPointer:
8705 {
8706 uint32_t result_type = ops[0];
8707 uint32_t id = ops[1];
8708 auto &e = set<SPIRExpression>(id, join(to_expression(ops[2]), ", ", to_expression(ops[3])), result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008709
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02008710 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008711 auto *var = maybe_get_backing_variable(ops[2]);
8712 e.loaded_from = var ? var->self : 0;
8713 break;
8714 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008715
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008716 case OpImageWrite:
8717 {
8718 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
8719 // not adding the proper qualifiers.
8720 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
8721 auto *var = maybe_get_backing_variable(ops[0]);
8722 if (var)
8723 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01008724 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01008725 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008726 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01008727 flags.clear(DecorationNonWritable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02008728 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008729 }
8730 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008731
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02008732 auto &type = expression_type(ops[0]);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02008733 auto &value_type = expression_type(ops[2]);
8734 auto store_type = value_type;
8735 store_type.vecsize = 4;
8736
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01008737 // imageStore only accepts int coords, not uint.
8738 auto coord_expr = to_expression(ops[1]);
8739 auto target_coord_type = expression_type(ops[1]);
8740 target_coord_type.basetype = SPIRType::Int;
8741 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
8742
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02008743 if (type.image.ms)
8744 {
8745 uint32_t operands = ops[3];
8746 if (operands != ImageOperandsSampleMask || length != 5)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008747 SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02008748 uint32_t samples = ops[4];
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01008749 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ", to_expression(samples), ", ",
8750 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02008751 }
8752 else
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01008753 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ",
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02008754 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008755
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008756 if (var && variable_storage_is_aliased(*var))
8757 flush_all_aliased_variables();
8758 break;
8759 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008760
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008761 case OpImageQuerySize:
8762 {
8763 auto &type = expression_type(ops[2]);
8764 uint32_t result_type = ops[0];
8765 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008766
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008767 if (type.basetype == SPIRType::Image)
8768 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008769 string expr;
8770 if (type.image.sampled == 2)
8771 {
8772 // The size of an image is always constant.
8773 expr = join("imageSize(", to_expression(ops[2]), ")");
8774 }
8775 else
8776 {
8777 // This path is hit for samplerBuffers and multisampled images which do not have LOD.
Hans-Kristian Arntzenc07c3032018-09-27 13:36:38 +02008778 expr = join("textureSize(", convert_separate_image_to_expression(ops[2]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02008779 }
8780
8781 auto &restype = get<SPIRType>(ops[0]);
8782 expr = bitcast_expression(restype, SPIRType::Int, expr);
8783 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008784 }
8785 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008786 SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008787 break;
8788 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008789
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008790 // Compute
8791 case OpControlBarrier:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008792 case OpMemoryBarrier:
8793 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008794 uint32_t execution_scope = 0;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008795 uint32_t memory;
8796 uint32_t semantics;
8797
8798 if (opcode == OpMemoryBarrier)
8799 {
8800 memory = get<SPIRConstant>(ops[0]).scalar();
8801 semantics = get<SPIRConstant>(ops[1]).scalar();
8802 }
8803 else
8804 {
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008805 execution_scope = get<SPIRConstant>(ops[0]).scalar();
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008806 memory = get<SPIRConstant>(ops[1]).scalar();
8807 semantics = get<SPIRConstant>(ops[2]).scalar();
8808 }
8809
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008810 if (execution_scope == ScopeSubgroup || memory == ScopeSubgroup)
8811 {
8812 if (!options.vulkan_semantics)
8813 SPIRV_CROSS_THROW("Can only use subgroup operations in Vulkan semantics.");
8814 require_extension_internal("GL_KHR_shader_subgroup_basic");
8815 }
8816
8817 if (execution_scope != ScopeSubgroup && get_entry_point().model == ExecutionModelTessellationControl)
8818 {
8819 // Control shaders only have barriers, and it implies memory barriers.
8820 if (opcode == OpControlBarrier)
8821 statement("barrier();");
8822 break;
8823 }
8824
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008825 // We only care about these flags, acquire/release and friends are not relevant to GLSL.
8826 semantics = mask_relevant_memory_semantics(semantics);
8827
8828 if (opcode == OpMemoryBarrier)
8829 {
8830 // If we are a memory barrier, and the next instruction is a control barrier, check if that memory barrier
8831 // does what we need, so we avoid redundant barriers.
8832 const Instruction *next = get_next_instruction_in_block(instruction);
8833 if (next && next->op == OpControlBarrier)
8834 {
8835 auto *next_ops = stream(*next);
8836 uint32_t next_memory = get<SPIRConstant>(next_ops[1]).scalar();
8837 uint32_t next_semantics = get<SPIRConstant>(next_ops[2]).scalar();
8838 next_semantics = mask_relevant_memory_semantics(next_semantics);
8839
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +01008840 bool memory_scope_covered = false;
8841 if (next_memory == memory)
8842 memory_scope_covered = true;
8843 else if (next_semantics == MemorySemanticsWorkgroupMemoryMask)
8844 {
8845 // If we only care about workgroup memory, either Device or Workgroup scope is fine,
8846 // scope does not have to match.
8847 if ((next_memory == ScopeDevice || next_memory == ScopeWorkgroup) &&
8848 (memory == ScopeDevice || memory == ScopeWorkgroup))
8849 {
8850 memory_scope_covered = true;
8851 }
8852 }
8853 else if (memory == ScopeWorkgroup && next_memory == ScopeDevice)
8854 {
8855 // The control barrier has device scope, but the memory barrier just has workgroup scope.
8856 memory_scope_covered = true;
8857 }
8858
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008859 // If we have the same memory scope, and all memory types are covered, we're good.
Hans-Kristian Arntzen7bb88742018-01-09 12:17:38 +01008860 if (memory_scope_covered && (semantics & next_semantics) == semantics)
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008861 break;
8862 }
8863 }
8864
8865 // We are synchronizing some memory or syncing execution,
8866 // so we cannot forward any loads beyond the memory barrier.
8867 if (semantics || opcode == OpControlBarrier)
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008868 {
8869 assert(current_emitting_block);
8870 flush_control_dependent_expressions(current_emitting_block->self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008871 flush_all_active_variables();
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008872 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008873
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008874 if (memory == ScopeWorkgroup) // Only need to consider memory within a group
8875 {
8876 if (semantics == MemorySemanticsWorkgroupMemoryMask)
8877 statement("memoryBarrierShared();");
8878 else if (semantics != 0)
8879 statement("groupMemoryBarrier();");
8880 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008881 else if (memory == ScopeSubgroup)
8882 {
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02008883 const uint32_t all_barriers =
8884 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask;
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008885
8886 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
8887 {
8888 // These are not relevant for GLSL, but assume it means memoryBarrier().
8889 // memoryBarrier() does everything, so no need to test anything else.
8890 statement("subgroupMemoryBarrier();");
8891 }
8892 else if ((semantics & all_barriers) == all_barriers)
8893 {
8894 // Short-hand instead of emitting 3 barriers.
8895 statement("subgroupMemoryBarrier();");
8896 }
8897 else
8898 {
8899 // Pick out individual barriers.
8900 if (semantics & MemorySemanticsWorkgroupMemoryMask)
8901 statement("subgroupMemoryBarrierShared();");
8902 if (semantics & MemorySemanticsUniformMemoryMask)
8903 statement("subgroupMemoryBarrierBuffer();");
8904 if (semantics & MemorySemanticsImageMemoryMask)
8905 statement("subgroupMemoryBarrierImage();");
8906 }
8907 }
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008908 else
8909 {
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +01008910 const uint32_t all_barriers = MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask |
8911 MemorySemanticsImageMemoryMask | MemorySemanticsAtomicCounterMemoryMask;
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +01008912
8913 if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask))
8914 {
8915 // These are not relevant for GLSL, but assume it means memoryBarrier().
8916 // memoryBarrier() does everything, so no need to test anything else.
8917 statement("memoryBarrier();");
8918 }
8919 else if ((semantics & all_barriers) == all_barriers)
8920 {
8921 // Short-hand instead of emitting 4 barriers.
8922 statement("memoryBarrier();");
8923 }
8924 else
8925 {
8926 // Pick out individual barriers.
8927 if (semantics & MemorySemanticsWorkgroupMemoryMask)
8928 statement("memoryBarrierShared();");
8929 if (semantics & MemorySemanticsUniformMemoryMask)
8930 statement("memoryBarrierBuffer();");
8931 if (semantics & MemorySemanticsImageMemoryMask)
8932 statement("memoryBarrierImage();");
8933 if (semantics & MemorySemanticsAtomicCounterMemoryMask)
8934 statement("memoryBarrierAtomicCounter();");
8935 }
8936 }
8937
8938 if (opcode == OpControlBarrier)
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008939 {
8940 if (execution_scope == ScopeSubgroup)
8941 statement("subgroupBarrier();");
8942 else
8943 statement("barrier();");
8944 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008945 break;
8946 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008947
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008948 case OpExtInst:
8949 {
8950 uint32_t extension_set = ops[2];
Lou Kramer6671f522017-11-21 14:04:57 +01008951
8952 if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008953 {
Lou Kramer6671f522017-11-21 14:04:57 +01008954 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
8955 }
8956 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_ballot)
8957 {
8958 emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
8959 }
8960 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
8961 {
8962 emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
8963 }
8964 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_trinary_minmax)
8965 {
8966 emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
8967 }
8968 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_gcn_shader)
8969 {
8970 emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
8971 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01008972 else
8973 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008974 statement("// unimplemented ext op ", instruction.op);
8975 break;
8976 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008977
Lou Kramer6671f522017-11-21 14:04:57 +01008978 break;
8979 }
8980
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02008981 // Legacy sub-group stuff ...
Lou Kramer6671f522017-11-21 14:04:57 +01008982 case OpSubgroupBallotKHR:
8983 {
Lou Kramer6671f522017-11-21 14:04:57 +01008984 uint32_t result_type = ops[0];
8985 uint32_t id = ops[1];
8986 string expr;
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008987 expr = join("uvec4(unpackUint2x32(ballotARB(" + to_expression(ops[2]) + ")), 0u, 0u)");
Hans-Kristian Arntzen4979d102018-03-12 17:51:14 +01008988 emit_op(result_type, id, expr, should_forward(ops[2]));
Lou Kramer6671f522017-11-21 14:04:57 +01008989
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02008990 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzenae2680c2018-03-12 17:42:48 +01008991 inherit_expression_dependencies(id, ops[2]);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01008992 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01008993 break;
8994 }
8995
8996 case OpSubgroupFirstInvocationKHR:
8997 {
Lou Kramer6671f522017-11-21 14:04:57 +01008998 uint32_t result_type = ops[0];
8999 uint32_t id = ops[1];
9000 emit_unary_func_op(result_type, id, ops[2], "readFirstInvocationARB");
9001
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009002 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009003 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009004 break;
9005 }
9006
9007 case OpSubgroupReadInvocationKHR:
9008 {
Lou Kramer6671f522017-11-21 14:04:57 +01009009 uint32_t result_type = ops[0];
9010 uint32_t id = ops[1];
9011 emit_binary_func_op(result_type, id, ops[2], ops[3], "readInvocationARB");
9012
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009013 require_extension_internal("GL_ARB_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009014 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009015 break;
9016 }
9017
9018 case OpSubgroupAllKHR:
9019 {
Lou Kramer6671f522017-11-21 14:04:57 +01009020 uint32_t result_type = ops[0];
9021 uint32_t id = ops[1];
9022 emit_unary_func_op(result_type, id, ops[2], "allInvocationsARB");
9023
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009024 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009025 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009026 break;
9027 }
9028
9029 case OpSubgroupAnyKHR:
9030 {
Lou Kramer6671f522017-11-21 14:04:57 +01009031 uint32_t result_type = ops[0];
9032 uint32_t id = ops[1];
9033 emit_unary_func_op(result_type, id, ops[2], "anyInvocationARB");
9034
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009035 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009036 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009037 break;
9038 }
9039
9040 case OpSubgroupAllEqualKHR:
9041 {
Lou Kramer6671f522017-11-21 14:04:57 +01009042 uint32_t result_type = ops[0];
9043 uint32_t id = ops[1];
9044 emit_unary_func_op(result_type, id, ops[2], "allInvocationsEqualARB");
9045
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009046 require_extension_internal("GL_ARB_shader_group_vote");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009047 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009048 break;
9049 }
9050
9051 case OpGroupIAddNonUniformAMD:
9052 case OpGroupFAddNonUniformAMD:
9053 {
Lou Kramer6671f522017-11-21 14:04:57 +01009054 uint32_t result_type = ops[0];
9055 uint32_t id = ops[1];
9056 emit_unary_func_op(result_type, id, ops[4], "addInvocationsNonUniformAMD");
9057
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009058 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009059 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009060 break;
9061 }
9062
9063 case OpGroupFMinNonUniformAMD:
9064 case OpGroupUMinNonUniformAMD:
9065 case OpGroupSMinNonUniformAMD:
9066 {
Lou Kramer6671f522017-11-21 14:04:57 +01009067 uint32_t result_type = ops[0];
9068 uint32_t id = ops[1];
9069 emit_unary_func_op(result_type, id, ops[4], "minInvocationsNonUniformAMD");
9070
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009071 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009072 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009073 break;
9074 }
9075
9076 case OpGroupFMaxNonUniformAMD:
9077 case OpGroupUMaxNonUniformAMD:
9078 case OpGroupSMaxNonUniformAMD:
9079 {
Lou Kramer6671f522017-11-21 14:04:57 +01009080 uint32_t result_type = ops[0];
9081 uint32_t id = ops[1];
9082 emit_unary_func_op(result_type, id, ops[4], "maxInvocationsNonUniformAMD");
9083
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009084 require_extension_internal("GL_AMD_shader_ballot");
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01009085 register_control_dependent_expression(ops[1]);
Lou Kramer6671f522017-11-21 14:04:57 +01009086 break;
9087 }
9088
9089 case OpFragmentMaskFetchAMD:
9090 {
9091 auto &type = expression_type(ops[2]);
9092 uint32_t result_type = ops[0];
9093 uint32_t id = ops[1];
9094
9095 if (type.image.dim == spv::DimSubpassData)
9096 {
9097 emit_unary_func_op(result_type, id, ops[2], "fragmentMaskFetchAMD");
9098 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01009099 else
Lou Kramer6671f522017-11-21 14:04:57 +01009100 {
9101 emit_binary_func_op(result_type, id, ops[2], ops[3], "fragmentMaskFetchAMD");
9102 }
9103
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009104 require_extension_internal("GL_AMD_shader_fragment_mask");
Lou Kramer6671f522017-11-21 14:04:57 +01009105 break;
9106 }
9107
9108 case OpFragmentFetchAMD:
9109 {
9110 auto &type = expression_type(ops[2]);
9111 uint32_t result_type = ops[0];
9112 uint32_t id = ops[1];
9113
9114 if (type.image.dim == spv::DimSubpassData)
9115 {
9116 emit_binary_func_op(result_type, id, ops[2], ops[4], "fragmentFetchAMD");
9117 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01009118 else
Lou Kramer6671f522017-11-21 14:04:57 +01009119 {
9120 emit_trinary_func_op(result_type, id, ops[2], ops[3], ops[4], "fragmentFetchAMD");
9121 }
9122
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009123 require_extension_internal("GL_AMD_shader_fragment_mask");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009124 break;
9125 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009126
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02009127 // Vulkan 1.1 sub-group stuff ...
9128 case OpGroupNonUniformElect:
9129 case OpGroupNonUniformBroadcast:
9130 case OpGroupNonUniformBroadcastFirst:
9131 case OpGroupNonUniformBallot:
9132 case OpGroupNonUniformInverseBallot:
9133 case OpGroupNonUniformBallotBitExtract:
9134 case OpGroupNonUniformBallotBitCount:
9135 case OpGroupNonUniformBallotFindLSB:
9136 case OpGroupNonUniformBallotFindMSB:
9137 case OpGroupNonUniformShuffle:
9138 case OpGroupNonUniformShuffleXor:
9139 case OpGroupNonUniformShuffleUp:
9140 case OpGroupNonUniformShuffleDown:
9141 case OpGroupNonUniformAll:
9142 case OpGroupNonUniformAny:
9143 case OpGroupNonUniformAllEqual:
9144 case OpGroupNonUniformFAdd:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02009145 case OpGroupNonUniformIAdd:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02009146 case OpGroupNonUniformFMul:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02009147 case OpGroupNonUniformIMul:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02009148 case OpGroupNonUniformFMin:
9149 case OpGroupNonUniformFMax:
Hans-Kristian Arntzene1ccfd52018-04-10 17:16:41 +02009150 case OpGroupNonUniformSMin:
9151 case OpGroupNonUniformSMax:
9152 case OpGroupNonUniformUMin:
9153 case OpGroupNonUniformUMax:
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +02009154 case OpGroupNonUniformBitwiseAnd:
9155 case OpGroupNonUniformBitwiseOr:
9156 case OpGroupNonUniformBitwiseXor:
9157 case OpGroupNonUniformQuadSwap:
9158 case OpGroupNonUniformQuadBroadcast:
9159 emit_subgroup_op(instruction);
9160 break;
9161
Hans-Kristian Arntzenaf2d3ab2018-07-02 13:22:21 +02009162 case OpFUnordEqual:
9163 GLSL_BFOP(unsupported_FUnordEqual);
9164 break;
9165
9166 case OpFUnordNotEqual:
9167 GLSL_BFOP(unsupported_FUnordNotEqual);
9168 break;
9169
9170 case OpFUnordLessThan:
9171 GLSL_BFOP(unsupported_FUnordLessThan);
9172 break;
9173
9174 case OpFUnordGreaterThan:
9175 GLSL_BFOP(unsupported_FUnordGreaterThan);
9176 break;
9177
9178 case OpFUnordLessThanEqual:
9179 GLSL_BFOP(unsupported_FUnordLessThanEqual);
9180 break;
9181
9182 case OpFUnordGreaterThanEqual:
9183 GLSL_BFOP(unsupported_FUnordGreaterThanEqual);
9184 break;
9185
Patrick Moursda39a7b2019-02-26 15:43:03 +01009186 case OpReportIntersectionNV:
Patrick Moursc96bab02019-03-26 14:04:39 +01009187 statement("reportIntersectionNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Patrick Moursda39a7b2019-02-26 15:43:03 +01009188 break;
9189 case OpIgnoreIntersectionNV:
9190 statement("ignoreIntersectionNV();");
9191 break;
9192 case OpTerminateRayNV:
9193 statement("terminateRayNV();");
9194 break;
9195 case OpTraceNV:
Patrick Moursc96bab02019-03-26 14:04:39 +01009196 statement("traceNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
9197 to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
9198 to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
9199 to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
Patrick Moursda39a7b2019-02-26 15:43:03 +01009200 break;
9201 case OpExecuteCallableNV:
Patrick Moursc96bab02019-03-26 14:04:39 +01009202 statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
Patrick Moursda39a7b2019-02-26 15:43:03 +01009203 break;
9204
lifpan876627d2019-04-08 19:45:31 +08009205 case OpUndef:
9206 // Undefined value has been declared.
9207 break;
9208
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009209 default:
9210 statement("// unimplemented op ", instruction.op);
9211 break;
9212 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009213}
9214
Bill Hollingsa759e2c2016-10-19 14:09:51 -07009215// Appends function arguments, mapped from global variables, beyond the specified arg index.
Bill Hollingsfe8b8602016-07-06 16:55:45 -04009216// This is used when a function call uses fewer arguments than the function defines.
Bill Hollingsa759e2c2016-10-19 14:09:51 -07009217// This situation may occur if the function signature has been dynamically modified to
9218// extract global variables referenced from within the function, and convert them to
9219// function arguments. This is necessary for shader languages that do not support global
9220// access to shader input content from within a function (eg. Metal). Each additional
9221// function args uses the name of the global variable. Function nesting will modify the
Bill Hollingsfe3683e2018-01-24 15:38:17 -05009222// functions and function calls all the way up the nesting chain.
Bill Hollingsa759e2c2016-10-19 14:09:51 -07009223void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, vector<string> &arglist)
Bill Hollingsfe8b8602016-07-06 16:55:45 -04009224{
Bill Hollingsac00c602016-10-24 09:24:24 -04009225 auto &args = func.arguments;
Bill Hollings943191a2016-10-27 10:20:01 -04009226 uint32_t arg_cnt = uint32_t(args.size());
Bill Hollingsac00c602016-10-24 09:24:24 -04009227 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +01009228 {
Bill Hollingsfe3683e2018-01-24 15:38:17 -05009229 auto &arg = args[arg_idx];
9230 assert(arg.alias_global_variable);
Bill Hollingsfe3683e2018-01-24 15:38:17 -05009231
9232 // If the underlying variable needs to be declared
9233 // (ie. a local variable with deferred declaration), do so now.
9234 uint32_t var_id = get<SPIRVariable>(arg.id).basevariable;
9235 if (var_id)
9236 flush_variable_declaration(var_id);
Hans-Kristian Arntzen87de9512018-08-27 09:59:55 +02009237
9238 arglist.push_back(to_func_call_arg(arg.id));
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +01009239 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -04009240}
9241
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009242string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
9243{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009244 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009245 if (index < memb.size() && !memb[index].alias.empty())
9246 return memb[index].alias;
9247 else
Hans-Kristian Arntzen1c6df1b2017-07-29 21:44:20 +02009248 return join("_m", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009249}
9250
Chip Davis3bfb2f92018-12-03 02:06:33 -06009251string CompilerGLSL::to_member_reference(uint32_t, const SPIRType &type, uint32_t index, bool)
Chip Davis3a9af962018-09-26 20:06:05 -05009252{
9253 return join(".", to_member_name(type, index));
9254}
9255
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02009256void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
9257{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009258 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02009259 if (index < memb.size() && !memb[index].alias.empty())
9260 {
9261 auto &name = memb[index].alias;
9262 if (name.empty())
9263 return;
9264
9265 // Reserved for temporaries.
9266 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
9267 {
9268 name.clear();
9269 return;
9270 }
9271
9272 update_name_cache(type.member_name_cache, name);
9273 }
9274}
9275
Bill Hollingsb332bae2017-03-01 13:07:40 -05009276// Checks whether the ID is a row_major matrix that requires conversion before use
Bill Hollings13583622016-12-14 02:12:52 -05009277bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009278{
Bill Hollings13583622016-12-14 02:12:52 -05009279 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009280 // Legacy targets do not support row major.
9281 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -05009282 return false;
9283
9284 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +01009285 if (!has_decoration(id, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -05009286 return false;
9287
9288 // Only square row-major matrices can be converted at this time.
9289 // Converting non-square matrices will require defining custom GLSL function that
9290 // swaps matrix elements while retaining the original dimensional form of the matrix.
9291 const auto type = expression_type(id);
9292 if (type.columns != type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +01009293 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -05009294
9295 return true;
Bill Hollings343677e2016-12-11 11:01:08 -05009296}
9297
Bill Hollings13583622016-12-14 02:12:52 -05009298// Checks whether the member is a row_major matrix that requires conversion before use
9299bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index)
Bill Hollings343677e2016-12-11 11:01:08 -05009300{
Bill Hollings13583622016-12-14 02:12:52 -05009301 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01009302 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -05009303 return false;
9304
9305 // Non-matrix or column-major matrix types do not need to be converted.
Hans-Kristian Arntzen056a0ba2019-02-20 12:19:00 +01009306 if (!has_member_decoration(type.self, index, DecorationRowMajor))
Bill Hollings13583622016-12-14 02:12:52 -05009307 return false;
9308
9309 // Only square row-major matrices can be converted at this time.
9310 // Converting non-square matrices will require defining custom GLSL function that
9311 // swaps matrix elements while retaining the original dimensional form of the matrix.
9312 const auto mbr_type = get<SPIRType>(type.member_types[index]);
9313 if (mbr_type.columns != mbr_type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +01009314 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -05009315
9316 return true;
Bill Hollings343677e2016-12-11 11:01:08 -05009317}
9318
Bill Hollingsb332bae2017-03-01 13:07:40 -05009319// Checks whether the member is in packed data type, that might need to be unpacked.
9320// GLSL does not define packed data types, but certain subclasses do.
Bill Hollings1c180782017-11-05 21:34:42 -05009321bool CompilerGLSL::member_is_packed_type(const SPIRType &type, uint32_t index) const
Bill Hollingsb332bae2017-03-01 13:07:40 -05009322{
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01009323 return has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPacked);
Bill Hollingsb332bae2017-03-01 13:07:40 -05009324}
9325
Bill Hollings13583622016-12-14 02:12:52 -05009326// Wraps the expression string in a function call that converts the
9327// row_major matrix result of the expression to a column_major matrix.
9328// Base implementation uses the standard library transpose() function.
9329// Subclasses may override to use a different function.
Bill Hollings607b0d62018-02-11 16:52:57 -05009330string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType & /*exp_type*/, bool /*is_packed*/)
Bill Hollings343677e2016-12-11 11:01:08 -05009331{
9332 strip_enclosed_expression(exp_str);
9333 return join("transpose(", exp_str, ")");
9334}
9335
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +02009336string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009337{
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +02009338 string type_name = type_to_glsl(type, id);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +02009339 remap_variable_type_name(type, name, type_name);
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +02009340 return join(type_name, " ", name, type_to_array_glsl(type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009341}
9342
Bill Hollings484931d2017-02-28 21:44:36 -05009343// Emit a structure member. Subclasses may override to modify output,
9344// or to dynamically add a padding member if needed.
Bill Hollingsdc694272017-03-11 12:17:22 -05009345void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
msiglreithd096f5c2017-11-27 16:00:56 +01009346 const string &qualifier, uint32_t)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009347{
Bill Hollings484931d2017-02-28 21:44:36 -05009348 auto &membertype = get<SPIRType>(member_type_id);
9349
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009350 Bitset memberflags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009351 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009352 if (index < memb.size())
9353 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009354
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02009355 string qualifiers;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009356 bool is_block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
9357 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009358
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02009359 if (is_block)
9360 qualifiers = to_interpolation_qualifiers(memberflags);
9361
Bill Hollings484931d2017-02-28 21:44:36 -05009362 statement(layout_for_member(type, index), qualifiers, qualifier,
9363 flags_to_precision_qualifiers_glsl(membertype, memberflags),
9364 variable_decl(membertype, to_member_name(type, index)), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009365}
9366
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009367const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &type, const Bitset &flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009368{
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +01009369 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
9370 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
9371 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
9372 type.basetype != SPIRType::Sampler)
9373 return "";
9374
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009375 if (options.es)
9376 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02009377 auto &execution = get_entry_point();
9378
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009379 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009380 {
9381 bool implied_fmediump = type.basetype == SPIRType::Float &&
9382 options.fragment.default_float_precision == Options::Mediump &&
9383 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009385 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
9386 options.fragment.default_int_precision == Options::Mediump &&
9387 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009388
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009389 return implied_fmediump || implied_imediump ? "" : "mediump ";
9390 }
9391 else
9392 {
9393 bool implied_fhighp =
9394 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
9395 execution.model == ExecutionModelFragment) ||
9396 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009397
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009398 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
9399 ((options.fragment.default_int_precision == Options::Highp &&
9400 execution.model == ExecutionModelFragment) ||
9401 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009402
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009403 return implied_fhighp || implied_ihighp ? "" : "highp ";
9404 }
9405 }
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +01009406 else if (backend.allow_precision_qualifiers)
9407 {
9408 // Vulkan GLSL supports precision qualifiers, even in desktop profiles, which is convenient.
9409 // 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 +01009410 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen01080362018-05-11 10:59:29 +02009411 return "mediump ";
Hans-Kristian Arntzen2e686752017-12-06 10:25:30 +01009412 else
9413 return "";
9414 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009415 else
9416 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009417}
9418
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009419const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009420{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009421 return flags_to_precision_qualifiers_glsl(expression_type(id), ir.meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009422}
9423
9424string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
9425{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01009426 auto &flags = ir.meta[id].decoration.decoration_flags;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009427 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009428
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009429 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009430
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009431 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
9432 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009433
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02009434 res += to_interpolation_qualifiers(flags);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01009435 if (var)
9436 res += to_storage_qualifiers_glsl(*var);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01009437
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +02009438 auto &type = expression_type(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009439 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
9440 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009441 if (flags.get(DecorationCoherent))
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +02009442 res += "coherent ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009443 if (flags.get(DecorationRestrict))
Hans-Kristian Arntzen11dfcb62017-08-29 15:54:22 +02009444 res += "restrict ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009445 if (flags.get(DecorationNonWritable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009446 res += "readonly ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009447 if (flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009448 res += "writeonly ";
9449 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009450
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +02009451 res += to_precision_qualifiers_glsl(id);
9452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009453 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009454}
9455
9456string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
9457{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009458 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009459 auto &type = expression_type(arg.id);
9460 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009461
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009462 if (type.pointer)
9463 {
9464 if (arg.write_count && arg.read_count)
9465 direction = "inout ";
9466 else if (arg.write_count)
9467 direction = "out ";
9468 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009469
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +02009470 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 +01009471}
9472
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +02009473string CompilerGLSL::to_initializer_expression(const SPIRVariable &var)
9474{
9475 return to_expression(var.initializer);
9476}
9477
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009478string CompilerGLSL::variable_decl(const SPIRVariable &variable)
9479{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009480 // Ignore the pointer type since GLSL doesn't have pointers.
Chip Davis3bfb2f92018-12-03 02:06:33 -06009481 auto &type = get_variable_data_type(variable);
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +02009482
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +01009483 if (type.pointer_depth > 1)
9484 SPIRV_CROSS_THROW("Cannot declare pointer-to-pointer types.");
9485
Hans-Kristian Arntzenb0f7dee2017-06-17 10:56:24 +02009486 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 +02009487
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +01009488 if (variable.loop_variable && variable.static_expression)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +01009489 {
9490 uint32_t expr = variable.static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009491 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +01009492 res += join(" = ", to_expression(variable.static_expression));
9493 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01009494 else if (variable.initializer)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +01009495 {
9496 uint32_t expr = variable.initializer;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02009497 if (ir.ids[expr].get_type() != TypeUndef)
Hans-Kristian Arntzen2bf57d62018-07-05 15:29:49 +02009498 res += join(" = ", to_initializer_expression(variable));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +01009499 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009500 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009501}
9502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009503const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009504{
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +01009505 auto &flags = ir.meta[variable.self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009506 if (flags.get(DecorationRelaxedPrecision))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009507 return "mediump ";
9508 else
9509 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009510}
9511
9512string CompilerGLSL::pls_decl(const PlsRemap &var)
9513{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009514 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009516 SPIRType type;
9517 type.vecsize = pls_format_to_components(var.format);
9518 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009519
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009520 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
9521 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009522}
9523
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01009524uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type) const
9525{
9526 return to_array_size_literal(type, uint32_t(type.array.size() - 1));
9527}
9528
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02009529uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t index) const
9530{
9531 assert(type.array.size() == type.array_size_literal.size());
9532
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +01009533 if (type.array_size_literal[index])
9534 {
9535 return type.array[index];
9536 }
9537 else
9538 {
9539 // Use the default spec constant value.
9540 // This is the best we can do.
9541 uint32_t array_size_id = type.array[index];
Hans-Kristian Arntzen480acda2018-11-01 14:56:25 +01009542
9543 // Explicitly check for this case. The error message you would get (bad cast) makes no sense otherwise.
9544 if (ir.ids[array_size_id].get_type() == TypeConstantOp)
9545 SPIRV_CROSS_THROW("An array size was found to be an OpSpecConstantOp. This is not supported since "
9546 "SPIRV-Cross cannot deduce the actual size here.");
9547
Hans-Kristian Arntzendd603ea2018-02-23 15:09:28 +01009548 uint32_t array_size = get<SPIRConstant>(array_size_id).scalar();
9549 return array_size;
9550 }
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02009551}
9552
9553string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index)
9554{
9555 assert(type.array.size() == type.array_size_literal.size());
9556
Hans-Kristian Arntzenddfd2612019-01-09 10:47:16 +01009557 // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays.
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009558 // Opt for unsized as it's the more "correct" variant to use.
Hans-Kristian Arntzenddfd2612019-01-09 10:47:16 +01009559 if (type.storage == StorageClassInput && (get_entry_point().model == ExecutionModelTessellationControl ||
9560 get_entry_point().model == ExecutionModelTessellationEvaluation))
Hans-Kristian Arntzen9bdfd702018-01-04 16:22:44 +01009561 return "";
9562
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02009563 auto &size = type.array[index];
9564 if (!type.array_size_literal[index])
9565 return to_expression(size);
9566 else if (size)
9567 return convert_to_string(size);
9568 else if (!backend.flexible_member_array_supported)
9569 {
9570 // For runtime-sized arrays, we can work around
9571 // lack of standard support for this by simply having
9572 // a single element array.
9573 //
9574 // Runtime length arrays must always be the last element
9575 // in an interface block.
9576 return "1";
9577 }
9578 else
9579 return "";
9580}
9581
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009582string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
9583{
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02009584 if (type.array.empty())
9585 return "";
9586
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009587 if (options.flatten_multidimensional_arrays)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009588 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009589 string res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009590 res += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009591 for (auto i = uint32_t(type.array.size()); i; i--)
9592 {
9593 res += enclose_expression(to_array_size(type, i - 1));
9594 if (i > 1)
9595 res += " * ";
9596 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009597 res += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009598 return res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009599 }
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009600 else
9601 {
9602 if (type.array.size() > 1)
9603 {
9604 if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009605 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009606 else if (options.es && options.version < 310)
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02009607 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
9608 "Try using --flatten-multidimensional-arrays or set "
9609 "options.flatten_multidimensional_arrays to true.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02009610 }
9611
9612 string res;
9613 for (auto i = uint32_t(type.array.size()); i; i--)
9614 {
9615 res += "[";
9616 res += to_array_size(type, i - 1);
9617 res += "]";
9618 }
9619 return res;
9620 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009621}
9622
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02009623string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009624{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009625 auto &imagetype = get<SPIRType>(type.image.type);
9626 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009628 switch (imagetype.basetype)
9629 {
9630 case SPIRType::Int:
9631 res = "i";
9632 break;
9633 case SPIRType::UInt:
9634 res = "u";
9635 break;
9636 default:
9637 break;
9638 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009639
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02009640 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02009641 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02009642
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009643 // If we're emulating subpassInput with samplers, force sampler2D
9644 // so we don't have to specify format.
9645 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02009646 {
9647 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
9648 if (type.image.dim == DimBuffer && type.image.sampled == 1)
9649 res += "sampler";
9650 else
9651 res += type.image.sampled == 2 ? "image" : "texture";
9652 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009653 else
9654 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009655
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009656 switch (type.image.dim)
9657 {
9658 case Dim1D:
9659 res += "1D";
9660 break;
9661 case Dim2D:
9662 res += "2D";
9663 break;
9664 case Dim3D:
9665 res += "3D";
9666 break;
9667 case DimCube:
9668 res += "Cube";
9669 break;
Sidney Justfbb4df32019-01-06 12:21:59 -08009670 case DimRect:
9671 if (options.es)
9672 SPIRV_CROSS_THROW("Rectangle textures are not supported on OpenGL ES.");
9673
9674 if (is_legacy_desktop())
9675 require_extension_internal("GL_ARB_texture_rectangle");
9676
9677 res += "2DRect";
9678 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009680 case DimBuffer:
9681 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009682 require_extension_internal("GL_OES_texture_buffer");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009683 else if (!options.es && options.version < 300)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009684 require_extension_internal("GL_EXT_texture_buffer_object");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009685 res += "Buffer";
9686 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009687
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009688 case DimSubpassData:
9689 res += "2D";
9690 break;
9691 default:
Sidney Justfbb4df32019-01-06 12:21:59 -08009692 SPIRV_CROSS_THROW("Only 1D, 2D, 2DRect, 3D, Buffer, InputTarget and Cube textures supported.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009693 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009694
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02009695 if (type.image.ms)
9696 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009697 if (type.image.arrayed)
Rob Fischer21990632016-09-17 17:01:50 +09009698 {
Lubos Lenco52158642016-09-17 15:56:23 +02009699 if (is_legacy_desktop())
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009700 require_extension_internal("GL_EXT_texture_array");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009701 res += "Array";
Rob Fischer21990632016-09-17 17:01:50 +09009702 }
Hans-Kristian Arntzena3ae8612018-02-09 12:37:17 +01009703
9704 // "Shadow" state in GLSL only exists for samplers and combined image samplers.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02009705 if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) &&
9706 image_is_comparison(type, id))
9707 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009708 res += "Shadow";
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02009709 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009711 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009712}
9713
9714string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
9715{
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +02009716 if (type.array.size() > 1)
9717 {
9718 if (options.flatten_multidimensional_arrays)
9719 SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, e.g. float[][]().");
9720 else if (!options.es && options.version < 430)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009721 require_extension_internal("GL_ARB_arrays_of_arrays");
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +02009722 else if (options.es && options.version < 310)
9723 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
9724 }
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02009725
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009726 auto e = type_to_glsl(type);
9727 for (uint32_t i = 0; i < type.array.size(); i++)
9728 e += "[]";
9729 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009730}
9731
Bill Hollingsb41e1482017-05-29 20:45:05 -04009732// The optional id parameter indicates the object whose type we are trying
9733// to find the description for. It is optional. Most type descriptions do not
9734// depend on a specific object's use of that type.
9735string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009736{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009737 // Ignore the pointer type since GLSL doesn't have pointers.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009738
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009739 switch (type.basetype)
9740 {
9741 case SPIRType::Struct:
9742 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02009743 if (backend.explicit_struct_type)
9744 return join("struct ", to_name(type.self));
9745 else
9746 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009747
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009748 case SPIRType::Image:
9749 case SPIRType::SampledImage:
Bill Hollingsb41e1482017-05-29 20:45:05 -04009750 return image_type_glsl(type, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009751
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009752 case SPIRType::Sampler:
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +02009753 // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
9754 // this distinction into the type system.
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02009755 return comparison_ids.count(id) ? "samplerShadow" : "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009756
Patrick Moursda39a7b2019-02-26 15:43:03 +01009757 case SPIRType::AccelerationStructureNV:
9758 return "accelerationStructureNV";
9759
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009760 case SPIRType::Void:
9761 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009762
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009763 default:
9764 break;
9765 }
9766
Hans-Kristian Arntzene930f792018-04-17 14:56:49 +02009767 if (type.basetype == SPIRType::UInt && is_legacy())
9768 SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
9769
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009770 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
9771 {
9772 switch (type.basetype)
9773 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02009774 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009775 return "bool";
Chip Davis117ccf42018-11-01 17:20:07 -05009776 case SPIRType::SByte:
9777 return backend.basic_int8_type;
9778 case SPIRType::UByte:
9779 return backend.basic_uint8_type;
9780 case SPIRType::Short:
9781 return backend.basic_int16_type;
9782 case SPIRType::UShort:
9783 return backend.basic_uint16_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009784 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -05009785 return backend.basic_int_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009786 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -05009787 return backend.basic_uint_type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009788 case SPIRType::AtomicCounter:
9789 return "atomic_uint";
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01009790 case SPIRType::Half:
9791 return "float16_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009792 case SPIRType::Float:
9793 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02009794 case SPIRType::Double:
9795 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02009796 case SPIRType::Int64:
9797 return "int64_t";
9798 case SPIRType::UInt64:
9799 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009800 default:
9801 return "???";
9802 }
9803 }
9804 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
9805 {
9806 switch (type.basetype)
9807 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02009808 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009809 return join("bvec", type.vecsize);
Chip Davis117ccf42018-11-01 17:20:07 -05009810 case SPIRType::SByte:
9811 return join("i8vec", type.vecsize);
9812 case SPIRType::UByte:
9813 return join("u8vec", type.vecsize);
9814 case SPIRType::Short:
9815 return join("i16vec", type.vecsize);
9816 case SPIRType::UShort:
9817 return join("u16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009818 case SPIRType::Int:
Chip Davis117ccf42018-11-01 17:20:07 -05009819 return join("ivec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009820 case SPIRType::UInt:
Chip Davis117ccf42018-11-01 17:20:07 -05009821 return join("uvec", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01009822 case SPIRType::Half:
9823 return join("f16vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009824 case SPIRType::Float:
9825 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02009826 case SPIRType::Double:
9827 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02009828 case SPIRType::Int64:
9829 return join("i64vec", type.vecsize);
9830 case SPIRType::UInt64:
9831 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009832 default:
9833 return "???";
9834 }
9835 }
9836 else if (type.vecsize == type.columns) // Simple Matrix builtin
9837 {
9838 switch (type.basetype)
9839 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02009840 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009841 return join("bmat", type.vecsize);
9842 case SPIRType::Int:
9843 return join("imat", type.vecsize);
9844 case SPIRType::UInt:
9845 return join("umat", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01009846 case SPIRType::Half:
9847 return join("f16mat", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009848 case SPIRType::Float:
9849 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02009850 case SPIRType::Double:
9851 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02009852 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009853 default:
9854 return "???";
9855 }
9856 }
9857 else
9858 {
9859 switch (type.basetype)
9860 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02009861 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009862 return join("bmat", type.columns, "x", type.vecsize);
9863 case SPIRType::Int:
9864 return join("imat", type.columns, "x", type.vecsize);
9865 case SPIRType::UInt:
9866 return join("umat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01009867 case SPIRType::Half:
9868 return join("f16mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009869 case SPIRType::Float:
9870 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02009871 case SPIRType::Double:
9872 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02009873 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009874 default:
9875 return "???";
9876 }
9877 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009878}
9879
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01009880void CompilerGLSL::add_variable(unordered_set<string> &variables_primary,
9881 const unordered_set<string> &variables_secondary, string &name)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009882{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009883 if (name.empty())
9884 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009885
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009886 // Reserved for temporaries.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02009887 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009888 {
9889 name.clear();
9890 return;
9891 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009892
Hans-Kristian Arntzen6bcc8902018-06-04 10:13:57 +02009893 // Avoid double underscores.
9894 name = sanitize_underscores(name);
9895
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01009896 update_name_cache(variables_primary, variables_secondary, name);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01009897}
9898
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02009899void CompilerGLSL::add_local_variable_name(uint32_t id)
9900{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01009901 add_variable(local_variable_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02009902}
9903
9904void CompilerGLSL::add_resource_name(uint32_t id)
9905{
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01009906 add_variable(resource_names, block_names, ir.meta[id].decoration.alias);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009907}
9908
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +02009909void CompilerGLSL::add_header_line(const std::string &line)
9910{
9911 header_lines.push_back(line);
9912}
9913
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01009914bool CompilerGLSL::has_extension(const std::string &ext) const
9915{
9916 auto itr = find(begin(forced_extensions), end(forced_extensions), ext);
9917 return itr != end(forced_extensions);
9918}
9919
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009920void CompilerGLSL::require_extension(const std::string &ext)
9921{
9922 if (!has_extension(ext))
9923 forced_extensions.push_back(ext);
9924}
9925
9926void CompilerGLSL::require_extension_internal(const string &ext)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009927{
Hans-Kristian Arntzen047ad7d2018-02-23 13:06:20 +01009928 if (backend.supports_extensions && !has_extension(ext))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009929 {
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01009930 forced_extensions.push_back(ext);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009931 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009932 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009933}
9934
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009935void CompilerGLSL::flatten_buffer_block(uint32_t id)
9936{
9937 auto &var = get<SPIRVariable>(id);
9938 auto &type = get<SPIRType>(var.basetype);
9939 auto name = to_name(type.self, false);
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01009940 auto &flags = ir.meta[type.self].decoration.decoration_flags;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009941
9942 if (!type.array.empty())
9943 SPIRV_CROSS_THROW(name + " is an array of UBOs.");
9944 if (type.basetype != SPIRType::Struct)
9945 SPIRV_CROSS_THROW(name + " is not a struct.");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009946 if (!flags.get(DecorationBlock))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009947 SPIRV_CROSS_THROW(name + " is not a block.");
9948 if (type.member_types.empty())
9949 SPIRV_CROSS_THROW(name + " is an empty struct.");
9950
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08009951 flattened_buffer_blocks.insert(id);
9952}
9953
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009954bool CompilerGLSL::check_atomic_image(uint32_t id)
9955{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009956 auto &type = expression_type(id);
9957 if (type.storage == StorageClassImage)
9958 {
9959 if (options.es && options.version < 320)
Hans-Kristian Arntzen31a3fdf2018-04-05 14:42:52 +02009960 require_extension_internal("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009961
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009962 auto *var = maybe_get_backing_variable(id);
9963 if (var)
9964 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +01009965 auto &flags = ir.meta[var->self].decoration.decoration_flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009966 if (flags.get(DecorationNonWritable) || flags.get(DecorationNonReadable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009967 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01009968 flags.clear(DecorationNonWritable);
9969 flags.clear(DecorationNonReadable);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02009970 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02009971 }
9972 }
9973 return true;
9974 }
9975 else
9976 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01009977}
9978
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +01009979void CompilerGLSL::add_function_overload(const SPIRFunction &func)
9980{
9981 Hasher hasher;
9982 for (auto &arg : func.arguments)
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +01009983 {
9984 // Parameters can vary with pointer type or not,
9985 // but that will not change the signature in GLSL/HLSL,
9986 // so strip the pointer type before hashing.
Chip Davisfc02b3d2019-01-08 12:54:40 -06009987 uint32_t type_id = get_pointee_type_id(arg.type);
Bill Hollingse0910312018-06-24 15:06:12 -04009988 auto &type = get<SPIRType>(type_id);
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +02009989
9990 if (!combined_image_samplers.empty())
9991 {
9992 // If we have combined image samplers, we cannot really trust the image and sampler arguments
9993 // we pass down to callees, because they may be shuffled around.
9994 // Ignore these arguments, to make sure that functions need to differ in some other way
9995 // to be considered different overloads.
Bill Hollingse0910312018-06-24 15:06:12 -04009996 if (type.basetype == SPIRType::SampledImage ||
9997 (type.basetype == SPIRType::Image && type.image.sampled == 1) || type.basetype == SPIRType::Sampler)
Hans-Kristian Arntzen17be3c62018-05-02 10:35:37 +02009998 {
9999 continue;
10000 }
10001 }
10002
Hans-Kristian Arntzenfda36f82018-02-25 10:58:22 +010010003 hasher.u32(type_id);
10004 }
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010010005 uint64_t types_hash = hasher.get();
10006
10007 auto function_name = to_name(func.self);
10008 auto itr = function_overloads.find(function_name);
10009 if (itr != end(function_overloads))
10010 {
10011 // There exists a function with this name already.
10012 auto &overloads = itr->second;
10013 if (overloads.count(types_hash) != 0)
10014 {
10015 // Overload conflict, assign a new name.
10016 add_resource_name(func.self);
10017 function_overloads[to_name(func.self)].insert(types_hash);
10018 }
10019 else
10020 {
10021 // Can reuse the name.
10022 overloads.insert(types_hash);
10023 }
10024 }
10025 else
10026 {
10027 // First time we see this function name.
10028 add_resource_name(func.self);
10029 function_overloads[to_name(func.self)].insert(types_hash);
10030 }
10031}
10032
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010033void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010034{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010035 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +010010036 add_function_overload(func);
10037
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020010038 // Avoid shadow declarations.
10039 local_variable_names = resource_names;
10040
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010041 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010043 auto &type = get<SPIRType>(func.return_type);
10044 decl += flags_to_precision_qualifiers_glsl(type, return_flags);
10045 decl += type_to_glsl(type);
Hans-Kristian Arntzen9fa91f72018-02-05 09:34:54 +010010046 decl += type_to_array_glsl(type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010047 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010048
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010049 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010050 {
Bill Hollings1c180782017-11-05 21:34:42 -050010051 decl += "main";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010052 processing_entry_point = true;
10053 }
10054 else
Bill Hollings1c180782017-11-05 21:34:42 -050010055 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010056
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010057 decl += "(";
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010058 vector<string> arglist;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010059 for (auto &arg : func.arguments)
10060 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010061 // Do not pass in separate images or samplers if we're remapping
10062 // to combined image samplers.
10063 if (skip_argument(arg.id))
10064 continue;
10065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010066 // Might change the variable name if it already exists in this function.
10067 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
10068 // to use same name for variables.
10069 // 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 +020010070 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010071
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010072 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010073
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010074 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
10075 auto *var = maybe_get<SPIRVariable>(arg.id);
10076 if (var)
10077 var->parameter = &arg;
10078 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010079
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +020010080 for (auto &arg : func.shadow_arguments)
10081 {
10082 // Might change the variable name if it already exists in this function.
10083 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
10084 // to use same name for variables.
10085 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
10086 add_local_variable_name(arg.id);
10087
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010088 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010089
10090 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
10091 auto *var = maybe_get<SPIRVariable>(arg.id);
10092 if (var)
10093 var->parameter = &arg;
10094 }
10095
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +020010096 decl += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010097 decl += ")";
10098 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010099}
10100
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010101void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010102{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010103 // Avoid potential cycles.
10104 if (func.active)
10105 return;
10106 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010107
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010108 // If we depend on a function, emit that function before we emit our own function.
10109 for (auto block : func.blocks)
10110 {
10111 auto &b = get<SPIRBlock>(block);
10112 for (auto &i : b.ops)
10113 {
10114 auto ops = stream(i);
10115 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010116
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010117 if (op == OpFunctionCall)
10118 {
10119 // Recursively emit functions which are called.
10120 uint32_t id = ops[2];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010121 emit_function(get<SPIRFunction>(id), ir.meta[ops[1]].decoration.decoration_flags);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010122 }
10123 }
10124 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010125
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010126 emit_function_prototype(func, return_flags);
10127 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010128
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010129 if (func.self == ir.default_entry_point)
Hans-Kristian Arntzendf58deb2018-04-17 17:43:10 +020010130 emit_entry_point_declarations();
10131
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010132 current_function = &func;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010133 auto &entry_block = get<SPIRBlock>(func.entry_block);
10134
Hans-Kristian Arntzen7ee04932019-01-14 10:08:35 +010010135 sort(begin(func.constant_arrays_needed_on_stack), end(func.constant_arrays_needed_on_stack));
10136 for (auto &array : func.constant_arrays_needed_on_stack)
10137 {
10138 auto &c = get<SPIRConstant>(array);
10139 auto &type = get<SPIRType>(c.constant_type);
10140 statement(variable_decl(type, join("_", array, "_array_copy")), " = ", constant_expression(c), ";");
10141 }
10142
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010143 for (auto &v : func.local_variables)
10144 {
10145 auto &var = get<SPIRVariable>(v);
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020010146 if (var.storage == StorageClassWorkgroup)
10147 {
10148 // Special variable type which cannot have initializer,
10149 // need to be declared as standalone variables.
10150 // Comes from MSL which can push global variables as local variables in main function.
10151 add_local_variable_name(var.self);
10152 statement(variable_decl(var), ";");
10153 var.deferred_declaration = false;
10154 }
Hans-Kristian Arntzenbcaae842018-05-16 10:49:30 +020010155 else if (var.storage == StorageClassPrivate)
10156 {
10157 // These variables will not have had their CFG usage analyzed, so move it to the entry block.
10158 // Comes from MSL which can push global variables as local variables in main function.
10159 // We could just declare them right now, but we would miss out on an important initialization case which is
10160 // LUT declaration in MSL.
10161 // If we don't declare the variable when it is assigned we're forced to go through a helper function
10162 // which copies elements one by one.
10163 add_local_variable_name(var.self);
10164 auto &dominated = entry_block.dominated_variables;
10165 if (find(begin(dominated), end(dominated), var.self) == end(dominated))
10166 entry_block.dominated_variables.push_back(var.self);
10167 var.deferred_declaration = true;
10168 }
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +020010169 else if (var.storage == StorageClassFunction && var.remapped_variable && var.static_expression)
10170 {
10171 // No need to declare this variable, it has a static expression.
10172 var.deferred_declaration = false;
10173 }
Hans-Kristian Arntzen26b887e2018-05-15 16:03:20 +020010174 else if (expression_is_lvalue(v))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010175 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +020010176 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010178 if (var.initializer)
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +010010179 statement(variable_decl_function_local(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010180 else
10181 {
10182 // Don't declare variable until first use to declutter the GLSL output quite a lot.
10183 // If we don't touch the variable before first branch,
10184 // declare it then since we need variable declaration to be in top scope.
Hans-Kristian Arntzen694b3142018-04-05 16:26:54 +020010185 var.deferred_declaration = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010186 }
10187 }
10188 else
10189 {
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +020010190 // 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 +010010191 // For these types (non-lvalue), we enforce forwarding through a shadowed variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010192 // This means that when we OpStore to these variables, we just write in the expression ID directly.
10193 // This breaks any kind of branching, since the variable must be statically assigned.
10194 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
10195 var.statically_assigned = true;
10196 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010197
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010198 var.loop_variable_enable = false;
Hans-Kristian Arntzenb847c882016-11-18 17:06:49 +010010199
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010200 // Loop variables are never declared outside their for-loop, so block any implicit declaration.
10201 if (var.loop_variable)
10202 var.deferred_declaration = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010203 }
10204
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020010205 for (auto &line : current_function->fixup_hooks_in)
10206 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040010207
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010208 entry_block.loop_dominator = SPIRBlock::NoDominator;
10209 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010210
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010211 end_scope();
10212 processing_entry_point = false;
10213 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010214}
10215
10216void CompilerGLSL::emit_fixup()
10217{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +020010218 auto &execution = get_entry_point();
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020010219 if (execution.model == ExecutionModelVertex)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010220 {
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +020010221 if (options.vertex.fixup_clipspace)
10222 {
10223 const char *suffix = backend.float_literal_suffix ? "f" : "";
10224 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
10225 }
10226
10227 if (options.vertex.flip_vert_y)
10228 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010229 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010230}
10231
10232bool CompilerGLSL::flush_phi_required(uint32_t from, uint32_t to)
10233{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010234 auto &child = get<SPIRBlock>(to);
10235 for (auto &phi : child.phi_variables)
10236 if (phi.parent == from)
10237 return true;
10238 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010239}
10240
10241void CompilerGLSL::flush_phi(uint32_t from, uint32_t to)
10242{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010243 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010244
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010245 unordered_set<uint32_t> temporary_phi_variables;
10246
10247 for (auto itr = begin(child.phi_variables); itr != end(child.phi_variables); ++itr)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020010248 {
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010249 auto &phi = *itr;
10250
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010251 if (phi.parent == from)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020010252 {
10253 auto &var = get<SPIRVariable>(phi.function_variable);
10254
10255 // A Phi variable might be a loop variable, so flush to static expression.
10256 if (var.loop_variable && !var.loop_variable_enable)
10257 var.static_expression = phi.local_variable;
10258 else
10259 {
10260 flush_variable_declaration(phi.function_variable);
10261
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010262 // Check if we are going to write to a Phi variable that another statement will read from
10263 // as part of another Phi node in our target block.
10264 // For this case, we will need to copy phi.function_variable to a temporary, and use that for future reads.
10265 // This is judged to be extremely rare, so deal with it here using a simple, but suboptimal algorithm.
10266 bool need_saved_temporary =
10267 find_if(itr + 1, end(child.phi_variables), [&](const SPIRBlock::Phi &future_phi) -> bool {
10268 return future_phi.local_variable == phi.function_variable && future_phi.parent == from;
10269 }) != end(child.phi_variables);
10270
10271 if (need_saved_temporary)
10272 {
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010010273 // Need to make sure we declare the phi variable with a copy at the right scope.
10274 // We cannot safely declare a temporary here since we might be inside a continue block.
10275 if (!var.allocate_temporary_copy)
10276 {
10277 var.allocate_temporary_copy = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020010278 force_recompile();
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010010279 }
10280 statement("_", phi.function_variable, "_copy", " = ", to_name(phi.function_variable), ";");
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010281 temporary_phi_variables.insert(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010282 }
10283
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020010284 // This might be called in continue block, so make sure we
Hans-Kristian Arntzen91753632017-09-25 10:16:45 +020010285 // use this to emit ESSL 1.0 compliant increments/decrements.
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020010286 auto lhs = to_expression(phi.function_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010287
10288 string rhs;
10289 if (temporary_phi_variables.count(phi.local_variable))
10290 rhs = join("_", phi.local_variable, "_copy");
10291 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060010292 rhs = to_pointer_expression(phi.local_variable);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010293
Hans-Kristian Arntzen85a8f062018-05-04 10:35:32 +020010294 if (!optimize_read_modify_write(get<SPIRType>(var.basetype), lhs, rhs))
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020010295 statement(lhs, " = ", rhs, ";");
10296 }
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +010010297
10298 register_write(phi.function_variable);
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +020010299 }
10300 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010301}
10302
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010010303void CompilerGLSL::branch_to_continue(uint32_t from, uint32_t to)
10304{
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010010305 auto &to_block = get<SPIRBlock>(to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010010306 if (from == to)
10307 return;
10308
10309 assert(is_continue(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010010310 if (to_block.complex_continue)
10311 {
10312 // Just emit the whole block chain as is.
10313 auto usage_counts = expression_usage_counts;
10314 auto invalid = invalid_expressions;
10315
10316 emit_block_chain(to_block);
10317
10318 // Expression usage counts and invalid expressions
10319 // are moot after returning from the continue block.
10320 // Since we emit the same block multiple times,
10321 // we don't want to invalidate ourselves.
10322 expression_usage_counts = usage_counts;
10323 invalid_expressions = invalid;
10324 }
10325 else
10326 {
10327 auto &from_block = get<SPIRBlock>(from);
10328 bool outside_control_flow = false;
10329 uint32_t loop_dominator = 0;
10330
10331 // FIXME: Refactor this to not use the old loop_dominator tracking.
10332 if (from_block.merge_block)
10333 {
10334 // If we are a loop header, we don't set the loop dominator,
10335 // so just use "self" here.
10336 loop_dominator = from;
10337 }
10338 else if (from_block.loop_dominator != SPIRBlock::NoDominator)
10339 {
10340 loop_dominator = from_block.loop_dominator;
10341 }
10342
10343 if (loop_dominator != 0)
10344 {
10345 auto &dominator = get<SPIRBlock>(loop_dominator);
10346
10347 // For non-complex continue blocks, we implicitly branch to the continue block
10348 // by having the continue block be part of the loop header in for (; ; continue-block).
10349 outside_control_flow = block_is_outside_flow_control_from_block(dominator, from_block);
10350 }
10351
10352 // Some simplification for for-loops. We always end up with a useless continue;
10353 // statement since we branch to a loop block.
10354 // Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block,
10355 // we can avoid writing out an explicit continue statement.
10356 // Similar optimization to return statements if we know we're outside flow control.
10357 if (!outside_control_flow)
10358 statement("continue;");
10359 }
10360}
10361
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010362void CompilerGLSL::branch(uint32_t from, uint32_t to)
10363{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010364 flush_phi(from, to);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +010010365 flush_control_dependent_expressions(from);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010366 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010367
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010368 // This is only a continue if we branch to our loop dominator.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010369 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 +020010370 {
10371 // This can happen if we had a complex continue block which was emitted.
10372 // Once the continue block tries to branch to the loop header, just emit continue;
10373 // and end the chain here.
10374 statement("continue;");
10375 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010376 else if (is_break(to))
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020010377 {
10378 // Very dirty workaround.
10379 // Switch constructs are able to break, but they cannot break out of a loop at the same time.
10380 // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block,
10381 // write to the ladder here, and defer the break.
10382 // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case.
Hans-Kristian Arntzen6157bf32018-10-26 10:53:11 +020010383 if (current_emitting_switch && is_loop_break(to) && current_emitting_switch->loop_dominator != ~0u &&
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020010384 get<SPIRBlock>(current_emitting_switch->loop_dominator).merge_block == to)
10385 {
10386 if (!current_emitting_switch->need_ladder_break)
10387 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020010388 force_recompile();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020010389 current_emitting_switch->need_ladder_break = true;
10390 }
10391
10392 statement("_", current_emitting_switch->self, "_ladder_break = true;");
10393 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010394 statement("break;");
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020010395 }
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010010396 else if (is_continue(to) || (from == to))
10397 {
10398 // For from == to case can happen for a do-while loop which branches into itself.
10399 // We don't mark these cases as continue blocks, but the only possible way to branch into
10400 // ourselves is through means of continue blocks.
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010010401 branch_to_continue(from, to);
Hans-Kristian Arntzen9fbd8b72018-03-12 14:58:40 +010010402 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010403 else if (!is_conditional(to))
10404 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010010405
10406 // It is important that we check for break before continue.
10407 // A block might serve two purposes, a break block for the inner scope, and
10408 // a continue block in the outer scope.
10409 // Inner scope always takes precedence.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010410}
10411
10412void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block)
10413{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010414 // If we branch directly to a selection merge target, we don't really need a code path.
10415 bool true_sub = !is_conditional(true_block);
10416 bool false_sub = !is_conditional(false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010417
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010418 if (true_sub)
10419 {
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020010420 emit_block_hints(get<SPIRBlock>(from));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010421 statement("if (", to_expression(cond), ")");
10422 begin_scope();
10423 branch(from, true_block);
10424 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010425
Hans-Kristian Arntzen1de74fd2018-03-09 13:59:39 +010010426 if (false_sub || is_continue(false_block) || is_break(false_block))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010427 {
10428 statement("else");
10429 begin_scope();
10430 branch(from, false_block);
10431 end_scope();
10432 }
10433 else if (flush_phi_required(from, false_block))
10434 {
10435 statement("else");
10436 begin_scope();
10437 flush_phi(from, false_block);
10438 end_scope();
10439 }
10440 }
10441 else if (false_sub && !true_sub)
10442 {
10443 // Only need false path, use negative conditional.
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020010444 emit_block_hints(get<SPIRBlock>(from));
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010010445 statement("if (!", to_enclosed_expression(cond), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010446 begin_scope();
10447 branch(from, false_block);
10448 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010449
Hans-Kristian Arntzen1de74fd2018-03-09 13:59:39 +010010450 if (is_continue(true_block) || is_break(true_block))
10451 {
10452 statement("else");
10453 begin_scope();
10454 branch(from, true_block);
10455 end_scope();
10456 }
10457 else if (flush_phi_required(from, true_block))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010458 {
10459 statement("else");
10460 begin_scope();
10461 flush_phi(from, true_block);
10462 end_scope();
10463 }
10464 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010465}
10466
10467void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
10468{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010469 // Propagate down the loop dominator block, so that dominated blocks can back trace.
10470 if (block.merge == SPIRBlock::MergeLoop || block.loop_dominator)
10471 {
10472 uint32_t dominator = block.merge == SPIRBlock::MergeLoop ? block.self : block.loop_dominator;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010473
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +020010474 auto set_dominator = [this](uint32_t self, uint32_t new_dominator) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010475 auto &dominated_block = this->get<SPIRBlock>(self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010476
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010477 // If we already have a loop dominator, we're trying to break out to merge targets
10478 // which should not update the loop dominator.
10479 if (!dominated_block.loop_dominator)
10480 dominated_block.loop_dominator = new_dominator;
10481 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010482
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010483 // After merging a loop, we inherit the loop dominator always.
10484 if (block.merge_block)
10485 set_dominator(block.merge_block, block.loop_dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +020010486
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010487 if (block.true_block)
10488 set_dominator(block.true_block, dominator);
10489 if (block.false_block)
10490 set_dominator(block.false_block, dominator);
10491 if (block.next_block)
10492 set_dominator(block.next_block, dominator);
lifpane4d8ef22018-09-18 15:53:02 +080010493 if (block.default_block)
10494 set_dominator(block.default_block, dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +020010495
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010496 for (auto &c : block.cases)
10497 set_dominator(c.block, dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010498
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010499 // In older glslang output continue_block can be == loop header.
10500 if (block.continue_block && block.continue_block != block.self)
10501 set_dominator(block.continue_block, dominator);
10502 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010503}
10504
10505// FIXME: This currently cannot handle complex continue blocks
10506// as in do-while.
10507// This should be seen as a "trivial" continue block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010010508string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010509{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010510 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010512 // While emitting the continue block, declare_temporary will check this
10513 // if we have to emit temporaries.
10514 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010516 vector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010517
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010518 // Capture all statements into our list.
10519 auto *old = redirect_statement;
10520 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010521
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010522 // Stamp out all blocks one after each other.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010523 while ((ir.block_meta[block->self] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) == 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010524 {
10525 propagate_loop_dominators(*block);
10526 // Write out all instructions we have in this block.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010527 emit_block_instructions(*block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010529 // For plain branchless for/while continue blocks.
10530 if (block->next_block)
10531 {
10532 flush_phi(continue_block, block->next_block);
10533 block = &get<SPIRBlock>(block->next_block);
10534 }
10535 // For do while blocks. The last block will be a select block.
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010010536 else if (block->true_block && follow_true_block)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010537 {
10538 flush_phi(continue_block, block->true_block);
10539 block = &get<SPIRBlock>(block->true_block);
10540 }
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010010541 else if (block->false_block && follow_false_block)
10542 {
10543 flush_phi(continue_block, block->false_block);
10544 block = &get<SPIRBlock>(block->false_block);
10545 }
10546 else
10547 {
10548 SPIRV_CROSS_THROW("Invalid continue block detected!");
10549 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010550 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010551
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010552 // Restore old pointer.
10553 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010555 // Somewhat ugly, strip off the last ';' since we use ',' instead.
10556 // Ideally, we should select this behavior in statement().
10557 for (auto &s : statements)
10558 {
10559 if (!s.empty() && s.back() == ';')
Corentin Wallezef9ee492016-10-05 13:01:31 -040010560 s.erase(s.size() - 1, 1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010561 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010562
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010563 current_continue_block = nullptr;
10564 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010565}
10566
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020010567void CompilerGLSL::emit_while_loop_initializers(const SPIRBlock &block)
10568{
10569 // While loops do not take initializers, so declare all of them outside.
10570 for (auto &loop_var : block.loop_variables)
10571 {
10572 auto &var = get<SPIRVariable>(loop_var);
10573 statement(variable_decl(var), ";");
10574 }
10575}
10576
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010577string CompilerGLSL::emit_for_loop_initializers(const SPIRBlock &block)
10578{
10579 if (block.loop_variables.empty())
10580 return "";
10581
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010010582 bool same_types = for_loop_initializers_are_same_type(block);
10583 // We can only declare for loop initializers if all variables are of same type.
10584 // If we cannot do this, declare individual variables before the loop header.
10585
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010010586 // We might have a loop variable candidate which was not assigned to for some reason.
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010587 uint32_t missing_initializers = 0;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010010588 for (auto &variable : block.loop_variables)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010589 {
10590 uint32_t expr = get<SPIRVariable>(variable).static_expression;
Hans-Kristian Arntzen4a7a3722018-01-23 20:27:43 +010010591
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010592 // Sometimes loop variables are initialized with OpUndef, but we can just declare
10593 // a plain variable without initializer in this case.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010594 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010595 missing_initializers++;
10596 }
10597
10598 if (block.loop_variables.size() == 1 && missing_initializers == 0)
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010599 {
10600 return variable_decl(get<SPIRVariable>(block.loop_variables.front()));
10601 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010602 else if (!same_types || missing_initializers == uint32_t(block.loop_variables.size()))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010010603 {
10604 for (auto &loop_var : block.loop_variables)
10605 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
10606 return "";
10607 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010608 else
10609 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010610 // We have a mix of loop variables, either ones with a clear initializer, or ones without.
10611 // Separate the two streams.
10612 string expr;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010613
10614 for (auto &loop_var : block.loop_variables)
10615 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010616 uint32_t static_expr = get<SPIRVariable>(loop_var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010617 if (static_expr == 0 || ir.ids[static_expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010618 {
10619 statement(variable_decl(get<SPIRVariable>(loop_var)), ";");
10620 }
10621 else
10622 {
Chip Davis3bfb2f92018-12-03 02:06:33 -060010623 auto &var = get<SPIRVariable>(loop_var);
10624 auto &type = get_variable_data_type(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010625 if (expr.empty())
10626 {
10627 // For loop initializers are of the form <type id = value, id = value, id = value, etc ...
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010628 expr = join(to_qualifiers_glsl(var.self), type_to_glsl(type), " ");
10629 }
10630 else
Chip Davis3bfb2f92018-12-03 02:06:33 -060010631 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010632 expr += ", ";
Chip Davis3bfb2f92018-12-03 02:06:33 -060010633 // In MSL, being based on C++, the asterisk marking a pointer
10634 // binds to the identifier, not the type.
10635 if (type.pointer)
10636 expr += "* ";
10637 }
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010638
Chip Davis3bfb2f92018-12-03 02:06:33 -060010639 expr += join(to_name(loop_var), " = ", to_pointer_expression(var.static_expression));
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010640 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010641 }
10642 return expr;
10643 }
10644}
10645
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010010646bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
10647{
10648 if (block.loop_variables.size() <= 1)
10649 return true;
10650
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010651 uint32_t expected = 0;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010652 Bitset expected_flags;
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010010653 for (auto &var : block.loop_variables)
10654 {
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010655 // Don't care about uninitialized variables as they will not be part of the initializers.
10656 uint32_t expr = get<SPIRVariable>(var).static_expression;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020010657 if (expr == 0 || ir.ids[expr].get_type() == TypeUndef)
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010658 continue;
10659
10660 if (expected == 0)
10661 {
10662 expected = get<SPIRVariable>(var).basetype;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010663 expected_flags = get_decoration_bitset(var);
Hans-Kristian Arntzenaf0a8872018-01-23 21:15:09 +010010664 }
10665 else if (expected != get<SPIRVariable>(var).basetype)
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010010666 return false;
10667
10668 // Precision flags and things like that must also match.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010010669 if (expected_flags != get_decoration_bitset(var))
Hans-Kristian Arntzenb902d542018-01-16 10:27:58 +010010670 return false;
10671 }
10672
10673 return true;
10674}
10675
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010676bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
10677{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010678 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010679
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010010680 if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010681 {
10682 uint32_t current_count = statement_count;
10683 // If we're trying to create a true for loop,
10684 // we need to make sure that all opcodes before branch statement do not actually emit any code.
10685 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010686 emit_block_instructions(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010687
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010688 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010689
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010690 // This can work! We only did trivial things which could be forwarded in block body!
10691 if (current_count == statement_count && condition_is_temporary)
10692 {
10693 switch (continue_type)
10694 {
10695 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010010696 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010010697 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
10698 flush_undeclared_variables(block);
10699
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010010700 // Important that we do this in this order because
10701 // emitting the continue block can invalidate the condition expression.
10702 auto initializer = emit_for_loop_initializers(block);
10703 auto condition = to_expression(block.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010704
10705 // Condition might have to be inverted.
10706 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
10707 condition = join("!", enclose_expression(condition));
10708
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020010709 emit_block_hints(block);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010010710 if (method != SPIRBlock::MergeToSelectContinueForLoop)
10711 {
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010010712 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010010713 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
10714 }
10715 else
10716 statement("for (", initializer, "; ", condition, "; )");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010717 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010010718 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010719
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010720 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010721 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +010010722 // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
10723 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020010724 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020010725 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010726
10727 auto condition = to_expression(block.condition);
10728 // Condition might have to be inverted.
10729 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
10730 condition = join("!", enclose_expression(condition));
10731
10732 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010733 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010734 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010735
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010736 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010737 SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010738 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010740 begin_scope();
10741 return true;
10742 }
10743 else
10744 {
10745 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020010746 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010747 begin_scope(); // We'll see an end_scope() later.
10748 return false;
10749 }
10750 }
10751 else if (method == SPIRBlock::MergeToDirectForLoop)
10752 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010753 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010754
Hans-Kristian Arntzen5ff11cc2016-11-18 16:45:11 +010010755 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
10756 flush_undeclared_variables(child);
10757
10758 uint32_t current_count = statement_count;
10759
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010760 // If we're trying to create a true for loop,
10761 // we need to make sure that all opcodes before branch statement do not actually emit any code.
10762 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010763 emit_block_instructions(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010764
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010765 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010766
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010767 if (current_count == statement_count && condition_is_temporary)
10768 {
10769 propagate_loop_dominators(child);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010770 uint32_t target_block = child.true_block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010771
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010772 switch (continue_type)
10773 {
10774 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010010775 {
10776 // Important that we do this in this order because
10777 // emitting the continue block can invalidate the condition expression.
10778 auto initializer = emit_for_loop_initializers(block);
10779 auto condition = to_expression(child.condition);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010780
10781 // Condition might have to be inverted.
10782 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
10783 {
10784 condition = join("!", enclose_expression(condition));
10785 target_block = child.false_block;
10786 }
10787
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010010788 auto continue_block = emit_continue_block(block.continue_block, false, false);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020010789 emit_block_hints(block);
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010010790 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010791 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +010010792 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010793
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010794 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010795 {
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020010796 emit_while_loop_initializers(block);
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020010797 emit_block_hints(block);
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010798
10799 auto condition = to_expression(child.condition);
10800 // Condition might have to be inverted.
10801 if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
10802 {
10803 condition = join("!", enclose_expression(condition));
10804 target_block = child.false_block;
10805 }
10806
10807 statement("while (", condition, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010808 break;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010809 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010810
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010811 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010010812 SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010813 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010814
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010815 begin_scope();
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010816 branch(child.self, target_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010817 return true;
10818 }
10819 else
10820 {
10821 block.disable_block_optimization = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020010822 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010823 begin_scope(); // We'll see an end_scope() later.
10824 return false;
10825 }
10826 }
10827 else
10828 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010829}
10830
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010010831void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010832{
Hans-Kristian Arntzen7238e572017-11-22 13:20:17 +010010833 // Enforce declaration order for regression testing purposes.
10834 sort(begin(block.dominated_variables), end(block.dominated_variables));
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010010835 for (auto &v : block.dominated_variables)
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +010010836 flush_variable_declaration(v);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010837}
10838
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010010839void CompilerGLSL::emit_hoisted_temporaries(vector<pair<uint32_t, uint32_t>> &temporaries)
10840{
10841 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
10842 // Need to sort these to ensure that reference output is stable.
10843 sort(begin(temporaries), end(temporaries),
10844 [](const pair<uint32_t, uint32_t> &a, const pair<uint32_t, uint32_t> &b) { return a.second < b.second; });
10845
10846 for (auto &tmp : temporaries)
10847 {
10848 add_local_variable_name(tmp.second);
Hans-Kristian Arntzenc8ddf7e2019-01-07 11:47:01 +010010849 auto &flags = ir.meta[tmp.second].decoration.decoration_flags;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010010850 auto &type = get<SPIRType>(tmp.first);
10851 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";");
10852
10853 hoisted_temporaries.insert(tmp.second);
10854 forced_temporaries.insert(tmp.second);
10855
10856 // The temporary might be read from before it's assigned, set up the expression now.
10857 set<SPIRExpression>(tmp.second, to_name(tmp.second), tmp.first, true);
10858 }
10859}
10860
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010861void CompilerGLSL::emit_block_chain(SPIRBlock &block)
10862{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010863 propagate_loop_dominators(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010864
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010865 bool select_branch_to_true_block = false;
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010866 bool select_branch_to_false_block = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010867 bool skip_direct_branch = false;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010010868 bool emitted_loop_header_variables = false;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010010869 bool force_complex_continue_block = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010870
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010010871 emit_hoisted_temporaries(block.declare_temporary);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010872
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010873 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
10874 if (block.continue_block)
10875 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010876
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +010010877 // If we have loop variables, stop masking out access to the variable now.
10878 for (auto var : block.loop_variables)
10879 get<SPIRVariable>(var).loop_variable_enable = true;
10880
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010010881 // This is the method often used by spirv-opt to implement loops.
10882 // The loop header goes straight into the continue block.
10883 // However, don't attempt this on ESSL 1.0, because if a loop variable is used in a continue block,
10884 // it *MUST* be used in the continue block. This loop method will not work.
10885 if (!is_legacy_es() && block_is_loop_candidate(block, SPIRBlock::MergeToSelectContinueForLoop))
10886 {
10887 flush_undeclared_variables(block);
10888 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
10889 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010890 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
10891 select_branch_to_false_block = true;
10892 else
10893 select_branch_to_true_block = true;
10894
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010010895 emitted_loop_header_variables = true;
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010010896 force_complex_continue_block = true;
10897 }
10898 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010899 // 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 +010010900 else if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010901 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010010902 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010903 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
10904 {
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010010905 // The body of while, is actually just the true (or false) block, so always branch there unconditionally.
10906 if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
10907 select_branch_to_false_block = true;
10908 else
10909 select_branch_to_true_block = true;
10910
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010010911 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010912 }
10913 }
10914 // This is the newer loop behavior in glslang which branches from Loop header directly to
10915 // a new block, which in turn has a OpBranchSelection without a selection merge.
10916 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
10917 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010010918 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010919 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010920 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010921 skip_direct_branch = true;
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010010922 emitted_loop_header_variables = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010923 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010924 }
10925 else if (continue_type == SPIRBlock::DoWhileLoop)
10926 {
Hans-Kristian Arntzenb3f6e3d2018-01-24 19:46:53 +010010927 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020010928 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010010929 emitted_loop_header_variables = true;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010010930 // We have some temporaries where the loop header is the dominator.
10931 // We risk a case where we have code like:
10932 // for (;;) { create-temporary; break; } consume-temporary;
10933 // so force-declare temporaries here.
10934 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010935 statement("do");
10936 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010937
10938 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010939 }
10940 else if (block.merge == SPIRBlock::MergeLoop)
10941 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010010942 flush_undeclared_variables(block);
Hans-Kristian Arntzen3a268792018-08-06 12:52:22 +020010943 emit_while_loop_initializers(block);
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010010944 emitted_loop_header_variables = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010945
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010946 // We have a generic loop without any distinguishable pattern like for, while or do while.
10947 get<SPIRBlock>(block.continue_block).complex_continue = true;
10948 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010949
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +010010950 // We have some temporaries where the loop header is the dominator.
10951 // We risk a case where we have code like:
10952 // for (;;) { create-temporary; break; } consume-temporary;
10953 // so force-declare temporaries here.
10954 emit_hoisted_temporaries(block.potential_declare_temporary);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010955 statement("for (;;)");
10956 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010957
10958 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010959 }
10960 else
10961 {
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +020010962 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010963 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010964
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010965 // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
10966 // as writes to said loop variables might have been masked out, we need a recompile.
Hans-Kristian Arntzencff057c2019-03-06 12:30:11 +010010967 if (!emitted_loop_header_variables && !block.loop_variables.empty())
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010968 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020010969 force_recompile();
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +010010970 for (auto var : block.loop_variables)
10971 get<SPIRVariable>(var).loop_variable = false;
10972 block.loop_variables.clear();
10973 }
10974
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010010975 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010976 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010977
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010978 // Handle end of block.
10979 switch (block.terminator)
10980 {
10981 case SPIRBlock::Direct:
10982 // True when emitting complex continue block.
10983 if (block.loop_dominator == block.next_block)
10984 {
10985 branch(block.self, block.next_block);
10986 emit_next_block = false;
10987 }
10988 // True if MergeToDirectForLoop succeeded.
10989 else if (skip_direct_branch)
10990 emit_next_block = false;
10991 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
10992 {
10993 branch(block.self, block.next_block);
10994 emit_next_block = false;
10995 }
10996 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010010997
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020010998 case SPIRBlock::Select:
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010010999 // True if MergeToSelectForLoop or MergeToSelectContinueForLoop succeeded.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011000 if (select_branch_to_true_block)
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +010011001 {
11002 if (force_complex_continue_block)
11003 {
11004 assert(block.true_block == block.continue_block);
11005
11006 // We're going to emit a continue block directly here, so make sure it's marked as complex.
11007 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
11008 bool old_complex = complex_continue;
11009 complex_continue = true;
11010 branch(block.self, block.true_block);
11011 complex_continue = old_complex;
11012 }
11013 else
11014 branch(block.self, block.true_block);
11015 }
Hans-Kristian Arntzen70ff96b2019-03-06 11:24:43 +010011016 else if (select_branch_to_false_block)
11017 {
11018 if (force_complex_continue_block)
11019 {
11020 assert(block.false_block == block.continue_block);
11021
11022 // We're going to emit a continue block directly here, so make sure it's marked as complex.
11023 auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
11024 bool old_complex = complex_continue;
11025 complex_continue = true;
11026 branch(block.self, block.false_block);
11027 complex_continue = old_complex;
11028 }
11029 else
11030 branch(block.self, block.false_block);
11031 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011032 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011033 branch(block.self, block.condition, block.true_block, block.false_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011034 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011036 case SPIRBlock::MultiSelect:
11037 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011038 auto &type = expression_type(block.condition);
Chip Davis117ccf42018-11-01 17:20:07 -050011039 bool unsigned_case = type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011040
Hans-Kristian Arntzen45baf242019-03-20 10:42:38 +010011041 if (block.merge == SPIRBlock::MergeNone)
11042 SPIRV_CROSS_THROW("Switch statement is not structured");
11043
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010011044 if (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64)
11045 {
11046 // SPIR-V spec suggests this is allowed, but we cannot support it in higher level languages.
11047 SPIRV_CROSS_THROW("Cannot use 64-bit switch selectors.");
11048 }
11049
11050 const char *label_suffix = "";
11051 if (type.basetype == SPIRType::UInt && backend.uint32_t_literal_suffix)
11052 label_suffix = "u";
11053 else if (type.basetype == SPIRType::UShort)
11054 label_suffix = backend.uint16_t_literal_suffix;
11055 else if (type.basetype == SPIRType::Short)
11056 label_suffix = backend.int16_t_literal_suffix;
11057
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020011058 SPIRBlock *old_emitting_switch = current_emitting_switch;
11059 current_emitting_switch = &block;
11060
11061 if (block.need_ladder_break)
11062 statement("bool _", block.self, "_ladder_break = false;");
11063
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020011064 emit_block_hints(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011065 statement("switch (", to_expression(block.condition), ")");
11066 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011067
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020011068 // Multiple case labels can branch to same block, so find all unique blocks.
11069 bool emitted_default = false;
11070 unordered_set<uint32_t> emitted_blocks;
11071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011072 for (auto &c : block.cases)
11073 {
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020011074 if (emitted_blocks.count(c.block) != 0)
11075 continue;
11076
11077 // Emit all case labels which branch to our target.
11078 // FIXME: O(n^2), revisit if we hit shaders with 100++ case labels ...
11079 for (auto &other_case : block.cases)
11080 {
11081 if (other_case.block == c.block)
11082 {
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010011083 // The case label value must be sign-extended properly in SPIR-V, so we can assume 32-bit values here.
Chip Davis117ccf42018-11-01 17:20:07 -050011084 auto case_value = unsigned_case ? convert_to_string(uint32_t(other_case.value)) :
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020011085 convert_to_string(int32_t(other_case.value));
Hans-Kristian Arntzen04f410d2018-11-26 10:35:39 +010011086 statement("case ", case_value, label_suffix, ":");
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020011087 }
11088 }
11089
11090 // Maybe we share with default block?
11091 if (block.default_block == c.block)
11092 {
11093 statement("default:");
11094 emitted_default = true;
11095 }
11096
11097 // Complete the target.
11098 emitted_blocks.insert(c.block);
11099
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011100 begin_scope();
11101 branch(block.self, c.block);
11102 end_scope();
11103 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011104
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020011105 if (!emitted_default)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011106 {
Hans-Kristian Arntzen9d311542018-06-20 10:49:03 +020011107 if (block.default_block != block.next_block)
11108 {
11109 statement("default:");
11110 begin_scope();
11111 if (is_break(block.default_block))
11112 SPIRV_CROSS_THROW("Cannot break; out of a switch statement and out of a loop at the same time ...");
11113 branch(block.self, block.default_block);
11114 end_scope();
11115 }
11116 else if (flush_phi_required(block.self, block.next_block))
11117 {
11118 statement("default:");
11119 begin_scope();
11120 flush_phi(block.self, block.next_block);
11121 statement("break;");
11122 end_scope();
11123 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011124 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011125
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011126 end_scope();
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +020011127
11128 if (block.need_ladder_break)
11129 {
11130 statement("if (_", block.self, "_ladder_break)");
11131 begin_scope();
11132 statement("break;");
11133 end_scope();
11134 }
11135
11136 current_emitting_switch = old_emitting_switch;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011137 break;
11138 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011139
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011140 case SPIRBlock::Return:
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +020011141 for (auto &line : current_function->fixup_hooks_out)
11142 line();
Bill Hollings9b4defe2018-06-12 11:41:35 -040011143
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011144 if (processing_entry_point)
11145 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011146
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011147 if (block.return_value)
11148 {
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011149 auto &type = expression_type(block.return_value);
11150 if (!type.array.empty() && !backend.can_return_array)
11151 {
11152 // If we cannot return arrays, we will have a special out argument we can write to instead.
11153 // The backend is responsible for setting this up, and redirection the return values as appropriate.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010011154 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011155 emit_array_copy("SPIRV_Cross_return_value", block.return_value);
11156
11157 if (!block_is_outside_flow_control_from_block(get<SPIRBlock>(current_function->entry_block), block) ||
11158 block.loop_dominator != SPIRBlock::NoDominator)
11159 {
11160 statement("return;");
11161 }
11162 }
11163 else
11164 {
11165 // OpReturnValue can return Undef, so don't emit anything for this case.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010011166 if (ir.ids[block.return_value].get_type() != TypeUndef)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011167 statement("return ", to_expression(block.return_value), ";");
11168 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011169 }
11170 // If this block is the very final block and not called from control flow,
11171 // we do not need an explicit return which looks out of place. Just end the function here.
11172 // In the very weird case of for(;;) { return; } executing return is unconditional,
11173 // but we actually need a return here ...
11174 else if (!block_is_outside_flow_control_from_block(get<SPIRBlock>(current_function->entry_block), block) ||
11175 block.loop_dominator != SPIRBlock::NoDominator)
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011176 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011177 statement("return;");
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011178 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011179 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011180
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011181 case SPIRBlock::Kill:
Bill Hollings943191a2016-10-27 10:20:01 -040011182 statement(backend.discard_literal, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011183 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011184
Hans-Kristian Arntzen0f4adaa2018-01-15 09:35:09 +010011185 case SPIRBlock::Unreachable:
11186 emit_next_block = false;
11187 break;
11188
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011189 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011190 SPIRV_CROSS_THROW("Unimplemented block terminator.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011191 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011193 if (block.next_block && emit_next_block)
11194 {
11195 // If we hit this case, we're dealing with an unconditional branch, which means we will output
11196 // that block after this. If we had selection merge, we already flushed phi variables.
11197 if (block.merge != SPIRBlock::MergeSelection)
11198 flush_phi(block.self, block.next_block);
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010011199
11200 // For merge selects we might have ignored the fact that a merge target
11201 // could have been a break; or continue;
11202 // We will need to deal with it here.
11203 if (is_loop_break(block.next_block))
11204 {
11205 // Cannot check for just break, because switch statements will also use break.
11206 assert(block.merge == SPIRBlock::MergeSelection);
11207 statement("break;");
11208 }
11209 else if (is_continue(block.next_block))
11210 {
11211 assert(block.merge == SPIRBlock::MergeSelection);
11212 branch_to_continue(block.self, block.next_block);
11213 }
11214 else
11215 emit_block_chain(get<SPIRBlock>(block.next_block));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011216 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011218 if (block.merge == SPIRBlock::MergeLoop)
11219 {
11220 if (continue_type == SPIRBlock::DoWhileLoop)
11221 {
11222 // Make sure that we run the continue block to get the expressions set, but this
11223 // should become an empty string.
11224 // We have no fallbacks if we cannot forward everything to temporaries ...
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010011225 const auto &continue_block = get<SPIRBlock>(block.continue_block);
Hans-Kristian Arntzen8bfb04d2019-03-06 12:20:13 +010011226 bool positive_test = execution_is_noop(get<SPIRBlock>(continue_block.true_block),
11227 get<SPIRBlock>(continue_block.loop_dominator));
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010011228
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011229 uint32_t current_count = statement_count;
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010011230 auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011231 if (statement_count != current_count)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011232 {
11233 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
11234 get<SPIRBlock>(block.continue_block).complex_continue = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +020011235 force_recompile();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011236 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011237
Hans-Kristian Arntzenef243372019-03-06 12:17:38 +010011238 // Might have to invert the do-while test here.
11239 auto condition = to_expression(continue_block.condition);
11240 if (!positive_test)
11241 condition = join("!", enclose_expression(condition));
11242
11243 end_scope_decl(join("while (", condition, ")"));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011244 }
11245 else
11246 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011247
Hans-Kristian Arntzen8d557d42018-03-08 14:01:10 +010011248 // We cannot break out of two loops at once, so don't check for break; here.
11249 // Using block.self as the "from" block isn't quite right, but it has the same scope
11250 // and dominance structure, so it's fine.
11251 if (is_continue(block.merge_block))
11252 branch_to_continue(block.self, block.merge_block);
11253 else
11254 emit_block_chain(get<SPIRBlock>(block.merge_block));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011255 }
Hans-Kristian Arntzenf6c0e532018-04-10 16:13:33 +020011256
11257 // Forget about control dependent expressions now.
11258 block.invalidate_expressions.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011259}
11260
11261void CompilerGLSL::begin_scope()
11262{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011263 statement("{");
11264 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011265}
11266
11267void CompilerGLSL::end_scope()
11268{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011269 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011270 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011271 indent--;
11272 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011273}
11274
11275void CompilerGLSL::end_scope_decl()
11276{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011277 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011278 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011279 indent--;
11280 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011281}
11282
11283void CompilerGLSL::end_scope_decl(const string &decl)
11284{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011285 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011286 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020011287 indent--;
11288 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010011289}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011290
11291void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
11292{
11293 // If our variable is remapped, and we rely on type-remapping information as
11294 // well, then we cannot pass the variable as a function parameter.
11295 // Fixing this is non-trivial without stamping out variants of the same function,
11296 // so for now warn about this and suggest workarounds instead.
11297 for (uint32_t i = 0; i < length; i++)
11298 {
11299 auto *var = maybe_get<SPIRVariable>(args[i]);
11300 if (!var || !var->remapped_variable)
11301 continue;
11302
11303 auto &type = get<SPIRType>(var->basetype);
11304 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
11305 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +010011306 SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
11307 "This will not work correctly because type-remapping information is lost. "
11308 "To workaround, please consider not passing the subpass input as a function parameter, "
11309 "or use in/out variables instead which do not need type remapping information.");
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020011310 }
11311 }
11312}
Hans-Kristian Arntzen9c72aa02018-01-09 12:07:07 +010011313
11314const Instruction *CompilerGLSL::get_next_instruction_in_block(const Instruction &instr)
11315{
11316 // FIXME: This is kind of hacky. There should be a cleaner way.
11317 auto offset = uint32_t(&instr - current_emitting_block->ops.data());
11318 if ((offset + 1) < current_emitting_block->ops.size())
11319 return &current_emitting_block->ops[offset + 1];
11320 else
11321 return nullptr;
11322}
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010011323
11324uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
11325{
Hans-Kristian Arntzen44a4eb72018-01-09 12:51:21 +010011326 return semantics & (MemorySemanticsAtomicCounterMemoryMask | MemorySemanticsImageMemoryMask |
11327 MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask |
11328 MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +010011329}
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +010011330
11331void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t rhs_id)
11332{
11333 statement(lhs, " = ", to_expression(rhs_id), ";");
11334}
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020011335
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011336void 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 +010011337{
11338 if (!backend.force_gl_in_out_block)
11339 return;
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011340 // This path is only relevant for GL backends.
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011341
11342 auto *var = maybe_get<SPIRVariable>(source_id);
11343 if (!var)
11344 return;
11345
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011346 if (var->storage != StorageClassInput)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011347 return;
11348
11349 auto &type = get_variable_data_type(*var);
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011350 if (type.array.empty())
11351 return;
11352
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011353 auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn));
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011354 bool is_builtin = is_builtin_variable(*var) && (builtin == BuiltInPointSize || builtin == BuiltInPosition);
11355 bool is_tess = is_tessellation_shader();
11356
11357 // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it.
11358 // We must unroll the array load.
11359 // For builtins, we couldn't catch this case normally,
11360 // because this is resolved in the OpAccessChain in most cases.
11361 // If we load the entire array, we have no choice but to unroll here.
11362 if (is_builtin || is_tess)
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011363 {
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011364 auto new_expr = join("_", target_id, "_unrolled");
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011365 statement(variable_decl(type, new_expr, target_id), ";");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011366 string array_expr;
11367 if (type.array_size_literal.front())
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011368 {
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011369 array_expr = convert_to_string(type.array.front());
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011370 if (type.array.front() == 0)
11371 SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array.");
11372 }
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011373 else
11374 array_expr = to_expression(type.array.front());
11375
11376 // The array size might be a specialization constant, so use a for-loop instead.
11377 statement("for (int i = 0; i < int(", array_expr, "); i++)");
11378 begin_scope();
Hans-Kristian Arntzen0b201802019-03-21 11:50:53 +010011379 if (is_builtin)
11380 statement(new_expr, "[i] = gl_in[i].", expr, ";");
11381 else
11382 statement(new_expr, "[i] = ", expr, "[i];");
Hans-Kristian Arntzend2961b32019-03-21 11:25:41 +010011383 end_scope();
11384
11385 expr = move(new_expr);
11386 }
11387}
11388
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020011389void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &expr,
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010011390 const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020011391{
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020011392 auto *var = maybe_get_backing_variable(source_id);
11393 if (var)
11394 source_id = var->self;
11395
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020011396 // Only interested in standalone builtin variables.
11397 if (!has_decoration(source_id, DecorationBuiltIn))
11398 return;
11399
11400 auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
11401 auto expected_type = expr_type.basetype;
11402
11403 // TODO: Fill in for more builtins.
11404 switch (builtin)
11405 {
11406 case BuiltInLayer:
11407 case BuiltInPrimitiveId:
11408 case BuiltInViewportIndex:
11409 case BuiltInInstanceId:
11410 case BuiltInInstanceIndex:
11411 case BuiltInVertexId:
11412 case BuiltInVertexIndex:
11413 case BuiltInSampleId:
Chip Davisfcad0192018-08-28 13:47:29 -050011414 case BuiltInBaseVertex:
11415 case BuiltInBaseInstance:
11416 case BuiltInDrawIndex:
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020011417 expected_type = SPIRType::Int;
11418 break;
11419
Hans-Kristian Arntzen32a0d052018-09-11 09:42:55 +020011420 case BuiltInGlobalInvocationId:
11421 case BuiltInLocalInvocationId:
11422 case BuiltInWorkgroupId:
11423 case BuiltInLocalInvocationIndex:
11424 case BuiltInWorkgroupSize:
11425 case BuiltInNumWorkgroups:
11426 expected_type = SPIRType::UInt;
11427 break;
11428
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020011429 default:
11430 break;
11431 }
11432
11433 if (expected_type != expr_type.basetype)
11434 expr = bitcast_expression(expr_type, expected_type, expr);
11435}
11436
11437void CompilerGLSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr,
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010011438 const SPIRType &expr_type)
Hans-Kristian Arntzend94d20f2018-06-22 11:30:13 +020011439{
11440 // Only interested in standalone builtin variables.
11441 if (!has_decoration(target_id, DecorationBuiltIn))
11442 return;
11443
11444 auto builtin = static_cast<BuiltIn>(get_decoration(target_id, DecorationBuiltIn));
11445 auto expected_type = expr_type.basetype;
11446
11447 // TODO: Fill in for more builtins.
11448 switch (builtin)
11449 {
11450 case BuiltInLayer:
11451 case BuiltInPrimitiveId:
11452 case BuiltInViewportIndex:
11453 expected_type = SPIRType::Int;
11454 break;
11455
11456 default:
11457 break;
11458 }
11459
11460 if (expected_type != expr_type.basetype)
11461 {
11462 auto type = expr_type;
11463 type.basetype = expected_type;
11464 expr = bitcast_expression(type, expr_type.basetype, expr);
11465 }
11466}
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +020011467
11468void CompilerGLSL::emit_block_hints(const SPIRBlock &)
11469{
11470}
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +010011471
11472void CompilerGLSL::preserve_alias_on_reset(uint32_t id)
11473{
11474 preserved_aliases[id] = get_name(id);
11475}
11476
11477void CompilerGLSL::reset_name_caches()
11478{
11479 for (auto &preserved : preserved_aliases)
11480 set_name(preserved.first, preserved.second);
11481
11482 preserved_aliases.clear();
11483 resource_names.clear();
11484 block_input_names.clear();
11485 block_output_names.clear();
11486 block_ubo_names.clear();
11487 block_ssbo_names.clear();
11488 block_names.clear();
11489 function_overloads.clear();
11490}