blob: 51529496512a863599aae91fbffd9670dfb0dbfa [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzen18c37bc2017-01-28 09:00:40 +01002 * Copyright 2015-2017 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 Arntzen3eb2e522017-01-21 13:49:32 +010022#include <utility>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010023
24using namespace spv;
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020025using namespace spirv_cross;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010026using namespace std;
27
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +020028static bool packing_is_vec4_padded(BufferPackingStandard packing)
29{
30 switch (packing)
31 {
32 case BufferPackingHLSLCbuffer:
33 case BufferPackingHLSLCbufferPackOffset:
34 case BufferPackingStd140:
35 case BufferPackingStd140EnhancedLayout:
36 return true;
37
38 default:
39 return false;
40 }
41}
42
43static bool packing_is_hlsl(BufferPackingStandard packing)
44{
45 switch (packing)
46 {
47 case BufferPackingHLSLCbuffer:
48 case BufferPackingHLSLCbufferPackOffset:
49 return true;
50
51 default:
52 return false;
53 }
54}
55
56static bool packing_has_flexible_offset(BufferPackingStandard packing)
57{
58 switch (packing)
59 {
60 case BufferPackingStd140:
61 case BufferPackingStd430:
62 case BufferPackingHLSLCbuffer:
63 return false;
64
65 default:
66 return true;
67 }
68}
69
70static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard packing)
71{
72 switch (packing)
73 {
74 case BufferPackingStd140EnhancedLayout:
75 return BufferPackingStd140;
76 case BufferPackingStd430EnhancedLayout:
77 return BufferPackingStd430;
78 case BufferPackingHLSLCbufferPackOffset:
79 return BufferPackingHLSLCbuffer;
80 default:
81 return packing;
82 }
83}
84
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +010085// Sanitizes underscores for GLSL where multiple underscores in a row are not allowed.
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +020086string CompilerGLSL::sanitize_underscores(const string &str)
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +010087{
88 string res;
89 res.reserve(str.size());
90
91 bool last_underscore = false;
92 for (auto c : str)
93 {
94 if (c == '_')
95 {
96 if (last_underscore)
97 continue;
98
99 res += c;
100 last_underscore = true;
101 }
102 else
103 {
104 res += c;
105 last_underscore = false;
106 }
107 }
108 return res;
109}
110
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +0200111// Returns true if an arithmetic operation does not change behavior depending on signedness.
112static bool opcode_is_sign_invariant(Op opcode)
113{
114 switch (opcode)
115 {
116 case OpIEqual:
117 case OpINotEqual:
118 case OpISub:
119 case OpIAdd:
120 case OpIMul:
121 case OpShiftLeftLogical:
122 case OpBitwiseOr:
123 case OpBitwiseXor:
124 case OpBitwiseAnd:
125 return true;
126
127 default:
128 return false;
129 }
130}
131
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200132static const char *to_pls_layout(PlsFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100133{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200134 switch (format)
135 {
136 case PlsR11FG11FB10F:
137 return "layout(r11f_g11f_b10f) ";
138 case PlsR32F:
139 return "layout(r32f) ";
140 case PlsRG16F:
141 return "layout(rg16f) ";
142 case PlsRGB10A2:
143 return "layout(rgb10_a2) ";
144 case PlsRGBA8:
145 return "layout(rgba8) ";
146 case PlsRG16:
147 return "layout(rg16) ";
148 case PlsRGBA8I:
149 return "layout(rgba8i)";
150 case PlsRG16I:
151 return "layout(rg16i) ";
152 case PlsRGB10A2UI:
153 return "layout(rgb10_a2ui) ";
154 case PlsRGBA8UI:
155 return "layout(rgba8ui) ";
156 case PlsRG16UI:
157 return "layout(rg16ui) ";
158 case PlsR32UI:
159 return "layout(r32ui) ";
160 default:
161 return "";
162 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100163}
164
165static SPIRType::BaseType pls_format_to_basetype(PlsFormat format)
166{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200167 switch (format)
168 {
169 default:
170 case PlsR11FG11FB10F:
171 case PlsR32F:
172 case PlsRG16F:
173 case PlsRGB10A2:
174 case PlsRGBA8:
175 case PlsRG16:
176 return SPIRType::Float;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200178 case PlsRGBA8I:
179 case PlsRG16I:
180 return SPIRType::Int;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100181
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200182 case PlsRGB10A2UI:
183 case PlsRGBA8UI:
184 case PlsRG16UI:
185 case PlsR32UI:
186 return SPIRType::UInt;
187 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100188}
189
190static uint32_t pls_format_to_components(PlsFormat format)
191{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200192 switch (format)
193 {
194 default:
195 case PlsR32F:
196 case PlsR32UI:
197 return 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100198
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200199 case PlsRG16F:
200 case PlsRG16:
201 case PlsRG16UI:
202 case PlsRG16I:
203 return 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100204
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200205 case PlsR11FG11FB10F:
206 return 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100207
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200208 case PlsRGB10A2:
209 case PlsRGBA8:
210 case PlsRGBA8I:
211 case PlsRGB10A2UI:
212 case PlsRGBA8UI:
213 return 4;
214 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100215}
216
Bill Hollings2d0d3282017-01-20 11:33:59 -0500217static const char *vector_swizzle(int vecsize, int index)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800218{
Bill Hollings2d0d3282017-01-20 11:33:59 -0500219 static const char *swizzle[4][4] = {
220 { ".x", ".y", ".z", ".w" }, { ".xy", ".yz", ".zw" }, { ".xyz", ".yzw" }, { "" }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -0800221 };
222
223 assert(vecsize >= 1 && vecsize <= 4);
224 assert(index >= 0 && index < 4);
225 assert(swizzle[vecsize - 1][index]);
226
227 return swizzle[vecsize - 1][index];
228}
229
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100230void CompilerGLSL::reset()
231{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200232 // We do some speculative optimizations which should pretty much always work out,
233 // but just in case the SPIR-V is rather weird, recompile until it's happy.
234 // This typically only means one extra pass.
235 force_recompile = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100236
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200237 // Clear invalid expression tracking.
238 invalid_expressions.clear();
239 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100240
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200241 // Clear temporary usage tracking.
242 expression_usage_counts.clear();
243 forwarded_temporaries.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100244
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200245 resource_names.clear();
246
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200247 for (auto &id : ids)
248 {
249 if (id.get_type() == TypeVariable)
250 {
251 // Clear unflushed dependees.
252 id.get<SPIRVariable>().dependees.clear();
253 }
254 else if (id.get_type() == TypeExpression)
255 {
256 // And remove all expressions.
257 id.reset();
258 }
259 else if (id.get_type() == TypeFunction)
260 {
261 // Reset active state for all functions.
262 id.get<SPIRFunction>().active = false;
263 id.get<SPIRFunction>().flush_undeclared = true;
264 }
265 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100266
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200267 statement_count = 0;
268 indent = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100269}
270
271void CompilerGLSL::remap_pls_variables()
272{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200273 for (auto &input : pls_inputs)
274 {
275 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100276
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200277 bool input_is_target = false;
278 if (var.storage == StorageClassUniformConstant)
279 {
280 auto &type = get<SPIRType>(var.basetype);
281 input_is_target = type.image.dim == DimSubpassData;
282 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100283
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200284 if (var.storage != StorageClassInput && !input_is_target)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100285 SPIRV_CROSS_THROW("Can only use in and target variables for PLS inputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200286 var.remapped_variable = true;
287 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200289 for (auto &output : pls_outputs)
290 {
291 auto &var = get<SPIRVariable>(output.id);
292 if (var.storage != StorageClassOutput)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100293 SPIRV_CROSS_THROW("Can only use out variables for PLS outputs.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200294 var.remapped_variable = true;
295 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100296}
297
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200298void CompilerGLSL::find_static_extensions()
299{
300 for (auto &id : ids)
301 {
302 if (id.get_type() == TypeType)
303 {
304 auto &type = id.get<SPIRType>();
305 if (type.basetype == SPIRType::Double)
306 {
307 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100308 SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200309 if (!options.es && options.version < 400)
310 require_extension("GL_ARB_gpu_shader_fp64");
311 }
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200312
313 if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
314 {
315 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100316 SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200317 if (!options.es)
318 require_extension("GL_ARB_gpu_shader_int64");
319 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200320 }
321 }
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200322
323 auto &execution = get_entry_point();
324 switch (execution.model)
325 {
326 case ExecutionModelGLCompute:
327 if (!options.es && options.version < 430)
328 require_extension("GL_ARB_compute_shader");
329 if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100330 SPIRV_CROSS_THROW("At least ESSL 3.10 required for compute shaders.");
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200331 break;
332
333 case ExecutionModelGeometry:
334 if (options.es && options.version < 320)
335 require_extension("GL_EXT_geometry_shader");
robfb1820e2017-06-17 10:06:46 +0900336 if (!options.es && options.version < 150)
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200337 require_extension("GL_ARB_geometry_shader4");
338
339 if ((execution.flags & (1ull << ExecutionModeInvocations)) && execution.invocations != 1)
340 {
341 // Instanced GS is part of 400 core or this extension.
342 if (!options.es && options.version < 400)
343 require_extension("GL_ARB_gpu_shader5");
344 }
345 break;
346
347 case ExecutionModelTessellationEvaluation:
348 case ExecutionModelTessellationControl:
349 if (options.es && options.version < 320)
350 require_extension("GL_EXT_tessellation_shader");
351 if (!options.es && options.version < 400)
352 require_extension("GL_ARB_tessellation_shader");
353 break;
354
355 default:
356 break;
357 }
358
359 if (!pls_inputs.empty() || !pls_outputs.empty())
360 require_extension("GL_EXT_shader_pixel_local_storage");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +0200361
362 if (options.separate_shader_objects && !options.es && options.version < 410)
363 require_extension("GL_ARB_separate_shader_objects");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200364}
365
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100366string CompilerGLSL::compile()
367{
Endre Oma6ad8b302017-01-11 15:57:05 +0100368 // Force a classic "C" locale, reverts when function returns
369 ClassicLocale classic_locale;
370
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200371 // Scan the SPIR-V to find trivial uses of extensions.
372 find_static_extensions();
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +0100373 fixup_image_load_store_access();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +0100374 update_active_builtins();
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +0200375 analyze_sampler_comparison_states();
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200376
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200377 uint32_t pass_count = 0;
378 do
379 {
380 if (pass_count >= 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100381 SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100382
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200383 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200385 // Move constructor for this type is broken on GCC 4.9 ...
386 buffer = unique_ptr<ostringstream>(new ostringstream());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100387
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200388 emit_header();
389 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100390
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200391 emit_function(get<SPIRFunction>(entry_point), 0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100392
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200393 pass_count++;
394 } while (force_recompile);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100395
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +0100396 // Entry point in GLSL is always main().
397 get_entry_point().name = "main";
398
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200399 return buffer->str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100400}
401
Bill Hollingsc5c07362016-11-27 12:34:04 -0500402std::string CompilerGLSL::get_partial_source()
403{
Bill Hollingsf591bc02017-06-30 19:10:46 -0400404 return buffer ? buffer->str() : "No compiled source available yet.";
Bill Hollingsc5c07362016-11-27 12:34:04 -0500405}
406
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100407void CompilerGLSL::emit_header()
408{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200409 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200410 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100411
Ben Claytone9621822017-10-09 10:33:42 +0100412 if (!options.es && options.version < 420)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200413 {
Ben Claytone9621822017-10-09 10:33:42 +0100414 // Needed for binding = # on UBOs, etc.
415 if (options.enable_420pack_extension)
416 {
417 statement("#ifdef GL_ARB_shading_language_420pack");
418 statement("#extension GL_ARB_shading_language_420pack : require");
419 statement("#endif");
420 }
421 // Needed for: layout(early_fragment_tests) in;
422 if (execution.flags & (1ull << ExecutionModeEarlyFragmentTests))
423 require_extension("GL_ARB_shader_image_load_store");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200424 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100425
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200426 for (auto &ext : forced_extensions)
427 statement("#extension ", ext, " : require");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100428
Hans-Kristian Arntzen6204d8e2016-09-23 14:21:30 +0200429 for (auto &header : header_lines)
430 statement(header);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200432 vector<string> inputs;
433 vector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100434
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200435 switch (execution.model)
436 {
437 case ExecutionModelGeometry:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200438 outputs.push_back(join("max_vertices = ", execution.output_vertices));
Hans-Kristian Arntzen05a97882016-06-23 13:42:59 +0200439 if ((execution.flags & (1ull << ExecutionModeInvocations)) && execution.invocations != 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200440 inputs.push_back(join("invocations = ", execution.invocations));
441 if (execution.flags & (1ull << ExecutionModeInputPoints))
442 inputs.push_back("points");
443 if (execution.flags & (1ull << ExecutionModeInputLines))
444 inputs.push_back("lines");
445 if (execution.flags & (1ull << ExecutionModeInputLinesAdjacency))
446 inputs.push_back("lines_adjacency");
447 if (execution.flags & (1ull << ExecutionModeTriangles))
448 inputs.push_back("triangles");
449 if (execution.flags & (1ull << ExecutionModeInputTrianglesAdjacency))
450 inputs.push_back("triangles_adjacency");
451 if (execution.flags & (1ull << ExecutionModeOutputTriangleStrip))
452 outputs.push_back("triangle_strip");
453 if (execution.flags & (1ull << ExecutionModeOutputPoints))
454 outputs.push_back("points");
455 if (execution.flags & (1ull << ExecutionModeOutputLineStrip))
456 outputs.push_back("line_strip");
457 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100458
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200459 case ExecutionModelTessellationControl:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200460 if (execution.flags & (1ull << ExecutionModeOutputVertices))
461 outputs.push_back(join("vertices = ", execution.output_vertices));
462 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100463
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200464 case ExecutionModelTessellationEvaluation:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200465 if (execution.flags & (1ull << ExecutionModeQuads))
466 inputs.push_back("quads");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200467 if (execution.flags & (1ull << ExecutionModeTriangles))
468 inputs.push_back("triangles");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200469 if (execution.flags & (1ull << ExecutionModeIsolines))
470 inputs.push_back("isolines");
471 if (execution.flags & (1ull << ExecutionModePointMode))
472 inputs.push_back("point_mode");
Hans-Kristian Arntzenf3220832016-09-28 08:12:04 +0200473
474 if ((execution.flags & (1ull << ExecutionModeIsolines)) == 0)
475 {
476 if (execution.flags & (1ull << ExecutionModeVertexOrderCw))
477 inputs.push_back("cw");
478 if (execution.flags & (1ull << ExecutionModeVertexOrderCcw))
479 inputs.push_back("ccw");
480 }
481
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200482 if (execution.flags & (1ull << ExecutionModeSpacingFractionalEven))
483 inputs.push_back("fractional_even_spacing");
484 if (execution.flags & (1ull << ExecutionModeSpacingFractionalOdd))
485 inputs.push_back("fractional_odd_spacing");
486 if (execution.flags & (1ull << ExecutionModeSpacingEqual))
487 inputs.push_back("equal_spacing");
488 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100489
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200490 case ExecutionModelGLCompute:
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200491 {
492 if (execution.workgroup_size.constant != 0)
493 {
494 SpecializationConstant wg_x, wg_y, wg_z;
495 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
496
Hans-Kristian Arntzen6583de82017-09-29 10:33:28 +0200497 if (wg_x.id)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200498 {
499 if (options.vulkan_semantics)
500 inputs.push_back(join("local_size_x_id = ", wg_x.constant_id));
501 else
502 inputs.push_back(join("local_size_x = ", get<SPIRConstant>(wg_x.id).scalar()));
503 }
504 else
505 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
506
Hans-Kristian Arntzen6583de82017-09-29 10:33:28 +0200507 if (wg_y.id)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200508 {
509 if (options.vulkan_semantics)
510 inputs.push_back(join("local_size_y_id = ", wg_y.constant_id));
511 else
512 inputs.push_back(join("local_size_y = ", get<SPIRConstant>(wg_y.id).scalar()));
513 }
514 else
515 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
516
Hans-Kristian Arntzen6583de82017-09-29 10:33:28 +0200517 if (wg_z.id)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200518 {
519 if (options.vulkan_semantics)
520 inputs.push_back(join("local_size_z_id = ", wg_z.constant_id));
521 else
522 inputs.push_back(join("local_size_z = ", get<SPIRConstant>(wg_z.id).scalar()));
523 }
524 else
525 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
526 }
527 else
528 {
529 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
530 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
531 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
532 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200533 break;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200534 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100535
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200536 case ExecutionModelFragment:
537 if (options.es)
538 {
539 switch (options.fragment.default_float_precision)
540 {
541 case Options::Lowp:
542 statement("precision lowp float;");
543 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200545 case Options::Mediump:
546 statement("precision mediump float;");
547 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100548
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200549 case Options::Highp:
550 statement("precision highp float;");
551 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100552
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200553 default:
554 break;
555 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200557 switch (options.fragment.default_int_precision)
558 {
559 case Options::Lowp:
560 statement("precision lowp int;");
561 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100562
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200563 case Options::Mediump:
564 statement("precision mediump int;");
565 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100566
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200567 case Options::Highp:
568 statement("precision highp int;");
569 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100570
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200571 default:
572 break;
573 }
574 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200576 if (execution.flags & (1ull << ExecutionModeEarlyFragmentTests))
577 inputs.push_back("early_fragment_tests");
578 if (execution.flags & (1ull << ExecutionModeDepthGreater))
579 inputs.push_back("depth_greater");
580 if (execution.flags & (1ull << ExecutionModeDepthLess))
581 inputs.push_back("depth_less");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100582
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200583 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100584
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200585 default:
586 break;
587 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100588
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200589 if (!inputs.empty())
590 statement("layout(", merge(inputs), ") in;");
591 if (!outputs.empty())
592 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100593
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200594 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100595}
596
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +0100597bool CompilerGLSL::type_is_empty(const SPIRType &type)
598{
599 return type.basetype == SPIRType::Struct && type.member_types.empty();
600}
601
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200602void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100603{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200604 // Struct types can be stamped out multiple times
605 // with just different offsets, matrix layouts, etc ...
606 // Type-punning with these types is legal, which complicates things
607 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200608 if (type.type_alias != 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200609 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200610
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +0100611 // Don't declare empty structs in GLSL, this is not allowed.
612 // Empty structs is a corner case of HLSL output, and only sensible thing to do is avoiding to declare
613 // these types.
614 if (type_is_empty(type))
615 return;
616
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200617 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200618 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100619
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200620 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200621 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100622
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200623 type.member_name_cache.clear();
624
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200625 uint32_t i = 0;
626 bool emitted = false;
627 for (auto &member : type.member_types)
628 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200629 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -0500630 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200631 i++;
632 emitted = true;
633 }
634 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200636 if (emitted)
637 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100638}
639
640uint64_t CompilerGLSL::combined_decoration_for_member(const SPIRType &type, uint32_t index)
641{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200642 uint64_t flags = 0;
643 auto &memb = meta[type.self].members;
644 if (index >= memb.size())
645 return 0;
646 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100647
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200648 // If our type is a struct, traverse all the members as well recursively.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200649 flags |= dec.decoration_flags;
650 for (uint32_t i = 0; i < type.member_types.size(); i++)
651 flags |= combined_decoration_for_member(get<SPIRType>(type.member_types[i]), i);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100652
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200653 return flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100654}
655
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +0200656string CompilerGLSL::to_interpolation_qualifiers(uint64_t flags)
657{
658 string res;
659 //if (flags & (1ull << DecorationSmooth))
660 // res += "smooth ";
661 if (flags & (1ull << DecorationFlat))
662 res += "flat ";
663 if (flags & (1ull << DecorationNoPerspective))
664 res += "noperspective ";
665 if (flags & (1ull << DecorationCentroid))
666 res += "centroid ";
667 if (flags & (1ull << DecorationPatch))
668 res += "patch ";
669 if (flags & (1ull << DecorationSample))
670 res += "sample ";
671 if (flags & (1ull << DecorationInvariant))
672 res += "invariant ";
673
674 return res;
675}
676
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100677string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
678{
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +0100679 if (is_legacy())
680 return "";
681
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200682 bool is_block = (meta[type.self].decoration.decoration_flags &
683 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
684 if (!is_block)
685 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200687 auto &memb = meta[type.self].members;
688 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +0200689 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200690 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100691
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200692 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100693
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200694 // We can only apply layouts on members in block interfaces.
695 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
696 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
697 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
698 //
699 // We would like to go from (SPIR-V style):
700 //
701 // struct Foo { layout(row_major) mat4 matrix; };
702 // buffer UBO { Foo foo; };
703 //
704 // to
705 //
706 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
707 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
708 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100709
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200710 if (flags & (1ull << DecorationRowMajor))
711 attr.push_back("row_major");
712 // We don't emit any global layouts, so column_major is default.
713 //if (flags & (1ull << DecorationColMajor))
714 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100715
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +0200716 if ((dec.decoration_flags & (1ull << DecorationLocation)) != 0 && can_use_io_location(type.storage))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200717 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100718
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +0200719 // DecorationCPacked is set by layout_for_variable earlier to mark that we need to emit offset qualifiers.
720 // This is only done selectively in GLSL as needed.
721 if (has_decoration(type.self, DecorationCPacked) && (dec.decoration_flags & (1ull << DecorationOffset)) != 0)
722 attr.push_back(join("offset = ", dec.offset));
723
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200724 if (attr.empty())
725 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100726
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200727 string res = "layout(";
728 res += merge(attr);
729 res += ") ";
730 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100731}
732
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200733const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100734{
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200735 auto check_desktop = [this] {
736 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +0100737 SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200738 };
739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200740 switch (format)
741 {
742 case ImageFormatRgba32f:
743 return "rgba32f";
744 case ImageFormatRgba16f:
745 return "rgba16f";
746 case ImageFormatR32f:
747 return "r32f";
748 case ImageFormatRgba8:
749 return "rgba8";
750 case ImageFormatRgba8Snorm:
751 return "rgba8_snorm";
752 case ImageFormatRg32f:
753 return "rg32f";
754 case ImageFormatRg16f:
755 return "rg16f";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100756
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200757 case ImageFormatRgba32i:
758 return "rgba32i";
759 case ImageFormatRgba16i:
760 return "rgba16i";
761 case ImageFormatR32i:
762 return "r32i";
763 case ImageFormatRgba8i:
764 return "rgba8i";
765 case ImageFormatRg32i:
766 return "rg32i";
767 case ImageFormatRg16i:
768 return "rg16i";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100769
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200770 case ImageFormatRgba32ui:
771 return "rgba32ui";
772 case ImageFormatRgba16ui:
773 return "rgba16ui";
774 case ImageFormatR32ui:
775 return "r32ui";
776 case ImageFormatRgba8ui:
777 return "rgba8ui";
778 case ImageFormatRg32ui:
779 return "rg32ui";
780 case ImageFormatRg16ui:
781 return "rg16ui";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100782
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200783 // Desktop-only formats
784 case ImageFormatR11fG11fB10f:
785 check_desktop();
786 return "r11f_g11f_b10f";
787 case ImageFormatR16f:
788 check_desktop();
789 return "r16f";
790 case ImageFormatRgb10A2:
791 check_desktop();
792 return "rgb10_a2";
793 case ImageFormatR8:
794 check_desktop();
795 return "r8";
796 case ImageFormatRg8:
797 check_desktop();
798 return "rg8";
799 case ImageFormatR16:
800 check_desktop();
801 return "r16";
802 case ImageFormatRg16:
803 check_desktop();
804 return "rg16";
805 case ImageFormatRgba16:
806 check_desktop();
807 return "rgba16";
808 case ImageFormatR16Snorm:
809 check_desktop();
810 return "r16_snorm";
811 case ImageFormatRg16Snorm:
812 check_desktop();
813 return "rg16_snorm";
814 case ImageFormatRgba16Snorm:
815 check_desktop();
816 return "rgba16_snorm";
817 case ImageFormatR8Snorm:
818 check_desktop();
819 return "r8_snorm";
820 case ImageFormatRg8Snorm:
821 check_desktop();
822 return "rg8_snorm";
823
824 case ImageFormatR8ui:
825 check_desktop();
826 return "r8ui";
827 case ImageFormatRg8ui:
828 check_desktop();
829 return "rg8ui";
830 case ImageFormatR16ui:
831 check_desktop();
832 return "r16ui";
833 case ImageFormatRgb10a2ui:
834 check_desktop();
835 return "rgb10_a2ui";
836
837 case ImageFormatR8i:
838 check_desktop();
839 return "r8i";
840 case ImageFormatRg8i:
841 check_desktop();
842 return "rg8i";
843 case ImageFormatR16i:
844 check_desktop();
845 return "r16i";
846
847 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200848 case ImageFormatUnknown:
849 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200850 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100851}
852
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200853uint32_t CompilerGLSL::type_to_packed_base_size(const SPIRType &type, BufferPackingStandard)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200854{
855 switch (type.basetype)
856 {
857 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200858 case SPIRType::Int64:
859 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200860 return 8;
861 default:
862 return 4;
863 }
864}
865
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200866uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, uint64_t flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100867{
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200868 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100869
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200870 if (!type.array.empty())
871 {
872 uint32_t minimum_alignment = 1;
873 if (packing_is_vec4_padded(packing))
874 minimum_alignment = 16;
875
876 auto *tmp = &get<SPIRType>(type.parent_type);
877 while (!tmp->array.empty())
878 tmp = &get<SPIRType>(tmp->parent_type);
879
880 // Get the alignment of the base type, then maybe round up.
881 return max(minimum_alignment, type_to_packed_alignment(*tmp, flags, packing));
882 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100883
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200884 if (type.basetype == SPIRType::Struct)
885 {
886 // Rule 9. Structs alignments are maximum alignment of its members.
887 uint32_t alignment = 0;
888 for (uint32_t i = 0; i < type.member_types.size(); i++)
889 {
890 auto member_flags = meta[type.self].members.at(i).decoration_flags;
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +0200891 alignment =
892 max(alignment, type_to_packed_alignment(get<SPIRType>(type.member_types[i]), member_flags, packing));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200893 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100894
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200895 // In std140, struct alignment is rounded up to 16.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200896 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200897 alignment = max(alignment, 16u);
898
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200899 return alignment;
900 }
901 else
902 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200903 // Vectors are *not* aligned in HLSL, but there's an extra rule where vectors cannot straddle
904 // a vec4, this is handled outside since that part knows our current offset.
905 if (type.columns == 1 && packing_is_hlsl(packing))
906 return base_alignment;
907
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200908 // From 7.6.2.2 in GL 4.5 core spec.
909 // Rule 1
910 if (type.vecsize == 1 && type.columns == 1)
911 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100912
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200913 // Rule 2
914 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
915 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100916
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200917 // Rule 3
918 if (type.vecsize == 3 && type.columns == 1)
919 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100920
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200921 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100922
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200923 // Rule 5. Column-major matrices are stored as arrays of
924 // vectors.
925 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
926 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200927 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +0200928 return 4 * base_alignment;
929 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200930 return 4 * base_alignment;
931 else
932 return type.vecsize * base_alignment;
933 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100934
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200935 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100936
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200937 // Rule 7.
938 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
939 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200940 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +0200941 return 4 * base_alignment;
942 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200943 return 4 * base_alignment;
944 else
945 return type.columns * base_alignment;
946 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100947
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200948 // Rule 8 implied.
949 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100950
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200951 SPIRV_CROSS_THROW("Did not find suitable rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100952}
953
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200954uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, uint64_t flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100955{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200956 // Array stride is equal to aligned size of the underlying type.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200957 uint32_t parent = type.parent_type;
958 assert(parent);
959
960 auto &tmp = get<SPIRType>(parent);
961
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200962 uint32_t size = type_to_packed_size(tmp, flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200963 if (tmp.array.empty())
964 {
965 uint32_t alignment = type_to_packed_alignment(type, flags, packing);
966 return (size + alignment - 1) & ~(alignment - 1);
967 }
968 else
969 {
970 // For multidimensional arrays, array stride always matches size of subtype.
971 // The alignment cannot change because multidimensional arrays are basically N * M array elements.
972 return size;
973 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100974}
975
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200976uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, uint64_t flags, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100977{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200978 if (!type.array.empty())
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200979 {
Hans-Kristian Arntzen1079e792017-10-10 10:22:40 +0200980 return to_array_size_literal(type, uint32_t(type.array.size()) - 1) *
981 type_to_packed_array_stride(type, flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +0200982 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100983
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200984 const uint32_t base_alignment = type_to_packed_base_size(type, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200985 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100986
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200987 if (type.basetype == SPIRType::Struct)
988 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200989 uint32_t pad_alignment = 1;
990
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200991 for (uint32_t i = 0; i < type.member_types.size(); i++)
992 {
993 auto member_flags = meta[type.self].members.at(i).decoration_flags;
994 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200995
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +0200996 uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
997 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200998
999 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1000 // GL 4.5 spec, 7.6.2.2.
1001 if (member_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001002 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001003 else
1004 pad_alignment = 1;
1005
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001006 size = (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001007 size += type_to_packed_size(member_type, member_flags, packing);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001008 }
1009 }
1010 else
1011 {
1012 if (type.columns == 1)
1013 size = type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001014
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001015 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
1016 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001017 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001018 size = type.columns * 4 * base_alignment;
1019 else if (type.vecsize == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001020 size = type.columns * 4 * base_alignment;
1021 else
1022 size = type.columns * type.vecsize * base_alignment;
1023 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001025 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
1026 {
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001027 if (packing_is_vec4_padded(packing))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001028 size = type.vecsize * 4 * base_alignment;
1029 else if (type.columns == 3)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001030 size = type.vecsize * 4 * base_alignment;
1031 else
1032 size = type.vecsize * type.columns * base_alignment;
1033 }
1034 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001036 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001037}
1038
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001039bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001040{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001041 // This is very tricky and error prone, but try to be exhaustive and correct here.
1042 // SPIR-V doesn't directly say if we're using std430 or std140.
1043 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
1044 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
1045 // 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).
1046 //
1047 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
1048 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
1049 //
1050 // The only two differences between std140 and std430 are related to padding alignment/array stride
1051 // in arrays and structs. In std140 they take minimum vec4 alignment.
1052 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001053
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001054 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001055 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001056
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001057 for (uint32_t i = 0; i < type.member_types.size(); i++)
1058 {
1059 auto &memb_type = get<SPIRType>(type.member_types[i]);
1060 auto member_flags = meta[type.self].members.at(i).decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001061
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001062 // Verify alignment rules.
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001063 uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001064 uint32_t packed_size = type_to_packed_size(memb_type, member_flags, packing);
1065
1066 if (packing_is_hlsl(packing))
1067 {
1068 // If a member straddles across a vec4 boundary, alignment is actually vec4.
1069 uint32_t begin_word = offset / 16;
1070 uint32_t end_word = (offset + packed_size - 1) / 16;
1071 if (begin_word != end_word)
1072 packed_alignment = max(packed_alignment, 16u);
1073 }
1074
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001075 uint32_t alignment = max(packed_alignment, pad_alignment);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001076 offset = (offset + alignment - 1) & ~(alignment - 1);
1077
1078 // The next member following a struct member is aligned to the base alignment of the struct that came before.
1079 // GL 4.5 spec, 7.6.2.2.
1080 if (memb_type.basetype == SPIRType::Struct)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001081 pad_alignment = packed_alignment;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +02001082 else
1083 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001084
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001085 // We only care about offsets in std140, std430, etc ...
1086 // For EnhancedLayout variants, we have the flexibility to choose our own offsets.
1087 if (!packing_has_flexible_offset(packing))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001088 {
1089 uint32_t actual_offset = type_struct_member_offset(type, i);
1090 if (actual_offset != offset) // This cannot be the packing we're looking for.
1091 return false;
1092 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001094 // Verify array stride rules.
1095 if (!memb_type.array.empty() &&
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001096 type_to_packed_array_stride(memb_type, member_flags, packing) != type_struct_member_array_stride(type, i))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001097 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001098
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001099 // Verify that sub-structs also follow packing rules.
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001100 // We cannot use enhanced layouts on substructs, so they better be up to spec.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001101 auto substruct_packing = packing_to_substruct_packing(packing);
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001102
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001103 if (!memb_type.member_types.empty() && !buffer_is_packing_standard(memb_type, substruct_packing))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001104 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001105
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001106 // Bump size.
Hans-Kristian Arntzenb9814a02017-10-10 15:23:07 +02001107 offset += packed_size;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001108 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001109
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001110 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001111}
1112
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001113bool CompilerGLSL::can_use_io_location(StorageClass storage)
1114{
1115 // Location specifiers are must have in SPIR-V, but they aren't really supported in earlier versions of GLSL.
1116 // Be very explicit here about how to solve the issue.
1117 if ((get_execution_model() != ExecutionModelVertex && storage == StorageClassInput) ||
1118 (get_execution_model() != ExecutionModelFragment && storage == StorageClassOutput))
1119 {
1120 if (!options.es && options.version < 410 && !options.separate_shader_objects)
1121 return false;
1122 else if (options.es && options.version < 310)
1123 return false;
1124 }
1125
1126 if ((get_execution_model() == ExecutionModelVertex && storage == StorageClassInput) ||
1127 (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput))
1128 {
1129 if (options.es && options.version < 300)
1130 return false;
1131 else if (!options.es && options.version < 330)
1132 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001133 }
1134
1135 return true;
1136}
1137
1138string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
1139{
Hans-Kristian Arntzen62d223a2016-09-21 08:20:04 +02001140 // FIXME: Come up with a better solution for when to disable layouts.
1141 // Having layouts depend on extensions as well as which types
1142 // of layouts are used. For now, the simple solution is to just disable
1143 // layouts for legacy versions.
1144 if (is_legacy())
rob42fe8c32016-09-18 13:18:33 +09001145 return "";
1146
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001147 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001149 auto &dec = meta[var.self].decoration;
1150 auto &type = get<SPIRType>(var.basetype);
1151 auto flags = dec.decoration_flags;
1152 auto typeflags = meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001153
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001154 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
1155 attr.push_back("push_constant");
1156
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001157 if (flags & (1ull << DecorationRowMajor))
1158 attr.push_back("row_major");
1159 if (flags & (1ull << DecorationColMajor))
1160 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001161
1162 if (options.vulkan_semantics)
1163 {
1164 if (flags & (1ull << DecorationInputAttachmentIndex))
1165 attr.push_back(join("input_attachment_index = ", dec.input_attachment));
1166 }
1167
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001168 if ((flags & (1ull << DecorationLocation)) != 0 && can_use_io_location(var.storage))
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001169 {
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001170 uint64_t combined_decoration = 0;
1171 for (uint32_t i = 0; i < meta[type.self].members.size(); i++)
1172 combined_decoration |= combined_decoration_for_member(type, i);
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001173
Hans-Kristian Arntzenf4d23cd2017-10-19 14:17:18 +02001174 // If our members have location decorations, we don't need to
1175 // emit location decorations at the top as well (looks weird).
1176 if ((combined_decoration & (1ull << DecorationLocation)) == 0)
1177 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02001178 }
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +02001179
1180 // set = 0 is the default. Do not emit set = decoration in regular GLSL output, but
1181 // we should preserve it in Vulkan GLSL mode.
1182 if (var.storage != StorageClassPushConstant)
1183 {
1184 if ((flags & (1ull << DecorationDescriptorSet)) && (dec.set != 0 || options.vulkan_semantics))
1185 attr.push_back(join("set = ", dec.set));
1186 }
1187
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001188 bool can_use_binding;
1189 if (options.es)
1190 can_use_binding = options.version >= 310;
1191 else
1192 can_use_binding = options.enable_420pack_extension || (options.version >= 420);
1193
1194 if (can_use_binding && (flags & (1ull << DecorationBinding)))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001195 attr.push_back(join("binding = ", dec.binding));
Hans-Kristian Arntzen6599a412017-09-08 09:56:06 +02001196
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001197 if (flags & (1ull << DecorationOffset))
1198 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001199
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001200 bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant;
1201 bool ssbo_block = var.storage == StorageClassStorageBuffer ||
1202 (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock)));
1203
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001204 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
1205 // If SPIR-V does not comply with either layout, we cannot really work around it.
1206 if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBlock)))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001207 {
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001208 if (buffer_is_packing_standard(type, BufferPackingStd140))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001209 attr.push_back("std140");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001210 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001211 {
Hans-Kristian Arntzen4d112202017-10-10 11:30:29 +02001212 attr.push_back("std140");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001213 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
1214 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
1215 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
1216 if (options.es && !options.vulkan_semantics)
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001217 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1218 "not support GL_ARB_enhanced_layouts.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001219 if (!options.es && !options.vulkan_semantics && options.version < 440)
1220 require_extension("GL_ARB_enhanced_layouts");
1221
1222 // This is a very last minute to check for this, but use this unused decoration to mark that we should emit
1223 // explicit offsets for this block type.
1224 // layout_for_variable() will be called before the actual buffer emit.
1225 // The alternative is a full pass before codegen where we deduce this decoration,
1226 // but then we are just doing the exact same work twice, and more complexity.
1227 set_decoration(type.self, DecorationCPacked);
1228 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001229 else
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001230 {
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001231 SPIRV_CROSS_THROW("Uniform buffer cannot be expressed as std140, even with enhanced layouts. You can try "
1232 "flattening this block to "
1233 "support a more flexible layout.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001234 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001235 }
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001236 else if (push_constant_block || ssbo_block)
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001237 {
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001238 if (buffer_is_packing_standard(type, BufferPackingStd430))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001239 attr.push_back("std430");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001240 else if (buffer_is_packing_standard(type, BufferPackingStd140))
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001241 attr.push_back("std140");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001242 else if (buffer_is_packing_standard(type, BufferPackingStd140EnhancedLayout))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001243 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001244 attr.push_back("std140");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001245
1246 // Fallback time. We might be able to use the ARB_enhanced_layouts to deal with this difference,
1247 // however, we can only use layout(offset) on the block itself, not any substructs, so the substructs better be the appropriate layout.
1248 // Enhanced layouts seem to always work in Vulkan GLSL, so no need for extensions there.
1249 if (options.es && !options.vulkan_semantics)
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001250 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1251 "not support GL_ARB_enhanced_layouts.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001252 if (!options.es && !options.vulkan_semantics && options.version < 440)
1253 require_extension("GL_ARB_enhanced_layouts");
1254
1255 set_decoration(type.self, DecorationCPacked);
1256 }
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02001257 else if (buffer_is_packing_standard(type, BufferPackingStd430EnhancedLayout))
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001258 {
1259 attr.push_back("std430");
1260 if (options.es && !options.vulkan_semantics)
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001261 SPIRV_CROSS_THROW("Push constant block cannot be expressed as neither std430 nor std140. ES-targets do "
1262 "not support GL_ARB_enhanced_layouts.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001263 if (!options.es && !options.vulkan_semantics && options.version < 440)
1264 require_extension("GL_ARB_enhanced_layouts");
1265
1266 set_decoration(type.self, DecorationCPacked);
1267 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001268 else
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001269 {
Hans-Kristian Arntzena8e991d2017-10-10 11:31:05 +02001270 SPIRV_CROSS_THROW("Buffer block cannot be expressed as neither std430 nor std140, even with enhanced "
1271 "layouts. You can try flattening this block to support a more flexible layout.");
Hans-Kristian Arntzen5a896062017-10-10 11:05:46 +02001272 }
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02001273 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001274
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001275 // For images, the type itself adds a layout qualifer.
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02001276 // Only emit the format for storage images.
1277 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001278 {
1279 const char *fmt = format_to_glsl(type.image.format);
1280 if (fmt)
1281 attr.push_back(fmt);
1282 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001283
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001284 if (attr.empty())
1285 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001286
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001287 string res = "layout(";
1288 res += merge(attr);
1289 res += ") ";
1290 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001291}
1292
1293void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
1294{
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01001295 if (flattened_buffer_blocks.count(var.self))
1296 emit_buffer_block_flattened(var);
1297 else if (options.vulkan_semantics)
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001298 emit_push_constant_block_vulkan(var);
1299 else
1300 emit_push_constant_block_glsl(var);
1301}
1302
1303void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
1304{
1305 emit_buffer_block(var);
1306}
1307
1308void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
1309{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001310 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
1311 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001312
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001313 auto &flags = meta[var.self].decoration.decoration_flags;
1314 flags &= ~((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001315
1316#if 0
1317 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001318 SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001319 "Remap to location with reflection API first or disable these decorations.");
1320#endif
1321
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001322 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1323 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
1324 auto &block_flags = meta[type.self].decoration.decoration_flags;
1325 uint64_t block_flag = block_flags & (1ull << DecorationBlock);
1326 block_flags &= ~block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001327
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001328 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001329
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001330 block_flags |= block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001332 emit_uniform(var);
1333 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001334}
1335
1336void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
1337{
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001338 if (flattened_buffer_blocks.count(var.self))
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001339 emit_buffer_block_flattened(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001340 else if (is_legacy())
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001341 emit_buffer_block_legacy(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001342 else
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001343 emit_buffer_block_native(var);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001344}
1345
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001346void CompilerGLSL::emit_buffer_block_legacy(const SPIRVariable &var)
1347{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001348 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001349 bool ssbo = var.storage == StorageClassStorageBuffer ||
1350 ((meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)) != 0);
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001351 if (ssbo)
1352 SPIRV_CROSS_THROW("SSBOs not supported in legacy targets.");
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01001353
1354 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
1355 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
1356 auto &block_flags = meta[type.self].decoration.decoration_flags;
1357 uint64_t block_flag = block_flags & (1ull << DecorationBlock);
1358 block_flags &= ~block_flag;
1359 emit_struct(type);
1360 block_flags |= block_flag;
1361 emit_uniform(var);
1362 statement("");
1363}
1364
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001365void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001366{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001367 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01001368
1369 uint64_t flags = get_buffer_block_flags(var);
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001370 bool ssbo = var.storage == StorageClassStorageBuffer ||
1371 ((meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)) != 0);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01001372 bool is_restrict = ssbo && (flags & (1ull << DecorationRestrict)) != 0;
1373 bool is_writeonly = ssbo && (flags & (1ull << DecorationNonReadable)) != 0;
1374 bool is_readonly = ssbo && (flags & (1ull << DecorationNonWritable)) != 0;
Hans-Kristian Arntzen89a29be2017-08-28 08:59:54 +02001375 bool is_coherent = ssbo && (flags & (1ull << DecorationCoherent)) != 0;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +02001376
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001377 // 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 +02001378 auto buffer_name = to_name(type.self, false);
1379
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001380 // Shaders never use the block by interface name, so we don't
1381 // have to track this other than updating name caches.
Hans-Kristian Arntzenaab31072017-09-29 12:16:53 +02001382 if (meta[type.self].decoration.alias.empty() || resource_names.find(buffer_name) != end(resource_names))
1383 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001384
1385 // Make sure we get something unique.
1386 add_variable(resource_names, buffer_name);
1387
1388 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
1389 // This cannot conflict with anything else, so we're safe now.
1390 if (buffer_name.empty())
1391 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
1392
1393 // Save for post-reflection later.
1394 declared_block_names[var.self] = buffer_name;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001395
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02001396 statement(layout_for_variable(var), is_coherent ? "coherent " : "", is_restrict ? "restrict " : "",
1397 is_writeonly ? "writeonly " : "", is_readonly ? "readonly " : "", ssbo ? "buffer " : "uniform ",
1398 buffer_name);
Hans-Kristian Arntzen016b1d82017-01-21 10:07:38 +01001399
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001400 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001401
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001402 type.member_name_cache.clear();
1403
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001404 uint32_t i = 0;
1405 for (auto &member : type.member_types)
1406 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001407 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05001408 emit_struct_member(type, member, i);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001409 i++;
1410 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001411
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001412 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001413 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
1414 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001415}
1416
Arseny Kapoulkinec5a821c2017-01-17 12:18:35 -08001417void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08001418{
1419 auto &type = get<SPIRType>(var.basetype);
1420
1421 // Block names should never alias.
1422 auto buffer_name = to_name(type.self, false);
1423 size_t buffer_size = (get_declared_struct_size(type) + 15) / 16;
1424
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001425 SPIRType::BaseType basic_type;
1426 if (get_common_basic_type(type, basic_type))
1427 {
1428 SPIRType tmp;
1429 tmp.basetype = basic_type;
Hans-Kristian Arntzenefba6102017-01-22 08:53:52 +01001430 tmp.vecsize = 4;
1431 if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt)
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001432 SPIRV_CROSS_THROW("Basic types in a flattened UBO must be float, int or uint.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001433
1434 auto flags = get_buffer_block_flags(var);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01001435 statement("uniform ", flags_to_precision_qualifiers_glsl(tmp, flags), type_to_glsl(tmp), " ", buffer_name, "[",
1436 buffer_size, "];");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01001437 }
1438 else
1439 SPIRV_CROSS_THROW("All basic types in a flattened block must be the same.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08001440}
1441
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001442const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001443{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001444 auto &execution = get_entry_point();
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001445
1446 if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
1447 {
1448 if (is_legacy() && execution.model == ExecutionModelVertex)
1449 return var.storage == StorageClassInput ? "attribute " : "varying ";
1450 else if (is_legacy() && execution.model == ExecutionModelFragment)
1451 return "varying "; // Fragment outputs are renamed so they never hit this case.
1452 else
1453 return var.storage == StorageClassInput ? "in " : "out ";
1454 }
1455 else if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
1456 var.storage == StorageClassPushConstant)
1457 {
1458 return "uniform ";
1459 }
1460
1461 return "";
1462}
1463
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001464void CompilerGLSL::emit_flattened_io_block(const SPIRVariable &var, const char *qual)
1465{
1466 auto &type = get<SPIRType>(var.basetype);
1467 if (!type.array.empty())
1468 SPIRV_CROSS_THROW("Array of varying structs cannot be flattened to legacy-compatible varyings.");
1469
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001470 auto old_flags = meta[type.self].decoration.decoration_flags;
1471 // Emit the members as if they are part of a block to get all qualifiers.
1472 meta[type.self].decoration.decoration_flags |= 1ull << DecorationBlock;
1473
Hans-Kristian Arntzena8df0802017-11-22 11:19:54 +01001474 type.member_name_cache.clear();
1475
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001476 uint32_t i = 0;
1477 for (auto &member : type.member_types)
1478 {
1479 add_member_name(type, i);
1480 auto &membertype = get<SPIRType>(member);
1481
1482 if (membertype.basetype == SPIRType::Struct)
1483 SPIRV_CROSS_THROW("Cannot flatten struct inside structs in I/O variables.");
1484
1485 // Pass in the varying qualifier here so it will appear in the correct declaration order.
1486 // Replace member name while emitting it so it encodes both struct name and member name.
1487 // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row,
1488 // which is not allowed.
Hans-Kristian Arntzen94ff3552017-10-10 17:32:26 +02001489 auto backup_name = get_member_name(type.self, i);
1490 auto member_name = to_member_name(type, i);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001491 set_member_name(type.self, i, sanitize_underscores(join(to_name(type.self), "_", member_name)));
Bill Hollingsdc694272017-03-11 12:17:22 -05001492 emit_struct_member(type, member, i, qual);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001493 // Restore member name.
1494 set_member_name(type.self, i, member_name);
1495 i++;
1496 }
1497
1498 meta[type.self].decoration.decoration_flags = old_flags;
1499
1500 // Treat this variable as flattened from now on.
1501 flattened_structs.insert(var.self);
1502}
1503
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001504void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
1505{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001506 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001507
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001508 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
1509 bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001510 const char *qual = to_storage_qualifiers_glsl(var);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001512 if (block)
1513 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001514 // ESSL earlier than 310 and GLSL earlier than 150 did not support
1515 // I/O variables which are struct types.
1516 // To support this, flatten the struct into separate varyings instead.
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001517 if ((options.es && options.version < 310) || (!options.es && options.version < 150))
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001518 {
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001519 // I/O blocks on ES require version 310 with Android Extension Pack extensions, or core version 320.
1520 // On desktop, I/O blocks were introduced with geometry shaders in GL 3.2 (GLSL 150).
1521 emit_flattened_io_block(var, qual);
1522 }
1523 else
1524 {
1525 if (options.es && options.version < 320)
1526 {
1527 // Geometry and tessellation extensions imply this extension.
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01001528 if (!has_extension("GL_EXT_geometry_shader") && !has_extension("GL_EXT_tessellation_shader"))
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001529 require_extension("GL_EXT_shader_io_blocks");
1530 }
1531
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001532 // Block names should never alias.
1533 auto block_name = to_name(type.self, false);
1534
1535 // Shaders never use the block by interface name, so we don't
1536 // have to track this other than updating name caches.
1537 if (resource_names.find(block_name) != end(resource_names))
1538 block_name = get_fallback_name(type.self);
1539 else
1540 resource_names.insert(block_name);
1541
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001542 statement(layout_for_variable(var), qual, block_name);
1543 begin_scope();
1544
1545 type.member_name_cache.clear();
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001546
1547 uint32_t i = 0;
1548 for (auto &member : type.member_types)
1549 {
1550 add_member_name(type, i);
Bill Hollingsdc694272017-03-11 12:17:22 -05001551 emit_struct_member(type, member, i);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001552 i++;
1553 }
1554
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01001555 add_resource_name(var.self);
Hans-Kristian Arntzenc5de1cf2017-03-06 14:01:51 +01001556 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
1557 statement("");
1558 }
1559 }
1560 else
1561 {
1562 // ESSL earlier than 310 and GLSL earlier than 150 did not support
1563 // I/O variables which are struct types.
1564 // To support this, flatten the struct into separate varyings instead.
1565 if (type.basetype == SPIRType::Struct &&
1566 ((options.es && options.version < 310) || (!options.es && options.version < 150)))
1567 {
1568 emit_flattened_io_block(var, qual);
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001569 }
1570 else
1571 {
1572 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001573 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01001574 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001575 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001576}
1577
1578void CompilerGLSL::emit_uniform(const SPIRVariable &var)
1579{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001580 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen32b463f2016-09-10 13:00:07 +02001581 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001582 {
1583 if (!options.es && options.version < 420)
1584 require_extension("GL_ARB_shader_image_load_store");
1585 else if (options.es && options.version < 310)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001586 SPIRV_CROSS_THROW("At least ESSL 3.10 required for shader image load store.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001587 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001588
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001589 add_resource_name(var.self);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01001590 statement(layout_for_variable(var), variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001591}
1592
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02001593void CompilerGLSL::emit_specialization_constant(const SPIRConstant &constant)
1594{
1595 auto &type = get<SPIRType>(constant.constant_type);
1596 auto name = to_name(constant.self);
1597
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001598 SpecializationConstant wg_x, wg_y, wg_z;
1599 uint32_t workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
1600
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001601 if (constant.self == workgroup_size_id || constant.self == wg_x.id || constant.self == wg_y.id ||
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001602 constant.self == wg_z.id)
1603 {
1604 // These specialization constants are implicitly declared by emitting layout() in;
1605 return;
1606 }
1607
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001608 // Only scalars have constant IDs.
1609 if (has_decoration(constant.self, DecorationSpecId))
1610 {
1611 statement("layout(constant_id = ", get_decoration(constant.self, DecorationSpecId), ") const ",
1612 variable_decl(type, name), " = ", constant_expression(constant), ";");
1613 }
1614 else
1615 {
1616 statement("const ", variable_decl(type, name), " = ", constant_expression(constant), ";");
1617 }
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02001618}
1619
Robert Konrad76936562016-08-13 00:14:52 +02001620void CompilerGLSL::replace_illegal_names()
1621{
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02001622 // clang-format off
1623 static const unordered_set<string> keywords = {
David Srbeckyedec5ea2017-06-27 15:35:47 +01001624 "active", "asm", "atomic_uint", "attribute", "bool", "break",
1625 "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard",
1626 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4",
1627 "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float",
1628 "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray",
1629 "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube",
1630 "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect",
1631 "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant",
1632 "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect",
1633 "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp",
1634 "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump",
1635 "namespace", "noinline", "noperspective", "out", "output", "packed", "partition", "patch", "precision", "public", "readonly",
1636 "resource", "restrict", "return", "row_major", "sample", "sampler1D", "sampler1DArray", "sampler1DArrayShadow",
1637 "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray",
1638 "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer",
1639 "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "short", "sizeof", "smooth", "static",
1640 "struct", "subroutine", "superp", "switch", "template", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D",
1641 "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube",
1642 "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray",
1643 "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube",
1644 "usamplerCubeArray", "using", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "volatile",
1645 "while", "writeonly", "texture"
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02001646 };
1647 // clang-format on
Bas Zalmstraf537adf2016-10-27 12:51:22 +02001648
Robert Konrad76936562016-08-13 00:14:52 +02001649 for (auto &id : ids)
1650 {
1651 if (id.get_type() == TypeVariable)
1652 {
1653 auto &var = id.get<SPIRVariable>();
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02001654 if (!is_hidden_variable(var))
Robert Konrad76936562016-08-13 00:14:52 +02001655 {
1656 auto &m = meta[var.self].decoration;
Hans-Kristian Arntzen48636b42016-10-27 13:55:47 +02001657 if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords))
Robert Konrad76936562016-08-13 00:14:52 +02001658 m.alias = join("_", m.alias);
Robert Konrad76936562016-08-13 00:14:52 +02001659 }
1660 }
1661 }
1662}
1663
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001664void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
1665{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001666 auto &m = meta[var.self].decoration;
1667 uint32_t location = 0;
1668 if (m.decoration_flags & (1ull << DecorationLocation))
1669 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001670
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001671 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
1672 // do the access chain part of this for us.
1673 auto &type = get<SPIRType>(var.basetype);
1674
1675 if (type.array.empty())
1676 {
1677 // Redirect the write to a specific render target in legacy GLSL.
1678 m.alias = join("gl_FragData[", location, "]");
Lubos Lenco52158642016-09-17 15:56:23 +02001679
1680 if (is_legacy_es() && location != 0)
1681 require_extension("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001682 }
1683 else if (type.array.size() == 1)
1684 {
1685 // If location is non-zero, we probably have to add an offset.
1686 // This gets really tricky since we'd have to inject an offset in the access chain.
1687 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
1688 m.alias = "gl_FragData";
1689 if (location != 0)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001690 SPIRV_CROSS_THROW("Arrayed output variable used, but location is not 0. "
1691 "This is unimplemented in SPIRV-Cross.");
Hans-Kristian Arntzen6cc96242016-09-17 18:46:10 +02001692
Lubos Lenco80c39412016-09-17 14:33:16 +02001693 if (is_legacy_es())
1694 require_extension("GL_EXT_draw_buffers");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001695 }
1696 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001697 SPIRV_CROSS_THROW("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001698
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001699 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 +01001700}
1701
1702void CompilerGLSL::replace_fragment_outputs()
1703{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001704 for (auto &id : ids)
1705 {
1706 if (id.get_type() == TypeVariable)
1707 {
1708 auto &var = id.get<SPIRVariable>();
1709 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001711 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
1712 var.storage == StorageClassOutput)
1713 replace_fragment_output(var);
1714 }
1715 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001716}
1717
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02001718string CompilerGLSL::remap_swizzle(const SPIRType &out_type, uint32_t input_components, const string &expr)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001719{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001720 if (out_type.vecsize == input_components)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02001721 return expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001722 else if (input_components == 1)
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02001723 return join(type_to_glsl(out_type), "(", expr, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001724 else
1725 {
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02001726 auto e = enclose_expression(expr) + ".";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001727 // Just clamp the swizzle index if we have more outputs than inputs.
1728 for (uint32_t c = 0; c < out_type.vecsize; c++)
1729 e += index_to_swizzle(min(c, input_components - 1));
1730 if (backend.swizzle_is_function && out_type.vecsize > 1)
1731 e += "()";
1732 return e;
1733 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001734}
1735
1736void CompilerGLSL::emit_pls()
1737{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001738 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001739 if (execution.model != ExecutionModelFragment)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001740 SPIRV_CROSS_THROW("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001741
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001742 if (!options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001743 SPIRV_CROSS_THROW("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001745 if (options.version < 300)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001746 SPIRV_CROSS_THROW("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001747
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001748 if (!pls_inputs.empty())
1749 {
1750 statement("__pixel_local_inEXT _PLSIn");
1751 begin_scope();
1752 for (auto &input : pls_inputs)
1753 statement(pls_decl(input), ";");
1754 end_scope_decl();
1755 statement("");
1756 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001757
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001758 if (!pls_outputs.empty())
1759 {
1760 statement("__pixel_local_outEXT _PLSOut");
1761 begin_scope();
1762 for (auto &output : pls_outputs)
1763 statement(pls_decl(output), ";");
1764 end_scope_decl();
1765 statement("");
1766 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001767}
1768
Hans-Kristian Arntzen97f7ab82017-01-05 18:16:33 +01001769void CompilerGLSL::fixup_image_load_store_access()
1770{
1771 for (auto &id : ids)
1772 {
1773 if (id.get_type() != TypeVariable)
1774 continue;
1775
1776 uint32_t var = id.get<SPIRVariable>().self;
1777 auto &vartype = expression_type(var);
1778 if (vartype.basetype == SPIRType::Image)
1779 {
1780 // Older glslangValidator does not emit required qualifiers here.
1781 // Solve this by making the image access as restricted as possible and loosen up if we need to.
1782 // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
1783
1784 auto &flags = meta.at(var).decoration.decoration_flags;
1785 static const uint64_t NoWrite = 1ull << DecorationNonWritable;
1786 static const uint64_t NoRead = 1ull << DecorationNonReadable;
1787 if ((flags & (NoWrite | NoRead)) == 0)
1788 flags |= NoRead | NoWrite;
1789 }
1790 }
1791}
1792
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001793void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model)
1794{
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01001795 uint64_t emitted_builtins = 0;
1796 uint64_t global_builtins = 0;
1797 const SPIRVariable *block_var = nullptr;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001798 bool emitted_block = false;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01001799 bool builtin_array = false;
1800
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001801 for (auto &id : ids)
1802 {
1803 if (id.get_type() != TypeVariable)
1804 continue;
1805
1806 auto &var = id.get<SPIRVariable>();
1807 auto &type = get<SPIRType>(var.basetype);
1808 bool block = has_decoration(type.self, DecorationBlock);
1809 uint64_t builtins = 0;
1810
1811 if (var.storage == storage && block && is_builtin_variable(var))
1812 {
1813 for (auto &m : meta[type.self].members)
1814 if (m.builtin)
1815 builtins |= 1ull << m.builtin_type;
1816 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01001817 else if (var.storage == storage && !block && is_builtin_variable(var))
1818 {
1819 // While we're at it, collect all declared global builtins (HLSL mostly ...).
1820 auto &m = meta[var.self].decoration;
1821 if (m.builtin)
1822 global_builtins |= 1ull << m.builtin_type;
1823 }
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001824
1825 if (!builtins)
1826 continue;
1827
1828 if (emitted_block)
1829 SPIRV_CROSS_THROW("Cannot use more than one builtin I/O block.");
1830
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01001831 emitted_builtins = builtins;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001832 emitted_block = true;
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01001833 builtin_array = !type.array.empty();
1834 block_var = &var;
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001835 }
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01001836
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01001837 global_builtins &= (1ull << BuiltInPosition) | (1ull << BuiltInPointSize) | (1ull << BuiltInClipDistance) |
1838 (1ull << BuiltInCullDistance);
Hans-Kristian Arntzendd604fe2017-11-17 13:37:28 +01001839
1840 // Try to collect all other declared builtins.
1841 if (!emitted_block)
1842 emitted_builtins = global_builtins;
1843
1844 // Can't declare an empty interface block.
1845 if (!emitted_builtins)
1846 return;
1847
1848 if (storage == StorageClassOutput)
1849 statement("out gl_PerVertex");
1850 else
1851 statement("in gl_PerVertex");
1852
1853 begin_scope();
1854 if (emitted_builtins & (1ull << BuiltInPosition))
1855 statement("vec4 gl_Position;");
1856 if (emitted_builtins & (1ull << BuiltInPointSize))
1857 statement("float gl_PointSize;");
1858 if (emitted_builtins & (1ull << BuiltInClipDistance))
1859 statement("float gl_ClipDistance[];"); // TODO: Do we need a fixed array size here?
1860 if (emitted_builtins & (1ull << BuiltInCullDistance))
1861 statement("float gl_CullDistance[];"); // TODO: Do we need a fixed array size here?
1862
1863 bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl;
1864 if (builtin_array)
1865 {
1866 // Make sure the array has a supported name in the code.
1867 if (storage == StorageClassOutput)
1868 set_name(block_var->self, "gl_out");
1869 else if (storage == StorageClassInput)
1870 set_name(block_var->self, "gl_in");
1871
1872 if (model == ExecutionModelTessellationControl && storage == StorageClassOutput)
1873 end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]"));
1874 else
1875 end_scope_decl(join(to_name(block_var->self), tessellation ? "[gl_MaxPatchVertices]" : "[]"));
1876 }
1877 else
1878 end_scope_decl();
1879 statement("");
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001880}
1881
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02001882void CompilerGLSL::declare_undefined_values()
1883{
1884 bool emitted = false;
1885 for (auto &id : ids)
1886 {
1887 if (id.get_type() != TypeUndef)
1888 continue;
1889
1890 auto &undef = id.get<SPIRUndef>();
1891 statement(variable_decl(get<SPIRType>(undef.basetype), to_name(undef.self), undef.self), ";");
1892 emitted = true;
1893 }
1894
1895 if (emitted)
1896 statement("");
1897}
1898
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001899void CompilerGLSL::emit_resources()
1900{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001901 auto &execution = get_entry_point();
1902
Robert Konrad76936562016-08-13 00:14:52 +02001903 replace_illegal_names();
1904
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001905 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
1906 // with builtins.
1907 if (execution.model == ExecutionModelFragment && is_legacy())
1908 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001909
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001910 // Emit PLS blocks if we have such variables.
1911 if (!pls_inputs.empty() || !pls_outputs.empty())
1912 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001913
Hans-Kristian Arntzen36650c82017-05-22 15:30:43 +02001914 // Emit custom gl_PerVertex for SSO compatibility.
1915 if (options.separate_shader_objects && !options.es)
1916 {
1917 switch (execution.model)
1918 {
1919 case ExecutionModelGeometry:
1920 case ExecutionModelTessellationControl:
1921 case ExecutionModelTessellationEvaluation:
1922 emit_declared_builtin_block(StorageClassInput, execution.model);
1923 emit_declared_builtin_block(StorageClassOutput, execution.model);
1924 break;
1925
1926 case ExecutionModelVertex:
1927 emit_declared_builtin_block(StorageClassOutput, execution.model);
1928 break;
1929
1930 default:
1931 break;
1932 }
1933 }
1934
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02001935 bool emitted = false;
1936
1937 // If emitted Vulkan GLSL,
1938 // emit specialization constants as actual floats,
1939 // spec op expressions will redirect to the constant name.
1940 //
1941 // TODO: If we have the fringe case that we create a spec constant which depends on a struct type,
1942 // we'll have to deal with that, but there's currently no known way to express that.
1943 if (options.vulkan_semantics)
1944 {
1945 for (auto &id : ids)
1946 {
1947 if (id.get_type() == TypeConstant)
1948 {
1949 auto &c = id.get<SPIRConstant>();
1950 if (!c.specialization)
1951 continue;
1952
1953 emit_specialization_constant(c);
1954 emitted = true;
1955 }
1956 }
1957 }
1958
1959 if (emitted)
1960 statement("");
1961 emitted = false;
1962
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001963 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
1964 // when such variables are instantiated.
1965 for (auto &id : ids)
1966 {
1967 if (id.get_type() == TypeType)
1968 {
1969 auto &type = id.get<SPIRType>();
1970 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
1971 (meta[type.self].decoration.decoration_flags &
1972 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
1973 {
1974 emit_struct(type);
1975 }
1976 }
1977 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001978
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001979 // Output UBOs and SSBOs
1980 for (auto &id : ids)
1981 {
1982 if (id.get_type() == TypeVariable)
1983 {
1984 auto &var = id.get<SPIRVariable>();
1985 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001986
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001987 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform;
1988 bool has_block_flags = (meta[type.self].decoration.decoration_flags &
1989 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
1990
1991 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
1992 has_block_flags)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001993 {
1994 emit_buffer_block(var);
1995 }
1996 }
1997 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001998
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001999 // Output push constant blocks
2000 for (auto &id : ids)
2001 {
2002 if (id.get_type() == TypeVariable)
2003 {
2004 auto &var = id.get<SPIRVariable>();
2005 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02002006 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
2007 !is_hidden_variable(var))
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02002008 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002009 emit_push_constant_block(var);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02002010 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002011 }
2012 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002013
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02002014 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002016 // Output Uniform Constants (values, samplers, images, etc).
2017 for (auto &id : ids)
2018 {
2019 if (id.get_type() == TypeVariable)
2020 {
2021 auto &var = id.get<SPIRVariable>();
2022 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002023
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02002024 // If we're remapping separate samplers and images, only emit the combined samplers.
2025 if (skip_separate_image_sampler)
2026 {
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02002027 // Sampler buffers are always used without a sampler, and they will also work in regular GL.
2028 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02002029 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
2030 bool separate_sampler = type.basetype == SPIRType::Sampler;
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02002031 if (!sampler_buffer && (separate_image || separate_sampler))
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02002032 continue;
2033 }
2034
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02002035 if (var.storage != StorageClassFunction && type.pointer &&
2036 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter) &&
2037 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002038 {
2039 emit_uniform(var);
2040 emitted = true;
2041 }
2042 }
2043 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002044
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002045 if (emitted)
2046 statement("");
2047 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002048
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002049 // Output in/out interfaces.
2050 for (auto &id : ids)
2051 {
2052 if (id.get_type() == TypeVariable)
2053 {
2054 auto &var = id.get<SPIRVariable>();
2055 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002056
Hans-Kristian Arntzen840a72d2017-03-24 10:03:11 +01002057 // HLSL output from glslang may emit interface variables which are "empty".
2058 // Just avoid declaring them.
2059 if (type_is_empty(type))
2060 continue;
2061
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02002062 if (var.storage != StorageClassFunction && type.pointer &&
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02002063 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02002064 interface_variable_exists_in_entry_point(var.self) && !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002065 {
2066 emit_interface_block(var);
2067 emitted = true;
2068 }
2069 else if (is_builtin_variable(var))
2070 {
2071 // For gl_InstanceIndex emulation on GLES, the API user needs to
2072 // supply this uniform.
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002073 if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002074 {
2075 statement("uniform int SPIRV_Cross_BaseInstance;");
2076 emitted = true;
2077 }
2078 }
2079 }
2080 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002081
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002082 // Global variables.
2083 for (auto global : global_variables)
2084 {
2085 auto &var = get<SPIRVariable>(global);
2086 if (var.storage != StorageClassOutput)
2087 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02002088 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002089 statement(variable_decl(var), ";");
2090 emitted = true;
2091 }
2092 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002094 if (emitted)
2095 statement("");
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02002096
2097 declare_undefined_values();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002098}
2099
Bill Hollingsb321b832016-07-06 20:30:47 -04002100// Returns a string representation of the ID, usable as a function arg.
2101// Default is to simply return the expression representation fo the arg ID.
2102// Subclasses may override to modify the return value.
2103string CompilerGLSL::to_func_call_arg(uint32_t id)
2104{
Bill Hollingsac00c602016-10-24 09:24:24 -04002105 return to_expression(id);
Bill Hollingsb321b832016-07-06 20:30:47 -04002106}
2107
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002108void CompilerGLSL::handle_invalid_expression(uint32_t id)
2109{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002110 // We tried to read an invalidated expression.
2111 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
2112 forced_temporaries.insert(id);
2113 force_recompile = true;
2114}
2115
Bill Hollingsb332bae2017-03-01 13:07:40 -05002116// Converts the format of the current expression from packed to unpacked,
2117// by wrapping the expression in a constructor of the appropriate type.
2118// GLSL does not support packed formats, so simply return the expression.
2119// Subclasses that do will override
2120string CompilerGLSL::unpack_expression_type(string expr_str, const SPIRType &)
2121{
2122 return expr_str;
2123}
2124
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01002125// Sometimes we proactively enclosed an expression where it turns out we might have not needed it after all.
2126void CompilerGLSL::strip_enclosed_expression(string &expr)
2127{
2128 if (expr.size() < 2 || expr.front() != '(' || expr.back() != ')')
2129 return;
2130
2131 // Have to make sure that our first and last parens actually enclose everything inside it.
2132 uint32_t paren_count = 0;
2133 for (auto &c : expr)
2134 {
2135 if (c == '(')
2136 paren_count++;
2137 else if (c == ')')
2138 {
2139 paren_count--;
2140
2141 // If we hit 0 and this is not the final char, our first and final parens actually don't
2142 // enclose the expression, and we cannot strip, e.g.: (a + b) * (c + d).
2143 if (paren_count == 0 && &c != &expr.back())
2144 return;
2145 }
2146 }
Corentin Walleze88c88c2017-01-18 17:22:19 -05002147 expr.erase(expr.size() - 1, 1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01002148 expr.erase(begin(expr));
2149}
2150
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02002151string CompilerGLSL::enclose_expression(const string &expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002152{
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002153 bool need_parens = false;
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02002154
2155 // If the expression starts with a unary we need to enclose to deal with cases where we have back-to-back
2156 // unary expressions.
2157 if (!expr.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002158 {
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02002159 auto c = expr.front();
2160 if (c == '-' || c == '+' || c == '!' || c == '~')
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002161 need_parens = true;
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002162 }
Hans-Kristian Arntzen6ff90072017-07-24 10:17:19 +02002163
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002164 if (!need_parens)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002165 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002166 uint32_t paren_count = 0;
2167 for (auto c : expr)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002168 {
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002169 if (c == '(')
2170 paren_count++;
2171 else if (c == ')')
2172 {
2173 assert(paren_count);
2174 paren_count--;
2175 }
2176 else if (c == ' ' && paren_count == 0)
2177 {
2178 need_parens = true;
2179 break;
2180 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002181 }
Hans-Kristian Arntzen0d144482017-07-25 18:25:03 +02002182 assert(paren_count == 0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002183 }
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002184
2185 // If this expression contains any spaces which are not enclosed by parentheses,
2186 // we need to enclose it so we can treat the whole string as an expression.
2187 // This happens when two expressions have been part of a binary op earlier.
2188 if (need_parens)
2189 return join('(', expr, ')');
2190 else
2191 return expr;
2192}
2193
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02002194// Just like to_expression except that we enclose the expression inside parentheses if needed.
2195string CompilerGLSL::to_enclosed_expression(uint32_t id)
2196{
2197 return enclose_expression(to_expression(id));
2198}
2199
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002200string CompilerGLSL::to_expression(uint32_t id)
2201{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002202 auto itr = invalid_expressions.find(id);
2203 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002204 handle_invalid_expression(id);
2205
2206 if (ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002207 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002208 // We might have a more complex chain of dependencies.
2209 // A possible scenario is that we
2210 //
2211 // %1 = OpLoad
2212 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
2213 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
2214 // 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.
2215 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
2216 //
2217 // 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,
2218 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002219 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002220 for (uint32_t dep : expr.expression_dependencies)
2221 if (invalid_expressions.find(dep) != end(invalid_expressions))
2222 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002223 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002224
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002225 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002226
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002227 switch (ids[id].get_type())
2228 {
2229 case TypeExpression:
2230 {
2231 auto &e = get<SPIRExpression>(id);
2232 if (e.base_expression)
Hans-Kristian Arntzenea781e62016-12-06 17:19:34 +01002233 return to_enclosed_expression(e.base_expression) + e.expression;
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01002234 else if (e.need_transpose)
2235 return convert_row_major_matrix(e.expression);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002236 else
2237 return e.expression;
2238 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002240 case TypeConstant:
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002241 {
2242 auto &c = get<SPIRConstant>(id);
Hans-Kristian Arntzenfae64f02017-09-28 12:34:48 +02002243
2244 // WorkGroupSize may be a constant.
2245 auto &dec = meta[c.self].decoration;
2246 if (dec.builtin)
2247 return builtin_to_glsl(dec.builtin_type, StorageClassGeneric);
2248 else if (c.specialization && options.vulkan_semantics)
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002249 return to_name(id);
2250 else
2251 return constant_expression(c);
2252 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002253
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002254 case TypeConstantOp:
2255 return constant_op_expression(get<SPIRConstantOp>(id));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002257 case TypeVariable:
2258 {
2259 auto &var = get<SPIRVariable>(id);
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01002260 // If we try to use a loop variable before the loop header, we have to redirect it to the static expression,
2261 // the variable has not been declared yet.
2262 if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002263 return to_expression(var.static_expression);
2264 else if (var.deferred_declaration)
2265 {
2266 var.deferred_declaration = false;
2267 return variable_decl(var);
2268 }
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01002269 else if (flattened_structs.count(id))
2270 {
2271 return load_flattened_struct(var);
2272 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002273 else
2274 {
2275 auto &dec = meta[var.self].decoration;
2276 if (dec.builtin)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02002277 return builtin_to_glsl(dec.builtin_type, var.storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002278 else
2279 return to_name(id);
2280 }
2281 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002282
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02002283 case TypeCombinedImageSampler:
2284 // This type should never be taken the expression of directly.
2285 // The intention is that texture sampling functions will extract the image and samplers
2286 // separately and take their expressions as needed.
2287 // GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
2288 // expression ala sampler2D(texture, sampler).
2289 SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
2290
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02002291 case TypeAccessChain:
2292 // We cannot express this type. They only have meaning in other OpAccessChains, OpStore or OpLoad.
2293 SPIRV_CROSS_THROW("Access chains have no default expression representation.");
2294
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002295 default:
2296 return to_name(id);
2297 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002298}
2299
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002300string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
2301{
2302 auto &type = get<SPIRType>(cop.basetype);
2303 bool binary = false;
2304 bool unary = false;
2305 string op;
2306
2307 // TODO: Find a clean way to reuse emit_instruction.
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002308 switch (cop.opcode)
2309 {
2310 case OpSConvert:
2311 case OpUConvert:
2312 case OpFConvert:
2313 op = type_to_glsl_constructor(type);
2314 break;
2315
2316#define BOP(opname, x) \
2317 case Op##opname: \
2318 binary = true; \
2319 op = x; \
2320 break
2321
2322#define UOP(opname, x) \
2323 case Op##opname: \
2324 unary = true; \
2325 op = x; \
2326 break
2327
2328 UOP(SNegate, "-");
2329 UOP(Not, "~");
2330 BOP(IAdd, "+");
2331 BOP(ISub, "-");
2332 BOP(IMul, "*");
2333 BOP(SDiv, "/");
2334 BOP(UDiv, "/");
2335 BOP(UMod, "%");
2336 BOP(SMod, "%");
2337 BOP(ShiftRightLogical, ">>");
2338 BOP(ShiftRightArithmetic, ">>");
2339 BOP(ShiftLeftLogical, "<<");
2340 BOP(BitwiseOr, "|");
2341 BOP(BitwiseXor, "^");
2342 BOP(BitwiseAnd, "&");
2343 BOP(LogicalOr, "||");
2344 BOP(LogicalAnd, "&&");
2345 UOP(LogicalNot, "!");
2346 BOP(LogicalEqual, "==");
2347 BOP(LogicalNotEqual, "!=");
2348 BOP(IEqual, "==");
2349 BOP(INotEqual, "!=");
2350 BOP(ULessThan, "<");
2351 BOP(SLessThan, "<");
2352 BOP(ULessThanEqual, "<=");
2353 BOP(SLessThanEqual, "<=");
2354 BOP(UGreaterThan, ">");
2355 BOP(SGreaterThan, ">");
2356 BOP(UGreaterThanEqual, ">=");
2357 BOP(SGreaterThanEqual, ">=");
2358
2359 case OpSelect:
2360 {
2361 if (cop.arguments.size() < 3)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002362 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002363
2364 // This one is pretty annoying. It's triggered from
2365 // uint(bool), int(bool) from spec constants.
2366 // In order to preserve its compile-time constness in Vulkan GLSL,
2367 // we need to reduce the OpSelect expression back to this simplified model.
2368 // If we cannot, fail.
2369 if (!to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
2370 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002371 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002372 "Cannot implement specialization constant op OpSelect. "
2373 "Need trivial select implementation which can be resolved to a simple cast from boolean.");
2374 }
2375 break;
2376 }
2377
2378 default:
2379 // Some opcodes are unimplemented here, these are currently not possible to test from glslang.
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002380 SPIRV_CROSS_THROW("Unimplemented spec constant op.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002381 }
2382
2383 SPIRType::BaseType input_type;
2384 bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
2385
2386 switch (cop.opcode)
2387 {
2388 case OpIEqual:
2389 case OpINotEqual:
2390 input_type = SPIRType::Int;
2391 break;
2392
2393 default:
2394 input_type = type.basetype;
2395 break;
2396 }
2397
2398#undef BOP
2399#undef UOP
2400 if (binary)
2401 {
2402 if (cop.arguments.size() < 2)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002403 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002404
2405 string cast_op0;
2406 string cast_op1;
2407 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, cop.arguments[0],
2408 cop.arguments[1], skip_cast_if_equal_type);
2409
2410 if (type.basetype != input_type && type.basetype != SPIRType::Boolean)
2411 {
2412 expected_type.basetype = input_type;
2413 auto expr = bitcast_glsl_op(type, expected_type);
2414 expr += '(';
2415 expr += join(cast_op0, " ", op, " ", cast_op1);
2416 expr += ')';
2417 return expr;
2418 }
2419 else
2420 return join("(", cast_op0, " ", op, " ", cast_op1, ")");
2421 }
2422 else if (unary)
2423 {
2424 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002425 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002426
2427 // Auto-bitcast to result type as needed.
2428 // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants.
2429 return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")");
2430 }
2431 else
2432 {
2433 if (cop.arguments.size() < 1)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002434 SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp.");
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02002435 return join(op, "(", to_expression(cop.arguments[0]), ")");
2436 }
2437}
2438
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002439string CompilerGLSL::constant_expression(const SPIRConstant &c)
2440{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002441 if (!c.subconstants.empty())
2442 {
2443 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002444 string res;
2445 if (backend.use_initializer_list)
2446 res = "{ ";
2447 else
2448 res = type_to_glsl_constructor(get<SPIRType>(c.constant_type)) + "(";
2449
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002450 for (auto &elem : c.subconstants)
2451 {
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002452 auto &subc = get<SPIRConstant>(elem);
2453 if (subc.specialization && options.vulkan_semantics)
2454 res += to_name(elem);
2455 else
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02002456 res += constant_expression(subc);
Hans-Kristian Arntzen081620f2016-10-03 12:52:56 +02002457
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002458 if (&elem != &c.subconstants.back())
2459 res += ", ";
2460 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002461
2462 res += backend.use_initializer_list ? " }" : ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002463 return res;
2464 }
2465 else if (c.columns() == 1)
2466 {
2467 return constant_expression_vector(c, 0);
2468 }
2469 else
2470 {
2471 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
2472 for (uint32_t col = 0; col < c.columns(); col++)
2473 {
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002474 if (options.vulkan_semantics && c.specialization_constant_id(col) != 0)
2475 res += to_name(c.specialization_constant_id(col));
2476 else
2477 res += constant_expression_vector(c, col);
2478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002479 if (col + 1 < c.columns())
2480 res += ", ";
2481 }
2482 res += ")";
2483 return res;
2484 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002485}
2486
2487string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
2488{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002489 auto type = get<SPIRType>(c.constant_type);
2490 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002491
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002492 string res;
2493 if (c.vector_size() > 1)
2494 res += type_to_glsl(type) + "(";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002495
Robert Konradea24ee82016-09-23 18:57:18 +02002496 bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002497
2498 if (splat)
2499 {
2500 // Cannot use constant splatting if we have specialization constants somewhere in the vector.
2501 for (uint32_t i = 0; i < c.vector_size(); i++)
2502 {
2503 if (options.vulkan_semantics && c.specialization_constant_id(vector, i) != 0)
2504 {
2505 splat = false;
2506 break;
2507 }
2508 }
2509 }
2510
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002511 if (splat)
2512 {
Hans-Kristian Arntzen6a7b95d2017-10-10 10:12:27 +02002513 if (type.width == 64)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02002514 {
2515 uint64_t ident = c.scalar_u64(vector, 0);
2516 for (uint32_t i = 1; i < c.vector_size(); i++)
2517 if (ident != c.scalar_u64(vector, i))
2518 splat = false;
2519 }
2520 else
2521 {
2522 uint32_t ident = c.scalar(vector, 0);
2523 for (uint32_t i = 1; i < c.vector_size(); i++)
2524 if (ident != c.scalar(vector, i))
2525 splat = false;
2526 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002527 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002529 switch (type.basetype)
2530 {
2531 case SPIRType::Float:
2532 if (splat)
2533 {
2534 res += convert_to_string(c.scalar_f32(vector, 0));
2535 if (backend.float_literal_suffix)
2536 res += "f";
2537 }
2538 else
2539 {
2540 for (uint32_t i = 0; i < c.vector_size(); i++)
2541 {
Hans-Kristian Arntzen0e4ed412017-09-28 12:24:04 +02002542 if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002543 res += to_name(c.specialization_constant_id(vector, i));
2544 else
2545 res += convert_to_string(c.scalar_f32(vector, i));
2546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002547 if (backend.float_literal_suffix)
2548 res += "f";
2549 if (i + 1 < c.vector_size())
2550 res += ", ";
2551 }
2552 }
2553 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002554
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02002555 case SPIRType::Double:
2556 if (splat)
2557 {
2558 res += convert_to_string(c.scalar_f64(vector, 0));
2559 if (backend.double_literal_suffix)
2560 res += "lf";
2561 }
2562 else
2563 {
2564 for (uint32_t i = 0; i < c.vector_size(); i++)
2565 {
Hans-Kristian Arntzen0e4ed412017-09-28 12:24:04 +02002566 if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002567 res += to_name(c.specialization_constant_id(vector, i));
2568 else
2569 {
2570 res += convert_to_string(c.scalar_f64(vector, i));
2571 if (backend.double_literal_suffix)
2572 res += "lf";
2573 }
2574
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02002575 if (i + 1 < c.vector_size())
2576 res += ", ";
2577 }
2578 }
2579 break;
2580
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002581 case SPIRType::Int64:
2582 if (splat)
2583 {
2584 res += convert_to_string(c.scalar_i64(vector, 0));
2585 if (backend.long_long_literal_suffix)
2586 res += "ll";
2587 else
2588 res += "l";
2589 }
2590 else
2591 {
2592 for (uint32_t i = 0; i < c.vector_size(); i++)
2593 {
Hans-Kristian Arntzen0e4ed412017-09-28 12:24:04 +02002594 if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002595 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002596 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002597 {
2598 res += convert_to_string(c.scalar_i64(vector, i));
2599 if (backend.long_long_literal_suffix)
2600 res += "ll";
2601 else
2602 res += "l";
2603 }
2604
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002605 if (i + 1 < c.vector_size())
2606 res += ", ";
2607 }
2608 }
2609 break;
2610
2611 case SPIRType::UInt64:
2612 if (splat)
2613 {
2614 res += convert_to_string(c.scalar_u64(vector, 0));
2615 if (backend.long_long_literal_suffix)
2616 res += "ull";
2617 else
2618 res += "ul";
2619 }
2620 else
2621 {
2622 for (uint32_t i = 0; i < c.vector_size(); i++)
2623 {
Hans-Kristian Arntzen0e4ed412017-09-28 12:24:04 +02002624 if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002625 res += to_name(c.specialization_constant_id(vector, i));
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002626 else
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002627 {
2628 res += convert_to_string(c.scalar_u64(vector, i));
2629 if (backend.long_long_literal_suffix)
2630 res += "ull";
2631 else
2632 res += "ul";
2633 }
2634
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002635 if (i + 1 < c.vector_size())
2636 res += ", ";
2637 }
2638 }
2639 break;
2640
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002641 case SPIRType::UInt:
2642 if (splat)
2643 {
2644 res += convert_to_string(c.scalar(vector, 0));
2645 if (backend.uint32_t_literal_suffix)
2646 res += "u";
2647 }
2648 else
2649 {
2650 for (uint32_t i = 0; i < c.vector_size(); i++)
2651 {
Hans-Kristian Arntzen0e4ed412017-09-28 12:24:04 +02002652 if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002653 res += to_name(c.specialization_constant_id(vector, i));
2654 else
2655 {
2656 res += convert_to_string(c.scalar(vector, i));
2657 if (backend.uint32_t_literal_suffix)
2658 res += "u";
2659 }
2660
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002661 if (i + 1 < c.vector_size())
2662 res += ", ";
2663 }
2664 }
2665 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002666
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002667 case SPIRType::Int:
2668 if (splat)
2669 res += convert_to_string(c.scalar_i32(vector, 0));
2670 else
2671 {
2672 for (uint32_t i = 0; i < c.vector_size(); i++)
2673 {
Hans-Kristian Arntzen0e4ed412017-09-28 12:24:04 +02002674 if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002675 res += to_name(c.specialization_constant_id(vector, i));
2676 else
2677 res += convert_to_string(c.scalar_i32(vector, i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002678 if (i + 1 < c.vector_size())
2679 res += ", ";
2680 }
2681 }
2682 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002683
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02002684 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002685 if (splat)
2686 res += c.scalar(vector, 0) ? "true" : "false";
2687 else
2688 {
2689 for (uint32_t i = 0; i < c.vector_size(); i++)
2690 {
Hans-Kristian Arntzen0e4ed412017-09-28 12:24:04 +02002691 if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02002692 res += to_name(c.specialization_constant_id(vector, i));
2693 else
2694 res += c.scalar(vector, i) ? "true" : "false";
2695
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002696 if (i + 1 < c.vector_size())
2697 res += ", ";
2698 }
2699 }
2700 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002701
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002702 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01002703 SPIRV_CROSS_THROW("Invalid constant expression basetype.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002704 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002705
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002706 if (c.vector_size() > 1)
2707 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002709 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002710}
2711
2712string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
2713{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002714 auto &type = get<SPIRType>(result_type);
2715 auto flags = meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002717 // If we're declaring temporaries inside continue blocks,
2718 // 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 +01002719 if (current_continue_block && !hoisted_temporaries.count(result_id))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002720 {
2721 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
2722 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02002723 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002724 return tmp.first == result_type && tmp.second == result_id;
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01002725 }) == end(header.declare_temporary))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002726 {
2727 header.declare_temporary.emplace_back(result_type, result_id);
2728 force_recompile = true;
2729 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002730
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002731 return join(to_name(result_id), " = ");
2732 }
Hans-Kristian Arntzenb629ca12017-11-21 09:27:49 +01002733 else if (hoisted_temporaries.count(result_id))
2734 {
2735 // The temporary has already been declared earlier, so just "declare" the temporary by writing to it.
2736 return join(to_name(result_id), " = ");
2737 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002738 else
2739 {
2740 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002741 return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002742 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002743}
2744
2745bool CompilerGLSL::expression_is_forwarded(uint32_t id)
2746{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002747 return forwarded_temporaries.find(id) != end(forwarded_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002748}
2749
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002750SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002751 bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002752{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002753 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
2754 {
2755 // Just forward it without temporary.
2756 // If the forward is trivial, we do not force flushing to temporary for this expression.
2757 if (!suppress_usage_tracking)
2758 forwarded_temporaries.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002759
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002760 return set<SPIRExpression>(result_id, rhs, result_type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002761 }
2762 else
2763 {
2764 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
2765 statement(declare_temporary(result_type, result_id), rhs, ";");
2766 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
2767 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002768}
2769
2770void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
2771{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002772 bool forward = should_forward(op0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002773 emit_op(result_type, result_id, join(op, to_enclosed_expression(op0)), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002774 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002775}
2776
2777void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
2778{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002779 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01002780 emit_op(result_type, result_id, join(to_enclosed_expression(op0), " ", op, " ", to_enclosed_expression(op1)),
2781 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002782
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002783 inherit_expression_dependencies(result_id, op0);
2784 inherit_expression_dependencies(result_id, op1);
2785}
2786
Robert Konradf3a82772017-03-24 15:00:48 +01002787void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op)
2788{
2789 auto &type = get<SPIRType>(result_type);
2790 auto expr = type_to_glsl_constructor(type);
2791 expr += '(';
2792 for (uint32_t i = 0; i < type.vecsize; i++)
2793 {
2794 // Make sure to call to_expression multiple times to ensure
2795 // that these expressions are properly flushed to temporaries if needed.
2796 expr += op;
2797 expr += to_enclosed_expression(operand);
2798 expr += '.';
2799 expr += index_to_swizzle(i);
2800
2801 if (i + 1 < type.vecsize)
2802 expr += ", ";
2803 }
2804 expr += ')';
2805 emit_op(result_type, result_id, expr, should_forward(operand));
2806
2807 inherit_expression_dependencies(result_id, operand);
2808}
2809
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002810void CompilerGLSL::emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
2811 const char *op)
2812{
2813 auto &type = get<SPIRType>(result_type);
2814 auto expr = type_to_glsl_constructor(type);
2815 expr += '(';
2816 for (uint32_t i = 0; i < type.vecsize; i++)
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002817 {
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002818 // Make sure to call to_expression multiple times to ensure
2819 // that these expressions are properly flushed to temporaries if needed.
2820 expr += to_enclosed_expression(op0);
2821 expr += '.';
2822 expr += index_to_swizzle(i);
2823 expr += ' ';
2824 expr += op;
2825 expr += ' ';
2826 expr += to_enclosed_expression(op1);
2827 expr += '.';
2828 expr += index_to_swizzle(i);
2829
2830 if (i + 1 < type.vecsize)
2831 expr += ", ";
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002832 }
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002833 expr += ')';
2834 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
2835
2836 inherit_expression_dependencies(result_id, op0);
2837 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002838}
2839
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002840SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
2841 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
2842{
2843 auto &type0 = expression_type(op0);
2844 auto &type1 = expression_type(op1);
2845
2846 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
2847 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
2848 // since equality test is exactly the same.
2849 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
2850
2851 // Create a fake type so we can bitcast to it.
2852 // We only deal with regular arithmetic types here like int, uints and so on.
2853 SPIRType expected_type;
2854 expected_type.basetype = input_type;
2855 expected_type.vecsize = type0.vecsize;
2856 expected_type.columns = type0.columns;
2857 expected_type.width = type0.width;
2858
2859 if (cast)
2860 {
2861 cast_op0 = bitcast_glsl(expected_type, op0);
2862 cast_op1 = bitcast_glsl(expected_type, op1);
2863 }
2864 else
2865 {
2866 // If we don't cast, our actual input type is that of the first (or second) argument.
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002867 cast_op0 = to_enclosed_expression(op0);
2868 cast_op1 = to_enclosed_expression(op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002869 input_type = type0.basetype;
2870 }
2871
2872 return expected_type;
2873}
2874
2875void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
2876 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
2877{
2878 string cast_op0, cast_op1;
2879 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
2880 auto &out_type = get<SPIRType>(result_type);
2881
2882 // We might have casted away from the result type, so bitcast again.
2883 // For example, arithmetic right shift with uint inputs.
2884 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002885 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02002886 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002887 {
2888 expected_type.basetype = input_type;
2889 expr = bitcast_glsl_op(out_type, expected_type);
2890 expr += '(';
2891 expr += join(cast_op0, " ", op, " ", cast_op1);
2892 expr += ')';
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002893 }
2894 else
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002895 expr += join(cast_op0, " ", op, " ", cast_op1);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002896
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002897 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002898}
2899
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002900void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
2901{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002902 bool forward = should_forward(op0);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002903 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002904 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002905}
2906
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002907void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
2908 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002909{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002910 bool forward = should_forward(op0) && should_forward(op1);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002911 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ")"), forward);
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002912 inherit_expression_dependencies(result_id, op0);
2913 inherit_expression_dependencies(result_id, op1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002914}
2915
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002916void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
2917 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
2918{
2919 string cast_op0, cast_op1;
2920 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
2921 auto &out_type = get<SPIRType>(result_type);
2922
2923 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
2924 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02002925 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002926 {
2927 expected_type.basetype = input_type;
2928 expr = bitcast_glsl_op(out_type, expected_type);
2929 expr += '(';
2930 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
2931 expr += ')';
2932 }
2933 else
2934 {
2935 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
2936 }
2937
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002938 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1));
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002939}
2940
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002941void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
2942 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002943{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002944 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002945 emit_op(result_type, result_id,
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002946 join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ")"), forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002947
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002948 inherit_expression_dependencies(result_id, op0);
2949 inherit_expression_dependencies(result_id, op1);
2950 inherit_expression_dependencies(result_id, op2);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002951}
2952
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002953void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
2954 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002955{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002956 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01002957 emit_op(result_type, result_id,
2958 join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ", ",
2959 to_expression(op3), ")"),
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01002960 forward);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002961
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01002962 inherit_expression_dependencies(result_id, op0);
2963 inherit_expression_dependencies(result_id, op1);
2964 inherit_expression_dependencies(result_id, op2);
2965 inherit_expression_dependencies(result_id, op3);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002966}
2967
Robert Konradedfc2972017-03-23 13:25:24 +01002968// EXT_shader_texture_lod only concerns fragment shaders so lod tex functions
2969// are not allowed in ES 2 vertex shaders. But SPIR-V only supports lod tex
2970// functions in vertex shaders so we revert those back to plain calls when
2971// the lod is a constant value of zero.
Robert Konrad9760f152017-03-23 14:43:54 +01002972bool CompilerGLSL::check_explicit_lod_allowed(uint32_t lod)
Robert Konradedfc2972017-03-23 13:25:24 +01002973{
2974 auto &execution = get_entry_point();
Robert Konrad9760f152017-03-23 14:43:54 +01002975 bool allowed = !is_legacy_es() || execution.model == ExecutionModelFragment;
Robert Konradec396472017-03-24 09:26:02 +01002976 if (!allowed && lod != 0)
Robert Konrad9760f152017-03-23 14:43:54 +01002977 {
2978 auto *lod_constant = maybe_get<SPIRConstant>(lod);
2979 if (!lod_constant || lod_constant->scalar_f32() != 0.0f)
2980 {
2981 SPIRV_CROSS_THROW("Explicit lod not allowed in legacy ES non-fragment shaders.");
2982 }
2983 }
2984 return allowed;
Robert Konradedfc2972017-03-23 13:25:24 +01002985}
2986
Robert Konrad3f745032017-03-23 09:55:32 +01002987string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002988{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002989 const char *type;
2990 switch (imgtype.image.dim)
2991 {
2992 case spv::Dim1D:
Rob Fischer21990632016-09-17 17:01:50 +09002993 type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002994 break;
2995 case spv::Dim2D:
Rob Fischer21990632016-09-17 17:01:50 +09002996 type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002997 break;
2998 case spv::Dim3D:
2999 type = "3D";
3000 break;
3001 case spv::DimCube:
3002 type = "Cube";
3003 break;
3004 case spv::DimBuffer:
3005 type = "Buffer";
3006 break;
3007 case spv::DimSubpassData:
3008 type = "2D";
3009 break;
3010 default:
3011 type = "";
3012 break;
3013 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003014
Robert Konrad9760f152017-03-23 14:43:54 +01003015 bool use_explicit_lod = check_explicit_lod_allowed(lod);
Robert Konrad3f745032017-03-23 09:55:32 +01003016
Bill Hollingsc5c07362016-11-27 12:34:04 -05003017 if (op == "textureLod" || op == "textureProjLod")
Lubos Lenco0028b4f2016-11-21 22:37:20 +01003018 {
Robert Konradedfc2972017-03-23 13:25:24 +01003019 if (is_legacy_es())
3020 {
Robert Konrad9760f152017-03-23 14:43:54 +01003021 if (use_explicit_lod)
Robert Konradedfc2972017-03-23 13:25:24 +01003022 require_extension("GL_EXT_shader_texture_lod");
3023 }
3024 else if (is_legacy())
Lubos Lenco0028b4f2016-11-21 22:37:20 +01003025 require_extension("GL_ARB_shader_texture_lod");
3026 }
Lubos Lenco52158642016-09-17 15:56:23 +02003027
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003028 if (op == "texture")
3029 return join("texture", type);
Robert Konradedfc2972017-03-23 13:25:24 +01003030 else if (op == "textureLod")
3031 {
Robert Konrad9760f152017-03-23 14:43:54 +01003032 if (use_explicit_lod)
Robert Konrad3f745032017-03-23 09:55:32 +01003033 return join("texture", type, is_legacy_es() ? "LodEXT" : "Lod");
Robert Konrad9760f152017-03-23 14:43:54 +01003034 else
3035 return join("texture", type);
Robert Konrad3f745032017-03-23 09:55:32 +01003036 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003037 else if (op == "textureProj")
3038 return join("texture", type, "Proj");
3039 else if (op == "textureProjLod")
Robert Konrad9760f152017-03-23 14:43:54 +01003040 {
3041 if (use_explicit_lod)
Robert Konrad3f745032017-03-23 09:55:32 +01003042 return join("texture", type, is_legacy_es() ? "ProjLodEXT" : "ProjLod");
Robert Konrad9760f152017-03-23 14:43:54 +01003043 else
3044 return join("texture", type);
3045 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003046 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003047 {
3048 SPIRV_CROSS_THROW(join("Unsupported legacy texture op: ", op));
3049 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003050}
3051
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003052bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t left, uint32_t right, uint32_t lerp)
3053{
3054 auto *cleft = maybe_get<SPIRConstant>(left);
3055 auto *cright = maybe_get<SPIRConstant>(right);
3056 auto &lerptype = expression_type(lerp);
3057
3058 // If our targets aren't constants, we cannot use construction.
3059 if (!cleft || !cright)
3060 return false;
3061
3062 // If our targets are spec constants, we cannot use construction.
3063 if (cleft->specialization || cright->specialization)
3064 return false;
3065
3066 // We can only use trivial construction if we have a scalar
3067 // (should be possible to do it for vectors as well, but that is overkill for now).
3068 if (lerptype.basetype != SPIRType::Boolean || lerptype.vecsize > 1)
3069 return false;
3070
3071 // If our bool selects between 0 and 1, we can cast from bool instead, making our trivial constructor.
3072 bool ret = false;
3073 switch (type.basetype)
3074 {
3075 case SPIRType::Int:
3076 case SPIRType::UInt:
3077 ret = cleft->scalar() == 0 && cright->scalar() == 1;
3078 break;
3079
3080 case SPIRType::Float:
3081 ret = cleft->scalar_f32() == 0.0f && cright->scalar_f32() == 1.0f;
3082 break;
3083
3084 case SPIRType::Double:
3085 ret = cleft->scalar_f64() == 0.0 && cright->scalar_f64() == 1.0;
3086 break;
3087
3088 case SPIRType::Int64:
3089 case SPIRType::UInt64:
3090 ret = cleft->scalar_u64() == 0 && cright->scalar_u64() == 1;
3091 break;
3092
3093 default:
3094 break;
3095 }
3096
3097 if (ret)
3098 op = type_to_glsl_constructor(type);
3099 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003100}
3101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003102void 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 +01003103{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003104 auto &lerptype = expression_type(lerp);
3105 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003106
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003107 string mix_op;
Hans-Kristian Arntzen851acf32017-05-04 10:28:30 +02003108 bool has_boolean_mix = backend.boolean_mix_support &&
3109 ((options.es && options.version >= 310) || (!options.es && options.version >= 450));
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003110 bool trivial_mix = to_trivial_mix_op(restype, mix_op, left, right, lerp);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003111
Hans-Kristian Arntzen0e7c33f2017-02-11 10:52:34 +01003112 // Cannot use boolean mix when the lerp argument is just one boolean,
3113 // fall back to regular trinary statements.
3114 if (lerptype.vecsize == 1)
3115 has_boolean_mix = false;
3116
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003117 // If we can reduce the mix to a simple cast, do so.
3118 // This helps for cases like int(bool), uint(bool) which is implemented with
3119 // OpSelect bool 1 0.
3120 if (trivial_mix)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003121 {
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02003122 emit_unary_func_op(result_type, id, lerp, mix_op.c_str());
3123 }
3124 else if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
3125 {
3126 // Boolean mix not supported on desktop without extension.
3127 // Was added in OpenGL 4.5 with ES 3.1 compat.
3128 //
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003129 // Could use GL_EXT_shader_integer_mix on desktop at least,
3130 // but Apple doesn't support it. :(
3131 // Just implement it as ternary expressions.
3132 string expr;
3133 if (lerptype.vecsize == 1)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01003134 expr = join(to_enclosed_expression(lerp), " ? ", to_enclosed_expression(right), " : ",
3135 to_enclosed_expression(left));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003136 else
3137 {
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003138 auto swiz = [this](uint32_t expression, uint32_t i) {
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003139 return join(to_enclosed_expression(expression), ".", index_to_swizzle(i));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003140 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003141
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003142 expr = type_to_glsl_constructor(restype);
3143 expr += "(";
3144 for (uint32_t i = 0; i < restype.vecsize; i++)
3145 {
3146 expr += swiz(lerp, i);
3147 expr += " ? ";
3148 expr += swiz(right, i);
3149 expr += " : ";
3150 expr += swiz(left, i);
3151 if (i + 1 < restype.vecsize)
3152 expr += ", ";
3153 }
3154 expr += ")";
3155 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003156
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003157 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003158 }
3159 else
3160 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003161}
3162
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02003163string CompilerGLSL::to_combined_image_sampler(uint32_t image_id, uint32_t samp_id)
3164{
3165 auto &args = current_function->arguments;
3166
3167 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
3168 // all possible combinations into new sampler2D uniforms.
3169 auto *image = maybe_get_backing_variable(image_id);
3170 auto *samp = maybe_get_backing_variable(samp_id);
3171 if (image)
3172 image_id = image->self;
3173 if (samp)
3174 samp_id = samp->self;
3175
3176 auto image_itr = find_if(begin(args), end(args),
3177 [image_id](const SPIRFunction::Parameter &param) { return param.id == image_id; });
3178
3179 auto sampler_itr = find_if(begin(args), end(args),
3180 [samp_id](const SPIRFunction::Parameter &param) { return param.id == samp_id; });
3181
3182 if (image_itr != end(args) || sampler_itr != end(args))
3183 {
3184 // If any parameter originates from a parameter, we will find it in our argument list.
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02003185 bool global_image = image_itr == end(args);
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02003186 bool global_sampler = sampler_itr == end(args);
Hans-Kristian Arntzen7630d3c2016-11-21 12:14:02 +01003187 uint32_t iid = global_image ? image_id : uint32_t(image_itr - begin(args));
3188 uint32_t sid = global_sampler ? samp_id : uint32_t(sampler_itr - begin(args));
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02003189
3190 auto &combined = current_function->combined_parameters;
3191 auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02003192 return p.global_image == global_image && p.global_sampler == global_sampler && p.image_id == iid &&
3193 p.sampler_id == sid;
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02003194 });
3195
3196 if (itr != end(combined))
3197 return to_expression(itr->id);
3198 else
3199 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003200 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02003201 "Cannot find mapping for combined sampler parameter, was build_combined_image_samplers() used "
3202 "before compile() was called?");
3203 }
3204 }
3205 else
3206 {
3207 // For global sampler2D, look directly at the global remapping table.
3208 auto &mapping = combined_image_samplers;
3209 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
3210 return combined.image_id == image_id && combined.sampler_id == samp_id;
3211 });
3212
3213 if (itr != end(combined_image_samplers))
3214 return to_expression(itr->combined_id);
3215 else
3216 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003217 SPIRV_CROSS_THROW("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
3218 "before compile() was called?");
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02003219 }
3220 }
3221}
3222
Bill Hollings5aafb282016-04-23 21:47:41 -04003223void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
3224{
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02003225 if (options.vulkan_semantics && combined_image_samplers.empty())
3226 {
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02003227 emit_binary_func_op(result_type, result_id, image_id, samp_id,
3228 type_to_glsl(get<SPIRType>(result_type)).c_str());
Hans-Kristian Arntzendfb65972016-09-11 12:05:20 +02003229 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02003230 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003231 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true);
Bill Hollings5aafb282016-04-23 21:47:41 -04003232}
3233
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003234void CompilerGLSL::emit_texture_op(const Instruction &i)
3235{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003236 auto ops = stream(i);
3237 auto op = static_cast<Op>(i.op);
3238 uint32_t length = i.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003240 if (i.offset + length > spirv.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003241 SPIRV_CROSS_THROW("Compiler::parse() opcode out of range.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003242
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003243 uint32_t result_type = ops[0];
3244 uint32_t id = ops[1];
3245 uint32_t img = ops[2];
3246 uint32_t coord = ops[3];
3247 uint32_t dref = 0;
3248 uint32_t comp = 0;
3249 bool gather = false;
3250 bool proj = false;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003251 bool fetch = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003252 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003254 switch (op)
3255 {
3256 case OpImageSampleDrefImplicitLod:
3257 case OpImageSampleDrefExplicitLod:
3258 dref = ops[4];
3259 opt = &ops[5];
3260 length -= 5;
3261 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003262
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003263 case OpImageSampleProjDrefImplicitLod:
3264 case OpImageSampleProjDrefExplicitLod:
3265 dref = ops[4];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003266 opt = &ops[5];
3267 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003268 proj = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003269 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003270
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003271 case OpImageDrefGather:
3272 dref = ops[4];
3273 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003274 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003275 gather = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003276 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003277
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003278 case OpImageGather:
3279 comp = ops[4];
3280 opt = &ops[5];
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003281 length -= 5;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003282 gather = true;
3283 break;
3284
3285 case OpImageFetch:
Bill Hollings8f6df772017-05-19 18:14:08 -04003286 case OpImageRead: // Reads == fetches in Metal (other langs will not get here)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003287 opt = &ops[4];
3288 length -= 4;
3289 fetch = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003290 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003291
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003292 case OpImageSampleProjImplicitLod:
3293 case OpImageSampleProjExplicitLod:
3294 opt = &ops[4];
3295 length -= 4;
3296 proj = true;
3297 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003298
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003299 default:
3300 opt = &ops[4];
3301 length -= 4;
3302 break;
3303 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003304
Bill Hollings8f6df772017-05-19 18:14:08 -04003305 // Bypass pointers because we need the real image struct
3306 auto &type = expression_type(img);
3307 auto &imgtype = get<SPIRType>(type.self);
3308
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003309 uint32_t coord_components = 0;
3310 switch (imgtype.image.dim)
3311 {
3312 case spv::Dim1D:
3313 coord_components = 1;
3314 break;
3315 case spv::Dim2D:
3316 coord_components = 2;
3317 break;
3318 case spv::Dim3D:
3319 coord_components = 3;
3320 break;
3321 case spv::DimCube:
3322 coord_components = 3;
3323 break;
3324 case spv::DimBuffer:
3325 coord_components = 1;
3326 break;
3327 default:
3328 coord_components = 2;
3329 break;
3330 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003332 if (proj)
3333 coord_components++;
3334 if (imgtype.image.arrayed)
3335 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003337 uint32_t bias = 0;
3338 uint32_t lod = 0;
3339 uint32_t grad_x = 0;
3340 uint32_t grad_y = 0;
3341 uint32_t coffset = 0;
3342 uint32_t offset = 0;
3343 uint32_t coffsets = 0;
3344 uint32_t sample = 0;
3345 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003346
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003347 if (length)
3348 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003349 flags = *opt++;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003350 length--;
3351 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003352
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003353 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003354 if (length && (flags & flag))
3355 {
3356 v = *opt++;
3357 length--;
3358 }
3359 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003360
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003361 test(bias, ImageOperandsBiasMask);
3362 test(lod, ImageOperandsLodMask);
3363 test(grad_x, ImageOperandsGradMask);
3364 test(grad_y, ImageOperandsGradMask);
3365 test(coffset, ImageOperandsConstOffsetMask);
3366 test(offset, ImageOperandsOffsetMask);
3367 test(coffsets, ImageOperandsConstOffsetsMask);
3368 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003369
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003370 string expr;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003371 bool forward = false;
Hans-Kristian Arntzen27f4f752017-01-13 16:32:54 +01003372 expr += to_function_name(img, imgtype, !!fetch, !!gather, !!proj, !!coffsets, (!!coffset || !!offset),
Robert Konradec396472017-03-24 09:26:02 +01003373 (!!grad_x || !!grad_y), !!dref, lod);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003374 expr += "(";
3375 expr += to_function_args(img, imgtype, fetch, gather, proj, coord, coord_components, dref, grad_x, grad_y, lod,
3376 coffset, offset, bias, comp, sample, &forward);
3377 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003378
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003379 emit_op(result_type, id, expr, forward);
3380}
3381
3382// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
3383// For some subclasses, the function is a method on the specified image.
Bill Hollings4e915e82017-01-08 08:52:57 -05003384string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
Robert Konradec396472017-03-24 09:26:02 +01003385 bool has_array_offsets, bool has_offset, bool has_grad, bool, uint32_t lod)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003386{
3387 string fname;
3388
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02003389 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003390 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
3391 // 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 +02003392 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003393 bool workaround_lod_array_shadow_as_grad = false;
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02003394 if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
3395 imgtype.image.depth && lod)
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003396 {
3397 auto *constant_lod = maybe_get<SPIRConstant>(lod);
3398 if (!constant_lod || constant_lod->scalar_f32() != 0.0f)
Hans-Kristian Arntzen7bb74912017-06-23 09:46:15 +02003399 SPIRV_CROSS_THROW(
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02003400 "textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be expressed in GLSL.");
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003401 workaround_lod_array_shadow_as_grad = true;
3402 }
3403
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003404 if (is_fetch)
3405 fname += "texelFetch";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003406 else
3407 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003408 fname += "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003409
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003410 if (is_gather)
3411 fname += "Gather";
3412 if (has_array_offsets)
3413 fname += "Offsets";
3414 if (is_proj)
3415 fname += "Proj";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003416 if (has_grad || workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003417 fname += "Grad";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003418 if (!!lod && !workaround_lod_array_shadow_as_grad)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003419 fname += "Lod";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003420 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003421
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003422 if (has_offset)
3423 fname += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003424
Robert Konrad3f745032017-03-23 09:55:32 +01003425 return is_legacy() ? legacy_tex_op(fname, imgtype, lod) : fname;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003426}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003427
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003428// Returns the function args for a texture sampling function for the specified image and sampling characteristics.
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02003429string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool, bool, bool is_proj, uint32_t coord,
Bill Hollings4e915e82017-01-08 08:52:57 -05003430 uint32_t coord_components, uint32_t dref, uint32_t grad_x, uint32_t grad_y,
3431 uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp,
3432 uint32_t sample, bool *p_forward)
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003433{
3434 string farg_str = to_expression(img);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003436 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003437 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003438 if (comps == in_comps)
3439 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003440
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003441 switch (comps)
3442 {
3443 case 1:
3444 return ".x";
3445 case 2:
3446 return swizz_func ? ".xy()" : ".xy";
3447 case 3:
3448 return swizz_func ? ".xyz()" : ".xyz";
3449 default:
3450 return "";
3451 }
3452 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003453
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003454 bool forward = should_forward(coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003455
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003456 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01003457 auto swizzle_expr = swizzle(coord_components, expression_type(coord).vecsize);
3458 // Only enclose the UV expression if needed.
3459 auto coord_expr = (*swizzle_expr == '\0') ? to_expression(coord) : (to_enclosed_expression(coord) + swizzle_expr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003460
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01003461 // texelFetch only takes int, not uint.
3462 auto &coord_type = expression_type(coord);
3463 if (coord_type.basetype == SPIRType::UInt)
3464 {
3465 auto expected_type = coord_type;
3466 expected_type.basetype = SPIRType::Int;
3467 coord_expr = bitcast_expression(expected_type, coord_type.basetype, coord_expr);
3468 }
3469
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02003470 // textureLod on sampler2DArrayShadow and samplerCubeShadow does not exist in GLSL for some reason.
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003471 // To emulate this, we will have to use textureGrad with a constant gradient of 0.
3472 // 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 +02003473 // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
Hans-Kristian Arntzend38b1b02017-06-23 09:50:01 +02003474 bool workaround_lod_array_shadow_as_grad =
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02003475 ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
3476 imgtype.image.depth && lod;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003477
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003478 if (dref)
3479 {
3480 forward = forward && should_forward(dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003481
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003482 // SPIR-V splits dref and coordinate.
3483 if (coord_components == 4) // GLSL also splits the arguments in two.
3484 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003485 farg_str += ", ";
3486 farg_str += to_expression(coord);
3487 farg_str += ", ";
3488 farg_str += to_expression(dref);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003489 }
Hans-Kristian Arntzencbcaca52017-07-31 10:05:32 +02003490 else if (is_proj)
3491 {
3492 // Have to reshuffle so we get vec4(coord, dref, proj), special case.
3493 // Other shading languages splits up the arguments for coord and compare value like SPIR-V.
3494 // The coordinate type for textureProj shadow is always vec4 even for sampler1DShadow.
3495 farg_str += ", vec4(";
3496
3497 if (imgtype.image.dim == Dim1D)
3498 {
3499 // Could reuse coord_expr, but we will mess up the temporary usage checking.
3500 farg_str += to_enclosed_expression(coord) + ".x";
3501 farg_str += ", ";
3502 farg_str += "0.0, ";
3503 farg_str += to_expression(dref);
3504 farg_str += ", ";
3505 farg_str += to_enclosed_expression(coord) + ".y)";
3506 }
3507 else if (imgtype.image.dim == Dim2D)
3508 {
3509 // Could reuse coord_expr, but we will mess up the temporary usage checking.
3510 farg_str += to_enclosed_expression(coord) + (swizz_func ? ".xy()" : ".xy");
3511 farg_str += ", ";
3512 farg_str += to_expression(dref);
3513 farg_str += ", ";
3514 farg_str += to_enclosed_expression(coord) + ".z)";
3515 }
3516 else
3517 SPIRV_CROSS_THROW("Invalid type for textureProj with shadow.");
3518 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003519 else
3520 {
3521 // Create a composite which merges coord/dref into a single vector.
3522 auto type = expression_type(coord);
3523 type.vecsize = coord_components + 1;
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003524 farg_str += ", ";
3525 farg_str += type_to_glsl_constructor(type);
3526 farg_str += "(";
3527 farg_str += coord_expr;
3528 farg_str += ", ";
3529 farg_str += to_expression(dref);
3530 farg_str += ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003531 }
3532 }
3533 else
3534 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003535 farg_str += ", ";
3536 farg_str += coord_expr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003537 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003538
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003539 if (grad_x || grad_y)
3540 {
3541 forward = forward && should_forward(grad_x);
3542 forward = forward && should_forward(grad_y);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003543 farg_str += ", ";
3544 farg_str += to_expression(grad_x);
3545 farg_str += ", ";
3546 farg_str += to_expression(grad_y);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003547 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003548
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003549 if (lod)
3550 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003551 if (workaround_lod_array_shadow_as_grad)
Robert Konrad3f745032017-03-23 09:55:32 +01003552 {
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003553 // Implement textureGrad() instead. LOD == 0.0 is implemented as gradient of 0.0.
3554 // Implementing this as plain texture() is not safe on some implementations.
Hans-Kristian Arntzendf6aa0e2017-07-24 09:28:24 +02003555 if (imgtype.image.dim == Dim2D)
3556 farg_str += ", vec2(0.0), vec2(0.0)";
3557 else if (imgtype.image.dim == DimCube)
3558 farg_str += ", vec3(0.0), vec3(0.0)";
Hans-Kristian Arntzenad2b7c02017-06-23 09:44:41 +02003559 }
3560 else
3561 {
3562 if (check_explicit_lod_allowed(lod))
3563 {
3564 forward = forward && should_forward(lod);
3565 farg_str += ", ";
3566 farg_str += to_expression(lod);
3567 }
Robert Konrad3f745032017-03-23 09:55:32 +01003568 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003569 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003570
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003571 if (coffset)
3572 {
3573 forward = forward && should_forward(coffset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003574 farg_str += ", ";
3575 farg_str += to_expression(coffset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003576 }
3577 else if (offset)
3578 {
3579 forward = forward && should_forward(offset);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003580 farg_str += ", ";
3581 farg_str += to_expression(offset);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003582 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003584 if (bias)
3585 {
3586 forward = forward && should_forward(bias);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003587 farg_str += ", ";
3588 farg_str += to_expression(bias);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003589 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003590
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003591 if (comp)
3592 {
3593 forward = forward && should_forward(comp);
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003594 farg_str += ", ";
3595 farg_str += to_expression(comp);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003596 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003597
Hans-Kristian Arntzen9d4360f2016-06-22 12:35:58 +02003598 if (sample)
3599 {
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003600 farg_str += ", ";
3601 farg_str += to_expression(sample);
Hans-Kristian Arntzen9d4360f2016-06-22 12:35:58 +02003602 }
3603
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003604 *p_forward = forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003605
Bill Hollingsa2b8a0e2016-12-28 18:36:42 -05003606 return farg_str;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003607}
3608
3609void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t)
3610{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003611 GLSLstd450 op = static_cast<GLSLstd450>(eop);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003613 switch (op)
3614 {
3615 // FP fiddling
3616 case GLSLstd450Round:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003617 emit_unary_func_op(result_type, id, args[0], "round");
3618 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003619
3620 case GLSLstd450RoundEven:
3621 if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
3622 emit_unary_func_op(result_type, id, args[0], "roundEven");
3623 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01003624 SPIRV_CROSS_THROW("roundEven supported only in ESSL 300 and GLSL 130 and up.");
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003625 break;
3626
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003627 case GLSLstd450Trunc:
3628 emit_unary_func_op(result_type, id, args[0], "trunc");
3629 break;
3630 case GLSLstd450SAbs:
3631 case GLSLstd450FAbs:
3632 emit_unary_func_op(result_type, id, args[0], "abs");
3633 break;
3634 case GLSLstd450SSign:
3635 case GLSLstd450FSign:
3636 emit_unary_func_op(result_type, id, args[0], "sign");
3637 break;
3638 case GLSLstd450Floor:
3639 emit_unary_func_op(result_type, id, args[0], "floor");
3640 break;
3641 case GLSLstd450Ceil:
3642 emit_unary_func_op(result_type, id, args[0], "ceil");
3643 break;
3644 case GLSLstd450Fract:
3645 emit_unary_func_op(result_type, id, args[0], "fract");
3646 break;
3647 case GLSLstd450Radians:
3648 emit_unary_func_op(result_type, id, args[0], "radians");
3649 break;
3650 case GLSLstd450Degrees:
3651 emit_unary_func_op(result_type, id, args[0], "degrees");
3652 break;
3653 case GLSLstd450Fma:
3654 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
3655 break;
3656 case GLSLstd450Modf:
3657 register_call_out_argument(args[1]);
3658 forced_temporaries.insert(id);
3659 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
3660 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003661
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02003662 case GLSLstd450ModfStruct:
3663 {
3664 forced_temporaries.insert(id);
3665 auto &type = get<SPIRType>(result_type);
3666 auto flags = meta[id].decoration.decoration_flags;
3667 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(id)), ";");
3668 set<SPIRExpression>(id, to_name(id), result_type, true);
3669
3670 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
3671 to_expression(id), ".", to_member_name(type, 1), ");");
3672 break;
3673 }
3674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003675 // Minmax
3676 case GLSLstd450FMin:
3677 case GLSLstd450UMin:
3678 case GLSLstd450SMin:
3679 emit_binary_func_op(result_type, id, args[0], args[1], "min");
3680 break;
3681 case GLSLstd450FMax:
3682 case GLSLstd450UMax:
3683 case GLSLstd450SMax:
3684 emit_binary_func_op(result_type, id, args[0], args[1], "max");
3685 break;
3686 case GLSLstd450FClamp:
3687 case GLSLstd450UClamp:
3688 case GLSLstd450SClamp:
3689 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
3690 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003691
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003692 // Trig
3693 case GLSLstd450Sin:
3694 emit_unary_func_op(result_type, id, args[0], "sin");
3695 break;
3696 case GLSLstd450Cos:
3697 emit_unary_func_op(result_type, id, args[0], "cos");
3698 break;
3699 case GLSLstd450Tan:
3700 emit_unary_func_op(result_type, id, args[0], "tan");
3701 break;
3702 case GLSLstd450Asin:
3703 emit_unary_func_op(result_type, id, args[0], "asin");
3704 break;
3705 case GLSLstd450Acos:
3706 emit_unary_func_op(result_type, id, args[0], "acos");
3707 break;
3708 case GLSLstd450Atan:
3709 emit_unary_func_op(result_type, id, args[0], "atan");
3710 break;
3711 case GLSLstd450Sinh:
3712 emit_unary_func_op(result_type, id, args[0], "sinh");
3713 break;
3714 case GLSLstd450Cosh:
3715 emit_unary_func_op(result_type, id, args[0], "cosh");
3716 break;
3717 case GLSLstd450Tanh:
3718 emit_unary_func_op(result_type, id, args[0], "tanh");
3719 break;
3720 case GLSLstd450Asinh:
3721 emit_unary_func_op(result_type, id, args[0], "asinh");
3722 break;
3723 case GLSLstd450Acosh:
3724 emit_unary_func_op(result_type, id, args[0], "acosh");
3725 break;
3726 case GLSLstd450Atanh:
3727 emit_unary_func_op(result_type, id, args[0], "atanh");
3728 break;
3729 case GLSLstd450Atan2:
3730 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
3731 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003732
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003733 // Exponentials
3734 case GLSLstd450Pow:
3735 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
3736 break;
3737 case GLSLstd450Exp:
3738 emit_unary_func_op(result_type, id, args[0], "exp");
3739 break;
3740 case GLSLstd450Log:
3741 emit_unary_func_op(result_type, id, args[0], "log");
3742 break;
3743 case GLSLstd450Exp2:
3744 emit_unary_func_op(result_type, id, args[0], "exp2");
3745 break;
3746 case GLSLstd450Log2:
3747 emit_unary_func_op(result_type, id, args[0], "log2");
3748 break;
3749 case GLSLstd450Sqrt:
3750 emit_unary_func_op(result_type, id, args[0], "sqrt");
3751 break;
3752 case GLSLstd450InverseSqrt:
3753 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
3754 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003755
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003756 // Matrix math
3757 case GLSLstd450Determinant:
3758 emit_unary_func_op(result_type, id, args[0], "determinant");
3759 break;
3760 case GLSLstd450MatrixInverse:
3761 emit_unary_func_op(result_type, id, args[0], "inverse");
3762 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003763
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003764 // Lerping
3765 case GLSLstd450FMix:
3766 case GLSLstd450IMix:
3767 {
3768 emit_mix_op(result_type, id, args[0], args[1], args[2]);
3769 break;
3770 }
3771 case GLSLstd450Step:
3772 emit_binary_func_op(result_type, id, args[0], args[1], "step");
3773 break;
3774 case GLSLstd450SmoothStep:
3775 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
3776 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003777
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003778 // Packing
3779 case GLSLstd450Frexp:
3780 register_call_out_argument(args[1]);
3781 forced_temporaries.insert(id);
3782 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
3783 break;
Hans-Kristian Arntzen9091ead2017-09-04 10:24:21 +02003784
3785 case GLSLstd450FrexpStruct:
3786 {
3787 forced_temporaries.insert(id);
3788 auto &type = get<SPIRType>(result_type);
3789 auto flags = meta[id].decoration.decoration_flags;
3790 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(id)), ";");
3791 set<SPIRExpression>(id, to_name(id), result_type, true);
3792
3793 statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
3794 to_expression(id), ".", to_member_name(type, 1), ");");
3795 break;
3796 }
3797
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003798 case GLSLstd450Ldexp:
3799 emit_binary_func_op(result_type, id, args[0], args[1], "ldexp");
3800 break;
3801 case GLSLstd450PackSnorm4x8:
3802 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
3803 break;
3804 case GLSLstd450PackUnorm4x8:
3805 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
3806 break;
3807 case GLSLstd450PackSnorm2x16:
3808 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
3809 break;
3810 case GLSLstd450PackUnorm2x16:
3811 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
3812 break;
3813 case GLSLstd450PackHalf2x16:
3814 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
3815 break;
3816 case GLSLstd450UnpackSnorm4x8:
3817 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
3818 break;
3819 case GLSLstd450UnpackUnorm4x8:
3820 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
3821 break;
3822 case GLSLstd450UnpackSnorm2x16:
3823 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
3824 break;
3825 case GLSLstd450UnpackUnorm2x16:
3826 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
3827 break;
3828 case GLSLstd450UnpackHalf2x16:
3829 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
3830 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003831
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003832 case GLSLstd450PackDouble2x32:
3833 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
3834 break;
3835 case GLSLstd450UnpackDouble2x32:
3836 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
3837 break;
3838
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003839 // Vector math
3840 case GLSLstd450Length:
3841 emit_unary_func_op(result_type, id, args[0], "length");
3842 break;
3843 case GLSLstd450Distance:
3844 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
3845 break;
3846 case GLSLstd450Cross:
3847 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
3848 break;
3849 case GLSLstd450Normalize:
3850 emit_unary_func_op(result_type, id, args[0], "normalize");
3851 break;
3852 case GLSLstd450FaceForward:
3853 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
3854 break;
3855 case GLSLstd450Reflect:
3856 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
3857 break;
3858 case GLSLstd450Refract:
3859 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
3860 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003861
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003862 // Bit-fiddling
3863 case GLSLstd450FindILsb:
3864 emit_unary_func_op(result_type, id, args[0], "findLSB");
3865 break;
3866 case GLSLstd450FindSMsb:
3867 case GLSLstd450FindUMsb:
3868 emit_unary_func_op(result_type, id, args[0], "findMSB");
3869 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003870
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003871 // Multisampled varying
3872 case GLSLstd450InterpolateAtCentroid:
3873 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
3874 break;
3875 case GLSLstd450InterpolateAtSample:
3876 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
3877 break;
3878 case GLSLstd450InterpolateAtOffset:
3879 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
3880 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003881
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003882 default:
3883 statement("// unimplemented GLSL op ", eop);
3884 break;
3885 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003886}
3887
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01003888void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
3889 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01003890{
3891 require_extension("GL_AMD_shader_ballot");
3892
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01003893 enum AMDShaderBallot
3894 {
Lou Kramer6671f522017-11-21 14:04:57 +01003895 SwizzleInvocationsAMD = 1,
3896 SwizzleInvocationsMaskedAMD = 2,
3897 WriteInvocationAMD = 3,
3898 MbcntAMD = 4
3899 };
3900
3901 auto op = static_cast<AMDShaderBallot>(eop);
3902
3903 switch (op)
3904 {
3905 case SwizzleInvocationsAMD:
3906 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsAMD");
3907 break;
3908
3909 case SwizzleInvocationsMaskedAMD:
3910 emit_binary_func_op(result_type, id, args[0], args[1], "swizzleInvocationsMaskedAMD");
3911 break;
3912
3913 case WriteInvocationAMD:
3914 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "writeInvocationAMD");
3915 break;
3916
3917 case MbcntAMD:
3918 emit_unary_func_op(result_type, id, args[0], "mbcntAMD");
3919 break;
3920
3921 default:
3922 statement("// unimplemented SPV AMD shader ballot op ", eop);
3923 break;
3924 }
3925}
3926
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01003927void CompilerGLSL::emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t id, uint32_t eop,
3928 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01003929{
3930 require_extension("GL_AMD_shader_explicit_vertex_parameter");
3931
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01003932 enum AMDShaderExplicitVertexParameter
3933 {
Lou Kramer6671f522017-11-21 14:04:57 +01003934 InterpolateAtVertexAMD = 1
3935 };
3936
3937 auto op = static_cast<AMDShaderExplicitVertexParameter>(eop);
3938
3939 switch (op)
3940 {
3941 case InterpolateAtVertexAMD:
3942 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtVertexAMD");
3943 break;
3944
3945 default:
3946 statement("// unimplemented SPV AMD shader explicit vertex parameter op ", eop);
3947 break;
3948 }
3949}
3950
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01003951void CompilerGLSL::emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t id, uint32_t eop,
3952 const uint32_t *args, uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01003953{
3954 require_extension("GL_AMD_shader_trinary_minmax");
3955
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01003956 enum AMDShaderTrinaryMinMax
3957 {
Lou Kramer6671f522017-11-21 14:04:57 +01003958 FMin3AMD = 1,
3959 UMin3AMD = 2,
3960 SMin3AMD = 3,
3961 FMax3AMD = 4,
3962 UMax3AMD = 5,
3963 SMax3AMD = 6,
3964 FMid3AMD = 7,
3965 UMid3AMD = 8,
3966 SMid3AMD = 9
3967 };
3968
3969 auto op = static_cast<AMDShaderTrinaryMinMax>(eop);
3970
3971 switch (op)
3972 {
3973 case FMin3AMD:
3974 case UMin3AMD:
3975 case SMin3AMD:
3976 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "min3");
3977 break;
3978
3979 case FMax3AMD:
3980 case UMax3AMD:
3981 case SMax3AMD:
3982 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "max3");
3983 break;
3984
3985 case FMid3AMD:
3986 case UMid3AMD:
3987 case SMid3AMD:
3988 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mid3");
3989 break;
3990
3991 default:
3992 statement("// unimplemented SPV AMD shader trinary minmax op ", eop);
3993 break;
3994 }
3995}
3996
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01003997void CompilerGLSL::emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
3998 uint32_t)
Lou Kramer6671f522017-11-21 14:04:57 +01003999{
4000 require_extension("GL_AMD_gcn_shader");
4001
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01004002 enum AMDGCNShader
4003 {
Lou Kramer6671f522017-11-21 14:04:57 +01004004 CubeFaceIndexAMD = 1,
4005 CubeFaceCoordAMD = 2,
4006 TimeAMD = 3
4007 };
4008
4009 auto op = static_cast<AMDGCNShader>(eop);
4010
4011 switch (op)
4012 {
4013 case CubeFaceIndexAMD:
4014 emit_unary_func_op(result_type, id, args[0], "cubeFaceIndexAMD");
4015 break;
4016 case CubeFaceCoordAMD:
4017 emit_unary_func_op(result_type, id, args[0], "cubeFaceCoordAMD");
4018 break;
4019 case TimeAMD:
4020 {
4021 string expr = "timeAMD()";
4022 emit_op(result_type, id, expr, true);
4023 break;
4024 }
4025
4026 default:
4027 statement("// unimplemented SPV AMD gcn shader op ", eop);
4028 break;
4029 }
4030}
4031
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004032string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004033{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004034 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
4035 return type_to_glsl(out_type);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004036 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Int64)
4037 return type_to_glsl(out_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004038 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
4039 return "floatBitsToUint";
4040 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
4041 return type_to_glsl(out_type);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004042 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::UInt64)
4043 return type_to_glsl(out_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004044 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
4045 return "floatBitsToInt";
4046 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
4047 return "uintBitsToFloat";
4048 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
4049 return "intBitsToFloat";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004050 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
4051 return "doubleBitsToInt64";
4052 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
4053 return "doubleBitsToUint64";
4054 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
4055 return "int64BitsToDouble";
4056 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
4057 return "uint64BitsToDouble";
Lou Kramer6671f522017-11-21 14:04:57 +01004058 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
Lou Kramer6671f522017-11-21 14:04:57 +01004059 return "packUint2x32";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004060 else
4061 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004062}
4063
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004064string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004065{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02004066 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004067 if (op.empty())
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004068 return to_enclosed_expression(argument);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004069 else
4070 return join(op, "(", to_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004071}
4072
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02004073std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg)
4074{
4075 auto expr = to_expression(arg);
4076 auto &src_type = expression_type(arg);
4077 if (src_type.basetype != target_type)
4078 {
4079 auto target = src_type;
4080 target.basetype = target_type;
4081 expr = join(bitcast_glsl_op(target, src_type), "(", expr, ")");
4082 }
4083
4084 return expr;
4085}
4086
4087std::string CompilerGLSL::bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type,
4088 const std::string &expr)
4089{
4090 if (target_type.basetype == expr_type)
4091 return expr;
4092
4093 auto src_type = target_type;
4094 src_type.basetype = expr_type;
4095 return join(bitcast_glsl_op(target_type, src_type), "(", expr, ")");
4096}
4097
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004098string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004099{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004100 switch (builtin)
4101 {
4102 case BuiltInPosition:
4103 return "gl_Position";
4104 case BuiltInPointSize:
4105 return "gl_PointSize";
Bill Hollingse73e8e42016-12-17 17:07:53 -05004106 case BuiltInClipDistance:
4107 return "gl_ClipDistance";
Hans-Kristian Arntzen7f2e1792017-03-05 12:44:29 +01004108 case BuiltInCullDistance:
4109 return "gl_CullDistance";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004110 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004111 if (options.vulkan_semantics)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004112 SPIRV_CROSS_THROW(
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004113 "Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004114 return "gl_VertexID";
4115 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004116 if (options.vulkan_semantics)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004117 SPIRV_CROSS_THROW(
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004118 "Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004119 return "gl_InstanceID";
4120 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004121 if (options.vulkan_semantics)
4122 return "gl_VertexIndex";
4123 else
4124 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004125 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004126 if (options.vulkan_semantics)
4127 return "gl_InstanceIndex";
4128 else
4129 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004130 case BuiltInPrimitiveId:
4131 return "gl_PrimitiveID";
4132 case BuiltInInvocationId:
4133 return "gl_InvocationID";
4134 case BuiltInLayer:
4135 return "gl_Layer";
4136 case BuiltInTessLevelOuter:
4137 return "gl_TessLevelOuter";
4138 case BuiltInTessLevelInner:
4139 return "gl_TessLevelInner";
4140 case BuiltInTessCoord:
4141 return "gl_TessCoord";
4142 case BuiltInFragCoord:
4143 return "gl_FragCoord";
4144 case BuiltInPointCoord:
4145 return "gl_PointCoord";
4146 case BuiltInFrontFacing:
4147 return "gl_FrontFacing";
4148 case BuiltInFragDepth:
4149 return "gl_FragDepth";
4150 case BuiltInNumWorkgroups:
4151 return "gl_NumWorkGroups";
4152 case BuiltInWorkgroupSize:
4153 return "gl_WorkGroupSize";
4154 case BuiltInWorkgroupId:
4155 return "gl_WorkGroupID";
4156 case BuiltInLocalInvocationId:
4157 return "gl_LocalInvocationID";
4158 case BuiltInGlobalInvocationId:
4159 return "gl_GlobalInvocationID";
4160 case BuiltInLocalInvocationIndex:
4161 return "gl_LocalInvocationIndex";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004162
4163 case BuiltInSampleId:
4164 if (options.es && options.version < 320)
4165 require_extension("GL_OES_sample_variables");
4166 if (!options.es && options.version < 400)
4167 SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
4168 return "gl_SampleID";
4169
4170 case BuiltInSampleMask:
4171 if (options.es && options.version < 320)
4172 require_extension("GL_OES_sample_variables");
4173 if (!options.es && options.version < 400)
4174 SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
4175
4176 if (storage == StorageClassInput)
4177 return "gl_SampleMaskIn";
4178 else
4179 return "gl_SampleMask";
4180
4181 case BuiltInSamplePosition:
4182 if (options.es && options.version < 320)
4183 require_extension("GL_OES_sample_variables");
4184 if (!options.es && options.version < 400)
4185 SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
4186 return "gl_SamplePosition";
4187
Hans-Kristian Arntzend7f38ab2017-08-15 13:28:16 +02004188 case BuiltInViewIndex:
4189 if (options.vulkan_semantics)
4190 {
4191 require_extension("GL_EXT_multiview");
4192 return "gl_ViewIndex";
4193 }
4194 else
4195 {
4196 require_extension("GL_OVR_multiview2");
4197 return "gl_ViewID_OVR";
4198 }
4199
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004200 default:
Bill Hollingse73e8e42016-12-17 17:07:53 -05004201 return join("gl_BuiltIn_", convert_to_string(builtin));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004202 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004203}
4204
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004205const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004206{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004207 switch (index)
4208 {
4209 case 0:
4210 return "x";
4211 case 1:
4212 return "y";
4213 case 2:
4214 return "z";
4215 case 3:
4216 return "w";
4217 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004218 SPIRV_CROSS_THROW("Swizzle index out of range");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004219 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004220}
4221
Hans-Kristian Arntzeneb5e09f2017-02-23 19:33:14 +01004222string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count,
4223 bool index_is_literal, bool chain_only, bool *need_transpose)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004224{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004225 string expr;
4226 if (!chain_only)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01004227 expr = to_enclosed_expression(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004228
Bill Hollings1e84a372017-08-12 00:21:13 -04004229 uint32_t type_id = expression_type_id(base);
4230 const auto *type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004231
Bill Hollings1e84a372017-08-12 00:21:13 -04004232 // Start traversing type hierarchy at the proper non-pointer types,
4233 // but keep type_id referencing the original pointer for use below.
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01004234 while (type->pointer)
4235 {
4236 assert(type->parent_type);
4237 type = &get<SPIRType>(type->parent_type);
4238 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004240 bool access_chain_is_arrayed = false;
Bill Hollings13583622016-12-14 02:12:52 -05004241 bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
Bill Hollings1c180782017-11-05 21:34:42 -05004242 bool vector_is_packed = false;
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004243 bool pending_array_enclose = false;
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02004244 bool dimension_flatten = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004245
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004246 for (uint32_t i = 0; i < count; i++)
4247 {
4248 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004250 // Arrays
4251 if (!type->array.empty())
4252 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004253 // If we are flattening multidimensional arrays, only create opening bracket on first
4254 // array index.
4255 if (options.flatten_multidimensional_arrays && !pending_array_enclose)
4256 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02004257 dimension_flatten = type->array.size() > 1;
4258 pending_array_enclose = dimension_flatten;
4259 if (pending_array_enclose)
4260 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004261 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004262
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01004263 assert(type->parent_type);
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004264 // If we are flattening multidimensional arrays, do manual stride computation.
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02004265 if (options.flatten_multidimensional_arrays && dimension_flatten)
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004266 {
4267 auto &parent_type = get<SPIRType>(type->parent_type);
4268
4269 if (index_is_literal)
4270 expr += convert_to_string(index);
4271 else
4272 expr += to_enclosed_expression(index);
4273
4274 for (auto j = uint32_t(parent_type.array.size()); j; j--)
4275 {
4276 expr += " * ";
4277 expr += enclose_expression(to_array_size(parent_type, j - 1));
4278 }
4279
4280 if (parent_type.array.empty())
4281 pending_array_enclose = false;
4282 else
4283 expr += " + ";
4284 }
4285 else
4286 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02004287 expr += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004288 if (index_is_literal)
4289 expr += convert_to_string(index);
4290 else
4291 expr += to_expression(index);
4292 }
4293
4294 if (!pending_array_enclose)
4295 expr += "]";
4296
Bill Hollings1e84a372017-08-12 00:21:13 -04004297 type_id = type->parent_type;
4298 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004299
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004300 access_chain_is_arrayed = true;
4301 }
4302 // For structs, the index refers to a constant, which indexes into the members.
4303 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
4304 else if (type->basetype == SPIRType::Struct)
4305 {
4306 if (!index_is_literal)
4307 index = get<SPIRConstant>(index).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004308
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004309 if (index >= type->member_types.size())
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004310 SPIRV_CROSS_THROW("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004312 BuiltIn builtin;
4313 if (is_member_builtin(*type, index, &builtin))
4314 {
4315 // FIXME: We rely here on OpName on gl_in/gl_out to make this work properly.
4316 // To make this properly work by omitting all OpName opcodes,
4317 // we need to infer gl_in or gl_out based on the builtin, and stage.
4318 if (access_chain_is_arrayed)
4319 {
4320 expr += ".";
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004321 expr += builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004322 }
4323 else
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02004324 expr = builtin_to_glsl(builtin, type->storage);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004325 }
4326 else
4327 {
Bill Hollingsc1b81542017-05-22 21:41:19 -04004328 // If the member has a qualified name, use it as the entire chain
Bill Hollings1e84a372017-08-12 00:21:13 -04004329 string qual_mbr_name = get_member_qualified_name(type_id, index);
Bill Hollingsc1b81542017-05-22 21:41:19 -04004330 if (!qual_mbr_name.empty())
4331 expr = qual_mbr_name;
4332 else
4333 {
4334 expr += ".";
4335 expr += to_member_name(*type, index);
4336 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004337 }
Bill Hollingsb332bae2017-03-01 13:07:40 -05004338
Bill Hollings1c180782017-11-05 21:34:42 -05004339 vector_is_packed = member_is_packed_type(*type, index);
Bill Hollings13583622016-12-14 02:12:52 -05004340 row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004341 type = &get<SPIRType>(type->member_types[index]);
4342 }
4343 // Matrix -> Vector
4344 else if (type->columns > 1)
4345 {
Bill Hollings13583622016-12-14 02:12:52 -05004346 if (row_major_matrix_needs_conversion)
Bill Hollings343677e2016-12-11 11:01:08 -05004347 {
Bill Hollings13583622016-12-14 02:12:52 -05004348 expr = convert_row_major_matrix(expr);
4349 row_major_matrix_needs_conversion = false;
Bill Hollings343677e2016-12-11 11:01:08 -05004350 }
4351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004352 expr += "[";
4353 if (index_is_literal)
4354 expr += convert_to_string(index);
4355 else
4356 expr += to_expression(index);
4357 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004358
Bill Hollings1e84a372017-08-12 00:21:13 -04004359 type_id = type->parent_type;
4360 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004361 }
4362 // Vector -> Scalar
4363 else if (type->vecsize > 1)
4364 {
Bill Hollings1c180782017-11-05 21:34:42 -05004365 if (vector_is_packed)
4366 expr = unpack_expression_type(expr, *type);
4367
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004368 if (index_is_literal)
4369 {
4370 expr += ".";
4371 expr += index_to_swizzle(index);
4372 }
4373 else if (ids[index].get_type() == TypeConstant)
4374 {
4375 auto &c = get<SPIRConstant>(index);
4376 expr += ".";
4377 expr += index_to_swizzle(c.scalar());
4378 }
4379 else
4380 {
4381 expr += "[";
4382 expr += to_expression(index);
4383 expr += "]";
4384 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004385
Bill Hollings1e84a372017-08-12 00:21:13 -04004386 type_id = type->parent_type;
4387 type = &get<SPIRType>(type_id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004388 }
4389 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01004390 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004391 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004392
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004393 if (pending_array_enclose)
4394 {
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02004395 SPIRV_CROSS_THROW("Flattening of multidimensional arrays were enabled, "
4396 "but the access chain was terminated in the middle of a multidimensional array. "
4397 "This is not supported.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02004398 }
4399
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01004400 if (need_transpose)
4401 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004402 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004403}
4404
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004405string CompilerGLSL::to_flattened_struct_member(const SPIRType &type, uint32_t index)
4406{
4407 return sanitize_underscores(join(to_name(type.self), "_", to_member_name(type, index)));
4408}
4409
Bill Hollings2d0d3282017-01-20 11:33:59 -05004410string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004411 bool *out_need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004412{
Arseny Kapoulkine24c66252017-01-16 14:19:49 -08004413 if (flattened_buffer_blocks.count(base))
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004414 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004415 uint32_t matrix_stride = 0;
4416 bool need_transpose = false;
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02004417 flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004418
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004419 if (out_need_transpose)
4420 *out_need_transpose = target_type.columns > 1 && need_transpose;
4421
4422 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004423 }
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01004424 else if (flattened_structs.count(base) && count > 0)
4425 {
4426 auto chain = access_chain_internal(base, indices, count, false, true).substr(1);
4427 auto &type = get<SPIRType>(get<SPIRVariable>(base).basetype);
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004428 if (out_need_transpose)
4429 *out_need_transpose = false;
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01004430 return sanitize_underscores(join(to_name(type.self), "_", chain));
4431 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004432 else
4433 {
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01004434 return access_chain_internal(base, indices, count, false, false, out_need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004435 }
4436}
4437
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004438string CompilerGLSL::load_flattened_struct(SPIRVariable &var)
4439{
4440 auto expr = type_to_glsl_constructor(get<SPIRType>(var.basetype));
4441 expr += '(';
4442
4443 auto &type = get<SPIRType>(var.basetype);
4444 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
4445 {
4446 if (i)
4447 expr += ", ";
4448
4449 // Flatten the varyings.
4450 // Apply name transformation for flattened I/O blocks.
4451 expr += to_flattened_struct_member(type, i);
4452 }
4453 expr += ')';
4454 return expr;
4455}
4456
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01004457void CompilerGLSL::store_flattened_struct(SPIRVariable &var, uint32_t value)
4458{
4459 // We're trying to store a structure which has been flattened.
4460 // Need to copy members one by one.
4461 auto rhs = to_expression(value);
4462
4463 // Store result locally.
4464 // Since we're declaring a variable potentially multiple times here,
4465 // store the variable in an isolated scope.
4466 begin_scope();
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01004467 statement(variable_decl_function_local(var), " = ", rhs, ";");
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01004468
4469 auto &type = get<SPIRType>(var.basetype);
4470 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
4471 {
4472 // Flatten the varyings.
4473 // Apply name transformation for flattened I/O blocks.
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01004474
4475 auto lhs = sanitize_underscores(join(to_name(type.self), "_", to_member_name(type, i)));
Hans-Kristian Arntzenfc80cd82017-02-23 19:24:59 +01004476 rhs = join(to_name(var.self), ".", to_member_name(type, i));
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01004477 statement(lhs, " = ", rhs, ";");
4478 }
4479 end_scope();
4480}
4481
Bill Hollings2d0d3282017-01-20 11:33:59 -05004482std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004483 const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride,
4484 bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004485{
4486 if (!target_type.array.empty())
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004487 SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004488 else if (target_type.basetype == SPIRType::Struct)
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004489 return flattened_access_chain_struct(base, indices, count, target_type, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004490 else if (target_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004491 return flattened_access_chain_matrix(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004492 else
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004493 return flattened_access_chain_vector(base, indices, count, target_type, offset, matrix_stride, need_transpose);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004494}
4495
Bill Hollings2d0d3282017-01-20 11:33:59 -05004496std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count,
4497 const SPIRType &target_type, uint32_t offset)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004498{
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004499 std::string expr;
4500
Hans-Kristian Arntzen7f787f02017-01-21 10:27:14 +01004501 expr += type_to_glsl_constructor(target_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004502 expr += "(";
4503
Henrik Rydgårdbfae0412017-03-07 09:59:26 +01004504 for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004505 {
4506 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08004507 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004508
4509 const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004510 uint32_t member_offset = type_struct_member_offset(target_type, i);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004511
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004512 // The access chain terminates at the struct, so we need to find matrix strides and row-major information
4513 // ahead of time.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004514 bool need_transpose = false;
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004515 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004516 if (member_type.columns > 1)
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004517 {
4518 need_transpose = (combined_decoration_for_member(target_type, i) & (1ull << DecorationRowMajor)) != 0;
4519 matrix_stride = type_struct_member_matrix_stride(target_type, i);
4520 }
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004521
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004522 auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride,
4523 need_transpose);
4524
4525 // Cannot forward transpositions, so resolve them here.
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004526 if (need_transpose)
4527 expr += convert_row_major_matrix(tmp);
4528 else
4529 expr += tmp;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004530 }
4531
4532 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004533
4534 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004535}
4536
Bill Hollings2d0d3282017-01-20 11:33:59 -05004537std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count,
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004538 const SPIRType &target_type, uint32_t offset,
4539 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004540{
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004541 assert(matrix_stride);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004542 SPIRType tmp_type = target_type;
4543 if (need_transpose)
4544 swap(tmp_type.vecsize, tmp_type.columns);
4545
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004546 std::string expr;
4547
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004548 expr += type_to_glsl_constructor(tmp_type);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004549 expr += "(";
4550
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004551 for (uint32_t i = 0; i < tmp_type.columns; i++)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004552 {
4553 if (i != 0)
Arseny Kapoulkine64c17b52017-01-17 12:06:06 -08004554 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004555
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004556 expr += flattened_access_chain_vector(base, indices, count, tmp_type, offset + i * matrix_stride, matrix_stride,
4557 /* need_transpose= */ false);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004558 }
4559
4560 expr += ")";
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004561
4562 return expr;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004563}
4564
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004565std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count,
4566 const SPIRType &target_type, uint32_t offset,
4567 uint32_t matrix_stride, bool need_transpose)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004568{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02004569 auto result = flattened_access_chain_offset(expression_type(base), indices, count, offset, 16);
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004570
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004571 auto buffer_name = to_name(expression_type(base).self);
4572
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004573 if (need_transpose)
4574 {
4575 std::string expr;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004576
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08004577 if (target_type.vecsize > 1)
4578 {
4579 expr += type_to_glsl_constructor(target_type);
4580 expr += "(";
4581 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004582
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004583 for (uint32_t i = 0; i < target_type.vecsize; ++i)
4584 {
4585 if (i != 0)
4586 expr += ", ";
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004587
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004588 uint32_t component_offset = result.second + i * matrix_stride;
4589
4590 assert(component_offset % (target_type.width / 8) == 0);
4591 uint32_t index = component_offset / (target_type.width / 8);
4592
4593 expr += buffer_name;
4594 expr += "[";
4595 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
4596 expr += convert_to_string(index / 4);
4597 expr += "]";
4598
4599 expr += vector_swizzle(1, index % 4);
4600 }
4601
Arseny Kapoulkine32a561a2017-01-24 08:09:58 -08004602 if (target_type.vecsize > 1)
4603 {
4604 expr += ")";
4605 }
Arseny Kapoulkineed04c952017-01-24 07:42:19 -08004606
4607 return expr;
4608 }
4609 else
4610 {
4611 assert(result.second % (target_type.width / 8) == 0);
4612 uint32_t index = result.second / (target_type.width / 8);
4613
4614 std::string expr;
4615
4616 expr += buffer_name;
4617 expr += "[";
4618 expr += result.first; // this is a series of N1 * k1 + N2 * k2 + ... that is either empty or ends with a +
4619 expr += convert_to_string(index / 4);
4620 expr += "]";
4621
4622 expr += vector_swizzle(target_type.vecsize, index % 4);
4623
4624 return expr;
4625 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004626}
4627
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02004628std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(const SPIRType &basetype,
4629 const uint32_t *indices, uint32_t count,
4630 uint32_t offset, uint32_t word_stride,
Hans-Kristian Arntzen87f3c572017-01-21 12:47:26 +01004631 bool *need_transpose,
4632 uint32_t *out_matrix_stride)
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004633{
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02004634 const auto *type = &basetype;
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004635
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01004636 // Start traversing type hierarchy at the proper non-pointer types.
4637 while (type->pointer)
4638 {
4639 assert(type->parent_type);
4640 type = &get<SPIRType>(type->parent_type);
4641 }
4642
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004643 // This holds the type of the current pointer which we are traversing through.
4644 // We always start out from a struct type which is the block.
4645 // This is primarily used to reflect the array strides and matrix strides later.
4646 // For the first access chain index, type_id won't be needed, so just keep it as 0, it will be set
4647 // accordingly as members of structs are accessed.
4648 assert(type->basetype == SPIRType::Struct);
4649 uint32_t type_id = 0;
4650
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004651 std::string expr;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004652
4653 // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout.
4654 bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false;
4655 uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0;
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004656
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004657 for (uint32_t i = 0; i < count; i++)
4658 {
4659 uint32_t index = indices[i];
4660
4661 // Arrays
4662 if (!type->array.empty())
4663 {
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004664 // Here, the type_id will be a type ID for the array type itself.
4665 uint32_t array_stride = get_decoration(type_id, DecorationArrayStride);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01004666 if (!array_stride)
4667 SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block.");
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004668
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01004669 auto *constant = maybe_get<SPIRConstant>(index);
4670 if (constant)
4671 {
4672 // Constant array access.
4673 offset += constant->scalar() * array_stride;
4674 }
4675 else
4676 {
4677 // Dynamic array access.
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01004678 if (array_stride % word_stride)
4679 {
Hans-Kristian Arntzen87f3c572017-01-21 12:47:26 +01004680 SPIRV_CROSS_THROW(
4681 "Array stride for dynamic indexing must be divisible by the size of a 4-component vector. "
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004682 "Likely culprit here is a float or vec2 array inside a push constant block which is std430. "
4683 "This cannot be flattened. Try using std140 layout instead.");
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01004684 }
4685
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02004686 expr += to_enclosed_expression(index);
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01004687 expr += " * ";
4688 expr += convert_to_string(array_stride / word_stride);
4689 expr += " + ";
4690 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004691
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01004692 uint32_t parent_type = type->parent_type;
4693 type = &get<SPIRType>(parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004694 type_id = parent_type;
4695
4696 // Type ID now refers to the array type with one less dimension.
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004697 }
4698 // For structs, the index refers to a constant, which indexes into the members.
4699 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
4700 else if (type->basetype == SPIRType::Struct)
4701 {
Hans-Kristian Arntzend87249a2017-01-22 09:21:22 +01004702 index = get<SPIRConstant>(index).scalar();
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004703
4704 if (index >= type->member_types.size())
4705 SPIRV_CROSS_THROW("Member index is out of bounds!");
4706
4707 offset += type_struct_member_offset(*type, index);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004708 type_id = type->member_types[index];
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01004709
4710 auto &struct_type = *type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004711 type = &get<SPIRType>(type->member_types[index]);
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01004712
4713 if (type->columns > 1)
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004714 {
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01004715 matrix_stride = type_struct_member_matrix_stride(struct_type, index);
Hans-Kristian Arntzen3eb2e522017-01-21 13:49:32 +01004716 row_major_matrix_needs_conversion =
4717 (combined_decoration_for_member(struct_type, index) & (1ull << DecorationRowMajor)) != 0;
4718 }
4719 else
4720 row_major_matrix_needs_conversion = false;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004721 }
4722 // Matrix -> Vector
4723 else if (type->columns > 1)
4724 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004725 auto *constant = maybe_get<SPIRConstant>(index);
4726 if (constant)
4727 {
4728 index = get<SPIRConstant>(index).scalar();
4729 offset += index * (row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride);
4730 }
4731 else
4732 {
4733 uint32_t indexing_stride = row_major_matrix_needs_conversion ? (type->width / 8) : matrix_stride;
4734 // Dynamic array access.
4735 if (indexing_stride % word_stride)
4736 {
4737 SPIRV_CROSS_THROW(
4738 "Matrix stride for dynamic indexing must be divisible by the size of a 4-component vector. "
4739 "Likely culprit here is a row-major matrix being accessed dynamically. "
4740 "This cannot be flattened. Try using std140 layout instead.");
4741 }
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004742
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004743 expr += to_enclosed_expression(index);
4744 expr += " * ";
4745 expr += convert_to_string(indexing_stride / word_stride);
4746 expr += " + ";
4747 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004748
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01004749 uint32_t parent_type = type->parent_type;
4750 type = &get<SPIRType>(type->parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004751 type_id = parent_type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004752 }
4753 // Vector -> Scalar
4754 else if (type->vecsize > 1)
4755 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004756 auto *constant = maybe_get<SPIRConstant>(index);
4757 if (constant)
4758 {
4759 index = get<SPIRConstant>(index).scalar();
4760 offset += index * (row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8));
4761 }
4762 else
4763 {
4764 uint32_t indexing_stride = row_major_matrix_needs_conversion ? matrix_stride : (type->width / 8);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004765
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004766 // Dynamic array access.
4767 if (indexing_stride % word_stride)
4768 {
4769 SPIRV_CROSS_THROW(
4770 "Stride for dynamic vector indexing must be divisible by the size of a 4-component vector. "
4771 "This cannot be flattened in legacy targets.");
4772 }
4773
4774 expr += to_enclosed_expression(index);
4775 expr += " * ";
4776 expr += convert_to_string(indexing_stride / word_stride);
4777 expr += " + ";
4778 }
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004779
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01004780 uint32_t parent_type = type->parent_type;
4781 type = &get<SPIRType>(type->parent_type);
Hans-Kristian Arntzenfe12fff2017-01-22 09:06:15 +01004782 type_id = parent_type;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004783 }
4784 else
4785 SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
4786 }
4787
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08004788 if (need_transpose)
4789 *need_transpose = row_major_matrix_needs_conversion;
Hans-Kristian Arntzen95409792017-01-21 12:29:20 +01004790 if (out_matrix_stride)
4791 *out_matrix_stride = matrix_stride;
Arseny Kapoulkine62b27f12017-01-17 18:10:28 -08004792
Arseny Kapoulkine1ec6c1a2017-01-17 18:07:56 -08004793 return std::make_pair(expr, offset);
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08004794}
4795
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004796bool CompilerGLSL::should_forward(uint32_t id)
4797{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02004798 // Immutable expression can always be forwarded.
4799 // If not immutable, we can speculate about it by forwarding potentially mutable variables.
4800 auto *var = maybe_get<SPIRVariable>(id);
4801 bool forward = var ? var->forwardable : false;
4802 return (is_immutable(id) || forward) && !options.force_temporary;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004803}
4804
4805void CompilerGLSL::track_expression_read(uint32_t id)
4806{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004807 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
4808 // In this case, it's better to just bind the complex expression to the temporary and read that temporary twice.
4809 if (expression_is_forwarded(id))
4810 {
4811 auto &v = expression_usage_counts[id];
4812 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004814 if (v >= 2)
4815 {
4816 //if (v == 2)
4817 // 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 +01004818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004819 forced_temporaries.insert(id);
4820 // Force a recompile after this pass to avoid forwarding this variable.
4821 force_recompile = true;
4822 }
4823 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004824}
4825
4826bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
4827{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004828 if (forced_temporaries.find(id) != end(forced_temporaries))
4829 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004830
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004831 for (uint32_t i = 0; i < num_args; i++)
4832 if (!should_forward(args[i]))
4833 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004835 // We need to forward globals as well.
4836 if (!pure)
4837 {
4838 for (auto global : global_variables)
4839 if (!should_forward(global))
4840 return false;
4841 for (auto aliased : aliased_variables)
4842 if (!should_forward(aliased))
4843 return false;
4844 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004845
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004846 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004847}
4848
4849void CompilerGLSL::register_impure_function_call()
4850{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004851 // Impure functions can modify globals and aliased variables, so invalidate them as well.
4852 for (auto global : global_variables)
4853 flush_dependees(get<SPIRVariable>(global));
4854 for (auto aliased : aliased_variables)
4855 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004856}
4857
4858void CompilerGLSL::register_call_out_argument(uint32_t id)
4859{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004860 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004861
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004862 auto *var = maybe_get<SPIRVariable>(id);
4863 if (var)
4864 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004865}
4866
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01004867string CompilerGLSL::variable_decl_function_local(SPIRVariable &var)
4868{
4869 // These variables are always function local,
4870 // so make sure we emit the variable without storage qualifiers.
4871 // Some backends will inject custom variables locally in a function
4872 // with a storage qualifier which is not function-local.
4873 auto old_storage = var.storage;
4874 var.storage = StorageClassFunction;
4875 auto expr = variable_decl(var);
4876 var.storage = old_storage;
4877 return expr;
4878}
4879
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004880void CompilerGLSL::flush_variable_declaration(uint32_t id)
4881{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004882 auto *var = maybe_get<SPIRVariable>(id);
4883 if (var && var->deferred_declaration)
4884 {
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01004885 statement(variable_decl_function_local(*var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004886 var->deferred_declaration = false;
4887 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004888}
4889
4890bool CompilerGLSL::remove_duplicate_swizzle(string &op)
4891{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004892 auto pos = op.find_last_of('.');
4893 if (pos == string::npos || pos == 0)
4894 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004895
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004896 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004897
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004898 if (backend.swizzle_is_function)
4899 {
4900 if (final_swiz.size() < 2)
4901 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004902
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004903 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
4904 final_swiz.erase(final_swiz.size() - 2, string::npos);
4905 else
4906 return false;
4907 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004908
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004909 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
4910 // If so, and previous swizzle is of same length,
4911 // we can drop the final swizzle altogether.
4912 for (uint32_t i = 0; i < final_swiz.size(); i++)
4913 {
4914 static const char expected[] = { 'x', 'y', 'z', 'w' };
4915 if (i >= 4 || final_swiz[i] != expected[i])
4916 return false;
4917 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004918
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004919 auto prevpos = op.find_last_of('.', pos - 1);
4920 if (prevpos == string::npos)
4921 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004922
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004923 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004924
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004925 // Make sure there are only swizzles here ...
4926 for (auto i = prevpos; i < pos; i++)
4927 {
4928 if (op[i] < 'w' || op[i] > 'z')
4929 {
4930 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
4931 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
4932 break;
4933 return false;
4934 }
4935 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004936
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004937 // If original swizzle is large enough, just carve out the components we need.
4938 // E.g. foobar.wyx.xy will turn into foobar.wy.
4939 if (pos - prevpos >= final_swiz.size())
4940 {
4941 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004942
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004943 // Add back the function call ...
4944 if (backend.swizzle_is_function)
4945 op += "()";
4946 }
4947 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004948}
4949
4950// Optimizes away vector swizzles where we have something like
4951// vec3 foo;
4952// foo.xyz <-- swizzle expression does nothing.
4953// This is a very common pattern after OpCompositeCombine.
4954bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
4955{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004956 auto pos = op.find_last_of('.');
4957 if (pos == string::npos || pos == 0)
4958 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004959
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004960 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004961
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004962 if (backend.swizzle_is_function)
4963 {
4964 if (final_swiz.size() < 2)
4965 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004966
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004967 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
4968 final_swiz.erase(final_swiz.size() - 2, string::npos);
4969 else
4970 return false;
4971 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004972
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004973 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
4974 // If so, and previous swizzle is of same length,
4975 // we can drop the final swizzle altogether.
4976 for (uint32_t i = 0; i < final_swiz.size(); i++)
4977 {
4978 static const char expected[] = { 'x', 'y', 'z', 'w' };
4979 if (i >= 4 || final_swiz[i] != expected[i])
4980 return false;
4981 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004982
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004983 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004985 // Sanity checking ...
4986 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004987
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004988 if (type.vecsize == final_swiz.size())
4989 op.erase(pos, string::npos);
4990 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004991}
4992
4993string CompilerGLSL::build_composite_combiner(const uint32_t *elems, uint32_t length)
4994{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004995 uint32_t base = 0;
4996 bool swizzle_optimization = false;
4997 string op;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01004998 string subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004999
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005000 for (uint32_t i = 0; i < length; i++)
5001 {
5002 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005003
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005004 // If we're merging another scalar which belongs to the same base
5005 // object, just merge the swizzles to avoid triggering more than 1 expression read as much as possible!
5006 if (e && e->base_expression && e->base_expression == base)
5007 {
5008 // Only supposed to be used for vector swizzle -> scalar.
5009 assert(!e->expression.empty() && e->expression.front() == '.');
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005010 subop += e->expression.substr(1, string::npos);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005011 swizzle_optimization = true;
5012 }
5013 else
5014 {
5015 // We'll likely end up with duplicated swizzles, e.g.
5016 // foobar.xyz.xyz from patterns like
5017 // OpVectorSwizzle
5018 // OpCompositeExtract x 3
5019 // OpCompositeConstruct 3x + other scalar.
5020 // Just modify op in-place.
5021 if (swizzle_optimization)
5022 {
5023 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005024 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005025
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005026 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
5027 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
5028 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
5029 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
5030 // Case 1:
5031 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
5032 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
5033 // Case 2:
5034 // foo.xyz: Duplicate swizzle won't kick in.
5035 // If foo is vec3, we can remove xyz, giving just foo.
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005036 if (!remove_duplicate_swizzle(subop))
5037 remove_unity_swizzle(base, subop);
5038
5039 // Strips away redundant parens if we created them during component extraction.
5040 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005041 swizzle_optimization = false;
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005042 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005043 }
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005044 else
5045 op += subop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005046
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005047 if (i)
5048 op += ", ";
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005049 subop = to_expression(elems[i]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005050 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005051
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005052 base = e ? e->base_expression : 0;
5053 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005054
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005055 if (swizzle_optimization)
5056 {
5057 if (backend.swizzle_is_function)
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005058 subop += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005059
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005060 if (!remove_duplicate_swizzle(subop))
5061 remove_unity_swizzle(base, subop);
5062 // Strips away redundant parens if we created them during component extraction.
5063 strip_enclosed_expression(subop);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005064 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005065
Hans-Kristian Arntzen03a26e52016-12-06 23:03:35 +01005066 op += subop;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005067 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005068}
5069
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02005070bool CompilerGLSL::skip_argument(uint32_t id) const
5071{
5072 if (!combined_image_samplers.empty() || !options.vulkan_semantics)
5073 {
5074 auto &type = expression_type(id);
5075 if (type.basetype == SPIRType::Sampler || (type.basetype == SPIRType::Image && type.image.sampled == 1))
5076 return true;
5077 }
5078 return false;
5079}
5080
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01005081bool CompilerGLSL::optimize_read_modify_write(const string &lhs, const string &rhs)
5082{
5083 // Do this with strings because we have a very clear pattern we can check for and it avoids
5084 // adding lots of special cases to the code emission.
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01005085 if (rhs.size() < lhs.size() + 3)
5086 return false;
5087
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01005088 auto index = rhs.find(lhs);
5089 if (index != 0)
5090 return false;
5091
5092 // TODO: Shift operators, but it's not important for now.
5093 auto op = rhs.find_first_of("+-/*%|&^", lhs.size() + 1);
5094 if (op != lhs.size() + 1)
5095 return false;
5096
David Srbeckye596d402017-09-05 16:05:53 +01005097 // Check that the op is followed by space. This excludes && and ||.
Hans-Kristian Arntzen03db5c42017-09-06 09:15:27 +02005098 if (rhs[op + 1] != ' ')
David Srbeckye596d402017-09-05 16:05:53 +01005099 return false;
5100
Hans-Kristian Arntzend11b8aa2016-12-16 13:24:49 +01005101 char bop = rhs[op];
5102 auto expr = rhs.substr(lhs.size() + 3);
5103 // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code.
5104 // Find some common patterns which are equivalent.
5105 if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)"))
5106 statement(lhs, bop, bop, ";");
5107 else
5108 statement(lhs, " ", bop, "= ", expr, ";");
Hans-Kristian Arntzen62613df2016-12-16 13:14:22 +01005109 return true;
5110}
5111
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02005112void CompilerGLSL::emit_block_instructions(const SPIRBlock &block)
5113{
5114 current_emitting_block = &block;
5115 for (auto &op : block.ops)
5116 emit_instruction(op);
5117 current_emitting_block = nullptr;
5118}
5119
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02005120void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005121{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005122 auto ops = stream(instruction);
5123 auto opcode = static_cast<Op>(instruction.op);
5124 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005125
5126#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005127#define BOP_CAST(op, type) \
5128 emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005129#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
5130#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
5131#define TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
5132#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005133#define BFOP_CAST(op, type) \
5134 emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005135#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005136#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
5137
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005138 switch (opcode)
5139 {
5140 // Dealing with memory
5141 case OpLoad:
5142 {
5143 uint32_t result_type = ops[0];
5144 uint32_t id = ops[1];
5145 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005146
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005147 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005149 // If we're loading from memory that cannot be changed by the shader,
5150 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005151 // If an expression is mutable and forwardable, we speculate that it is immutable.
5152 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
5153
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01005154 // If loading a non-native row-major matrix, mark the expression as need_transpose.
5155 bool need_transpose = false;
5156 bool old_need_transpose = false;
5157
5158 auto *ptr_expression = maybe_get<SPIRExpression>(ptr);
5159 if (ptr_expression && ptr_expression->need_transpose)
5160 {
5161 old_need_transpose = true;
5162 ptr_expression->need_transpose = false;
5163 need_transpose = true;
5164 }
5165 else if (is_non_native_row_major_matrix(ptr))
5166 need_transpose = true;
5167
Bill Hollings13583622016-12-14 02:12:52 -05005168 auto expr = to_expression(ptr);
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01005169
5170 if (ptr_expression)
5171 ptr_expression->need_transpose = old_need_transpose;
Bill Hollings13583622016-12-14 02:12:52 -05005172
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005173 // Suppress usage tracking since using same expression multiple times does not imply any extra work.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01005174 auto &e = emit_op(result_type, id, expr, forward, true);
5175 e.need_transpose = need_transpose;
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005176 register_read(id, ptr, forward);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005177 break;
5178 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005179
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005180 case OpInBoundsAccessChain:
5181 case OpAccessChain:
5182 {
5183 auto *var = maybe_get<SPIRVariable>(ops[2]);
5184 if (var)
5185 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005186
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005187 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005188 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01005189 bool need_transpose;
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08005190 auto e = access_chain(ops[2], &ops[3], length - 3, get<SPIRType>(ops[0]), &need_transpose);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02005191 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005192 expr.loaded_from = ops[2];
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01005193 expr.need_transpose = need_transpose;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005194 break;
5195 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005196
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005197 case OpStore:
5198 {
5199 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005200
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005201 if (var && var->statically_assigned)
5202 var->static_expression = ops[1];
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01005203 else if (var && var->loop_variable && !var->loop_variable_enable)
5204 var->static_expression = ops[1];
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01005205 else if (var && flattened_structs.count(ops[0]))
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01005206 {
Hans-Kristian Arntzen3c58bbb2017-02-22 20:17:58 +01005207 store_flattened_struct(*var, ops[1]);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01005208 register_write(ops[0]);
5209 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005210 else
5211 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005212 auto rhs = to_expression(ops[1]);
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02005213 // Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
5214 if (!rhs.empty())
5215 {
5216 auto lhs = to_expression(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005217
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02005218 // Tries to optimize assignments like "<lhs> = <lhs> op expr".
5219 // While this is purely cosmetic, this is important for legacy ESSL where loop
5220 // variable increments must be in either i++ or i += const-expr.
5221 // Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
5222 if (!optimize_read_modify_write(lhs, rhs))
5223 statement(lhs, " = ", rhs, ";");
5224 register_write(ops[0]);
5225 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005226 }
5227 break;
5228 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005229
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005230 case OpArrayLength:
5231 {
5232 uint32_t result_type = ops[0];
5233 uint32_t id = ops[1];
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01005234 auto e = access_chain_internal(ops[2], &ops[3], length - 3, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005235 set<SPIRExpression>(id, e + ".length()", result_type, true);
5236 break;
5237 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005238
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005239 // Function calls
5240 case OpFunctionCall:
5241 {
5242 uint32_t result_type = ops[0];
5243 uint32_t id = ops[1];
5244 uint32_t func = ops[2];
5245 const auto *arg = &ops[3];
5246 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005247
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005248 auto &callee = get<SPIRFunction>(func);
5249 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005250
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005251 bool callee_has_out_variables = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005252
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005253 // Invalidate out variables passed to functions since they can be OpStore'd to.
5254 for (uint32_t i = 0; i < length; i++)
5255 {
5256 if (callee.arguments[i].write_count)
5257 {
5258 register_call_out_argument(arg[i]);
5259 callee_has_out_variables = true;
5260 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005261
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005262 flush_variable_declaration(arg[i]);
5263 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005264
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005265 if (!pure)
5266 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005268 string funexpr;
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02005269 vector<string> arglist;
Bill Hollings1c180782017-11-05 21:34:42 -05005270 funexpr += to_name(func) + "(";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005271 for (uint32_t i = 0; i < length; i++)
5272 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02005273 // Do not pass in separate images or samplers if we're remapping
5274 // to combined image samplers.
5275 if (skip_argument(arg[i]))
5276 continue;
5277
Bill Hollingsac00c602016-10-24 09:24:24 -04005278 arglist.push_back(to_func_call_arg(arg[i]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005279 }
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02005280
5281 for (auto &combined : callee.combined_parameters)
5282 {
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02005283 uint32_t image_id = combined.global_image ? combined.image_id : arg[combined.image_id];
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02005284 uint32_t sampler_id = combined.global_sampler ? combined.sampler_id : arg[combined.sampler_id];
5285
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02005286 auto *image = maybe_get_backing_variable(image_id);
5287 if (image)
5288 image_id = image->self;
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02005289
5290 auto *samp = maybe_get_backing_variable(sampler_id);
5291 if (samp)
5292 sampler_id = samp->self;
5293
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +02005294 arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
Hans-Kristian Arntzenb4c67da2016-09-11 13:20:35 +02005295 }
Bill Hollingsa759e2c2016-10-19 14:09:51 -07005296
Bill Hollingsac00c602016-10-24 09:24:24 -04005297 append_global_func_args(callee, length, arglist);
Bill Hollingsa759e2c2016-10-19 14:09:51 -07005298
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02005299 funexpr += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005300 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005301
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02005302 // Check for function call constraints.
5303 check_function_call_constraints(arg, length);
5304
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005305 if (get<SPIRType>(result_type).basetype != SPIRType::Void)
5306 {
5307 // If the function actually writes to an out variable,
5308 // take the conservative route and do not forward.
5309 // The problem is that we might not read the function
5310 // result (and emit the function) before an out variable
5311 // is read (common case when return value is ignored!
5312 // In order to avoid start tracking invalid variables,
5313 // just avoid the forwarding problem altogether.
5314 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
5315 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005316
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005317 emit_op(result_type, id, funexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005318
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005319 // Function calls are implicit loads from all variables in question.
5320 // Set dependencies for them.
5321 for (uint32_t i = 0; i < length; i++)
5322 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005323
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005324 // If we're going to forward the temporary result,
5325 // put dependencies on every variable that must not change.
5326 if (forward)
5327 register_global_read_dependencies(callee, id);
5328 }
5329 else
5330 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005332 break;
5333 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005335 // Composite munging
5336 case OpCompositeConstruct:
5337 {
5338 uint32_t result_type = ops[0];
5339 uint32_t id = ops[1];
5340 const auto *elems = &ops[2];
5341 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005342
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005343 bool forward = true;
5344 for (uint32_t i = 0; i < length; i++)
5345 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005346
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005347 auto &out_type = get<SPIRType>(result_type);
5348
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02005349 if (!length)
5350 {
5351 if (out_type.basetype == SPIRType::Struct)
5352 {
5353 // It is technically allowed to make a blank struct,
5354 // but we cannot make a meaningful expression out of it in high level languages,
5355 // so make it a blank expression.
5356 emit_op(result_type, id, "", forward);
5357 break;
5358 }
5359 else
5360 SPIRV_CROSS_THROW("Invalid input to OpCompositeConstruct.");
5361 }
5362
5363 auto &in_type = expression_type(elems[0]);
5364
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005365 // Only splat if we have vector constructors.
5366 // Arrays and structs must be initialized properly in full.
5367 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
Robert Konradbeebcbd2016-10-05 19:18:04 +02005368 bool splat = in_type.vecsize == 1 && in_type.columns == 1 && !composite && backend.use_constructor_splatting;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005369
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005370 if (splat)
5371 {
5372 uint32_t input = elems[0];
5373 for (uint32_t i = 0; i < length; i++)
5374 if (input != elems[i])
5375 splat = false;
5376 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005377
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005378 string constructor_op;
5379 if (backend.use_initializer_list && composite)
5380 {
5381 // Only use this path if we are building composites.
5382 // This path cannot be used for arithmetic.
5383 constructor_op += "{ ";
5384 if (splat)
5385 constructor_op += to_expression(elems[0]);
5386 else
5387 constructor_op += build_composite_combiner(elems, length);
5388 constructor_op += " }";
5389 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005390 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005391 {
5392 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
5393 if (splat)
5394 constructor_op += to_expression(elems[0]);
5395 else
5396 constructor_op += build_composite_combiner(elems, length);
5397 constructor_op += ")";
5398 }
5399
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005400 emit_op(result_type, id, constructor_op, forward);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005401 break;
5402 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005403
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005404 case OpVectorInsertDynamic:
5405 {
5406 uint32_t result_type = ops[0];
5407 uint32_t id = ops[1];
5408 uint32_t vec = ops[2];
5409 uint32_t comp = ops[3];
5410 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005411
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005412 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005413
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005414 // Make a copy, then use access chain to store the variable.
5415 statement(declare_temporary(result_type, id), to_expression(vec), ";");
5416 set<SPIRExpression>(id, to_name(id), result_type, true);
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01005417 auto chain = access_chain_internal(id, &index, 1, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005418 statement(chain, " = ", to_expression(comp), ";");
5419 break;
5420 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005421
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005422 case OpVectorExtractDynamic:
5423 {
5424 uint32_t result_type = ops[0];
5425 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005426
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01005427 auto expr = access_chain_internal(ops[2], &ops[3], 1, false);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005428 emit_op(result_type, id, expr, should_forward(ops[2]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005429 break;
5430 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005432 case OpCompositeExtract:
5433 {
5434 uint32_t result_type = ops[0];
5435 uint32_t id = ops[1];
5436 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005437
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005438 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005439
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02005440 // We can only split the expression here if our expression is forwarded as a temporary.
5441 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
5442
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01005443 // Do not allow base expression for struct members. We risk doing "swizzle" optimizations in this case.
5444 auto &composite_type = expression_type(ops[2]);
Hans-Kristian Arntzen3fac2892017-11-22 12:07:37 +01005445 if (composite_type.basetype == SPIRType::Struct || !composite_type.array.empty())
Hans-Kristian Arntzen851e5842017-11-20 21:32:13 +01005446 allow_base_expression = false;
5447
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005448 // Only apply this optimization if result is scalar.
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02005449 if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005450 {
5451 // We want to split the access chain from the base.
5452 // This is so we can later combine different CompositeExtract results
5453 // with CompositeConstruct without emitting code like
5454 //
5455 // vec3 temp = texture(...).xyz
5456 // vec4(temp.x, temp.y, temp.z, 1.0).
5457 //
5458 // when we actually wanted to emit this
5459 // vec4(texture(...).xyz, 1.0).
5460 //
5461 // Including the base will prevent this and would trigger multiple reads
5462 // from expression causing it to be forced to an actual temporary in GLSL.
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01005463 auto expr = access_chain_internal(ops[2], &ops[3], length, true, true);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005464 auto &e = emit_op(result_type, id, expr, true, !expression_is_forwarded(ops[2]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005465 e.base_expression = ops[2];
5466 }
5467 else
5468 {
Hans-Kristian Arntzen97350d32017-02-23 19:03:07 +01005469 auto expr = access_chain_internal(ops[2], &ops[3], length, true);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005470 emit_op(result_type, id, expr, should_forward(ops[2]), !expression_is_forwarded(ops[2]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005471 }
5472 break;
5473 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005474
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005475 case OpCompositeInsert:
5476 {
5477 uint32_t result_type = ops[0];
5478 uint32_t id = ops[1];
5479 uint32_t obj = ops[2];
5480 uint32_t composite = ops[3];
5481 const auto *elems = &ops[4];
5482 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005483
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005484 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005485
David Srbecky77b5b442017-06-26 18:32:53 +01005486 // Make a copy, then use access chain to store the variable.
5487 statement(declare_temporary(result_type, id), to_expression(composite), ";");
5488 set<SPIRExpression>(id, to_name(id), result_type, true);
5489 auto chain = access_chain_internal(id, elems, length, true);
5490 statement(chain, " = ", to_expression(obj), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005491
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005492 break;
5493 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005494
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01005495 case OpCopyMemory:
5496 {
5497 uint32_t lhs = ops[0];
5498 uint32_t rhs = ops[1];
5499 if (lhs != rhs)
5500 {
5501 flush_variable_declaration(lhs);
5502 flush_variable_declaration(rhs);
5503 statement(to_expression(lhs), " = ", to_expression(rhs), ";");
5504 register_write(lhs);
5505 }
5506 break;
5507 }
5508
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005509 case OpCopyObject:
5510 {
5511 uint32_t result_type = ops[0];
5512 uint32_t id = ops[1];
5513 uint32_t rhs = ops[2];
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01005514 bool pointer = get<SPIRType>(result_type).pointer;
5515
5516 if (expression_is_lvalue(rhs) && !pointer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005517 {
5518 // Need a copy.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01005519 // For pointer types, we copy the pointer itself.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005520 statement(declare_temporary(result_type, id), to_expression(rhs), ";");
5521 set<SPIRExpression>(id, to_name(id), result_type, true);
5522 }
5523 else
5524 {
5525 // RHS expression is immutable, so just forward it.
5526 // Copying these things really make no sense, but
5527 // seems to be allowed anyways.
Hans-Kristian Arntzen0c9683c2016-11-18 09:59:54 +01005528 auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
5529 if (pointer)
5530 {
5531 auto *var = maybe_get_backing_variable(rhs);
5532 e.loaded_from = var ? var->self : 0;
5533 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005534 }
5535 break;
5536 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005538 case OpVectorShuffle:
5539 {
5540 uint32_t result_type = ops[0];
5541 uint32_t id = ops[1];
5542 uint32_t vec0 = ops[2];
5543 uint32_t vec1 = ops[3];
5544 const auto *elems = &ops[4];
5545 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005547 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005548
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005549 bool shuffle = false;
5550 for (uint32_t i = 0; i < length; i++)
5551 if (elems[i] >= type0.vecsize)
5552 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005553
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005554 string expr;
5555 bool trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005557 if (shuffle)
5558 {
5559 trivial_forward = !expression_is_forwarded(vec0) && !expression_is_forwarded(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005560
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005561 // Constructor style and shuffling from two different vectors.
5562 vector<string> args;
5563 for (uint32_t i = 0; i < length; i++)
5564 {
5565 if (elems[i] >= type0.vecsize)
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005566 args.push_back(join(to_enclosed_expression(vec1), ".", index_to_swizzle(elems[i] - type0.vecsize)));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005567 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005568 args.push_back(join(to_enclosed_expression(vec0), ".", index_to_swizzle(elems[i])));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005569 }
5570 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
5571 }
5572 else
5573 {
5574 trivial_forward = !expression_is_forwarded(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005576 // We only source from first vector, so can use swizzle.
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005577 expr += to_enclosed_expression(vec0);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005578 expr += ".";
5579 for (uint32_t i = 0; i < length; i++)
5580 expr += index_to_swizzle(elems[i]);
5581 if (backend.swizzle_is_function && length > 1)
5582 expr += "()";
5583 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005584
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005585 // A shuffle is trivial in that it doesn't actually *do* anything.
5586 // 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 +01005587
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005588 emit_op(result_type, id, expr, should_forward(vec0) && should_forward(vec1), trivial_forward);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005589 break;
5590 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005592 // ALU
5593 case OpIsNan:
5594 UFOP(isnan);
5595 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005596
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005597 case OpIsInf:
5598 UFOP(isinf);
5599 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005600
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005601 case OpSNegate:
5602 case OpFNegate:
5603 UOP(-);
5604 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005605
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005606 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005607 {
5608 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
5609 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005610 BOP_CAST(+, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005611 break;
5612 }
5613
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005614 case OpFAdd:
5615 BOP(+);
5616 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005617
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005618 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005619 {
5620 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005621 BOP_CAST(-, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005622 break;
5623 }
5624
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005625 case OpFSub:
5626 BOP(-);
5627 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005628
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005629 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005630 {
5631 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005632 BOP_CAST(*, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005633 break;
5634 }
5635
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01005636 case OpVectorTimesMatrix:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005637 case OpMatrixTimesVector:
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01005638 {
5639 // If the matrix needs transpose, just flip the multiply order.
5640 auto *e = maybe_get<SPIRExpression>(ops[opcode == OpMatrixTimesVector ? 2 : 3]);
5641 if (e && e->need_transpose)
5642 {
5643 e->need_transpose = false;
5644 emit_binary_op(ops[0], ops[1], ops[3], ops[2], "*");
5645 e->need_transpose = true;
5646 }
5647 else
5648 BOP(*);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005649 break;
5650 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005651
5652 case OpFMul:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005653 case OpMatrixTimesScalar:
5654 case OpVectorTimesScalar:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005655 case OpMatrixTimesMatrix:
5656 BOP(*);
5657 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005658
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005659 case OpOuterProduct:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02005660 BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005661 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005662
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005663 case OpDot:
5664 BFOP(dot);
5665 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005666
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005667 case OpTranspose:
5668 UFOP(transpose);
5669 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005671 case OpSDiv:
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005672 BOP_CAST(/, SPIRType::Int);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005673 break;
5674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005675 case OpUDiv:
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005676 BOP_CAST(/, SPIRType::UInt);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005677 break;
5678
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005679 case OpFDiv:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005680 BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005681 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005683 case OpShiftRightLogical:
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005684 BOP_CAST(>>, SPIRType::UInt);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005685 break;
5686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005687 case OpShiftRightArithmetic:
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005688 BOP_CAST(>>, SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005689 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005690
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005691 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02005692 {
5693 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005694 BOP_CAST(<<, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005695 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02005696 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005697
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005698 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005699 {
5700 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005701 BOP_CAST(|, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005702 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005703 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005705 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005706 {
5707 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005708 BOP_CAST (^, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005709 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005710 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005711
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005712 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005713 {
5714 auto type = get<SPIRType>(ops[0]).basetype;
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005715 BOP_CAST(&, type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005716 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005717 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005718
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005719 case OpNot:
5720 UOP(~);
5721 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005723 case OpUMod:
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005724 BOP_CAST(%, SPIRType::UInt);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005725 break;
5726
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005727 case OpSMod:
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005728 BOP_CAST(%, SPIRType::Int);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005729 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005730
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005731 case OpFMod:
5732 BFOP(mod);
5733 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +02005734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005735 // Relational
5736 case OpAny:
5737 UFOP(any);
5738 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005740 case OpAll:
5741 UFOP(all);
5742 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005743
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005744 case OpSelect:
5745 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
5746 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005747
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005748 case OpLogicalOr:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005749 {
5750 // No vector variant in GLSL for logical OR.
5751 auto result_type = ops[0];
5752 auto id = ops[1];
5753 auto &type = get<SPIRType>(result_type);
5754
5755 if (type.vecsize > 1)
5756 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||");
5757 else
5758 BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005759 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005760 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005761
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005762 case OpLogicalAnd:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005763 {
5764 // No vector variant in GLSL for logical AND.
5765 auto result_type = ops[0];
5766 auto id = ops[1];
5767 auto &type = get<SPIRType>(result_type);
5768
5769 if (type.vecsize > 1)
5770 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&");
5771 else
5772 BOP(&&);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005773 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005774 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005775
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005776 case OpLogicalNot:
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005777 {
5778 auto &type = get<SPIRType>(ops[0]);
5779 if (type.vecsize > 1)
5780 UFOP(not);
5781 else
5782 UOP(!);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005783 break;
Hans-Kristian Arntzen75391f92017-03-20 22:38:05 +01005784 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005785
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005786 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005787 {
5788 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005789 BFOP_CAST(equal, SPIRType::Int);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005790 else
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005791 BOP_CAST(==, SPIRType::Int);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005792 break;
5793 }
5794
5795 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005796 case OpFOrdEqual:
5797 {
5798 if (expression_type(ops[2]).vecsize > 1)
5799 BFOP(equal);
5800 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005801 BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005802 break;
5803 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005804
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005805 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005806 {
5807 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005808 BFOP_CAST(notEqual, SPIRType::Int);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005809 else
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005810 BOP_CAST(!=, SPIRType::Int);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005811 break;
5812 }
5813
5814 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005815 case OpFOrdNotEqual:
5816 {
5817 if (expression_type(ops[2]).vecsize > 1)
5818 BFOP(notEqual);
5819 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005820 BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005821 break;
5822 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005823
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005824 case OpUGreaterThan:
5825 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005826 {
5827 auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
5828 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005829 BFOP_CAST(greaterThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005830 else
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005831 BOP_CAST(>, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005832 break;
5833 }
5834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005835 case OpFOrdGreaterThan:
5836 {
5837 if (expression_type(ops[2]).vecsize > 1)
5838 BFOP(greaterThan);
5839 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005840 BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005841 break;
5842 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005843
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005844 case OpUGreaterThanEqual:
5845 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005846 {
5847 auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
5848 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005849 BFOP_CAST(greaterThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005850 else
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005851 BOP_CAST(>=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005852 break;
5853 }
5854
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005855 case OpFOrdGreaterThanEqual:
5856 {
5857 if (expression_type(ops[2]).vecsize > 1)
5858 BFOP(greaterThanEqual);
5859 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005860 BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005861 break;
5862 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005863
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005864 case OpULessThan:
5865 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005866 {
5867 auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
5868 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005869 BFOP_CAST(lessThan, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005870 else
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005871 BOP_CAST(<, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005872 break;
5873 }
5874
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005875 case OpFOrdLessThan:
5876 {
5877 if (expression_type(ops[2]).vecsize > 1)
5878 BFOP(lessThan);
5879 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005880 BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005881 break;
5882 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005883
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005884 case OpULessThanEqual:
5885 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005886 {
5887 auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
5888 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005889 BFOP_CAST(lessThanEqual, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005890 else
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +02005891 BOP_CAST(<=, type);
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005892 break;
5893 }
5894
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005895 case OpFOrdLessThanEqual:
5896 {
5897 if (expression_type(ops[2]).vecsize > 1)
5898 BFOP(lessThanEqual);
5899 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02005900 BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005901 break;
5902 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005903
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005904 // Conversion
5905 case OpConvertFToU:
5906 case OpConvertFToS:
5907 case OpConvertSToF:
5908 case OpConvertUToF:
5909 case OpUConvert:
5910 case OpSConvert:
5911 case OpFConvert:
5912 {
5913 uint32_t result_type = ops[0];
5914 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005915
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005916 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
5917 emit_unary_func_op(result_type, id, ops[2], func.c_str());
5918 break;
5919 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005920
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005921 case OpBitcast:
5922 {
5923 uint32_t result_type = ops[0];
5924 uint32_t id = ops[1];
5925 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005926
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02005927 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005928 emit_unary_func_op(result_type, id, arg, op.c_str());
5929 break;
5930 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005931
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02005932 case OpQuantizeToF16:
5933 {
5934 uint32_t result_type = ops[0];
5935 uint32_t id = ops[1];
5936 uint32_t arg = ops[2];
5937
5938 string op;
5939 auto &type = get<SPIRType>(result_type);
5940
5941 switch (type.vecsize)
5942 {
5943 case 1:
5944 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
5945 break;
5946 case 2:
5947 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
5948 break;
5949 case 3:
5950 {
5951 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
5952 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
5953 op = join("vec3(", op0, ", ", op1, ")");
5954 break;
5955 }
5956 case 4:
5957 {
5958 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
5959 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
5960 op = join("vec4(", op0, ", ", op1, ")");
5961 break;
5962 }
5963 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01005964 SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16.");
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02005965 }
5966
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01005967 emit_op(result_type, id, op, should_forward(arg));
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02005968 break;
5969 }
5970
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005971 // Derivatives
5972 case OpDPdx:
5973 UFOP(dFdx);
Lubos Lenco80c39412016-09-17 14:33:16 +02005974 if (is_legacy_es())
5975 require_extension("GL_OES_standard_derivatives");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005976 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005977
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005978 case OpDPdy:
5979 UFOP(dFdy);
Lubos Lenco80c39412016-09-17 14:33:16 +02005980 if (is_legacy_es())
5981 require_extension("GL_OES_standard_derivatives");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005982 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005983
Robert Konrad9ec9dd02017-03-24 13:59:19 +01005984 case OpDPdxFine:
5985 UFOP(dFdxFine);
Robert Konradcb637db2017-03-24 15:58:54 +01005986 if (options.es)
5987 {
5988 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
5989 }
5990 if (options.version < 450)
5991 require_extension("GL_ARB_derivative_control");
Robert Konrad9ec9dd02017-03-24 13:59:19 +01005992 break;
5993
5994 case OpDPdyFine:
5995 UFOP(dFdyFine);
Robert Konradcb637db2017-03-24 15:58:54 +01005996 if (options.es)
5997 {
5998 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
5999 }
6000 if (options.version < 450)
6001 require_extension("GL_ARB_derivative_control");
Robert Konrad9ec9dd02017-03-24 13:59:19 +01006002 break;
6003
6004 case OpDPdxCoarse:
Robert Konradcb637db2017-03-24 15:58:54 +01006005 if (options.es)
6006 {
6007 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
6008 }
Robert Konrad9ec9dd02017-03-24 13:59:19 +01006009 UFOP(dFdxCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +01006010 if (options.version < 450)
6011 require_extension("GL_ARB_derivative_control");
Robert Konrad9ec9dd02017-03-24 13:59:19 +01006012 break;
6013
6014 case OpDPdyCoarse:
6015 UFOP(dFdyCoarse);
Robert Konradcb637db2017-03-24 15:58:54 +01006016 if (options.es)
6017 {
6018 SPIRV_CROSS_THROW("GL_ARB_derivative_control is unavailable in OpenGL ES.");
6019 }
6020 if (options.version < 450)
6021 require_extension("GL_ARB_derivative_control");
Robert Konrad9ec9dd02017-03-24 13:59:19 +01006022 break;
6023
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006024 case OpFwidth:
6025 UFOP(fwidth);
Lubos Lenco80c39412016-09-17 14:33:16 +02006026 if (is_legacy_es())
6027 require_extension("GL_OES_standard_derivatives");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006028 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006030 // Bitfield
6031 case OpBitFieldInsert:
Hans-Kristian Arntzen6801af42017-03-25 15:38:20 +01006032 // TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006033 QFOP(bitfieldInsert);
6034 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006036 case OpBitFieldSExtract:
6037 case OpBitFieldUExtract:
Hans-Kristian Arntzen6801af42017-03-25 15:38:20 +01006038 // TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary.
6039 TFOP(bitfieldExtract);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006040 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006042 case OpBitReverse:
6043 UFOP(bitfieldReverse);
6044 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006045
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006046 case OpBitCount:
6047 UFOP(bitCount);
6048 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006049
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006050 // Atomics
6051 case OpAtomicExchange:
6052 {
6053 uint32_t result_type = ops[0];
6054 uint32_t id = ops[1];
6055 uint32_t ptr = ops[2];
6056 // Ignore semantics for now, probably only relevant to CL.
6057 uint32_t val = ops[5];
6058 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
6059 forced_temporaries.insert(id);
6060 emit_binary_func_op(result_type, id, ptr, val, op);
6061 flush_all_atomic_capable_variables();
6062 break;
6063 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006065 case OpAtomicCompareExchange:
6066 {
6067 uint32_t result_type = ops[0];
6068 uint32_t id = ops[1];
6069 uint32_t ptr = ops[2];
6070 uint32_t val = ops[6];
6071 uint32_t comp = ops[7];
6072 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006073
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006074 forced_temporaries.insert(id);
6075 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
6076 flush_all_atomic_capable_variables();
6077 break;
6078 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006079
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006080 case OpAtomicLoad:
6081 flush_all_atomic_capable_variables();
6082 // FIXME: Image?
6083 UFOP(atomicCounter);
6084 register_read(ops[1], ops[2], should_forward(ops[2]));
6085 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006086
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01006087 // OpAtomicStore unimplemented. Not sure what would use that.
6088 // OpAtomicLoad seems to only be relevant for atomic counters.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006090 case OpAtomicIIncrement:
6091 forced_temporaries.insert(ops[1]);
6092 // FIXME: Image?
6093 UFOP(atomicCounterIncrement);
6094 flush_all_atomic_capable_variables();
6095 register_read(ops[1], ops[2], should_forward(ops[2]));
6096 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006097
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006098 case OpAtomicIDecrement:
6099 forced_temporaries.insert(ops[1]);
6100 // FIXME: Image?
6101 UFOP(atomicCounterDecrement);
6102 flush_all_atomic_capable_variables();
6103 register_read(ops[1], ops[2], should_forward(ops[2]));
6104 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006105
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006106 case OpAtomicIAdd:
6107 {
6108 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
6109 forced_temporaries.insert(ops[1]);
6110 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
6111 flush_all_atomic_capable_variables();
6112 register_read(ops[1], ops[2], should_forward(ops[2]));
6113 break;
6114 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006115
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006116 case OpAtomicISub:
6117 {
6118 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
6119 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006120 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_enclosed_expression(ops[5]), ")");
6121 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006122 flush_all_atomic_capable_variables();
6123 register_read(ops[1], ops[2], should_forward(ops[2]));
6124 break;
6125 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006126
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006127 case OpAtomicSMin:
6128 case OpAtomicUMin:
6129 {
6130 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
6131 forced_temporaries.insert(ops[1]);
6132 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
6133 flush_all_atomic_capable_variables();
6134 register_read(ops[1], ops[2], should_forward(ops[2]));
6135 break;
6136 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006137
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006138 case OpAtomicSMax:
6139 case OpAtomicUMax:
6140 {
6141 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
6142 forced_temporaries.insert(ops[1]);
6143 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
6144 flush_all_atomic_capable_variables();
6145 register_read(ops[1], ops[2], should_forward(ops[2]));
6146 break;
6147 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006149 case OpAtomicAnd:
6150 {
6151 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
6152 forced_temporaries.insert(ops[1]);
6153 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
6154 flush_all_atomic_capable_variables();
6155 register_read(ops[1], ops[2], should_forward(ops[2]));
6156 break;
6157 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006158
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006159 case OpAtomicOr:
6160 {
6161 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
6162 forced_temporaries.insert(ops[1]);
6163 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
6164 flush_all_atomic_capable_variables();
6165 register_read(ops[1], ops[2], should_forward(ops[2]));
6166 break;
6167 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006168
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006169 case OpAtomicXor:
6170 {
6171 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
6172 forced_temporaries.insert(ops[1]);
6173 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
6174 flush_all_atomic_capable_variables();
6175 register_read(ops[1], ops[2], should_forward(ops[2]));
6176 break;
6177 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006178
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006179 // Geometry shaders
6180 case OpEmitVertex:
6181 statement("EmitVertex();");
6182 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006183
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006184 case OpEndPrimitive:
6185 statement("EndPrimitive();");
6186 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006187
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006188 case OpEmitStreamVertex:
6189 statement("EmitStreamVertex();");
6190 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006191
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006192 case OpEndStreamPrimitive:
6193 statement("EndStreamPrimitive();");
6194 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006195
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006196 // Textures
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006197 case OpImageSampleExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006198 case OpImageSampleProjExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006199 case OpImageSampleDrefExplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006200 case OpImageSampleProjDrefExplicitLod:
Lubos Lenco80c39412016-09-17 14:33:16 +02006201 case OpImageSampleImplicitLod:
6202 case OpImageSampleProjImplicitLod:
6203 case OpImageSampleDrefImplicitLod:
6204 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006205 case OpImageFetch:
6206 case OpImageGather:
6207 case OpImageDrefGather:
6208 // Gets a bit hairy, so move this to a separate instruction.
6209 emit_texture_op(instruction);
6210 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006211
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006212 case OpImage:
6213 {
6214 uint32_t result_type = ops[0];
6215 uint32_t id = ops[1];
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006216 auto &e = emit_op(result_type, id, to_expression(ops[2]), true);
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02006217
6218 // When using the image, we need to know which variable it is actually loaded from.
6219 auto *var = maybe_get_backing_variable(ops[2]);
6220 e.loaded_from = var ? var->self : 0;
6221 break;
6222 }
6223
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02006224 case OpImageQueryLod:
6225 {
6226 if (!options.es && options.version < 400)
6227 {
6228 require_extension("GL_ARB_texture_query_lod");
6229 // For some reason, the ARB spec is all-caps.
6230 BFOP(textureQueryLOD);
6231 }
6232 else if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006233 SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02006234 else
6235 BFOP(textureQueryLod);
6236 break;
6237 }
6238
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02006239 case OpImageQueryLevels:
6240 {
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02006241 uint32_t result_type = ops[0];
6242 uint32_t id = ops[1];
6243
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02006244 if (!options.es && options.version < 430)
6245 require_extension("GL_ARB_texture_query_levels");
6246 if (options.es)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006247 SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile.");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02006248
6249 auto expr = join("textureQueryLevels(", to_expression(ops[2]), ")");
6250 auto &restype = get<SPIRType>(ops[0]);
6251 expr = bitcast_expression(restype, SPIRType::Int, expr);
6252 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02006253 break;
6254 }
6255
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02006256 case OpImageQuerySamples:
6257 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006258 auto &type = expression_type(ops[2]);
6259 uint32_t result_type = ops[0];
6260 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02006261
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006262 string expr;
6263 if (type.image.sampled == 2)
6264 expr = join("imageSamples(", to_expression(ops[2]), ")");
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02006265 else
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006266 expr = join("textureSamples(", to_expression(ops[2]), ")");
6267
6268 auto &restype = get<SPIRType>(ops[0]);
6269 expr = bitcast_expression(restype, SPIRType::Int, expr);
6270 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006271 break;
6272 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006273
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006274 case OpSampledImage:
6275 {
6276 uint32_t result_type = ops[0];
6277 uint32_t id = ops[1];
6278 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
6279 break;
6280 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +02006281
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006282 case OpImageQuerySizeLod:
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006283 {
6284 uint32_t result_type = ops[0];
6285 uint32_t id = ops[1];
6286
Hans-Kristian Arntzen7c58f152017-09-19 16:09:19 +02006287 auto expr = join("textureSize(", to_expression(ops[2]), ", ", bitcast_expression(SPIRType::Int, ops[3]), ")");
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006288 auto &restype = get<SPIRType>(ops[0]);
6289 expr = bitcast_expression(restype, SPIRType::Int, expr);
6290 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006291 break;
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006292 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006293
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006294 // Image load/store
6295 case OpImageRead:
6296 {
6297 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
6298 // not adding the proper qualifiers.
6299 // If it turns out we need to read the image after all, remove the qualifier and recompile.
6300 auto *var = maybe_get_backing_variable(ops[2]);
6301 if (var)
6302 {
6303 auto &flags = meta.at(var->self).decoration.decoration_flags;
6304 if (flags & (1ull << DecorationNonReadable))
6305 {
6306 flags &= ~(1ull << DecorationNonReadable);
6307 force_recompile = true;
6308 }
6309 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006311 uint32_t result_type = ops[0];
6312 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006313
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006314 bool pure;
6315 string imgexpr;
6316 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006317
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02006318 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006319 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02006320 if (type.image.ms)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006321 SPIRV_CROSS_THROW("Trying to remap multisampled image to variable, this is not possible.");
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02006322
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02006323 auto itr =
6324 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 +01006325
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006326 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02006327 {
6328 // For non-PLS inputs, we rely on subpass type remapping information to get it right
6329 // since ImageRead always returns 4-component vectors and the backing type is opaque.
6330 if (!var->remapped_components)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006331 SPIRV_CROSS_THROW("subpassInput was remapped, but remap_components is not set correctly.");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02006332 imgexpr = remap_swizzle(get<SPIRType>(result_type), var->remapped_components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02006333 }
6334 else
6335 {
6336 // PLS input could have different number of components than what the SPIR expects, swizzle to
6337 // the appropriate vector size.
6338 uint32_t components = pls_format_to_components(itr->format);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02006339 imgexpr = remap_swizzle(get<SPIRType>(result_type), components, to_expression(ops[2]));
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02006340 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006341 pure = true;
6342 }
6343 else if (type.image.dim == DimSubpassData)
6344 {
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006345 if (options.vulkan_semantics)
6346 {
6347 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02006348 if (type.image.ms)
6349 {
6350 uint32_t operands = ops[4];
6351 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006352 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02006353 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
6354
6355 uint32_t samples = ops[5];
6356 imgexpr = join("subpassLoad(", to_expression(ops[2]), ", ", to_expression(samples), ")");
6357 }
6358 else
6359 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006360 }
6361 else
6362 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02006363 if (type.image.ms)
6364 {
6365 uint32_t operands = ops[4];
6366 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006367 SPIRV_CROSS_THROW(
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02006368 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
6369
6370 uint32_t samples = ops[5];
6371 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
6372 to_expression(samples), ")");
6373 }
6374 else
6375 {
6376 // Implement subpass loads via texture barrier style sampling.
6377 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
6378 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02006379 }
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02006380 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006381 pure = true;
6382 }
6383 else
6384 {
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006385 // imageLoad only accepts int coords, not uint.
6386 auto coord_expr = to_expression(ops[3]);
6387 auto target_coord_type = expression_type(ops[3]);
6388 target_coord_type.basetype = SPIRType::Int;
6389 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
6390
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006391 // Plain image load/store.
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02006392 if (type.image.ms)
6393 {
6394 uint32_t operands = ops[4];
6395 if (operands != ImageOperandsSampleMask || length != 6)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006396 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02006397
6398 uint32_t samples = ops[5];
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006399 imgexpr =
6400 join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ", ", to_expression(samples), ")");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02006401 }
6402 else
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006403 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", coord_expr, ")");
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02006404
6405 imgexpr = remap_swizzle(get<SPIRType>(result_type), 4, imgexpr);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006406 pure = false;
6407 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006408
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006409 if (var && var->forwardable)
6410 {
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +01006411 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
6412 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006413
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006414 // We only need to track dependencies if we're reading from image load/store.
6415 if (!pure)
6416 {
6417 e.loaded_from = var->self;
Hans-Kristian Arntzen473787e2017-11-22 11:28:58 +01006418 if (forward)
6419 var->dependees.push_back(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006420 }
6421 }
6422 else
Hans-Kristian Arntzene67f6f82016-12-05 10:22:54 +01006423 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006424 break;
6425 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006426
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006427 case OpImageTexelPointer:
6428 {
6429 uint32_t result_type = ops[0];
6430 uint32_t id = ops[1];
6431 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 +01006432
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02006433 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006434 auto *var = maybe_get_backing_variable(ops[2]);
6435 e.loaded_from = var ? var->self : 0;
6436 break;
6437 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006438
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006439 case OpImageWrite:
6440 {
6441 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
6442 // not adding the proper qualifiers.
6443 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
6444 auto *var = maybe_get_backing_variable(ops[0]);
6445 if (var)
6446 {
6447 auto &flags = meta.at(var->self).decoration.decoration_flags;
6448 if (flags & (1ull << DecorationNonWritable))
6449 {
6450 flags &= ~(1ull << DecorationNonWritable);
6451 force_recompile = true;
6452 }
6453 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006454
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02006455 auto &type = expression_type(ops[0]);
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02006456 auto &value_type = expression_type(ops[2]);
6457 auto store_type = value_type;
6458 store_type.vecsize = 4;
6459
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006460 // imageStore only accepts int coords, not uint.
6461 auto coord_expr = to_expression(ops[1]);
6462 auto target_coord_type = expression_type(ops[1]);
6463 target_coord_type.basetype = SPIRType::Int;
6464 coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
6465
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02006466 if (type.image.ms)
6467 {
6468 uint32_t operands = ops[3];
6469 if (operands != ImageOperandsSampleMask || length != 5)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006470 SPIRV_CROSS_THROW("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02006471 uint32_t samples = ops[4];
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006472 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ", to_expression(samples), ", ",
6473 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02006474 }
6475 else
Hans-Kristian Arntzen3c527712017-12-01 15:01:56 +01006476 statement("imageStore(", to_expression(ops[0]), ", ", coord_expr, ", ",
Hans-Kristian Arntzenab3f1142017-10-24 09:23:29 +02006477 remap_swizzle(store_type, value_type.vecsize, to_expression(ops[2])), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006479 if (var && variable_storage_is_aliased(*var))
6480 flush_all_aliased_variables();
6481 break;
6482 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006483
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006484 case OpImageQuerySize:
6485 {
6486 auto &type = expression_type(ops[2]);
6487 uint32_t result_type = ops[0];
6488 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006489
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006490 if (type.basetype == SPIRType::Image)
6491 {
Hans-Kristian Arntzen7064c542017-09-19 16:08:25 +02006492 string expr;
6493 if (type.image.sampled == 2)
6494 {
6495 // The size of an image is always constant.
6496 expr = join("imageSize(", to_expression(ops[2]), ")");
6497 }
6498 else
6499 {
6500 // This path is hit for samplerBuffers and multisampled images which do not have LOD.
6501 expr = join("textureSize(", to_expression(ops[2]), ")");
6502 }
6503
6504 auto &restype = get<SPIRType>(ops[0]);
6505 expr = bitcast_expression(restype, SPIRType::Int, expr);
6506 emit_op(result_type, id, expr, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006507 }
6508 else
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006509 SPIRV_CROSS_THROW("Invalid type for OpImageQuerySize.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006510 break;
6511 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006512
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006513 // Compute
6514 case OpControlBarrier:
6515 {
6516 // Ignore execution and memory scope.
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02006517 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006518 {
6519 uint32_t mem = get<SPIRConstant>(ops[2]).scalar();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02006520
6521 // We cannot forward any loads beyond the memory barrier.
6522 if (mem)
6523 flush_all_active_variables();
6524
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006525 if (mem == MemorySemanticsWorkgroupMemoryMask)
6526 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02006527 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006528 statement("memoryBarrier();");
6529 }
6530 statement("barrier();");
6531 break;
6532 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006534 case OpMemoryBarrier:
6535 {
6536 uint32_t mem = get<SPIRConstant>(ops[1]).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006538 // We cannot forward any loads beyond the memory barrier.
6539 if (mem)
6540 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006542 if (mem == MemorySemanticsWorkgroupMemoryMask)
6543 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02006544 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006545 statement("memoryBarrier();");
6546 break;
6547 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006548
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006549 case OpExtInst:
6550 {
6551 uint32_t extension_set = ops[2];
Lou Kramer6671f522017-11-21 14:04:57 +01006552
6553 if (get<SPIRExtension>(extension_set).ext == SPIRExtension::GLSL)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006554 {
Lou Kramer6671f522017-11-21 14:04:57 +01006555 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
6556 }
6557 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_ballot)
6558 {
6559 emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
6560 }
6561 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
6562 {
6563 emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
6564 }
6565 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_trinary_minmax)
6566 {
6567 emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
6568 }
6569 else if (get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_gcn_shader)
6570 {
6571 emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
6572 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006573 else
6574 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006575 statement("// unimplemented ext op ", instruction.op);
6576 break;
6577 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006578
Lou Kramer6671f522017-11-21 14:04:57 +01006579 break;
6580 }
6581
6582 case OpSubgroupBallotKHR:
6583 {
Lou Kramer6671f522017-11-21 14:04:57 +01006584 uint32_t result_type = ops[0];
6585 uint32_t id = ops[1];
6586 string expr;
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006587 expr = join("unpackUint2x32(ballotARB(" + to_expression(ops[2]) + "))");
Lou Kramer6671f522017-11-21 14:04:57 +01006588 emit_op(result_type, id, expr, true);
6589
6590 require_extension("GL_ARB_shader_ballot");
6591 break;
6592 }
6593
6594 case OpSubgroupFirstInvocationKHR:
6595 {
Lou Kramer6671f522017-11-21 14:04:57 +01006596 uint32_t result_type = ops[0];
6597 uint32_t id = ops[1];
6598 emit_unary_func_op(result_type, id, ops[2], "readFirstInvocationARB");
6599
6600 require_extension("GL_ARB_shader_ballot");
6601 break;
6602 }
6603
6604 case OpSubgroupReadInvocationKHR:
6605 {
Lou Kramer6671f522017-11-21 14:04:57 +01006606 uint32_t result_type = ops[0];
6607 uint32_t id = ops[1];
6608 emit_binary_func_op(result_type, id, ops[2], ops[3], "readInvocationARB");
6609
6610 require_extension("GL_ARB_shader_ballot");
6611 break;
6612 }
6613
6614 case OpSubgroupAllKHR:
6615 {
Lou Kramer6671f522017-11-21 14:04:57 +01006616 uint32_t result_type = ops[0];
6617 uint32_t id = ops[1];
6618 emit_unary_func_op(result_type, id, ops[2], "allInvocationsARB");
6619
6620 require_extension("GL_ARB_shader_group_vote");
6621 break;
6622 }
6623
6624 case OpSubgroupAnyKHR:
6625 {
Lou Kramer6671f522017-11-21 14:04:57 +01006626 uint32_t result_type = ops[0];
6627 uint32_t id = ops[1];
6628 emit_unary_func_op(result_type, id, ops[2], "anyInvocationARB");
6629
6630 require_extension("GL_ARB_shader_group_vote");
6631 break;
6632 }
6633
6634 case OpSubgroupAllEqualKHR:
6635 {
Lou Kramer6671f522017-11-21 14:04:57 +01006636 uint32_t result_type = ops[0];
6637 uint32_t id = ops[1];
6638 emit_unary_func_op(result_type, id, ops[2], "allInvocationsEqualARB");
6639
6640 require_extension("GL_ARB_shader_group_vote");
6641 break;
6642 }
6643
6644 case OpGroupIAddNonUniformAMD:
6645 case OpGroupFAddNonUniformAMD:
6646 {
Lou Kramer6671f522017-11-21 14:04:57 +01006647 uint32_t result_type = ops[0];
6648 uint32_t id = ops[1];
6649 emit_unary_func_op(result_type, id, ops[4], "addInvocationsNonUniformAMD");
6650
6651 require_extension("GL_AMD_shader_ballot");
6652 break;
6653 }
6654
6655 case OpGroupFMinNonUniformAMD:
6656 case OpGroupUMinNonUniformAMD:
6657 case OpGroupSMinNonUniformAMD:
6658 {
Lou Kramer6671f522017-11-21 14:04:57 +01006659 uint32_t result_type = ops[0];
6660 uint32_t id = ops[1];
6661 emit_unary_func_op(result_type, id, ops[4], "minInvocationsNonUniformAMD");
6662
6663 require_extension("GL_AMD_shader_ballot");
6664 break;
6665 }
6666
6667 case OpGroupFMaxNonUniformAMD:
6668 case OpGroupUMaxNonUniformAMD:
6669 case OpGroupSMaxNonUniformAMD:
6670 {
Lou Kramer6671f522017-11-21 14:04:57 +01006671 uint32_t result_type = ops[0];
6672 uint32_t id = ops[1];
6673 emit_unary_func_op(result_type, id, ops[4], "maxInvocationsNonUniformAMD");
6674
6675 require_extension("GL_AMD_shader_ballot");
6676 break;
6677 }
6678
6679 case OpFragmentMaskFetchAMD:
6680 {
6681 auto &type = expression_type(ops[2]);
6682 uint32_t result_type = ops[0];
6683 uint32_t id = ops[1];
6684
6685 if (type.image.dim == spv::DimSubpassData)
6686 {
6687 emit_unary_func_op(result_type, id, ops[2], "fragmentMaskFetchAMD");
6688 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006689 else
Lou Kramer6671f522017-11-21 14:04:57 +01006690 {
6691 emit_binary_func_op(result_type, id, ops[2], ops[3], "fragmentMaskFetchAMD");
6692 }
6693
6694 require_extension("GL_AMD_shader_fragment_mask");
6695 break;
6696 }
6697
6698 case OpFragmentFetchAMD:
6699 {
6700 auto &type = expression_type(ops[2]);
6701 uint32_t result_type = ops[0];
6702 uint32_t id = ops[1];
6703
6704 if (type.image.dim == spv::DimSubpassData)
6705 {
6706 emit_binary_func_op(result_type, id, ops[2], ops[4], "fragmentFetchAMD");
6707 }
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01006708 else
Lou Kramer6671f522017-11-21 14:04:57 +01006709 {
6710 emit_trinary_func_op(result_type, id, ops[2], ops[3], ops[4], "fragmentFetchAMD");
6711 }
6712
6713 require_extension("GL_AMD_shader_fragment_mask");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006714 break;
6715 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006717 default:
6718 statement("// unimplemented op ", instruction.op);
6719 break;
6720 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006721}
6722
Bill Hollingsa759e2c2016-10-19 14:09:51 -07006723// Appends function arguments, mapped from global variables, beyond the specified arg index.
Bill Hollingsfe8b8602016-07-06 16:55:45 -04006724// This is used when a function call uses fewer arguments than the function defines.
Bill Hollingsa759e2c2016-10-19 14:09:51 -07006725// This situation may occur if the function signature has been dynamically modified to
6726// extract global variables referenced from within the function, and convert them to
6727// function arguments. This is necessary for shader languages that do not support global
6728// access to shader input content from within a function (eg. Metal). Each additional
6729// function args uses the name of the global variable. Function nesting will modify the
6730// functions and calls all the way up the nesting chain.
6731void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, vector<string> &arglist)
Bill Hollingsfe8b8602016-07-06 16:55:45 -04006732{
Bill Hollingsac00c602016-10-24 09:24:24 -04006733 auto &args = func.arguments;
Bill Hollings943191a2016-10-27 10:20:01 -04006734 uint32_t arg_cnt = uint32_t(args.size());
Bill Hollingsac00c602016-10-24 09:24:24 -04006735 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +01006736 {
6737 assert(args[arg_idx].alias_global_variable);
Bill Hollingsac00c602016-10-24 09:24:24 -04006738 arglist.push_back(to_func_call_arg(args[arg_idx].id));
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +01006739 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -04006740}
6741
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006742string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
6743{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006744 auto &memb = meta[type.self].members;
6745 if (index < memb.size() && !memb[index].alias.empty())
6746 return memb[index].alias;
6747 else
Hans-Kristian Arntzen1c6df1b2017-07-29 21:44:20 +02006748 return join("_m", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006749}
6750
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02006751void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
6752{
6753 auto &memb = meta[type.self].members;
6754 if (index < memb.size() && !memb[index].alias.empty())
6755 {
6756 auto &name = memb[index].alias;
6757 if (name.empty())
6758 return;
6759
6760 // Reserved for temporaries.
6761 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
6762 {
6763 name.clear();
6764 return;
6765 }
6766
6767 update_name_cache(type.member_name_cache, name);
6768 }
6769}
6770
Bill Hollingsb332bae2017-03-01 13:07:40 -05006771// Checks whether the ID is a row_major matrix that requires conversion before use
Bill Hollings13583622016-12-14 02:12:52 -05006772bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02006773{
Bill Hollings13583622016-12-14 02:12:52 -05006774 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01006775 // Legacy targets do not support row major.
6776 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -05006777 return false;
6778
6779 // Non-matrix or column-major matrix types do not need to be converted.
6780 if (!(meta[id].decoration.decoration_flags & (1ull << DecorationRowMajor)))
6781 return false;
6782
6783 // Only square row-major matrices can be converted at this time.
6784 // Converting non-square matrices will require defining custom GLSL function that
6785 // swaps matrix elements while retaining the original dimensional form of the matrix.
6786 const auto type = expression_type(id);
6787 if (type.columns != type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +01006788 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -05006789
6790 return true;
Bill Hollings343677e2016-12-11 11:01:08 -05006791}
6792
Bill Hollings13583622016-12-14 02:12:52 -05006793// Checks whether the member is a row_major matrix that requires conversion before use
6794bool CompilerGLSL::member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index)
Bill Hollings343677e2016-12-11 11:01:08 -05006795{
Bill Hollings13583622016-12-14 02:12:52 -05006796 // Natively supported row-major matrices do not need to be converted.
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +01006797 if (backend.native_row_major_matrix && !is_legacy())
Bill Hollings13583622016-12-14 02:12:52 -05006798 return false;
6799
6800 // Non-matrix or column-major matrix types do not need to be converted.
6801 if (!(combined_decoration_for_member(type, index) & (1ull << DecorationRowMajor)))
6802 return false;
6803
6804 // Only square row-major matrices can be converted at this time.
6805 // Converting non-square matrices will require defining custom GLSL function that
6806 // swaps matrix elements while retaining the original dimensional form of the matrix.
6807 const auto mbr_type = get<SPIRType>(type.member_types[index]);
6808 if (mbr_type.columns != mbr_type.vecsize)
Panagiotis Christopoulos Charitos7f69f932016-12-15 20:46:10 +01006809 SPIRV_CROSS_THROW("Row-major matrices must be square on this platform.");
Bill Hollings13583622016-12-14 02:12:52 -05006810
6811 return true;
Bill Hollings343677e2016-12-11 11:01:08 -05006812}
6813
Bill Hollingsb332bae2017-03-01 13:07:40 -05006814// Checks whether the member is in packed data type, that might need to be unpacked.
6815// GLSL does not define packed data types, but certain subclasses do.
Bill Hollings1c180782017-11-05 21:34:42 -05006816bool CompilerGLSL::member_is_packed_type(const SPIRType &type, uint32_t index) const
Bill Hollingsb332bae2017-03-01 13:07:40 -05006817{
6818 return has_member_decoration(type.self, index, DecorationCPacked);
6819}
6820
Bill Hollings13583622016-12-14 02:12:52 -05006821// Wraps the expression string in a function call that converts the
6822// row_major matrix result of the expression to a column_major matrix.
6823// Base implementation uses the standard library transpose() function.
6824// Subclasses may override to use a different function.
6825string CompilerGLSL::convert_row_major_matrix(string exp_str)
Bill Hollings343677e2016-12-11 11:01:08 -05006826{
6827 strip_enclosed_expression(exp_str);
6828 return join("transpose(", exp_str, ")");
6829}
6830
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +02006831string CompilerGLSL::variable_decl(const SPIRType &type, const string &name, uint32_t id)
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02006832{
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +02006833 string type_name = type_to_glsl(type, id);
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +02006834 remap_variable_type_name(type, name, type_name);
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +02006835 return join(type_name, " ", name, type_to_array_glsl(type));
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02006836}
6837
Bill Hollings484931d2017-02-28 21:44:36 -05006838// Emit a structure member. Subclasses may override to modify output,
6839// or to dynamically add a padding member if needed.
Bill Hollingsdc694272017-03-11 12:17:22 -05006840void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
6841 const string &qualifier)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006842{
Bill Hollings484931d2017-02-28 21:44:36 -05006843 auto &membertype = get<SPIRType>(member_type_id);
6844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006845 uint64_t memberflags = 0;
6846 auto &memb = meta[type.self].members;
6847 if (index < memb.size())
6848 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006849
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02006850 string qualifiers;
6851 bool is_block = (meta[type.self].decoration.decoration_flags &
6852 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
6853 if (is_block)
6854 qualifiers = to_interpolation_qualifiers(memberflags);
6855
Bill Hollings484931d2017-02-28 21:44:36 -05006856 statement(layout_for_member(type, index), qualifiers, qualifier,
6857 flags_to_precision_qualifiers_glsl(membertype, memberflags),
6858 variable_decl(membertype, to_member_name(type, index)), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006859}
6860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006861const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006862{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006863 if (options.es)
6864 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02006865 auto &execution = get_entry_point();
6866
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02006867 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006868 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
6869 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
6870 type.basetype != SPIRType::Sampler)
6871 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006872
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006873 if (flags & (1ull << DecorationRelaxedPrecision))
6874 {
6875 bool implied_fmediump = type.basetype == SPIRType::Float &&
6876 options.fragment.default_float_precision == Options::Mediump &&
6877 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006878
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006879 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
6880 options.fragment.default_int_precision == Options::Mediump &&
6881 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006882
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006883 return implied_fmediump || implied_imediump ? "" : "mediump ";
6884 }
6885 else
6886 {
6887 bool implied_fhighp =
6888 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
6889 execution.model == ExecutionModelFragment) ||
6890 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006891
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006892 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
6893 ((options.fragment.default_int_precision == Options::Highp &&
6894 execution.model == ExecutionModelFragment) ||
6895 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006896
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006897 return implied_fhighp || implied_ihighp ? "" : "highp ";
6898 }
6899 }
6900 else
6901 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006902}
6903
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006904const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006905{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006906 return flags_to_precision_qualifiers_glsl(expression_type(id), meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006907}
6908
6909string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
6910{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006911 auto flags = meta[id].decoration.decoration_flags;
6912 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006913
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006914 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006915
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006916 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
6917 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006918
Hans-Kristian Arntzen206cb912016-10-07 16:27:39 +02006919 res += to_interpolation_qualifiers(flags);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01006920 if (var)
6921 res += to_storage_qualifiers_glsl(*var);
Hans-Kristian Arntzen036b9b72017-02-24 09:56:17 +01006922
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +02006923 auto &type = expression_type(id);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006924 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
6925 {
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +02006926 if (flags & (1ull << DecorationCoherent))
6927 res += "coherent ";
Hans-Kristian Arntzen11dfcb62017-08-29 15:54:22 +02006928 if (flags & (1ull << DecorationRestrict))
6929 res += "restrict ";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006930 if (flags & (1ull << DecorationNonWritable))
6931 res += "readonly ";
6932 if (flags & (1ull << DecorationNonReadable))
6933 res += "writeonly ";
6934 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006935
Hans-Kristian Arntzend55898e2017-08-29 15:52:59 +02006936 res += to_precision_qualifiers_glsl(id);
6937
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006938 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006939}
6940
6941string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
6942{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006943 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006944 auto &type = expression_type(arg.id);
6945 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006946
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006947 if (type.pointer)
6948 {
6949 if (arg.write_count && arg.read_count)
6950 direction = "inout ";
6951 else if (arg.write_count)
6952 direction = "out ";
6953 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006954
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +02006955 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 +01006956}
6957
6958string CompilerGLSL::variable_decl(const SPIRVariable &variable)
6959{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006960 // Ignore the pointer type since GLSL doesn't have pointers.
6961 auto &type = get<SPIRType>(variable.basetype);
Hans-Kristian Arntzen3eb8a342017-05-06 13:35:02 +02006962
Hans-Kristian Arntzenb0f7dee2017-06-17 10:56:24 +02006963 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 +02006964
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01006965 if (variable.loop_variable)
6966 res += join(" = ", to_expression(variable.static_expression));
6967 else if (variable.initializer)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006968 res += join(" = ", to_expression(variable.initializer));
6969 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006970}
6971
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006972const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006973{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006974 auto flags = meta[variable.self].decoration.decoration_flags;
6975 if (flags & (1ull << DecorationRelaxedPrecision))
6976 return "mediump ";
6977 else
6978 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006979}
6980
6981string CompilerGLSL::pls_decl(const PlsRemap &var)
6982{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006983 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006985 SPIRType type;
6986 type.vecsize = pls_format_to_components(var.format);
6987 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006988
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02006989 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
6990 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01006991}
6992
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02006993uint32_t CompilerGLSL::to_array_size_literal(const SPIRType &type, uint32_t index) const
6994{
6995 assert(type.array.size() == type.array_size_literal.size());
6996
6997 if (!type.array_size_literal[index])
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01006998 SPIRV_CROSS_THROW("The array size is not a literal, but a specialization constant or spec constant op.");
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +02006999
7000 return type.array[index];
7001}
7002
7003string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index)
7004{
7005 assert(type.array.size() == type.array_size_literal.size());
7006
7007 auto &size = type.array[index];
7008 if (!type.array_size_literal[index])
7009 return to_expression(size);
7010 else if (size)
7011 return convert_to_string(size);
7012 else if (!backend.flexible_member_array_supported)
7013 {
7014 // For runtime-sized arrays, we can work around
7015 // lack of standard support for this by simply having
7016 // a single element array.
7017 //
7018 // Runtime length arrays must always be the last element
7019 // in an interface block.
7020 return "1";
7021 }
7022 else
7023 return "";
7024}
7025
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007026string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
7027{
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007028 if (type.array.empty())
7029 return "";
7030
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007031 if (options.flatten_multidimensional_arrays)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007032 {
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007033 string res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007034 res += "[";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007035 for (auto i = uint32_t(type.array.size()); i; i--)
7036 {
7037 res += enclose_expression(to_array_size(type, i - 1));
7038 if (i > 1)
7039 res += " * ";
7040 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007041 res += "]";
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007042 return res;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007043 }
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007044 else
7045 {
7046 if (type.array.size() > 1)
7047 {
7048 if (!options.es && options.version < 430)
7049 require_extension("GL_ARB_arrays_of_arrays");
7050 else if (options.es && options.version < 310)
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02007051 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310. "
7052 "Try using --flatten-multidimensional-arrays or set "
7053 "options.flatten_multidimensional_arrays to true.");
Hans-Kristian Arntzenf0044b92017-05-22 16:52:25 +02007054 }
7055
7056 string res;
7057 for (auto i = uint32_t(type.array.size()); i; i--)
7058 {
7059 res += "[";
7060 res += to_array_size(type, i - 1);
7061 res += "]";
7062 }
7063 return res;
7064 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007065}
7066
Bill Hollingsb41e1482017-05-29 20:45:05 -04007067string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007068{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007069 auto &imagetype = get<SPIRType>(type.image.type);
7070 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007072 switch (imagetype.basetype)
7073 {
7074 case SPIRType::Int:
7075 res = "i";
7076 break;
7077 case SPIRType::UInt:
7078 res = "u";
7079 break;
7080 default:
7081 break;
7082 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007083
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02007084 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02007085 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02007086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007087 // If we're emulating subpassInput with samplers, force sampler2D
7088 // so we don't have to specify format.
7089 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
Hans-Kristian Arntzen543e3802017-04-02 10:54:11 +02007090 {
7091 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
7092 if (type.image.dim == DimBuffer && type.image.sampled == 1)
7093 res += "sampler";
7094 else
7095 res += type.image.sampled == 2 ? "image" : "texture";
7096 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007097 else
7098 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007099
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007100 switch (type.image.dim)
7101 {
7102 case Dim1D:
7103 res += "1D";
7104 break;
7105 case Dim2D:
7106 res += "2D";
7107 break;
7108 case Dim3D:
7109 res += "3D";
7110 break;
7111 case DimCube:
7112 res += "Cube";
7113 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007114
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007115 case DimBuffer:
7116 if (options.es && options.version < 320)
7117 require_extension("GL_OES_texture_buffer");
7118 else if (!options.es && options.version < 300)
7119 require_extension("GL_EXT_texture_buffer_object");
7120 res += "Buffer";
7121 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007122
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007123 case DimSubpassData:
7124 res += "2D";
7125 break;
7126 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01007127 SPIRV_CROSS_THROW("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007128 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007129
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02007130 if (type.image.ms)
7131 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007132 if (type.image.arrayed)
Rob Fischer21990632016-09-17 17:01:50 +09007133 {
Lubos Lenco52158642016-09-17 15:56:23 +02007134 if (is_legacy_desktop())
Lubos Lenco80c39412016-09-17 14:33:16 +02007135 require_extension("GL_EXT_texture_array");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007136 res += "Array";
Rob Fischer21990632016-09-17 17:01:50 +09007137 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007138 if (type.image.depth)
7139 res += "Shadow";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007140
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007141 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007142}
7143
7144string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
7145{
Hans-Kristian Arntzen326a7ff2017-05-22 17:47:03 +02007146 if (type.array.size() > 1)
7147 {
7148 if (options.flatten_multidimensional_arrays)
7149 SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, e.g. float[][]().");
7150 else if (!options.es && options.version < 430)
7151 require_extension("GL_ARB_arrays_of_arrays");
7152 else if (options.es && options.version < 310)
7153 SPIRV_CROSS_THROW("Arrays of arrays not supported before ESSL version 310.");
7154 }
Hans-Kristian Arntzen470ae7a2017-05-22 17:40:00 +02007155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007156 auto e = type_to_glsl(type);
7157 for (uint32_t i = 0; i < type.array.size(); i++)
7158 e += "[]";
7159 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007160}
7161
Bill Hollingsb41e1482017-05-29 20:45:05 -04007162// The optional id parameter indicates the object whose type we are trying
7163// to find the description for. It is optional. Most type descriptions do not
7164// depend on a specific object's use of that type.
7165string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007166{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007167 // Ignore the pointer type since GLSL doesn't have pointers.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007168
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007169 switch (type.basetype)
7170 {
7171 case SPIRType::Struct:
7172 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02007173 if (backend.explicit_struct_type)
7174 return join("struct ", to_name(type.self));
7175 else
7176 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007178 case SPIRType::Image:
7179 case SPIRType::SampledImage:
Bill Hollingsb41e1482017-05-29 20:45:05 -04007180 return image_type_glsl(type, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007181
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007182 case SPIRType::Sampler:
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +02007183 // The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
7184 // this distinction into the type system.
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +02007185 return comparison_samplers.count(id) ? "samplerShadow" : "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007186
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007187 case SPIRType::Void:
7188 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007189
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007190 default:
7191 break;
7192 }
7193
7194 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
7195 {
7196 switch (type.basetype)
7197 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02007198 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007199 return "bool";
7200 case SPIRType::Int:
7201 return backend.basic_int_type;
7202 case SPIRType::UInt:
7203 return backend.basic_uint_type;
7204 case SPIRType::AtomicCounter:
7205 return "atomic_uint";
7206 case SPIRType::Float:
7207 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007208 case SPIRType::Double:
7209 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02007210 case SPIRType::Int64:
7211 return "int64_t";
7212 case SPIRType::UInt64:
7213 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007214 default:
7215 return "???";
7216 }
7217 }
7218 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
7219 {
7220 switch (type.basetype)
7221 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02007222 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007223 return join("bvec", type.vecsize);
7224 case SPIRType::Int:
7225 return join("ivec", type.vecsize);
7226 case SPIRType::UInt:
7227 return join("uvec", type.vecsize);
7228 case SPIRType::Float:
7229 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007230 case SPIRType::Double:
7231 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02007232 case SPIRType::Int64:
7233 return join("i64vec", type.vecsize);
7234 case SPIRType::UInt64:
7235 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007236 default:
7237 return "???";
7238 }
7239 }
7240 else if (type.vecsize == type.columns) // Simple Matrix builtin
7241 {
7242 switch (type.basetype)
7243 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02007244 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007245 return join("bmat", type.vecsize);
7246 case SPIRType::Int:
7247 return join("imat", type.vecsize);
7248 case SPIRType::UInt:
7249 return join("umat", type.vecsize);
7250 case SPIRType::Float:
7251 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007252 case SPIRType::Double:
7253 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02007254 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007255 default:
7256 return "???";
7257 }
7258 }
7259 else
7260 {
7261 switch (type.basetype)
7262 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02007263 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007264 return join("bmat", type.columns, "x", type.vecsize);
7265 case SPIRType::Int:
7266 return join("imat", type.columns, "x", type.vecsize);
7267 case SPIRType::UInt:
7268 return join("umat", type.columns, "x", type.vecsize);
7269 case SPIRType::Float:
7270 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02007271 case SPIRType::Double:
7272 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02007273 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007274 default:
7275 return "???";
7276 }
7277 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007278}
7279
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01007280void CompilerGLSL::add_variable(unordered_set<string> &variables, string &name)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007281{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007282 if (name.empty())
7283 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007284
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007285 // Reserved for temporaries.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02007286 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007287 {
7288 name.clear();
7289 return;
7290 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007291
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02007292 update_name_cache(variables, name);
7293}
7294
Hans-Kristian Arntzen2c90ea32017-12-01 14:20:51 +01007295void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
7296{
7297 auto &name = meta[id].decoration.alias;
7298 add_variable(variables, name);
7299}
7300
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02007301void CompilerGLSL::add_local_variable_name(uint32_t id)
7302{
7303 add_variable(local_variable_names, id);
7304}
7305
7306void CompilerGLSL::add_resource_name(uint32_t id)
7307{
7308 add_variable(resource_names, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007309}
7310
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +02007311void CompilerGLSL::add_header_line(const std::string &line)
7312{
7313 header_lines.push_back(line);
7314}
7315
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007316bool CompilerGLSL::has_extension(const std::string &ext) const
7317{
7318 auto itr = find(begin(forced_extensions), end(forced_extensions), ext);
7319 return itr != end(forced_extensions);
7320}
7321
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007322void CompilerGLSL::require_extension(const string &ext)
7323{
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007324 if (!has_extension(ext))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007325 {
Hans-Kristian Arntzenbcdff2d2017-11-22 19:27:03 +01007326 forced_extensions.push_back(ext);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007327 force_recompile = true;
7328 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007329}
7330
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007331void CompilerGLSL::flatten_buffer_block(uint32_t id)
7332{
7333 auto &var = get<SPIRVariable>(id);
7334 auto &type = get<SPIRType>(var.basetype);
7335 auto name = to_name(type.self, false);
7336 auto flags = meta.at(type.self).decoration.decoration_flags;
7337
7338 if (!type.array.empty())
7339 SPIRV_CROSS_THROW(name + " is an array of UBOs.");
7340 if (type.basetype != SPIRType::Struct)
7341 SPIRV_CROSS_THROW(name + " is not a struct.");
7342 if ((flags & (1ull << DecorationBlock)) == 0)
7343 SPIRV_CROSS_THROW(name + " is not a block.");
7344 if (type.member_types.empty())
7345 SPIRV_CROSS_THROW(name + " is an empty struct.");
7346
Arseny Kapoulkine0185f0a2016-12-06 21:02:15 -08007347 flattened_buffer_blocks.insert(id);
7348}
7349
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007350bool CompilerGLSL::check_atomic_image(uint32_t id)
7351{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007352 auto &type = expression_type(id);
7353 if (type.storage == StorageClassImage)
7354 {
7355 if (options.es && options.version < 320)
7356 require_extension("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007357
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007358 auto *var = maybe_get_backing_variable(id);
7359 if (var)
7360 {
7361 auto &flags = meta.at(var->self).decoration.decoration_flags;
7362 if (flags & ((1ull << DecorationNonWritable) | (1ull << DecorationNonReadable)))
7363 {
7364 flags &= ~(1ull << DecorationNonWritable);
7365 flags &= ~(1ull << DecorationNonReadable);
7366 force_recompile = true;
7367 }
7368 }
7369 return true;
7370 }
7371 else
7372 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007373}
7374
7375void CompilerGLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_flags)
7376{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02007377 // Avoid shadow declarations.
7378 local_variable_names = resource_names;
7379
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007380 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007381
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007382 auto &type = get<SPIRType>(func.return_type);
7383 decl += flags_to_precision_qualifiers_glsl(type, return_flags);
7384 decl += type_to_glsl(type);
7385 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007386
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02007387 if (func.self == entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007388 {
Bill Hollings1c180782017-11-05 21:34:42 -05007389 decl += "main";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007390 processing_entry_point = true;
7391 }
7392 else
Bill Hollings1c180782017-11-05 21:34:42 -05007393 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007394
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007395 decl += "(";
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007396 vector<string> arglist;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007397 for (auto &arg : func.arguments)
7398 {
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007399 // Do not pass in separate images or samplers if we're remapping
7400 // to combined image samplers.
7401 if (skip_argument(arg.id))
7402 continue;
7403
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007404 // Might change the variable name if it already exists in this function.
7405 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
7406 // to use same name for variables.
7407 // 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 +02007408 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007409
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007410 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007411
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007412 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
7413 auto *var = maybe_get<SPIRVariable>(arg.id);
7414 if (var)
7415 var->parameter = &arg;
7416 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007417
Hans-Kristian Arntzen313cb5f2016-09-11 12:54:08 +02007418 for (auto &arg : func.shadow_arguments)
7419 {
7420 // Might change the variable name if it already exists in this function.
7421 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
7422 // to use same name for variables.
7423 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
7424 add_local_variable_name(arg.id);
7425
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007426 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007427
7428 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
7429 auto *var = maybe_get<SPIRVariable>(arg.id);
7430 if (var)
7431 var->parameter = &arg;
7432 }
7433
Hans-Kristian Arntzenbff27362016-09-11 13:05:44 +02007434 decl += merge(arglist);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007435 decl += ")";
7436 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007437}
7438
7439void CompilerGLSL::emit_function(SPIRFunction &func, uint64_t return_flags)
7440{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007441 // Avoid potential cycles.
7442 if (func.active)
7443 return;
7444 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007445
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007446 // If we depend on a function, emit that function before we emit our own function.
7447 for (auto block : func.blocks)
7448 {
7449 auto &b = get<SPIRBlock>(block);
7450 for (auto &i : b.ops)
7451 {
7452 auto ops = stream(i);
7453 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007455 if (op == OpFunctionCall)
7456 {
7457 // Recursively emit functions which are called.
7458 uint32_t id = ops[2];
7459 emit_function(get<SPIRFunction>(id), meta[ops[1]].decoration.decoration_flags);
7460 }
7461 }
7462 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007463
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007464 emit_function_prototype(func, return_flags);
7465 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007466
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007467 current_function = &func;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007468 auto &entry_block = get<SPIRBlock>(func.entry_block);
7469
7470 if (!func.analyzed_variable_scope)
7471 {
7472 if (options.cfg_analysis)
Hans-Kristian Arntzen51d45512016-12-15 17:54:49 +01007473 {
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007474 analyze_variable_scope(func);
Hans-Kristian Arntzen51d45512016-12-15 17:54:49 +01007475
7476 // Check if we can actually use the loop variables we found in analyze_variable_scope.
7477 // To use multiple initializers, we need the same type and qualifiers.
7478 for (auto block : func.blocks)
7479 {
7480 auto &b = get<SPIRBlock>(block);
7481 if (b.loop_variables.size() < 2)
7482 continue;
7483
7484 uint64_t flags = get_decoration_mask(b.loop_variables.front());
7485 uint32_t type = get<SPIRVariable>(b.loop_variables.front()).basetype;
7486 bool invalid_initializers = false;
7487 for (auto loop_variable : b.loop_variables)
7488 {
7489 if (flags != get_decoration_mask(loop_variable) ||
7490 type != get<SPIRVariable>(b.loop_variables.front()).basetype)
7491 {
7492 invalid_initializers = true;
7493 break;
7494 }
7495 }
7496
7497 if (invalid_initializers)
7498 {
7499 for (auto loop_variable : b.loop_variables)
7500 get<SPIRVariable>(loop_variable).loop_variable = false;
7501 b.loop_variables.clear();
7502 }
7503 }
7504 }
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007505 else
7506 entry_block.dominated_variables = func.local_variables;
7507 func.analyzed_variable_scope = true;
7508 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007509
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007510 for (auto &v : func.local_variables)
7511 {
7512 auto &var = get<SPIRVariable>(v);
7513 if (expression_is_lvalue(v))
7514 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02007515 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007516
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007517 if (var.initializer)
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +01007518 statement(variable_decl_function_local(var), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007519 else
7520 {
7521 // Don't declare variable until first use to declutter the GLSL output quite a lot.
7522 // If we don't touch the variable before first branch,
7523 // declare it then since we need variable declaration to be in top scope.
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02007524 // Never declare empty structs. They have no meaningful representation.
7525 auto &type = get<SPIRType>(var.basetype);
7526 bool empty_struct = type.basetype == SPIRType::Struct && type.member_types.empty();
7527 var.deferred_declaration = !empty_struct;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007528 }
7529 }
7530 else
7531 {
Hans-Kristian Arntzen8538b4c2017-10-06 13:03:34 +02007532 // 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 +01007533 // For these types (non-lvalue), we enforce forwarding through a shadowed variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007534 // This means that when we OpStore to these variables, we just write in the expression ID directly.
7535 // This breaks any kind of branching, since the variable must be statically assigned.
7536 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
7537 var.statically_assigned = true;
7538 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007539
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007540 var.loop_variable_enable = false;
Hans-Kristian Arntzenb847c882016-11-18 17:06:49 +01007541
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007542 // Loop variables are never declared outside their for-loop, so block any implicit declaration.
7543 if (var.loop_variable)
7544 var.deferred_declaration = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007545 }
7546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007547 entry_block.loop_dominator = SPIRBlock::NoDominator;
7548 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007549
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007550 end_scope();
7551 processing_entry_point = false;
7552 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007553}
7554
7555void CompilerGLSL::emit_fixup()
7556{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02007557 auto &execution = get_entry_point();
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +02007558 if (execution.model == ExecutionModelVertex)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007559 {
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +02007560 if (options.vertex.fixup_clipspace)
7561 {
7562 const char *suffix = backend.float_literal_suffix ? "f" : "";
7563 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
7564 }
7565
7566 if (options.vertex.flip_vert_y)
7567 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007568 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007569}
7570
7571bool CompilerGLSL::flush_phi_required(uint32_t from, uint32_t to)
7572{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007573 auto &child = get<SPIRBlock>(to);
7574 for (auto &phi : child.phi_variables)
7575 if (phi.parent == from)
7576 return true;
7577 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007578}
7579
7580void CompilerGLSL::flush_phi(uint32_t from, uint32_t to)
7581{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007582 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007584 for (auto &phi : child.phi_variables)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +02007585 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007586 if (phi.parent == from)
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +02007587 {
7588 auto &var = get<SPIRVariable>(phi.function_variable);
7589
7590 // A Phi variable might be a loop variable, so flush to static expression.
7591 if (var.loop_variable && !var.loop_variable_enable)
7592 var.static_expression = phi.local_variable;
7593 else
7594 {
7595 flush_variable_declaration(phi.function_variable);
7596
7597 // This might be called in continue block, so make sure we
Hans-Kristian Arntzen91753632017-09-25 10:16:45 +02007598 // use this to emit ESSL 1.0 compliant increments/decrements.
Hans-Kristian Arntzen3339fd42017-09-25 10:15:17 +02007599 auto lhs = to_expression(phi.function_variable);
7600 auto rhs = to_expression(phi.local_variable);
7601 if (!optimize_read_modify_write(lhs, rhs))
7602 statement(lhs, " = ", rhs, ";");
7603 }
7604 }
7605 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007606}
7607
7608void CompilerGLSL::branch(uint32_t from, uint32_t to)
7609{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007610 flush_phi(from, to);
7611 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007613 // This is only a continue if we branch to our loop dominator.
7614 if (loop_blocks.find(to) != end(loop_blocks) && get<SPIRBlock>(from).loop_dominator == to)
7615 {
7616 // This can happen if we had a complex continue block which was emitted.
7617 // Once the continue block tries to branch to the loop header, just emit continue;
7618 // and end the chain here.
7619 statement("continue;");
7620 }
7621 else if (is_continue(to))
7622 {
7623 auto &to_block = get<SPIRBlock>(to);
7624 if (to_block.complex_continue)
7625 {
7626 // Just emit the whole block chain as is.
7627 auto usage_counts = expression_usage_counts;
7628 auto invalid = invalid_expressions;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007629
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007630 emit_block_chain(to_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007631
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007632 // Expression usage counts and invalid expressions
7633 // are moot after returning from the continue block.
7634 // Since we emit the same block multiple times,
7635 // we don't want to invalidate ourselves.
7636 expression_usage_counts = usage_counts;
7637 invalid_expressions = invalid;
7638 }
7639 else
7640 {
7641 auto &from_block = get<SPIRBlock>(from);
7642 auto &dominator = get<SPIRBlock>(from_block.loop_dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007643
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007644 // For non-complex continue blocks, we implicitly branch to the continue block
7645 // by having the continue block be part of the loop header in for (; ; continue-block).
7646 bool outside_control_flow = block_is_outside_flow_control_from_block(dominator, from_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007647
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007648 // Some simplification for for-loops. We always end up with a useless continue;
7649 // statement since we branch to a loop block.
7650 // Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block,
7651 // we can avoid writing out an explicit continue statement.
7652 // Similar optimization to return statements if we know we're outside flow control.
7653 if (!outside_control_flow)
7654 statement("continue;");
7655 }
7656 }
7657 else if (is_break(to))
7658 statement("break;");
7659 else if (!is_conditional(to))
7660 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007661}
7662
7663void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block)
7664{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007665 // If we branch directly to a selection merge target, we don't really need a code path.
7666 bool true_sub = !is_conditional(true_block);
7667 bool false_sub = !is_conditional(false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007668
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007669 if (true_sub)
7670 {
7671 statement("if (", to_expression(cond), ")");
7672 begin_scope();
7673 branch(from, true_block);
7674 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007675
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007676 if (false_sub)
7677 {
7678 statement("else");
7679 begin_scope();
7680 branch(from, false_block);
7681 end_scope();
7682 }
7683 else if (flush_phi_required(from, false_block))
7684 {
7685 statement("else");
7686 begin_scope();
7687 flush_phi(from, false_block);
7688 end_scope();
7689 }
7690 }
7691 else if (false_sub && !true_sub)
7692 {
7693 // Only need false path, use negative conditional.
7694 statement("if (!", to_expression(cond), ")");
7695 begin_scope();
7696 branch(from, false_block);
7697 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007698
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007699 if (flush_phi_required(from, true_block))
7700 {
7701 statement("else");
7702 begin_scope();
7703 flush_phi(from, true_block);
7704 end_scope();
7705 }
7706 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007707}
7708
7709void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
7710{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007711 // Propagate down the loop dominator block, so that dominated blocks can back trace.
7712 if (block.merge == SPIRBlock::MergeLoop || block.loop_dominator)
7713 {
7714 uint32_t dominator = block.merge == SPIRBlock::MergeLoop ? block.self : block.loop_dominator;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007715
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02007716 auto set_dominator = [this](uint32_t self, uint32_t new_dominator) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007717 auto &dominated_block = this->get<SPIRBlock>(self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007718
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007719 // If we already have a loop dominator, we're trying to break out to merge targets
7720 // which should not update the loop dominator.
7721 if (!dominated_block.loop_dominator)
7722 dominated_block.loop_dominator = new_dominator;
7723 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007724
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007725 // After merging a loop, we inherit the loop dominator always.
7726 if (block.merge_block)
7727 set_dominator(block.merge_block, block.loop_dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02007728
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007729 if (block.true_block)
7730 set_dominator(block.true_block, dominator);
7731 if (block.false_block)
7732 set_dominator(block.false_block, dominator);
7733 if (block.next_block)
7734 set_dominator(block.next_block, dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02007735
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007736 for (auto &c : block.cases)
7737 set_dominator(c.block, dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007738
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007739 // In older glslang output continue_block can be == loop header.
7740 if (block.continue_block && block.continue_block != block.self)
7741 set_dominator(block.continue_block, dominator);
7742 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007743}
7744
7745// FIXME: This currently cannot handle complex continue blocks
7746// as in do-while.
7747// This should be seen as a "trivial" continue block.
7748string CompilerGLSL::emit_continue_block(uint32_t continue_block)
7749{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007750 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007751
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007752 // While emitting the continue block, declare_temporary will check this
7753 // if we have to emit temporaries.
7754 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007755
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007756 vector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007757
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007758 // Capture all statements into our list.
7759 auto *old = redirect_statement;
7760 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007761
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007762 // Stamp out all blocks one after each other.
7763 while (loop_blocks.find(block->self) == end(loop_blocks))
7764 {
7765 propagate_loop_dominators(*block);
7766 // Write out all instructions we have in this block.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02007767 emit_block_instructions(*block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007769 // For plain branchless for/while continue blocks.
7770 if (block->next_block)
7771 {
7772 flush_phi(continue_block, block->next_block);
7773 block = &get<SPIRBlock>(block->next_block);
7774 }
7775 // For do while blocks. The last block will be a select block.
7776 else if (block->true_block)
7777 {
7778 flush_phi(continue_block, block->true_block);
7779 block = &get<SPIRBlock>(block->true_block);
7780 }
7781 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007782
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007783 // Restore old pointer.
7784 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007785
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007786 // Somewhat ugly, strip off the last ';' since we use ',' instead.
7787 // Ideally, we should select this behavior in statement().
7788 for (auto &s : statements)
7789 {
7790 if (!s.empty() && s.back() == ';')
Corentin Wallezef9ee492016-10-05 13:01:31 -04007791 s.erase(s.size() - 1, 1);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007792 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007793
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007794 current_continue_block = nullptr;
7795 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007796}
7797
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007798string CompilerGLSL::emit_for_loop_initializers(const SPIRBlock &block)
7799{
7800 if (block.loop_variables.empty())
7801 return "";
7802
7803 if (block.loop_variables.size() == 1)
7804 {
7805 return variable_decl(get<SPIRVariable>(block.loop_variables.front()));
7806 }
7807 else
7808 {
7809 auto &var = get<SPIRVariable>(block.loop_variables.front());
7810 auto &type = get<SPIRType>(var.basetype);
7811
7812 // Don't remap the type here as we have multiple names,
7813 // doesn't make sense to remap types for loop variables anyways.
7814 // It is assumed here that all relevant qualifiers are equal for all loop variables.
7815 string expr = join(to_qualifiers_glsl(var.self), type_to_glsl(type), " ");
7816
7817 for (auto &loop_var : block.loop_variables)
7818 {
7819 auto &v = get<SPIRVariable>(loop_var);
7820 expr += join(to_name(loop_var), " = ", to_expression(v.static_expression));
7821 if (&loop_var != &block.loop_variables.back())
7822 expr += ", ";
7823 }
7824 return expr;
7825 }
7826}
7827
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007828bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
7829{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007830 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007831
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007832 if (method == SPIRBlock::MergeToSelectForLoop)
7833 {
7834 uint32_t current_count = statement_count;
7835 // If we're trying to create a true for loop,
7836 // we need to make sure that all opcodes before branch statement do not actually emit any code.
7837 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02007838 emit_block_instructions(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007839
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007840 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007841
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007842 // This can work! We only did trivial things which could be forwarded in block body!
7843 if (current_count == statement_count && condition_is_temporary)
7844 {
7845 switch (continue_type)
7846 {
7847 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +01007848 {
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +01007849 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
7850 flush_undeclared_variables(block);
7851
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +01007852 // Important that we do this in this order because
7853 // emitting the continue block can invalidate the condition expression.
7854 auto initializer = emit_for_loop_initializers(block);
7855 auto condition = to_expression(block.condition);
7856 auto continue_block = emit_continue_block(block.continue_block);
7857 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007858 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +01007859 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007861 case SPIRBlock::WhileLoop:
Hans-Kristian Arntzenb737d2b2017-12-05 17:40:23 +01007862 // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
7863 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007864 statement("while (", to_expression(block.condition), ")");
7865 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007866
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007867 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01007868 SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007869 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007870
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007871 begin_scope();
7872 return true;
7873 }
7874 else
7875 {
7876 block.disable_block_optimization = true;
7877 force_recompile = true;
7878 begin_scope(); // We'll see an end_scope() later.
7879 return false;
7880 }
7881 }
7882 else if (method == SPIRBlock::MergeToDirectForLoop)
7883 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007884 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007885
Hans-Kristian Arntzen5ff11cc2016-11-18 16:45:11 +01007886 // This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
7887 flush_undeclared_variables(child);
7888
7889 uint32_t current_count = statement_count;
7890
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007891 // If we're trying to create a true for loop,
7892 // we need to make sure that all opcodes before branch statement do not actually emit any code.
7893 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02007894 emit_block_instructions(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007895
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007896 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007897
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007898 if (current_count == statement_count && condition_is_temporary)
7899 {
7900 propagate_loop_dominators(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007901
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007902 switch (continue_type)
7903 {
7904 case SPIRBlock::ForLoop:
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +01007905 {
7906 // Important that we do this in this order because
7907 // emitting the continue block can invalidate the condition expression.
7908 auto initializer = emit_for_loop_initializers(block);
7909 auto condition = to_expression(child.condition);
7910 auto continue_block = emit_continue_block(block.continue_block);
7911 statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007912 break;
Hans-Kristian Arntzenab21dfb2017-02-04 10:07:20 +01007913 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007914
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007915 case SPIRBlock::WhileLoop:
7916 statement("while (", to_expression(child.condition), ")");
7917 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007918
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007919 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01007920 SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007921 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007922
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007923 begin_scope();
7924 branch(child.self, child.true_block);
7925 return true;
7926 }
7927 else
7928 {
7929 block.disable_block_optimization = true;
7930 force_recompile = true;
7931 begin_scope(); // We'll see an end_scope() later.
7932 return false;
7933 }
7934 }
7935 else
7936 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007937}
7938
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +01007939void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007940{
Hans-Kristian Arntzen7238e572017-11-22 13:20:17 +01007941 // Enforce declaration order for regression testing purposes.
7942 sort(begin(block.dominated_variables), end(block.dominated_variables));
7943
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +01007944 for (auto &v : block.dominated_variables)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007945 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +01007946 auto &var = get<SPIRVariable>(v);
7947 if (var.deferred_declaration)
7948 statement(variable_decl(var), ";");
7949 var.deferred_declaration = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007950 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007951}
7952
7953void CompilerGLSL::emit_block_chain(SPIRBlock &block)
7954{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007955 propagate_loop_dominators(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007956
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007957 bool select_branch_to_true_block = false;
7958 bool skip_direct_branch = false;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007959 bool emitted_for_loop_header = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007960
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007961 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
7962 for (auto &tmp : block.declare_temporary)
7963 {
7964 auto flags = meta[tmp.second].decoration.decoration_flags;
7965 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02007966 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007967 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007968
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007969 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
7970 if (block.continue_block)
7971 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01007972
Hans-Kristian Arntzena714d422016-12-16 12:43:12 +01007973 // If we have loop variables, stop masking out access to the variable now.
7974 for (auto var : block.loop_variables)
7975 get<SPIRVariable>(var).loop_variable_enable = true;
7976
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007977 // This is the older loop behavior in glslang which branches to loop body directly from the loop header.
7978 if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
7979 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +01007980 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007981 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
7982 {
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007983 // The body of while, is actually just the true block, so always branch there unconditionally.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007984 select_branch_to_true_block = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007985 emitted_for_loop_header = true;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007986 }
7987 }
7988 // This is the newer loop behavior in glslang which branches from Loop header directly to
7989 // a new block, which in turn has a OpBranchSelection without a selection merge.
7990 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
7991 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +01007992 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007993 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007994 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007995 skip_direct_branch = true;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01007996 emitted_for_loop_header = true;
7997 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02007998 }
7999 else if (continue_type == SPIRBlock::DoWhileLoop)
8000 {
8001 statement("do");
8002 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02008003
8004 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008005 }
8006 else if (block.merge == SPIRBlock::MergeLoop)
8007 {
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +01008008 flush_undeclared_variables(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008009
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008010 // We have a generic loop without any distinguishable pattern like for, while or do while.
8011 get<SPIRBlock>(block.continue_block).complex_continue = true;
8012 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008013
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008014 statement("for (;;)");
8015 begin_scope();
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02008016
8017 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008018 }
8019 else
8020 {
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02008021 emit_block_instructions(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008022 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008023
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01008024 // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
8025 // as writes to said loop variables might have been masked out, we need a recompile.
8026 if (!emitted_for_loop_header && !block.loop_variables.empty())
8027 {
8028 force_recompile = true;
8029 for (auto var : block.loop_variables)
8030 get<SPIRVariable>(var).loop_variable = false;
8031 block.loop_variables.clear();
8032 }
8033
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +01008034 flush_undeclared_variables(block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008035 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008036
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008037 // Handle end of block.
8038 switch (block.terminator)
8039 {
8040 case SPIRBlock::Direct:
8041 // True when emitting complex continue block.
8042 if (block.loop_dominator == block.next_block)
8043 {
8044 branch(block.self, block.next_block);
8045 emit_next_block = false;
8046 }
8047 // True if MergeToDirectForLoop succeeded.
8048 else if (skip_direct_branch)
8049 emit_next_block = false;
8050 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
8051 {
8052 branch(block.self, block.next_block);
8053 emit_next_block = false;
8054 }
8055 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008056
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008057 case SPIRBlock::Select:
8058 // True if MergeToSelectForLoop succeeded.
8059 if (select_branch_to_true_block)
8060 branch(block.self, block.true_block);
8061 else
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008062 branch(block.self, block.condition, block.true_block, block.false_block);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008063 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008065 case SPIRBlock::MultiSelect:
8066 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008067 auto &type = expression_type(block.condition);
8068 bool uint32_t_case = type.basetype == SPIRType::UInt;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008069
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008070 statement("switch (", to_expression(block.condition), ")");
8071 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008073 for (auto &c : block.cases)
8074 {
8075 auto case_value =
8076 uint32_t_case ? convert_to_string(uint32_t(c.value)) : convert_to_string(int32_t(c.value));
8077 statement("case ", case_value, ":");
8078 begin_scope();
8079 branch(block.self, c.block);
8080 end_scope();
8081 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008082
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008083 if (block.default_block != block.next_block)
8084 {
8085 statement("default:");
8086 begin_scope();
8087 if (is_break(block.default_block))
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008088 SPIRV_CROSS_THROW("Cannot break; out of a switch statement and out of a loop at the same time ...");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008089 branch(block.self, block.default_block);
8090 end_scope();
8091 }
8092 else if (flush_phi_required(block.self, block.next_block))
8093 {
8094 statement("default:");
8095 begin_scope();
8096 flush_phi(block.self, block.next_block);
8097 statement("break;");
8098 end_scope();
8099 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008100
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008101 end_scope();
8102 break;
8103 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008104
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008105 case SPIRBlock::Return:
8106 if (processing_entry_point)
8107 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008109 if (block.return_value)
8110 {
8111 // OpReturnValue can return Undef, so don't emit anything for this case.
8112 if (ids.at(block.return_value).get_type() != TypeUndef)
8113 statement("return ", to_expression(block.return_value), ";");
8114 }
8115 // If this block is the very final block and not called from control flow,
8116 // we do not need an explicit return which looks out of place. Just end the function here.
8117 // In the very weird case of for(;;) { return; } executing return is unconditional,
8118 // but we actually need a return here ...
8119 else if (!block_is_outside_flow_control_from_block(get<SPIRBlock>(current_function->entry_block), block) ||
8120 block.loop_dominator != SPIRBlock::NoDominator)
8121 statement("return;");
8122 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008123
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008124 case SPIRBlock::Kill:
Bill Hollings943191a2016-10-27 10:20:01 -04008125 statement(backend.discard_literal, ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008126 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008128 default:
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008129 SPIRV_CROSS_THROW("Unimplemented block terminator.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008130 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008131
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008132 if (block.next_block && emit_next_block)
8133 {
8134 // If we hit this case, we're dealing with an unconditional branch, which means we will output
8135 // that block after this. If we had selection merge, we already flushed phi variables.
8136 if (block.merge != SPIRBlock::MergeSelection)
8137 flush_phi(block.self, block.next_block);
8138 emit_block_chain(get<SPIRBlock>(block.next_block));
8139 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008140
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008141 if (block.merge == SPIRBlock::MergeLoop)
8142 {
8143 if (continue_type == SPIRBlock::DoWhileLoop)
8144 {
8145 // Make sure that we run the continue block to get the expressions set, but this
8146 // should become an empty string.
8147 // We have no fallbacks if we cannot forward everything to temporaries ...
8148 auto statements = emit_continue_block(block.continue_block);
8149 if (!statements.empty())
8150 {
8151 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
8152 get<SPIRBlock>(block.continue_block).complex_continue = true;
8153 force_recompile = true;
8154 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008156 end_scope_decl(join("while (", to_expression(get<SPIRBlock>(block.continue_block).condition), ")"));
8157 }
8158 else
8159 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008160
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008161 flush_phi(block.self, block.merge_block);
8162 emit_block_chain(get<SPIRBlock>(block.merge_block));
8163 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008164}
8165
8166void CompilerGLSL::begin_scope()
8167{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008168 statement("{");
8169 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008170}
8171
8172void CompilerGLSL::end_scope()
8173{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008174 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008175 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008176 indent--;
8177 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008178}
8179
8180void CompilerGLSL::end_scope_decl()
8181{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008182 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008183 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008184 indent--;
8185 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008186}
8187
8188void CompilerGLSL::end_scope_decl(const string &decl)
8189{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008190 if (!indent)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008191 SPIRV_CROSS_THROW("Popping empty indent stack.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02008192 indent--;
8193 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01008194}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02008195
8196void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
8197{
8198 // If our variable is remapped, and we rely on type-remapping information as
8199 // well, then we cannot pass the variable as a function parameter.
8200 // Fixing this is non-trivial without stamping out variants of the same function,
8201 // so for now warn about this and suggest workarounds instead.
8202 for (uint32_t i = 0; i < length; i++)
8203 {
8204 auto *var = maybe_get<SPIRVariable>(args[i]);
8205 if (!var || !var->remapped_variable)
8206 continue;
8207
8208 auto &type = get<SPIRType>(var->basetype);
8209 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
8210 {
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01008211 SPIRV_CROSS_THROW("Tried passing a remapped subpassInput variable to a function. "
8212 "This will not work correctly because type-remapping information is lost. "
8213 "To workaround, please consider not passing the subpass input as a function parameter, "
8214 "or use in/out variables instead which do not need type remapping information.");
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02008215 }
8216 }
8217}