blob: 33f542c5e00d06123369210a4bb0ab48d6c6b2bf [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
2 * Copyright 2015-2016 ARM Limited
3 *
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"
19#include <algorithm>
20#include <assert.h>
21
22using namespace spv;
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020023using namespace spirv_cross;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010024using namespace std;
25
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020026static const char *to_pls_layout(PlsFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010027{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020028 switch (format)
29 {
30 case PlsR11FG11FB10F:
31 return "layout(r11f_g11f_b10f) ";
32 case PlsR32F:
33 return "layout(r32f) ";
34 case PlsRG16F:
35 return "layout(rg16f) ";
36 case PlsRGB10A2:
37 return "layout(rgb10_a2) ";
38 case PlsRGBA8:
39 return "layout(rgba8) ";
40 case PlsRG16:
41 return "layout(rg16) ";
42 case PlsRGBA8I:
43 return "layout(rgba8i)";
44 case PlsRG16I:
45 return "layout(rg16i) ";
46 case PlsRGB10A2UI:
47 return "layout(rgb10_a2ui) ";
48 case PlsRGBA8UI:
49 return "layout(rgba8ui) ";
50 case PlsRG16UI:
51 return "layout(rg16ui) ";
52 case PlsR32UI:
53 return "layout(r32ui) ";
54 default:
55 return "";
56 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010057}
58
59static SPIRType::BaseType pls_format_to_basetype(PlsFormat format)
60{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020061 switch (format)
62 {
63 default:
64 case PlsR11FG11FB10F:
65 case PlsR32F:
66 case PlsRG16F:
67 case PlsRGB10A2:
68 case PlsRGBA8:
69 case PlsRG16:
70 return SPIRType::Float;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020072 case PlsRGBA8I:
73 case PlsRG16I:
74 return SPIRType::Int;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020076 case PlsRGB10A2UI:
77 case PlsRGBA8UI:
78 case PlsRG16UI:
79 case PlsR32UI:
80 return SPIRType::UInt;
81 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010082}
83
84static uint32_t pls_format_to_components(PlsFormat format)
85{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020086 switch (format)
87 {
88 default:
89 case PlsR32F:
90 case PlsR32UI:
91 return 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010092
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020093 case PlsRG16F:
94 case PlsRG16:
95 case PlsRG16UI:
96 case PlsRG16I:
97 return 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010098
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020099 case PlsR11FG11FB10F:
100 return 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200102 case PlsRGB10A2:
103 case PlsRGBA8:
104 case PlsRGBA8I:
105 case PlsRGB10A2UI:
106 case PlsRGBA8UI:
107 return 4;
108 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100109}
110
111void CompilerGLSL::reset()
112{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200113 // We do some speculative optimizations which should pretty much always work out,
114 // but just in case the SPIR-V is rather weird, recompile until it's happy.
115 // This typically only means one extra pass.
116 force_recompile = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200118 // Clear invalid expression tracking.
119 invalid_expressions.clear();
120 current_function = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100121
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200122 // Clear temporary usage tracking.
123 expression_usage_counts.clear();
124 forwarded_temporaries.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100125
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200126 resource_names.clear();
127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200128 for (auto &id : ids)
129 {
130 if (id.get_type() == TypeVariable)
131 {
132 // Clear unflushed dependees.
133 id.get<SPIRVariable>().dependees.clear();
134 }
135 else if (id.get_type() == TypeExpression)
136 {
137 // And remove all expressions.
138 id.reset();
139 }
140 else if (id.get_type() == TypeFunction)
141 {
142 // Reset active state for all functions.
143 id.get<SPIRFunction>().active = false;
144 id.get<SPIRFunction>().flush_undeclared = true;
145 }
146 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100147
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200148 statement_count = 0;
149 indent = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100150}
151
152void CompilerGLSL::remap_pls_variables()
153{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200154 for (auto &input : pls_inputs)
155 {
156 auto &var = get<SPIRVariable>(input.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100157
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200158 bool input_is_target = false;
159 if (var.storage == StorageClassUniformConstant)
160 {
161 auto &type = get<SPIRType>(var.basetype);
162 input_is_target = type.image.dim == DimSubpassData;
163 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100164
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200165 if (var.storage != StorageClassInput && !input_is_target)
166 throw CompilerError("Can only use in and target variables for PLS inputs.");
167 var.remapped_variable = true;
168 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100169
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200170 for (auto &output : pls_outputs)
171 {
172 auto &var = get<SPIRVariable>(output.id);
173 if (var.storage != StorageClassOutput)
174 throw CompilerError("Can only use out variables for PLS outputs.");
175 var.remapped_variable = true;
176 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100177}
178
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200179void CompilerGLSL::find_static_extensions()
180{
181 for (auto &id : ids)
182 {
183 if (id.get_type() == TypeType)
184 {
185 auto &type = id.get<SPIRType>();
186 if (type.basetype == SPIRType::Double)
187 {
188 if (options.es)
189 throw CompilerError("FP64 not supported in ES profile.");
190 if (!options.es && options.version < 400)
191 require_extension("GL_ARB_gpu_shader_fp64");
192 }
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200193
194 if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
195 {
196 if (options.es)
197 throw CompilerError("64-bit integers not supported in ES profile.");
198 if (!options.es)
199 require_extension("GL_ARB_gpu_shader_int64");
200 }
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200201 }
202 }
203}
204
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100205string CompilerGLSL::compile()
206{
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200207 // Scan the SPIR-V to find trivial uses of extensions.
208 find_static_extensions();
209
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200210 uint32_t pass_count = 0;
211 do
212 {
213 if (pass_count >= 3)
214 throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100215
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200216 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200218 // Move constructor for this type is broken on GCC 4.9 ...
219 buffer = unique_ptr<ostringstream>(new ostringstream());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100220
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200221 emit_header();
222 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100223
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200224 emit_function(get<SPIRFunction>(entry_point), 0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100225
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200226 pass_count++;
227 } while (force_recompile);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100228
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200229 return buffer->str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100230}
231
232void CompilerGLSL::emit_header()
233{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200234 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200235 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100236
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +0200237 for (auto &header : header_lines)
238 statement(header);
239
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200240 // Needed for binding = # on UBOs, etc.
241 if (!options.es && options.version < 420)
242 {
243 statement("#ifdef GL_ARB_shading_language_420pack");
244 statement("#extension GL_ARB_shading_language_420pack : require");
245 statement("#endif");
246 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100247
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200248 for (auto &ext : forced_extensions)
249 statement("#extension ", ext, " : require");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100250
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200251 if (!pls_inputs.empty() || !pls_outputs.empty())
252 statement("#extension GL_EXT_shader_pixel_local_storage : require");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200254 vector<string> inputs;
255 vector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200257 switch (execution.model)
258 {
259 case ExecutionModelGeometry:
260 if (options.es && options.version < 320)
261 statement("#extension GL_EXT_geometry_shader : require");
262 if (!options.es && options.version < 320)
263 statement("#extension GL_ARB_geometry_shader4 : require");
264 outputs.push_back(join("max_vertices = ", execution.output_vertices));
Hans-Kristian Arntzen05a97882016-06-23 13:42:59 +0200265 if ((execution.flags & (1ull << ExecutionModeInvocations)) && execution.invocations != 1)
266 {
267 // Instanced GS is part of 400 core or this extension.
268 if (!options.es && options.version < 400)
269 statement("#extension GL_ARB_gpu_shader5 : require");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200270 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzen05a97882016-06-23 13:42:59 +0200271 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200272 if (execution.flags & (1ull << ExecutionModeInputPoints))
273 inputs.push_back("points");
274 if (execution.flags & (1ull << ExecutionModeInputLines))
275 inputs.push_back("lines");
276 if (execution.flags & (1ull << ExecutionModeInputLinesAdjacency))
277 inputs.push_back("lines_adjacency");
278 if (execution.flags & (1ull << ExecutionModeTriangles))
279 inputs.push_back("triangles");
280 if (execution.flags & (1ull << ExecutionModeInputTrianglesAdjacency))
281 inputs.push_back("triangles_adjacency");
282 if (execution.flags & (1ull << ExecutionModeOutputTriangleStrip))
283 outputs.push_back("triangle_strip");
284 if (execution.flags & (1ull << ExecutionModeOutputPoints))
285 outputs.push_back("points");
286 if (execution.flags & (1ull << ExecutionModeOutputLineStrip))
287 outputs.push_back("line_strip");
288 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100289
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200290 case ExecutionModelTessellationControl:
291 if (options.es && options.version < 320)
292 statement("#extension GL_EXT_tessellation_shader : require");
293 if (!options.es && options.version < 400)
294 statement("#extension GL_ARB_tessellation_shader : require");
295 if (execution.flags & (1ull << ExecutionModeOutputVertices))
296 outputs.push_back(join("vertices = ", execution.output_vertices));
297 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100298
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200299 case ExecutionModelTessellationEvaluation:
300 if (options.es && options.version < 320)
301 statement("#extension GL_EXT_tessellation_shader : require");
302 if (!options.es && options.version < 400)
303 statement("#extension GL_ARB_tessellation_shader : require");
304 if (execution.flags & (1ull << ExecutionModeQuads))
305 inputs.push_back("quads");
306 if (execution.flags & (1ull << ExecutionModeIsolines))
307 inputs.push_back("isolines");
308 if (execution.flags & (1ull << ExecutionModePointMode))
309 inputs.push_back("point_mode");
310 if (execution.flags & (1ull << ExecutionModeVertexOrderCw))
311 inputs.push_back("cw");
312 if (execution.flags & (1ull << ExecutionModeVertexOrderCcw))
313 inputs.push_back("ccw");
314 if (execution.flags & (1ull << ExecutionModeSpacingFractionalEven))
315 inputs.push_back("fractional_even_spacing");
316 if (execution.flags & (1ull << ExecutionModeSpacingFractionalOdd))
317 inputs.push_back("fractional_odd_spacing");
318 if (execution.flags & (1ull << ExecutionModeSpacingEqual))
319 inputs.push_back("equal_spacing");
320 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100321
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200322 case ExecutionModelGLCompute:
323 if (!options.es && options.version < 430)
324 statement("#extension GL_ARB_compute_shader : require");
325 if (options.es && options.version < 310)
326 throw CompilerError("At least ESSL 3.10 required for compute shaders.");
327 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
328 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
329 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
330 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100331
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200332 case ExecutionModelFragment:
333 if (options.es)
334 {
335 switch (options.fragment.default_float_precision)
336 {
337 case Options::Lowp:
338 statement("precision lowp float;");
339 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 case Options::Mediump:
342 statement("precision mediump float;");
343 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200345 case Options::Highp:
346 statement("precision highp float;");
347 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200349 default:
350 break;
351 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100352
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200353 switch (options.fragment.default_int_precision)
354 {
355 case Options::Lowp:
356 statement("precision lowp int;");
357 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100358
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200359 case Options::Mediump:
360 statement("precision mediump int;");
361 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100362
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200363 case Options::Highp:
364 statement("precision highp int;");
365 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100366
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200367 default:
368 break;
369 }
370 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100371
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200372 if (execution.flags & (1ull << ExecutionModeEarlyFragmentTests))
373 inputs.push_back("early_fragment_tests");
374 if (execution.flags & (1ull << ExecutionModeDepthGreater))
375 inputs.push_back("depth_greater");
376 if (execution.flags & (1ull << ExecutionModeDepthLess))
377 inputs.push_back("depth_less");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100378
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200379 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100380
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200381 default:
382 break;
383 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200385 if (!inputs.empty())
386 statement("layout(", merge(inputs), ") in;");
387 if (!outputs.empty())
388 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200390 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100391}
392
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200393void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100394{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200395 // Struct types can be stamped out multiple times
396 // with just different offsets, matrix layouts, etc ...
397 // Type-punning with these types is legal, which complicates things
398 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200399 if (type.type_alias != 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200400 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200401
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200402 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200403 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100404
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200405 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200406 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100407
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200408 type.member_name_cache.clear();
409
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200410 uint32_t i = 0;
411 bool emitted = false;
412 for (auto &member : type.member_types)
413 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200414 add_member_name(type, i);
415
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200416 auto &membertype = get<SPIRType>(member);
417 statement(member_decl(type, membertype, i), ";");
418 i++;
419 emitted = true;
420 }
421 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100422
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200423 if (emitted)
424 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100425}
426
427uint64_t CompilerGLSL::combined_decoration_for_member(const SPIRType &type, uint32_t index)
428{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200429 uint64_t flags = 0;
430 auto &memb = meta[type.self].members;
431 if (index >= memb.size())
432 return 0;
433 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100434
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200435 // If our type is a sturct, traverse all the members as well recursively.
436 flags |= dec.decoration_flags;
437 for (uint32_t i = 0; i < type.member_types.size(); i++)
438 flags |= combined_decoration_for_member(get<SPIRType>(type.member_types[i]), i);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200440 return flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100441}
442
443string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
444{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200445 bool is_block = (meta[type.self].decoration.decoration_flags &
446 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
447 if (!is_block)
448 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100449
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200450 auto &memb = meta[type.self].members;
451 if (index >= memb.size())
Hans-Kristian Arntzen0eb89ec2016-08-13 10:31:01 +0200452 return "";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200453 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200455 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200457 // We can only apply layouts on members in block interfaces.
458 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
459 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
460 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
461 //
462 // We would like to go from (SPIR-V style):
463 //
464 // struct Foo { layout(row_major) mat4 matrix; };
465 // buffer UBO { Foo foo; };
466 //
467 // to
468 //
469 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
470 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
471 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100472
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200473 if (flags & (1ull << DecorationRowMajor))
474 attr.push_back("row_major");
475 // We don't emit any global layouts, so column_major is default.
476 //if (flags & (1ull << DecorationColMajor))
477 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200479 if (dec.decoration_flags & (1ull << DecorationLocation))
480 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100481
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200482 if (attr.empty())
483 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100484
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200485 string res = "layout(";
486 res += merge(attr);
487 res += ") ";
488 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100489}
490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200491const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100492{
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200493 auto check_desktop = [this] {
494 if (options.es)
495 throw CompilerError("Attempting to use image format not supported in ES profile.");
496 };
497
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200498 switch (format)
499 {
500 case ImageFormatRgba32f:
501 return "rgba32f";
502 case ImageFormatRgba16f:
503 return "rgba16f";
504 case ImageFormatR32f:
505 return "r32f";
506 case ImageFormatRgba8:
507 return "rgba8";
508 case ImageFormatRgba8Snorm:
509 return "rgba8_snorm";
510 case ImageFormatRg32f:
511 return "rg32f";
512 case ImageFormatRg16f:
513 return "rg16f";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100514
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200515 case ImageFormatRgba32i:
516 return "rgba32i";
517 case ImageFormatRgba16i:
518 return "rgba16i";
519 case ImageFormatR32i:
520 return "r32i";
521 case ImageFormatRgba8i:
522 return "rgba8i";
523 case ImageFormatRg32i:
524 return "rg32i";
525 case ImageFormatRg16i:
526 return "rg16i";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100527
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200528 case ImageFormatRgba32ui:
529 return "rgba32ui";
530 case ImageFormatRgba16ui:
531 return "rgba16ui";
532 case ImageFormatR32ui:
533 return "r32ui";
534 case ImageFormatRgba8ui:
535 return "rgba8ui";
536 case ImageFormatRg32ui:
537 return "rg32ui";
538 case ImageFormatRg16ui:
539 return "rg16ui";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100540
Hans-Kristian Arntzen606ecce2016-07-12 09:35:15 +0200541 // Desktop-only formats
542 case ImageFormatR11fG11fB10f:
543 check_desktop();
544 return "r11f_g11f_b10f";
545 case ImageFormatR16f:
546 check_desktop();
547 return "r16f";
548 case ImageFormatRgb10A2:
549 check_desktop();
550 return "rgb10_a2";
551 case ImageFormatR8:
552 check_desktop();
553 return "r8";
554 case ImageFormatRg8:
555 check_desktop();
556 return "rg8";
557 case ImageFormatR16:
558 check_desktop();
559 return "r16";
560 case ImageFormatRg16:
561 check_desktop();
562 return "rg16";
563 case ImageFormatRgba16:
564 check_desktop();
565 return "rgba16";
566 case ImageFormatR16Snorm:
567 check_desktop();
568 return "r16_snorm";
569 case ImageFormatRg16Snorm:
570 check_desktop();
571 return "rg16_snorm";
572 case ImageFormatRgba16Snorm:
573 check_desktop();
574 return "rgba16_snorm";
575 case ImageFormatR8Snorm:
576 check_desktop();
577 return "r8_snorm";
578 case ImageFormatRg8Snorm:
579 check_desktop();
580 return "rg8_snorm";
581
582 case ImageFormatR8ui:
583 check_desktop();
584 return "r8ui";
585 case ImageFormatRg8ui:
586 check_desktop();
587 return "rg8ui";
588 case ImageFormatR16ui:
589 check_desktop();
590 return "r16ui";
591 case ImageFormatRgb10a2ui:
592 check_desktop();
593 return "rgb10_a2ui";
594
595 case ImageFormatR8i:
596 check_desktop();
597 return "r8i";
598 case ImageFormatRg8i:
599 check_desktop();
600 return "rg8i";
601 case ImageFormatR16i:
602 check_desktop();
603 return "r16i";
604
605 default:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200606 case ImageFormatUnknown:
607 return nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200608 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100609}
610
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200611uint32_t CompilerGLSL::type_to_std430_base_size(const SPIRType &type)
612{
613 switch (type.basetype)
614 {
615 case SPIRType::Double:
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200616 case SPIRType::Int64:
617 case SPIRType::UInt64:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200618 return 8;
619 default:
620 return 4;
621 }
622}
623
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100624uint32_t CompilerGLSL::type_to_std430_alignment(const SPIRType &type, uint64_t flags)
625{
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200626 const uint32_t base_alignment = type_to_std430_base_size(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200628 if (type.basetype == SPIRType::Struct)
629 {
630 // Rule 9. Structs alignments are maximum alignment of its members.
631 uint32_t alignment = 0;
632 for (uint32_t i = 0; i < type.member_types.size(); i++)
633 {
634 auto member_flags = meta[type.self].members.at(i).decoration_flags;
635 alignment = max(alignment, type_to_std430_alignment(get<SPIRType>(type.member_types[i]), member_flags));
636 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100637
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200638 return alignment;
639 }
640 else
641 {
642 // From 7.6.2.2 in GL 4.5 core spec.
643 // Rule 1
644 if (type.vecsize == 1 && type.columns == 1)
645 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100646
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200647 // Rule 2
648 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
649 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100650
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200651 // Rule 3
652 if (type.vecsize == 3 && type.columns == 1)
653 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200655 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200657 // Rule 5. Column-major matrices are stored as arrays of
658 // vectors.
659 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
660 {
661 if (type.vecsize == 3)
662 return 4 * base_alignment;
663 else
664 return type.vecsize * base_alignment;
665 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100666
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200667 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100668
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200669 // Rule 7.
670 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
671 {
672 if (type.columns == 3)
673 return 4 * base_alignment;
674 else
675 return type.columns * base_alignment;
676 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100677
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200678 // Rule 8 implied.
679 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100680
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200681 throw CompilerError("Did not find suitable std430 rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100682}
683
684uint32_t CompilerGLSL::type_to_std430_array_stride(const SPIRType &type, uint64_t flags)
685{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200686 // Array stride is equal to aligned size of the underlying type.
687 SPIRType tmp = type;
688 tmp.array.pop_back();
689 uint32_t size = type_to_std430_size(tmp, flags);
690 uint32_t alignment = type_to_std430_alignment(tmp, flags);
691 return (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100692}
693
694uint32_t CompilerGLSL::type_to_std430_size(const SPIRType &type, uint64_t flags)
695{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200696 if (!type.array.empty())
697 return type.array.back() * type_to_std430_array_stride(type, flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100698
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200699 const uint32_t base_alignment = type_to_std430_base_size(type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200700 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100701
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200702 if (type.basetype == SPIRType::Struct)
703 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200704 uint32_t pad_alignment = 1;
705
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200706 for (uint32_t i = 0; i < type.member_types.size(); i++)
707 {
708 auto member_flags = meta[type.self].members.at(i).decoration_flags;
709 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200710
711 uint32_t std430_alignment = type_to_std430_alignment(member_type, member_flags);
712 uint32_t alignment = max(std430_alignment, pad_alignment);
713
714 // The next member following a struct member is aligned to the base alignment of the struct that came before.
715 // GL 4.5 spec, 7.6.2.2.
716 if (member_type.basetype == SPIRType::Struct)
717 pad_alignment = std430_alignment;
718 else
719 pad_alignment = 1;
720
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200721 size = (size + alignment - 1) & ~(alignment - 1);
722 size += type_to_std430_size(member_type, member_flags);
723 }
724 }
725 else
726 {
727 if (type.columns == 1)
728 size = type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100729
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200730 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
731 {
732 if (type.vecsize == 3)
733 size = type.columns * 4 * base_alignment;
734 else
735 size = type.columns * type.vecsize * base_alignment;
736 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200738 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
739 {
740 if (type.columns == 3)
741 size = type.vecsize * 4 * base_alignment;
742 else
743 size = type.vecsize * type.columns * base_alignment;
744 }
745 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100746
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200747 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100748}
749
750bool CompilerGLSL::ssbo_is_std430_packing(const SPIRType &type)
751{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200752 // This is very tricky and error prone, but try to be exhaustive and correct here.
753 // SPIR-V doesn't directly say if we're using std430 or std140.
754 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
755 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
756 // 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).
757 //
758 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
759 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
760 //
761 // The only two differences between std140 and std430 are related to padding alignment/array stride
762 // in arrays and structs. In std140 they take minimum vec4 alignment.
763 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100764
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200765 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200766 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100767
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200768 for (uint32_t i = 0; i < type.member_types.size(); i++)
769 {
770 auto &memb_type = get<SPIRType>(type.member_types[i]);
771 auto member_flags = meta[type.self].members.at(i).decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100772
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200773 // Verify alignment rules.
774 uint32_t std430_alignment = type_to_std430_alignment(memb_type, member_flags);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200775 uint32_t alignment = max(std430_alignment, pad_alignment);
776 offset = (offset + alignment - 1) & ~(alignment - 1);
777
778 // The next member following a struct member is aligned to the base alignment of the struct that came before.
779 // GL 4.5 spec, 7.6.2.2.
780 if (memb_type.basetype == SPIRType::Struct)
781 pad_alignment = std430_alignment;
782 else
783 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100784
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200785 uint32_t actual_offset = type_struct_member_offset(type, i);
786 if (actual_offset != offset) // This cannot be std430.
787 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100788
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200789 // Verify array stride rules.
790 if (!memb_type.array.empty() &&
791 type_to_std430_array_stride(memb_type, member_flags) != type_struct_member_array_stride(type, i))
792 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100793
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200794 // Verify that sub-structs also follow std430 rules.
795 if (!memb_type.member_types.empty() && !ssbo_is_std430_packing(memb_type))
796 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100797
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200798 // Bump size.
799 offset += type_to_std430_size(memb_type, member_flags);
800 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100801
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200802 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100803}
804
805string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
806{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200807 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100808
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200809 auto &dec = meta[var.self].decoration;
810 auto &type = get<SPIRType>(var.basetype);
811 auto flags = dec.decoration_flags;
812 auto typeflags = meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100813
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200814 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
815 attr.push_back("push_constant");
816
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200817 if (flags & (1ull << DecorationRowMajor))
818 attr.push_back("row_major");
819 if (flags & (1ull << DecorationColMajor))
820 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200821
822 if (options.vulkan_semantics)
823 {
824 if (flags & (1ull << DecorationInputAttachmentIndex))
825 attr.push_back(join("input_attachment_index = ", dec.input_attachment));
826 }
827
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200828 if (flags & (1ull << DecorationLocation))
829 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +0200830
831 // set = 0 is the default. Do not emit set = decoration in regular GLSL output, but
832 // we should preserve it in Vulkan GLSL mode.
833 if (var.storage != StorageClassPushConstant)
834 {
835 if ((flags & (1ull << DecorationDescriptorSet)) && (dec.set != 0 || options.vulkan_semantics))
836 attr.push_back(join("set = ", dec.set));
837 }
838
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200839 if (flags & (1ull << DecorationBinding))
840 attr.push_back(join("binding = ", dec.binding));
841 if (flags & (1ull << DecorationCoherent))
842 attr.push_back("coherent");
843 if (flags & (1ull << DecorationOffset))
844 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100845
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200846 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
847 // If SPIR-V does not comply with either layout, we cannot really work around it.
848 if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBlock)))
849 attr.push_back("std140");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200850 else if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock)))
851 attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
852 else if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200853 attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100854
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200855 // For images, the type itself adds a layout qualifer.
856 if (type.basetype == SPIRType::Image)
857 {
858 const char *fmt = format_to_glsl(type.image.format);
859 if (fmt)
860 attr.push_back(fmt);
861 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100862
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200863 if (attr.empty())
864 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200866 string res = "layout(";
867 res += merge(attr);
868 res += ") ";
869 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100870}
871
872void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
873{
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200874 if (options.vulkan_semantics)
875 emit_push_constant_block_vulkan(var);
876 else
877 emit_push_constant_block_glsl(var);
878}
879
880void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
881{
882 emit_buffer_block(var);
883}
884
885void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
886{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200887 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
888 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100889
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200890 auto &flags = meta[var.self].decoration.decoration_flags;
891 flags &= ~((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100892
893#if 0
894 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
895 throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
896 "Remap to location with reflection API first or disable these decorations.");
897#endif
898
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200899 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
900 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
901 auto &block_flags = meta[type.self].decoration.decoration_flags;
902 uint64_t block_flag = block_flags & (1ull << DecorationBlock);
903 block_flags &= ~block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100904
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200905 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100906
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200907 block_flags |= block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100908
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200909 emit_uniform(var);
910 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100911}
912
913void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
914{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200915 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +0200916 bool ssbo = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)) != 0;
Hans-Kristian Arntzen7d8add32016-07-12 15:00:10 +0200917 bool is_restrict = (meta[var.self].decoration.decoration_flags & (1ull << DecorationRestrict)) != 0;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200918
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200919 add_resource_name(var.self);
920
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200921 // Block names should never alias.
922 auto buffer_name = to_name(type.self, false);
923
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200924 // Shaders never use the block by interface name, so we don't
925 // have to track this other than updating name caches.
926 if (resource_names.find(buffer_name) != end(resource_names))
927 buffer_name = get_fallback_name(type.self);
928 else
929 resource_names.insert(buffer_name);
930
Hans-Kristian Arntzen7d8add32016-07-12 15:00:10 +0200931 statement(layout_for_variable(var), is_restrict ? "restrict " : "", ssbo ? "buffer " : "uniform ", buffer_name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200932 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100933
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200934 type.member_name_cache.clear();
935
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200936 uint32_t i = 0;
937 for (auto &member : type.member_types)
938 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200939 add_member_name(type, i);
940
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200941 auto &membertype = get<SPIRType>(member);
942 statement(member_decl(type, membertype, i), ";");
943 i++;
944 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100945
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200946 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
947 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100948}
949
950void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
951{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200952 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200953 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100954
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200955 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
956 bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100957
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200958 const char *qual = nullptr;
959 if (is_legacy() && execution.model == ExecutionModelVertex)
960 qual = var.storage == StorageClassInput ? "attribute " : "varying ";
961 else if (is_legacy() && execution.model == ExecutionModelFragment)
962 qual = "varying "; // Fragment outputs are renamed so they never hit this case.
963 else
964 qual = var.storage == StorageClassInput ? "in " : "out ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100965
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200966 if (block)
967 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200968 add_resource_name(var.self);
969
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200970 // Block names should never alias.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200971 auto block_name = to_name(type.self, false);
972
973 // Shaders never use the block by interface name, so we don't
974 // have to track this other than updating name caches.
975 if (resource_names.find(block_name) != end(resource_names))
976 block_name = get_fallback_name(type.self);
977 else
978 resource_names.insert(block_name);
979
980 statement(layout_for_variable(var), qual, block_name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200981 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100982
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200983 type.member_name_cache.clear();
984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200985 uint32_t i = 0;
986 for (auto &member : type.member_types)
987 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200988 add_member_name(type, i);
989
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200990 auto &membertype = get<SPIRType>(member);
991 statement(member_decl(type, membertype, i), ";");
992 i++;
993 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100994
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200995 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
996 statement("");
997 }
998 else
999 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001000 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001001 statement(layout_for_variable(var), qual, variable_decl(var), ";");
1002 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001003}
1004
1005void CompilerGLSL::emit_uniform(const SPIRVariable &var)
1006{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001007 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen32b463f2016-09-10 13:00:07 +02001008 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001009 {
1010 if (!options.es && options.version < 420)
1011 require_extension("GL_ARB_shader_image_load_store");
1012 else if (options.es && options.version < 310)
1013 throw CompilerError("At least ESSL 3.10 required for shader image load store.");
1014 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001015
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001016 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001017 statement(layout_for_variable(var), "uniform ", variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001018}
1019
Robert Konrad76936562016-08-13 00:14:52 +02001020void CompilerGLSL::replace_illegal_names()
1021{
1022 for (auto &id : ids)
1023 {
1024 if (id.get_type() == TypeVariable)
1025 {
1026 auto &var = id.get<SPIRVariable>();
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02001027 if (!is_hidden_variable(var))
Robert Konrad76936562016-08-13 00:14:52 +02001028 {
1029 auto &m = meta[var.self].decoration;
1030 if (m.alias.compare(0, 3, "gl_") == 0)
Robert Konrad76936562016-08-13 00:14:52 +02001031 m.alias = join("_", m.alias);
Robert Konrad76936562016-08-13 00:14:52 +02001032 }
1033 }
1034 }
1035}
1036
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001037void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
1038{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001039 auto &m = meta[var.self].decoration;
1040 uint32_t location = 0;
1041 if (m.decoration_flags & (1ull << DecorationLocation))
1042 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001043
Hans-Kristian Arntzen6ae838c2016-08-18 12:55:19 +02001044 // If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
1045 // do the access chain part of this for us.
1046 auto &type = get<SPIRType>(var.basetype);
1047
1048 if (type.array.empty())
1049 {
1050 // Redirect the write to a specific render target in legacy GLSL.
1051 m.alias = join("gl_FragData[", location, "]");
1052 }
1053 else if (type.array.size() == 1)
1054 {
1055 // If location is non-zero, we probably have to add an offset.
1056 // This gets really tricky since we'd have to inject an offset in the access chain.
1057 // FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
1058 m.alias = "gl_FragData";
1059 if (location != 0)
1060 throw CompilerError("Arrayed output variable used, but location is not 0. "
1061 "This is unimplemented in SPIRV-Cross.");
1062 }
1063 else
1064 throw CompilerError("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
1065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001066 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 +01001067}
1068
1069void CompilerGLSL::replace_fragment_outputs()
1070{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001071 for (auto &id : ids)
1072 {
1073 if (id.get_type() == TypeVariable)
1074 {
1075 auto &var = id.get<SPIRVariable>();
1076 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001078 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
1079 var.storage == StorageClassOutput)
1080 replace_fragment_output(var);
1081 }
1082 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001083}
1084
1085string CompilerGLSL::remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr)
1086{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001087 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001088
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001089 if (out_type.vecsize == input_components)
1090 return to_expression(expr);
1091 else if (input_components == 1)
1092 return join(type_to_glsl(out_type), "(", to_expression(expr), ")");
1093 else
1094 {
1095 auto e = to_expression(expr) + ".";
1096 // Just clamp the swizzle index if we have more outputs than inputs.
1097 for (uint32_t c = 0; c < out_type.vecsize; c++)
1098 e += index_to_swizzle(min(c, input_components - 1));
1099 if (backend.swizzle_is_function && out_type.vecsize > 1)
1100 e += "()";
1101 return e;
1102 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001103}
1104
1105void CompilerGLSL::emit_pls()
1106{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001107 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001108 if (execution.model != ExecutionModelFragment)
1109 throw CompilerError("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001110
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001111 if (!options.es)
1112 throw CompilerError("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001113
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001114 if (options.version < 300)
1115 throw CompilerError("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001116
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001117 if (!pls_inputs.empty())
1118 {
1119 statement("__pixel_local_inEXT _PLSIn");
1120 begin_scope();
1121 for (auto &input : pls_inputs)
1122 statement(pls_decl(input), ";");
1123 end_scope_decl();
1124 statement("");
1125 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001126
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001127 if (!pls_outputs.empty())
1128 {
1129 statement("__pixel_local_outEXT _PLSOut");
1130 begin_scope();
1131 for (auto &output : pls_outputs)
1132 statement(pls_decl(output), ";");
1133 end_scope_decl();
1134 statement("");
1135 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001136}
1137
1138void CompilerGLSL::emit_resources()
1139{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001140 auto &execution = get_entry_point();
1141
Robert Konrad76936562016-08-13 00:14:52 +02001142 replace_illegal_names();
1143
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001144 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
1145 // with builtins.
1146 if (execution.model == ExecutionModelFragment && is_legacy())
1147 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001149 // Emit PLS blocks if we have such variables.
1150 if (!pls_inputs.empty() || !pls_outputs.empty())
1151 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001152
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001153 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
1154 // when such variables are instantiated.
1155 for (auto &id : ids)
1156 {
1157 if (id.get_type() == TypeType)
1158 {
1159 auto &type = id.get<SPIRType>();
1160 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
1161 (meta[type.self].decoration.decoration_flags &
1162 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
1163 {
1164 emit_struct(type);
1165 }
1166 }
1167 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001168
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001169 // Output UBOs and SSBOs
1170 for (auto &id : ids)
1171 {
1172 if (id.get_type() == TypeVariable)
1173 {
1174 auto &var = id.get<SPIRVariable>();
1175 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001176
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +02001177 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02001178 !is_hidden_variable(var) && (meta[type.self].decoration.decoration_flags &
1179 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001180 {
1181 emit_buffer_block(var);
1182 }
1183 }
1184 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001185
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001186 // Output push constant blocks
1187 for (auto &id : ids)
1188 {
1189 if (id.get_type() == TypeVariable)
1190 {
1191 auto &var = id.get<SPIRVariable>();
1192 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02001193 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
1194 !is_hidden_variable(var))
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02001195 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001196 emit_push_constant_block(var);
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02001197 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001198 }
1199 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001200
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001201 bool emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001202
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02001203 bool skip_separate_image_sampler = !combined_image_samplers.empty() || !options.vulkan_semantics;
1204
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001205 // Output Uniform Constants (values, samplers, images, etc).
1206 for (auto &id : ids)
1207 {
1208 if (id.get_type() == TypeVariable)
1209 {
1210 auto &var = id.get<SPIRVariable>();
1211 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001212
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02001213 // If we're remapping separate samplers and images, only emit the combined samplers.
1214 if (skip_separate_image_sampler)
1215 {
1216 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
1217 bool separate_sampler = type.basetype == SPIRType::Sampler;
1218 if (separate_image || separate_sampler)
1219 continue;
1220 }
1221
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02001222 if (var.storage != StorageClassFunction && type.pointer &&
1223 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter) &&
1224 !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001225 {
1226 emit_uniform(var);
1227 emitted = true;
1228 }
1229 }
1230 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001232 if (emitted)
1233 statement("");
1234 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001235
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001236 // Output in/out interfaces.
1237 for (auto &id : ids)
1238 {
1239 if (id.get_type() == TypeVariable)
1240 {
1241 auto &var = id.get<SPIRVariable>();
1242 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001243
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02001244 if (var.storage != StorageClassFunction && type.pointer &&
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +02001245 (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
Hans-Kristian Arntzen14bc1ff2016-09-10 18:07:52 +02001246 interface_variable_exists_in_entry_point(var.self) && !is_hidden_variable(var))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001247 {
1248 emit_interface_block(var);
1249 emitted = true;
1250 }
1251 else if (is_builtin_variable(var))
1252 {
1253 // For gl_InstanceIndex emulation on GLES, the API user needs to
1254 // supply this uniform.
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001255 if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001256 {
1257 statement("uniform int SPIRV_Cross_BaseInstance;");
1258 emitted = true;
1259 }
1260 }
1261 }
1262 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001263
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001264 // Global variables.
1265 for (auto global : global_variables)
1266 {
1267 auto &var = get<SPIRVariable>(global);
1268 if (var.storage != StorageClassOutput)
1269 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001270 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001271 statement(variable_decl(var), ";");
1272 emitted = true;
1273 }
1274 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001275
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001276 if (emitted)
1277 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001278}
1279
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001280void CompilerGLSL::handle_invalid_expression(uint32_t id)
1281{
1282 auto &expr = get<SPIRExpression>(id);
1283
1284 // This expression has been invalidated in the past.
1285 // Be careful with this expression next pass ...
1286 // Used for OpCompositeInsert forwarding atm.
1287 expr.used_while_invalidated = true;
1288
1289 // We tried to read an invalidated expression.
1290 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
1291 forced_temporaries.insert(id);
1292 force_recompile = true;
1293}
1294
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001295string CompilerGLSL::to_expression(uint32_t id)
1296{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001297 auto itr = invalid_expressions.find(id);
1298 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001299 handle_invalid_expression(id);
1300
1301 if (ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001302 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001303 // We might have a more complex chain of dependencies.
1304 // A possible scenario is that we
1305 //
1306 // %1 = OpLoad
1307 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
1308 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
1309 // 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.
1310 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
1311 //
1312 // 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,
1313 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001314 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001315 for (uint32_t dep : expr.expression_dependencies)
1316 if (invalid_expressions.find(dep) != end(invalid_expressions))
1317 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001318 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001320 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001321
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001322 switch (ids[id].get_type())
1323 {
1324 case TypeExpression:
1325 {
1326 auto &e = get<SPIRExpression>(id);
1327 if (e.base_expression)
1328 return to_expression(e.base_expression) + e.expression;
1329 else
1330 return e.expression;
1331 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001332
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001333 case TypeConstant:
1334 return constant_expression(get<SPIRConstant>(id));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001335
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001336 case TypeVariable:
1337 {
1338 auto &var = get<SPIRVariable>(id);
1339 if (var.statically_assigned)
1340 return to_expression(var.static_expression);
1341 else if (var.deferred_declaration)
1342 {
1343 var.deferred_declaration = false;
1344 return variable_decl(var);
1345 }
1346 else
1347 {
1348 auto &dec = meta[var.self].decoration;
1349 if (dec.builtin)
1350 return builtin_to_glsl(dec.builtin_type);
1351 else
1352 return to_name(id);
1353 }
1354 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001355
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001356 default:
1357 return to_name(id);
1358 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001359}
1360
1361string CompilerGLSL::constant_expression(const SPIRConstant &c)
1362{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001363 if (!c.subconstants.empty())
1364 {
1365 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001366 string res;
1367 if (backend.use_initializer_list)
1368 res = "{ ";
1369 else
1370 res = type_to_glsl_constructor(get<SPIRType>(c.constant_type)) + "(";
1371
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001372 for (auto &elem : c.subconstants)
1373 {
1374 res += constant_expression(get<SPIRConstant>(elem));
1375 if (&elem != &c.subconstants.back())
1376 res += ", ";
1377 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001378
1379 res += backend.use_initializer_list ? " }" : ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001380 return res;
1381 }
1382 else if (c.columns() == 1)
1383 {
1384 return constant_expression_vector(c, 0);
1385 }
1386 else
1387 {
1388 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
1389 for (uint32_t col = 0; col < c.columns(); col++)
1390 {
1391 res += constant_expression_vector(c, col);
1392 if (col + 1 < c.columns())
1393 res += ", ";
1394 }
1395 res += ")";
1396 return res;
1397 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001398}
1399
1400string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
1401{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001402 auto type = get<SPIRType>(c.constant_type);
1403 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001404
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001405 string res;
1406 if (c.vector_size() > 1)
1407 res += type_to_glsl(type) + "(";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001408
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001409 bool splat = c.vector_size() > 1;
1410 if (splat)
1411 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001412 if (type_to_std430_base_size(type) == 8)
1413 {
1414 uint64_t ident = c.scalar_u64(vector, 0);
1415 for (uint32_t i = 1; i < c.vector_size(); i++)
1416 if (ident != c.scalar_u64(vector, i))
1417 splat = false;
1418 }
1419 else
1420 {
1421 uint32_t ident = c.scalar(vector, 0);
1422 for (uint32_t i = 1; i < c.vector_size(); i++)
1423 if (ident != c.scalar(vector, i))
1424 splat = false;
1425 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001426 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001428 switch (type.basetype)
1429 {
1430 case SPIRType::Float:
1431 if (splat)
1432 {
1433 res += convert_to_string(c.scalar_f32(vector, 0));
1434 if (backend.float_literal_suffix)
1435 res += "f";
1436 }
1437 else
1438 {
1439 for (uint32_t i = 0; i < c.vector_size(); i++)
1440 {
1441 res += convert_to_string(c.scalar_f32(vector, i));
1442 if (backend.float_literal_suffix)
1443 res += "f";
1444 if (i + 1 < c.vector_size())
1445 res += ", ";
1446 }
1447 }
1448 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001449
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001450 case SPIRType::Double:
1451 if (splat)
1452 {
1453 res += convert_to_string(c.scalar_f64(vector, 0));
1454 if (backend.double_literal_suffix)
1455 res += "lf";
1456 }
1457 else
1458 {
1459 for (uint32_t i = 0; i < c.vector_size(); i++)
1460 {
1461 res += convert_to_string(c.scalar_f64(vector, i));
1462 if (backend.double_literal_suffix)
1463 res += "lf";
1464 if (i + 1 < c.vector_size())
1465 res += ", ";
1466 }
1467 }
1468 break;
1469
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02001470 case SPIRType::Int64:
1471 if (splat)
1472 {
1473 res += convert_to_string(c.scalar_i64(vector, 0));
1474 if (backend.long_long_literal_suffix)
1475 res += "ll";
1476 else
1477 res += "l";
1478 }
1479 else
1480 {
1481 for (uint32_t i = 0; i < c.vector_size(); i++)
1482 {
1483 res += convert_to_string(c.scalar_i64(vector, i));
1484 if (backend.long_long_literal_suffix)
1485 res += "ll";
1486 else
1487 res += "l";
1488 if (i + 1 < c.vector_size())
1489 res += ", ";
1490 }
1491 }
1492 break;
1493
1494 case SPIRType::UInt64:
1495 if (splat)
1496 {
1497 res += convert_to_string(c.scalar_u64(vector, 0));
1498 if (backend.long_long_literal_suffix)
1499 res += "ull";
1500 else
1501 res += "ul";
1502 }
1503 else
1504 {
1505 for (uint32_t i = 0; i < c.vector_size(); i++)
1506 {
1507 res += convert_to_string(c.scalar_u64(vector, i));
1508 if (backend.long_long_literal_suffix)
1509 res += "ull";
1510 else
1511 res += "ul";
1512 if (i + 1 < c.vector_size())
1513 res += ", ";
1514 }
1515 }
1516 break;
1517
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001518 case SPIRType::UInt:
1519 if (splat)
1520 {
1521 res += convert_to_string(c.scalar(vector, 0));
1522 if (backend.uint32_t_literal_suffix)
1523 res += "u";
1524 }
1525 else
1526 {
1527 for (uint32_t i = 0; i < c.vector_size(); i++)
1528 {
1529 res += convert_to_string(c.scalar(vector, i));
1530 if (backend.uint32_t_literal_suffix)
1531 res += "u";
1532 if (i + 1 < c.vector_size())
1533 res += ", ";
1534 }
1535 }
1536 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001538 case SPIRType::Int:
1539 if (splat)
1540 res += convert_to_string(c.scalar_i32(vector, 0));
1541 else
1542 {
1543 for (uint32_t i = 0; i < c.vector_size(); i++)
1544 {
1545 res += convert_to_string(c.scalar_i32(vector, i));
1546 if (i + 1 < c.vector_size())
1547 res += ", ";
1548 }
1549 }
1550 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001551
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001552 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001553 if (splat)
1554 res += c.scalar(vector, 0) ? "true" : "false";
1555 else
1556 {
1557 for (uint32_t i = 0; i < c.vector_size(); i++)
1558 {
1559 res += c.scalar(vector, i) ? "true" : "false";
1560 if (i + 1 < c.vector_size())
1561 res += ", ";
1562 }
1563 }
1564 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001565
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001566 default:
1567 throw CompilerError("Invalid constant expression basetype.");
1568 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001569
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001570 if (c.vector_size() > 1)
1571 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001572
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001573 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001574}
1575
1576string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
1577{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001578 auto &type = get<SPIRType>(result_type);
1579 auto flags = meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001580
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001581 // If we're declaring temporaries inside continue blocks,
1582 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
1583 if (current_continue_block)
1584 {
1585 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
1586 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001587 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001588 return tmp.first == result_type && tmp.second == result_id;
1589 }) == end(header.declare_temporary))
1590 {
1591 header.declare_temporary.emplace_back(result_type, result_id);
1592 force_recompile = true;
1593 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001595 return join(to_name(result_id), " = ");
1596 }
1597 else
1598 {
1599 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001600 return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001601 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001602}
1603
1604bool CompilerGLSL::expression_is_forwarded(uint32_t id)
1605{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001606 return forwarded_temporaries.find(id) != end(forwarded_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001607}
1608
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001609SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
1610 bool extra_parens, bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001611{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001612 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
1613 {
1614 // Just forward it without temporary.
1615 // If the forward is trivial, we do not force flushing to temporary for this expression.
1616 if (!suppress_usage_tracking)
1617 forwarded_temporaries.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001618
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001619 if (extra_parens)
1620 return set<SPIRExpression>(result_id, join("(", rhs, ")"), result_type, true);
1621 else
1622 return set<SPIRExpression>(result_id, rhs, result_type, true);
1623 }
1624 else
1625 {
1626 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
1627 statement(declare_temporary(result_type, result_id), rhs, ";");
1628 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
1629 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001630}
1631
1632void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1633{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001634 bool forward = should_forward(op0);
1635 emit_op(result_type, result_id, join(op, to_expression(op0)), forward, true);
1636
1637 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1638 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001639}
1640
1641void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
1642{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001643 bool forward = should_forward(op0) && should_forward(op1);
1644 emit_op(result_type, result_id, join(to_expression(op0), " ", op, " ", to_expression(op1)), forward, true);
1645
1646 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1647 {
1648 inherit_expression_dependencies(result_id, op0);
1649 inherit_expression_dependencies(result_id, op1);
1650 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001651}
1652
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001653SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
1654 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
1655{
1656 auto &type0 = expression_type(op0);
1657 auto &type1 = expression_type(op1);
1658
1659 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
1660 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
1661 // since equality test is exactly the same.
1662 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
1663
1664 // Create a fake type so we can bitcast to it.
1665 // We only deal with regular arithmetic types here like int, uints and so on.
1666 SPIRType expected_type;
1667 expected_type.basetype = input_type;
1668 expected_type.vecsize = type0.vecsize;
1669 expected_type.columns = type0.columns;
1670 expected_type.width = type0.width;
1671
1672 if (cast)
1673 {
1674 cast_op0 = bitcast_glsl(expected_type, op0);
1675 cast_op1 = bitcast_glsl(expected_type, op1);
1676 }
1677 else
1678 {
1679 // If we don't cast, our actual input type is that of the first (or second) argument.
1680 cast_op0 = to_expression(op0);
1681 cast_op1 = to_expression(op1);
1682 input_type = type0.basetype;
1683 }
1684
1685 return expected_type;
1686}
1687
1688void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1689 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1690{
1691 string cast_op0, cast_op1;
1692 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1693 auto &out_type = get<SPIRType>(result_type);
1694
1695 // We might have casted away from the result type, so bitcast again.
1696 // For example, arithmetic right shift with uint inputs.
1697 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1698 bool extra_parens = true;
1699 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001700 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001701 {
1702 expected_type.basetype = input_type;
1703 expr = bitcast_glsl_op(out_type, expected_type);
1704 expr += '(';
1705 expr += join(cast_op0, " ", op, " ", cast_op1);
1706 expr += ')';
1707 extra_parens = false;
1708 }
1709 else
1710 {
1711 expr += join(cast_op0, " ", op, " ", cast_op1);
1712 }
1713
1714 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), extra_parens);
1715}
1716
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001717void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1718{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001719 bool forward = should_forward(op0);
1720 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), forward, false);
1721 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1722 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001723}
1724
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001725void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1726 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001727{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001728 bool forward = should_forward(op0) && should_forward(op1);
1729 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ")"), forward, false);
1730
1731 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1732 {
1733 inherit_expression_dependencies(result_id, op0);
1734 inherit_expression_dependencies(result_id, op1);
1735 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001736}
1737
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001738void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1739 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1740{
1741 string cast_op0, cast_op1;
1742 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1743 auto &out_type = get<SPIRType>(result_type);
1744
1745 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1746 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001747 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001748 {
1749 expected_type.basetype = input_type;
1750 expr = bitcast_glsl_op(out_type, expected_type);
1751 expr += '(';
1752 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1753 expr += ')';
1754 }
1755 else
1756 {
1757 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1758 }
1759
1760 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), false);
1761}
1762
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001763void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1764 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001765{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001766 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001767 emit_op(result_type, result_id,
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001768 join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ")"), forward, false);
1769
1770 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1771 {
1772 inherit_expression_dependencies(result_id, op0);
1773 inherit_expression_dependencies(result_id, op1);
1774 inherit_expression_dependencies(result_id, op2);
1775 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001776}
1777
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001778void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1779 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001780{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001781 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001782 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ",
1783 to_expression(op2), ", ", to_expression(op3), ")"),
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001784 forward, false);
1785
1786 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1787 {
1788 inherit_expression_dependencies(result_id, op0);
1789 inherit_expression_dependencies(result_id, op1);
1790 inherit_expression_dependencies(result_id, op2);
1791 inherit_expression_dependencies(result_id, op3);
1792 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001793}
1794
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001795string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001796{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001797 const char *type;
1798 switch (imgtype.image.dim)
1799 {
1800 case spv::Dim1D:
1801 type = "1D";
1802 break;
1803 case spv::Dim2D:
1804 type = "2D";
1805 break;
1806 case spv::Dim3D:
1807 type = "3D";
1808 break;
1809 case spv::DimCube:
1810 type = "Cube";
1811 break;
1812 case spv::DimBuffer:
1813 type = "Buffer";
1814 break;
1815 case spv::DimSubpassData:
1816 type = "2D";
1817 break;
1818 default:
1819 type = "";
1820 break;
1821 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001823 if (op == "texture")
1824 return join("texture", type);
1825 else if (op == "textureLod")
1826 return join("texture", type, "Lod");
1827 else if (op == "textureProj")
1828 return join("texture", type, "Proj");
1829 else if (op == "textureProjLod")
1830 return join("texture", type, "ProjLod");
1831 else
1832 throw CompilerError(join("Unsupported legacy texture op: ", op));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001833}
1834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001835void 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 +01001836{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001837 auto &lerptype = expression_type(lerp);
1838 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001839
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001840 bool has_boolean_mix = (options.es && options.version >= 310) || (!options.es && options.version >= 450);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001841
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001842 // Boolean mix not supported on desktop without extension.
1843 // Was added in OpenGL 4.5 with ES 3.1 compat.
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001844 if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001845 {
1846 // Could use GL_EXT_shader_integer_mix on desktop at least,
1847 // but Apple doesn't support it. :(
1848 // Just implement it as ternary expressions.
1849 string expr;
1850 if (lerptype.vecsize == 1)
1851 expr = join(to_expression(lerp), " ? ", to_expression(right), " : ", to_expression(left));
1852 else
1853 {
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001854 auto swiz = [this](uint32_t expression, uint32_t i) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001855 return join(to_expression(expression), ".", index_to_swizzle(i));
1856 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001858 expr = type_to_glsl_constructor(restype);
1859 expr += "(";
1860 for (uint32_t i = 0; i < restype.vecsize; i++)
1861 {
1862 expr += swiz(lerp, i);
1863 expr += " ? ";
1864 expr += swiz(right, i);
1865 expr += " : ";
1866 expr += swiz(left, i);
1867 if (i + 1 < restype.vecsize)
1868 expr += ", ";
1869 }
1870 expr += ")";
1871 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001872
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001873 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp), false);
1874 }
1875 else
1876 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001877}
1878
Bill Hollings5aafb282016-04-23 21:47:41 -04001879void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
1880{
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02001881 if (options.vulkan_semantics)
1882 emit_binary_func_op(result_type, result_id, image_id, samp_id,
1883 type_to_glsl(get<SPIRType>(result_type)).c_str());
1884 else
1885 {
1886 // For GLSL and ESSL targets, we must enumerate all possible combinations for sampler2D(texture2D, sampler) and redirect
1887 // all possible combinations into new sampler2D uniforms.
1888 auto *image = maybe_get_backing_variable(image_id);
1889 auto *samp = maybe_get_backing_variable(samp_id);
1890 if (image)
1891 image_id = image->self;
1892 if (samp)
1893 samp_id = samp->self;
1894
1895 // FIXME: This must be context-dependent.
1896 auto &mapping = combined_image_samplers;
1897
1898 auto itr = find_if(begin(mapping), end(mapping), [image_id, samp_id](const CombinedImageSampler &combined) {
1899 return combined.image_id == image_id && combined.sampler_id == samp_id;
1900 });
1901
1902 if (itr != end(combined_image_samplers))
1903 emit_op(result_type, result_id, to_expression(itr->combined_id), true, false);
1904 else
Hans-Kristian Arntzendd1513b2016-09-10 21:52:22 +02001905 {
1906 //throw CompilerError("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
1907 // "before compile() was called?");
1908 emit_op(result_type, result_id, "DUMMY", true, false);
1909 }
Hans-Kristian Arntzen71bacc42016-09-10 17:48:52 +02001910 }
Bill Hollings5aafb282016-04-23 21:47:41 -04001911}
1912
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001913void CompilerGLSL::emit_texture_op(const Instruction &i)
1914{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001915 auto ops = stream(i);
1916 auto op = static_cast<Op>(i.op);
1917 uint32_t length = i.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001918
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001919 if (i.offset + length > spirv.size())
1920 throw CompilerError("Compiler::parse() opcode out of range.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001921
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001922 uint32_t result_type = ops[0];
1923 uint32_t id = ops[1];
1924 uint32_t img = ops[2];
1925 uint32_t coord = ops[3];
1926 uint32_t dref = 0;
1927 uint32_t comp = 0;
1928 bool gather = false;
1929 bool proj = false;
1930 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001931
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001932 switch (op)
1933 {
1934 case OpImageSampleDrefImplicitLod:
1935 case OpImageSampleDrefExplicitLod:
1936 dref = ops[4];
1937 opt = &ops[5];
1938 length -= 5;
1939 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001940
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001941 case OpImageSampleProjDrefImplicitLod:
1942 case OpImageSampleProjDrefExplicitLod:
1943 dref = ops[4];
1944 proj = true;
1945 opt = &ops[5];
1946 length -= 5;
1947 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001948
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001949 case OpImageDrefGather:
1950 dref = ops[4];
1951 opt = &ops[5];
1952 gather = true;
1953 length -= 5;
1954 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001955
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001956 case OpImageGather:
1957 comp = ops[4];
1958 opt = &ops[5];
1959 gather = true;
1960 length -= 5;
1961 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001962
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001963 case OpImageSampleProjImplicitLod:
1964 case OpImageSampleProjExplicitLod:
1965 opt = &ops[4];
1966 length -= 4;
1967 proj = true;
1968 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001969
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001970 default:
1971 opt = &ops[4];
1972 length -= 4;
1973 break;
1974 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001975
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001976 auto &imgtype = expression_type(img);
1977 uint32_t coord_components = 0;
1978 switch (imgtype.image.dim)
1979 {
1980 case spv::Dim1D:
1981 coord_components = 1;
1982 break;
1983 case spv::Dim2D:
1984 coord_components = 2;
1985 break;
1986 case spv::Dim3D:
1987 coord_components = 3;
1988 break;
1989 case spv::DimCube:
1990 coord_components = 3;
1991 break;
1992 case spv::DimBuffer:
1993 coord_components = 1;
1994 break;
1995 default:
1996 coord_components = 2;
1997 break;
1998 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001999
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002000 if (proj)
2001 coord_components++;
2002 if (imgtype.image.arrayed)
2003 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002004
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002005 uint32_t bias = 0;
2006 uint32_t lod = 0;
2007 uint32_t grad_x = 0;
2008 uint32_t grad_y = 0;
2009 uint32_t coffset = 0;
2010 uint32_t offset = 0;
2011 uint32_t coffsets = 0;
2012 uint32_t sample = 0;
2013 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002014
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002015 if (length)
2016 {
2017 flags = opt[0];
2018 opt++;
2019 length--;
2020 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002021
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02002022 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002023 if (length && (flags & flag))
2024 {
2025 v = *opt++;
2026 length--;
2027 }
2028 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002030 test(bias, ImageOperandsBiasMask);
2031 test(lod, ImageOperandsLodMask);
2032 test(grad_x, ImageOperandsGradMask);
2033 test(grad_y, ImageOperandsGradMask);
2034 test(coffset, ImageOperandsConstOffsetMask);
2035 test(offset, ImageOperandsOffsetMask);
2036 test(coffsets, ImageOperandsConstOffsetsMask);
2037 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002038
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002039 string expr;
2040 string texop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002042 if (op == OpImageFetch)
2043 texop += "texelFetch";
2044 else
2045 {
2046 texop += "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002047
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002048 if (gather)
2049 texop += "Gather";
2050 if (coffsets)
2051 texop += "Offsets";
2052 if (proj)
2053 texop += "Proj";
2054 if (grad_x || grad_y)
2055 texop += "Grad";
2056 if (lod)
2057 texop += "Lod";
2058 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002059
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002060 if (coffset || offset)
2061 texop += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002062
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002063 if (is_legacy())
2064 texop = legacy_tex_op(texop, imgtype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002066 expr += texop;
2067 expr += "(";
2068 expr += to_expression(img);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002069
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002070 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02002071 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002072 if (comps == in_comps)
2073 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002074
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002075 switch (comps)
2076 {
2077 case 1:
2078 return ".x";
2079 case 2:
2080 return swizz_func ? ".xy()" : ".xy";
2081 case 3:
2082 return swizz_func ? ".xyz()" : ".xyz";
2083 default:
2084 return "";
2085 }
2086 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002087
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002088 bool forward = should_forward(coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002090 // The IR can give us more components than we need, so chop them off as needed.
2091 auto coord_expr = to_expression(coord) + swizzle(coord_components, expression_type(coord).vecsize);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002092
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002093 // TODO: implement rest ... A bit intensive.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002094
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002095 if (dref)
2096 {
2097 forward = forward && should_forward(dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002098
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002099 // SPIR-V splits dref and coordinate.
2100 if (coord_components == 4) // GLSL also splits the arguments in two.
2101 {
2102 expr += ", ";
2103 expr += to_expression(coord);
2104 expr += ", ";
2105 expr += to_expression(dref);
2106 }
2107 else
2108 {
2109 // Create a composite which merges coord/dref into a single vector.
2110 auto type = expression_type(coord);
2111 type.vecsize = coord_components + 1;
2112 expr += ", ";
2113 expr += type_to_glsl_constructor(type);
2114 expr += "(";
2115 expr += coord_expr;
2116 expr += ", ";
2117 expr += to_expression(dref);
2118 expr += ")";
2119 }
2120 }
2121 else
2122 {
2123 expr += ", ";
2124 expr += coord_expr;
2125 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002126
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002127 if (grad_x || grad_y)
2128 {
2129 forward = forward && should_forward(grad_x);
2130 forward = forward && should_forward(grad_y);
2131 expr += ", ";
2132 expr += to_expression(grad_x);
2133 expr += ", ";
2134 expr += to_expression(grad_y);
2135 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002136
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002137 if (lod)
2138 {
2139 forward = forward && should_forward(lod);
2140 expr += ", ";
2141 expr += to_expression(lod);
2142 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002143
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002144 if (coffset)
2145 {
2146 forward = forward && should_forward(coffset);
2147 expr += ", ";
2148 expr += to_expression(coffset);
2149 }
2150 else if (offset)
2151 {
2152 forward = forward && should_forward(offset);
2153 expr += ", ";
2154 expr += to_expression(offset);
2155 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002156
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002157 if (bias)
2158 {
2159 forward = forward && should_forward(bias);
2160 expr += ", ";
2161 expr += to_expression(bias);
2162 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002163
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002164 if (comp)
2165 {
2166 forward = forward && should_forward(comp);
2167 expr += ", ";
2168 expr += to_expression(comp);
2169 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002170
Hans-Kristian Arntzen9d4360f2016-06-22 12:35:58 +02002171 if (sample)
2172 {
2173 expr += ", ";
2174 expr += to_expression(sample);
2175 }
2176
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002177 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002178
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002179 emit_op(result_type, id, expr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002180}
2181
2182void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t)
2183{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002184 GLSLstd450 op = static_cast<GLSLstd450>(eop);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002185
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002186 switch (op)
2187 {
2188 // FP fiddling
2189 case GLSLstd450Round:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002190 emit_unary_func_op(result_type, id, args[0], "round");
2191 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02002192
2193 case GLSLstd450RoundEven:
2194 if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
2195 emit_unary_func_op(result_type, id, args[0], "roundEven");
2196 else
2197 throw CompilerError("roundEven supported only in ESSL 300 and GLSL 130 and up.");
2198 break;
2199
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002200 case GLSLstd450Trunc:
2201 emit_unary_func_op(result_type, id, args[0], "trunc");
2202 break;
2203 case GLSLstd450SAbs:
2204 case GLSLstd450FAbs:
2205 emit_unary_func_op(result_type, id, args[0], "abs");
2206 break;
2207 case GLSLstd450SSign:
2208 case GLSLstd450FSign:
2209 emit_unary_func_op(result_type, id, args[0], "sign");
2210 break;
2211 case GLSLstd450Floor:
2212 emit_unary_func_op(result_type, id, args[0], "floor");
2213 break;
2214 case GLSLstd450Ceil:
2215 emit_unary_func_op(result_type, id, args[0], "ceil");
2216 break;
2217 case GLSLstd450Fract:
2218 emit_unary_func_op(result_type, id, args[0], "fract");
2219 break;
2220 case GLSLstd450Radians:
2221 emit_unary_func_op(result_type, id, args[0], "radians");
2222 break;
2223 case GLSLstd450Degrees:
2224 emit_unary_func_op(result_type, id, args[0], "degrees");
2225 break;
2226 case GLSLstd450Fma:
2227 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
2228 break;
2229 case GLSLstd450Modf:
2230 register_call_out_argument(args[1]);
2231 forced_temporaries.insert(id);
2232 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
2233 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002234
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002235 // Minmax
2236 case GLSLstd450FMin:
2237 case GLSLstd450UMin:
2238 case GLSLstd450SMin:
2239 emit_binary_func_op(result_type, id, args[0], args[1], "min");
2240 break;
2241 case GLSLstd450FMax:
2242 case GLSLstd450UMax:
2243 case GLSLstd450SMax:
2244 emit_binary_func_op(result_type, id, args[0], args[1], "max");
2245 break;
2246 case GLSLstd450FClamp:
2247 case GLSLstd450UClamp:
2248 case GLSLstd450SClamp:
2249 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
2250 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002252 // Trig
2253 case GLSLstd450Sin:
2254 emit_unary_func_op(result_type, id, args[0], "sin");
2255 break;
2256 case GLSLstd450Cos:
2257 emit_unary_func_op(result_type, id, args[0], "cos");
2258 break;
2259 case GLSLstd450Tan:
2260 emit_unary_func_op(result_type, id, args[0], "tan");
2261 break;
2262 case GLSLstd450Asin:
2263 emit_unary_func_op(result_type, id, args[0], "asin");
2264 break;
2265 case GLSLstd450Acos:
2266 emit_unary_func_op(result_type, id, args[0], "acos");
2267 break;
2268 case GLSLstd450Atan:
2269 emit_unary_func_op(result_type, id, args[0], "atan");
2270 break;
2271 case GLSLstd450Sinh:
2272 emit_unary_func_op(result_type, id, args[0], "sinh");
2273 break;
2274 case GLSLstd450Cosh:
2275 emit_unary_func_op(result_type, id, args[0], "cosh");
2276 break;
2277 case GLSLstd450Tanh:
2278 emit_unary_func_op(result_type, id, args[0], "tanh");
2279 break;
2280 case GLSLstd450Asinh:
2281 emit_unary_func_op(result_type, id, args[0], "asinh");
2282 break;
2283 case GLSLstd450Acosh:
2284 emit_unary_func_op(result_type, id, args[0], "acosh");
2285 break;
2286 case GLSLstd450Atanh:
2287 emit_unary_func_op(result_type, id, args[0], "atanh");
2288 break;
2289 case GLSLstd450Atan2:
2290 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
2291 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002292
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002293 // Exponentials
2294 case GLSLstd450Pow:
2295 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
2296 break;
2297 case GLSLstd450Exp:
2298 emit_unary_func_op(result_type, id, args[0], "exp");
2299 break;
2300 case GLSLstd450Log:
2301 emit_unary_func_op(result_type, id, args[0], "log");
2302 break;
2303 case GLSLstd450Exp2:
2304 emit_unary_func_op(result_type, id, args[0], "exp2");
2305 break;
2306 case GLSLstd450Log2:
2307 emit_unary_func_op(result_type, id, args[0], "log2");
2308 break;
2309 case GLSLstd450Sqrt:
2310 emit_unary_func_op(result_type, id, args[0], "sqrt");
2311 break;
2312 case GLSLstd450InverseSqrt:
2313 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
2314 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002315
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002316 // Matrix math
2317 case GLSLstd450Determinant:
2318 emit_unary_func_op(result_type, id, args[0], "determinant");
2319 break;
2320 case GLSLstd450MatrixInverse:
2321 emit_unary_func_op(result_type, id, args[0], "inverse");
2322 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002323
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002324 // Lerping
2325 case GLSLstd450FMix:
2326 case GLSLstd450IMix:
2327 {
2328 emit_mix_op(result_type, id, args[0], args[1], args[2]);
2329 break;
2330 }
2331 case GLSLstd450Step:
2332 emit_binary_func_op(result_type, id, args[0], args[1], "step");
2333 break;
2334 case GLSLstd450SmoothStep:
2335 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
2336 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002337
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002338 // Packing
2339 case GLSLstd450Frexp:
2340 register_call_out_argument(args[1]);
2341 forced_temporaries.insert(id);
2342 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
2343 break;
2344 case GLSLstd450Ldexp:
2345 emit_binary_func_op(result_type, id, args[0], args[1], "ldexp");
2346 break;
2347 case GLSLstd450PackSnorm4x8:
2348 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
2349 break;
2350 case GLSLstd450PackUnorm4x8:
2351 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
2352 break;
2353 case GLSLstd450PackSnorm2x16:
2354 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
2355 break;
2356 case GLSLstd450PackUnorm2x16:
2357 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
2358 break;
2359 case GLSLstd450PackHalf2x16:
2360 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
2361 break;
2362 case GLSLstd450UnpackSnorm4x8:
2363 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
2364 break;
2365 case GLSLstd450UnpackUnorm4x8:
2366 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
2367 break;
2368 case GLSLstd450UnpackSnorm2x16:
2369 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
2370 break;
2371 case GLSLstd450UnpackUnorm2x16:
2372 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
2373 break;
2374 case GLSLstd450UnpackHalf2x16:
2375 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
2376 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002377
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02002378 case GLSLstd450PackDouble2x32:
2379 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
2380 break;
2381 case GLSLstd450UnpackDouble2x32:
2382 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
2383 break;
2384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002385 // Vector math
2386 case GLSLstd450Length:
2387 emit_unary_func_op(result_type, id, args[0], "length");
2388 break;
2389 case GLSLstd450Distance:
2390 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
2391 break;
2392 case GLSLstd450Cross:
2393 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
2394 break;
2395 case GLSLstd450Normalize:
2396 emit_unary_func_op(result_type, id, args[0], "normalize");
2397 break;
2398 case GLSLstd450FaceForward:
2399 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
2400 break;
2401 case GLSLstd450Reflect:
2402 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
2403 break;
2404 case GLSLstd450Refract:
2405 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
2406 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002407
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002408 // Bit-fiddling
2409 case GLSLstd450FindILsb:
2410 emit_unary_func_op(result_type, id, args[0], "findLSB");
2411 break;
2412 case GLSLstd450FindSMsb:
2413 case GLSLstd450FindUMsb:
2414 emit_unary_func_op(result_type, id, args[0], "findMSB");
2415 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002417 // Multisampled varying
2418 case GLSLstd450InterpolateAtCentroid:
2419 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
2420 break;
2421 case GLSLstd450InterpolateAtSample:
2422 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
2423 break;
2424 case GLSLstd450InterpolateAtOffset:
2425 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
2426 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002428 default:
2429 statement("// unimplemented GLSL op ", eop);
2430 break;
2431 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002432}
2433
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002434string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002435{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002436 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
2437 return type_to_glsl(out_type);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002438 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Int64)
2439 return type_to_glsl(out_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002440 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
2441 return "floatBitsToUint";
2442 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
2443 return type_to_glsl(out_type);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002444 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::UInt64)
2445 return type_to_glsl(out_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002446 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
2447 return "floatBitsToInt";
2448 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
2449 return "uintBitsToFloat";
2450 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
2451 return "intBitsToFloat";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002452 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
2453 return "doubleBitsToInt64";
2454 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
2455 return "doubleBitsToUint64";
2456 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
2457 return "int64BitsToDouble";
2458 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
2459 return "uint64BitsToDouble";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002460 else
2461 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002462}
2463
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002464string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002465{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002466 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002467 if (op.empty())
2468 return to_expression(argument);
2469 else
2470 return join(op, "(", to_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002471}
2472
Bill Hollings103aabf2016-04-06 17:42:27 -04002473string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002474{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002475 switch (builtin)
2476 {
2477 case BuiltInPosition:
2478 return "gl_Position";
2479 case BuiltInPointSize:
2480 return "gl_PointSize";
2481 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002482 if (options.vulkan_semantics)
2483 throw CompilerError(
2484 "Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002485 return "gl_VertexID";
2486 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002487 if (options.vulkan_semantics)
2488 throw CompilerError(
2489 "Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002490 return "gl_InstanceID";
2491 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002492 if (options.vulkan_semantics)
2493 return "gl_VertexIndex";
2494 else
2495 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002496 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002497 if (options.vulkan_semantics)
2498 return "gl_InstanceIndex";
2499 else
2500 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002501 case BuiltInPrimitiveId:
2502 return "gl_PrimitiveID";
2503 case BuiltInInvocationId:
2504 return "gl_InvocationID";
2505 case BuiltInLayer:
2506 return "gl_Layer";
2507 case BuiltInTessLevelOuter:
2508 return "gl_TessLevelOuter";
2509 case BuiltInTessLevelInner:
2510 return "gl_TessLevelInner";
2511 case BuiltInTessCoord:
2512 return "gl_TessCoord";
2513 case BuiltInFragCoord:
2514 return "gl_FragCoord";
2515 case BuiltInPointCoord:
2516 return "gl_PointCoord";
2517 case BuiltInFrontFacing:
2518 return "gl_FrontFacing";
2519 case BuiltInFragDepth:
2520 return "gl_FragDepth";
2521 case BuiltInNumWorkgroups:
2522 return "gl_NumWorkGroups";
2523 case BuiltInWorkgroupSize:
2524 return "gl_WorkGroupSize";
2525 case BuiltInWorkgroupId:
2526 return "gl_WorkGroupID";
2527 case BuiltInLocalInvocationId:
2528 return "gl_LocalInvocationID";
2529 case BuiltInGlobalInvocationId:
2530 return "gl_GlobalInvocationID";
2531 case BuiltInLocalInvocationIndex:
2532 return "gl_LocalInvocationIndex";
2533 default:
2534 return "gl_???";
2535 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002536}
2537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002538const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002539{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002540 switch (index)
2541 {
2542 case 0:
2543 return "x";
2544 case 1:
2545 return "y";
2546 case 2:
2547 return "z";
2548 case 3:
2549 return "w";
2550 default:
2551 throw CompilerError("Swizzle index out of range");
2552 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002553}
2554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002555string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal,
2556 bool chain_only)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002557{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002558 string expr;
2559 if (!chain_only)
2560 expr = to_expression(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002561
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002562 const auto *type = &expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002563
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002564 // For resolving array accesses, etc, keep a local copy for poking.
2565 SPIRType temp;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002566
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002567 bool access_chain_is_arrayed = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002568
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002569 for (uint32_t i = 0; i < count; i++)
2570 {
2571 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002572
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002573 // Arrays
2574 if (!type->array.empty())
2575 {
2576 expr += "[";
2577 if (index_is_literal)
2578 expr += convert_to_string(index);
2579 else
2580 expr += to_expression(index);
2581 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002582
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002583 // We have to modify the type, so keep a local copy.
2584 if (&temp != type)
2585 temp = *type;
2586 type = &temp;
2587 temp.array.pop_back();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002588
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002589 access_chain_is_arrayed = true;
2590 }
2591 // For structs, the index refers to a constant, which indexes into the members.
2592 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
2593 else if (type->basetype == SPIRType::Struct)
2594 {
2595 if (!index_is_literal)
2596 index = get<SPIRConstant>(index).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002597
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002598 if (index >= type->member_types.size())
2599 throw CompilerError("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002600
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002601 BuiltIn builtin;
2602 if (is_member_builtin(*type, index, &builtin))
2603 {
2604 // FIXME: We rely here on OpName on gl_in/gl_out to make this work properly.
2605 // To make this properly work by omitting all OpName opcodes,
2606 // we need to infer gl_in or gl_out based on the builtin, and stage.
2607 if (access_chain_is_arrayed)
2608 {
2609 expr += ".";
2610 expr += builtin_to_glsl(builtin);
2611 }
2612 else
2613 expr = builtin_to_glsl(builtin);
2614 }
2615 else
2616 {
2617 expr += ".";
2618 expr += to_member_name(*type, index);
2619 }
2620 type = &get<SPIRType>(type->member_types[index]);
2621 }
2622 // Matrix -> Vector
2623 else if (type->columns > 1)
2624 {
2625 expr += "[";
2626 if (index_is_literal)
2627 expr += convert_to_string(index);
2628 else
2629 expr += to_expression(index);
2630 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002631
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002632 // We have to modify the type, so keep a local copy.
2633 if (&temp != type)
2634 temp = *type;
2635 type = &temp;
2636 temp.columns = 1;
2637 }
2638 // Vector -> Scalar
2639 else if (type->vecsize > 1)
2640 {
2641 if (index_is_literal)
2642 {
2643 expr += ".";
2644 expr += index_to_swizzle(index);
2645 }
2646 else if (ids[index].get_type() == TypeConstant)
2647 {
2648 auto &c = get<SPIRConstant>(index);
2649 expr += ".";
2650 expr += index_to_swizzle(c.scalar());
2651 }
2652 else
2653 {
2654 expr += "[";
2655 expr += to_expression(index);
2656 expr += "]";
2657 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002658
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002659 // We have to modify the type, so keep a local copy.
2660 if (&temp != type)
2661 temp = *type;
2662 type = &temp;
2663 temp.vecsize = 1;
2664 }
2665 else
2666 throw CompilerError("Cannot subdivide a scalar value!");
2667 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002668
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002669 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002670}
2671
2672bool CompilerGLSL::should_forward(uint32_t id)
2673{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002674 // Immutable expression can always be forwarded.
2675 // If not immutable, we can speculate about it by forwarding potentially mutable variables.
2676 auto *var = maybe_get<SPIRVariable>(id);
2677 bool forward = var ? var->forwardable : false;
2678 return (is_immutable(id) || forward) && !options.force_temporary;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002679}
2680
2681void CompilerGLSL::track_expression_read(uint32_t id)
2682{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002683 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
2684 // In this case, it's better to just bind the complex expression to the temporary and read that temporary twice.
2685 if (expression_is_forwarded(id))
2686 {
2687 auto &v = expression_usage_counts[id];
2688 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002689
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002690 if (v >= 2)
2691 {
2692 //if (v == 2)
2693 // 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 +01002694
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002695 forced_temporaries.insert(id);
2696 // Force a recompile after this pass to avoid forwarding this variable.
2697 force_recompile = true;
2698 }
2699 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002700}
2701
2702bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
2703{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002704 if (forced_temporaries.find(id) != end(forced_temporaries))
2705 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002706
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002707 for (uint32_t i = 0; i < num_args; i++)
2708 if (!should_forward(args[i]))
2709 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002711 // We need to forward globals as well.
2712 if (!pure)
2713 {
2714 for (auto global : global_variables)
2715 if (!should_forward(global))
2716 return false;
2717 for (auto aliased : aliased_variables)
2718 if (!should_forward(aliased))
2719 return false;
2720 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002721
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002722 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002723}
2724
2725void CompilerGLSL::register_impure_function_call()
2726{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002727 // Impure functions can modify globals and aliased variables, so invalidate them as well.
2728 for (auto global : global_variables)
2729 flush_dependees(get<SPIRVariable>(global));
2730 for (auto aliased : aliased_variables)
2731 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002732}
2733
2734void CompilerGLSL::register_call_out_argument(uint32_t id)
2735{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002736 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002738 auto *var = maybe_get<SPIRVariable>(id);
2739 if (var)
2740 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002741}
2742
2743void CompilerGLSL::flush_variable_declaration(uint32_t id)
2744{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002745 auto *var = maybe_get<SPIRVariable>(id);
2746 if (var && var->deferred_declaration)
2747 {
2748 statement(variable_decl(*var), ";");
2749 var->deferred_declaration = false;
2750 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002751}
2752
2753bool CompilerGLSL::remove_duplicate_swizzle(string &op)
2754{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002755 auto pos = op.find_last_of('.');
2756 if (pos == string::npos || pos == 0)
2757 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002758
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002759 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002760
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002761 if (backend.swizzle_is_function)
2762 {
2763 if (final_swiz.size() < 2)
2764 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002765
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002766 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2767 final_swiz.erase(final_swiz.size() - 2, string::npos);
2768 else
2769 return false;
2770 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002771
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002772 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2773 // If so, and previous swizzle is of same length,
2774 // we can drop the final swizzle altogether.
2775 for (uint32_t i = 0; i < final_swiz.size(); i++)
2776 {
2777 static const char expected[] = { 'x', 'y', 'z', 'w' };
2778 if (i >= 4 || final_swiz[i] != expected[i])
2779 return false;
2780 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002781
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002782 auto prevpos = op.find_last_of('.', pos - 1);
2783 if (prevpos == string::npos)
2784 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002785
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002786 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002787
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002788 // Make sure there are only swizzles here ...
2789 for (auto i = prevpos; i < pos; i++)
2790 {
2791 if (op[i] < 'w' || op[i] > 'z')
2792 {
2793 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
2794 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
2795 break;
2796 return false;
2797 }
2798 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002799
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002800 // If original swizzle is large enough, just carve out the components we need.
2801 // E.g. foobar.wyx.xy will turn into foobar.wy.
2802 if (pos - prevpos >= final_swiz.size())
2803 {
2804 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002806 // Add back the function call ...
2807 if (backend.swizzle_is_function)
2808 op += "()";
2809 }
2810 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002811}
2812
2813// Optimizes away vector swizzles where we have something like
2814// vec3 foo;
2815// foo.xyz <-- swizzle expression does nothing.
2816// This is a very common pattern after OpCompositeCombine.
2817bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
2818{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002819 auto pos = op.find_last_of('.');
2820 if (pos == string::npos || pos == 0)
2821 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002823 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002824
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002825 if (backend.swizzle_is_function)
2826 {
2827 if (final_swiz.size() < 2)
2828 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002829
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002830 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2831 final_swiz.erase(final_swiz.size() - 2, string::npos);
2832 else
2833 return false;
2834 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002836 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2837 // If so, and previous swizzle is of same length,
2838 // we can drop the final swizzle altogether.
2839 for (uint32_t i = 0; i < final_swiz.size(); i++)
2840 {
2841 static const char expected[] = { 'x', 'y', 'z', 'w' };
2842 if (i >= 4 || final_swiz[i] != expected[i])
2843 return false;
2844 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002845
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002846 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002847
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002848 // Sanity checking ...
2849 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002850
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002851 if (type.vecsize == final_swiz.size())
2852 op.erase(pos, string::npos);
2853 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002854}
2855
2856string CompilerGLSL::build_composite_combiner(const uint32_t *elems, uint32_t length)
2857{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002858 uint32_t base = 0;
2859 bool swizzle_optimization = false;
2860 string op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002861
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002862 for (uint32_t i = 0; i < length; i++)
2863 {
2864 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002866 // If we're merging another scalar which belongs to the same base
2867 // object, just merge the swizzles to avoid triggering more than 1 expression read as much as possible!
2868 if (e && e->base_expression && e->base_expression == base)
2869 {
2870 // Only supposed to be used for vector swizzle -> scalar.
2871 assert(!e->expression.empty() && e->expression.front() == '.');
2872 op += e->expression.substr(1, string::npos);
2873 swizzle_optimization = true;
2874 }
2875 else
2876 {
2877 // We'll likely end up with duplicated swizzles, e.g.
2878 // foobar.xyz.xyz from patterns like
2879 // OpVectorSwizzle
2880 // OpCompositeExtract x 3
2881 // OpCompositeConstruct 3x + other scalar.
2882 // Just modify op in-place.
2883 if (swizzle_optimization)
2884 {
2885 if (backend.swizzle_is_function)
2886 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002887
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002888 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
2889 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
2890 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
2891 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
2892 // Case 1:
2893 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
2894 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
2895 // Case 2:
2896 // foo.xyz: Duplicate swizzle won't kick in.
2897 // If foo is vec3, we can remove xyz, giving just foo.
2898 if (!remove_duplicate_swizzle(op))
2899 remove_unity_swizzle(base, op);
2900 swizzle_optimization = false;
2901 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002902
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002903 if (i)
2904 op += ", ";
2905 op += to_expression(elems[i]);
2906 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002907
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002908 base = e ? e->base_expression : 0;
2909 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002910
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002911 if (swizzle_optimization)
2912 {
2913 if (backend.swizzle_is_function)
2914 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002915
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002916 if (!remove_duplicate_swizzle(op))
2917 remove_unity_swizzle(base, op);
2918 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002919
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002920 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002921}
2922
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02002923void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002924{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002925 auto ops = stream(instruction);
2926 auto opcode = static_cast<Op>(instruction.op);
2927 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002928
2929#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002930#define BOP_CAST(op, type, skip_cast) emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002931#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
2932#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
2933#define TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
2934#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002935#define BFOP_CAST(op, type, skip_cast) emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
2936#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002937#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
2938
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002939 switch (opcode)
2940 {
2941 // Dealing with memory
2942 case OpLoad:
2943 {
2944 uint32_t result_type = ops[0];
2945 uint32_t id = ops[1];
2946 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002947
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002948 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002949
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002950 // If we're loading from memory that cannot be changed by the shader,
2951 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002952 // If an expression is mutable and forwardable, we speculate that it is immutable.
2953 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
2954
2955 // Suppress usage tracking since using same expression multiple times does not imply any extra work.
2956 emit_op(result_type, id, to_expression(ptr), forward, false, true);
2957 register_read(id, ptr, forward);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002958 break;
2959 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002960
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002961 case OpInBoundsAccessChain:
2962 case OpAccessChain:
2963 {
2964 auto *var = maybe_get<SPIRVariable>(ops[2]);
2965 if (var)
2966 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002967
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002968 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002969 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002970 auto e = access_chain(ops[2], &ops[3], length - 3, false);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002971 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002972 expr.loaded_from = ops[2];
2973 break;
2974 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002975
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002976 case OpStore:
2977 {
2978 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002979
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002980 if (var && var->statically_assigned)
2981 var->static_expression = ops[1];
2982 else
2983 {
2984 auto lhs = to_expression(ops[0]);
2985 auto rhs = to_expression(ops[1]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002986
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002987 // It is possible with OpLoad/OpCompositeInsert/OpStore that we get <expr> = <same-expr>.
2988 // For this case, we don't need to invalidate anything and emit any opcode.
2989 if (lhs != rhs)
2990 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002991 statement(lhs, " = ", rhs, ";");
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002992 register_write(ops[0]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002993 }
2994 }
2995 break;
2996 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002997
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002998 case OpArrayLength:
2999 {
3000 uint32_t result_type = ops[0];
3001 uint32_t id = ops[1];
3002 auto e = access_chain(ops[2], &ops[3], length - 3, true);
3003 set<SPIRExpression>(id, e + ".length()", result_type, true);
3004 break;
3005 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003006
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003007 // Function calls
3008 case OpFunctionCall:
3009 {
3010 uint32_t result_type = ops[0];
3011 uint32_t id = ops[1];
3012 uint32_t func = ops[2];
3013 const auto *arg = &ops[3];
3014 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003016 auto &callee = get<SPIRFunction>(func);
3017 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003018
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003019 bool callee_has_out_variables = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003020
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003021 // Invalidate out variables passed to functions since they can be OpStore'd to.
3022 for (uint32_t i = 0; i < length; i++)
3023 {
3024 if (callee.arguments[i].write_count)
3025 {
3026 register_call_out_argument(arg[i]);
3027 callee_has_out_variables = true;
3028 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003030 flush_variable_declaration(arg[i]);
3031 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003032
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003033 if (!pure)
3034 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003036 string funexpr;
3037 funexpr += to_name(func) + "(";
3038 for (uint32_t i = 0; i < length; i++)
3039 {
3040 funexpr += to_expression(arg[i]);
3041 if (i + 1 < length)
3042 funexpr += ", ";
3043 }
3044 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003045
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02003046 // Check for function call constraints.
3047 check_function_call_constraints(arg, length);
3048
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003049 if (get<SPIRType>(result_type).basetype != SPIRType::Void)
3050 {
3051 // If the function actually writes to an out variable,
3052 // take the conservative route and do not forward.
3053 // The problem is that we might not read the function
3054 // result (and emit the function) before an out variable
3055 // is read (common case when return value is ignored!
3056 // In order to avoid start tracking invalid variables,
3057 // just avoid the forwarding problem altogether.
3058 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
3059 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003061 emit_op(result_type, id, funexpr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003062
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003063 // Function calls are implicit loads from all variables in question.
3064 // Set dependencies for them.
3065 for (uint32_t i = 0; i < length; i++)
3066 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003067
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003068 // If we're going to forward the temporary result,
3069 // put dependencies on every variable that must not change.
3070 if (forward)
3071 register_global_read_dependencies(callee, id);
3072 }
3073 else
3074 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003076 break;
3077 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003078
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003079 // Composite munging
3080 case OpCompositeConstruct:
3081 {
3082 uint32_t result_type = ops[0];
3083 uint32_t id = ops[1];
3084 const auto *elems = &ops[2];
3085 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003087 if (!length)
3088 throw CompilerError("Invalid input to OpCompositeConstruct.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003090 bool forward = true;
3091 for (uint32_t i = 0; i < length; i++)
3092 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003094 auto &in_type = expression_type(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003095 auto &out_type = get<SPIRType>(result_type);
3096
3097 // Only splat if we have vector constructors.
3098 // Arrays and structs must be initialized properly in full.
3099 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
3100 bool splat = in_type.vecsize == 1 && in_type.columns == 1 && !composite;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003102 if (splat)
3103 {
3104 uint32_t input = elems[0];
3105 for (uint32_t i = 0; i < length; i++)
3106 if (input != elems[i])
3107 splat = false;
3108 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003109
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003110 string constructor_op;
3111 if (backend.use_initializer_list && composite)
3112 {
3113 // Only use this path if we are building composites.
3114 // This path cannot be used for arithmetic.
3115 constructor_op += "{ ";
3116 if (splat)
3117 constructor_op += to_expression(elems[0]);
3118 else
3119 constructor_op += build_composite_combiner(elems, length);
3120 constructor_op += " }";
3121 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003122 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003123 {
3124 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
3125 if (splat)
3126 constructor_op += to_expression(elems[0]);
3127 else
3128 constructor_op += build_composite_combiner(elems, length);
3129 constructor_op += ")";
3130 }
3131
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003132 emit_op(result_type, id, constructor_op, forward, false);
3133 break;
3134 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003135
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003136 case OpVectorInsertDynamic:
3137 {
3138 uint32_t result_type = ops[0];
3139 uint32_t id = ops[1];
3140 uint32_t vec = ops[2];
3141 uint32_t comp = ops[3];
3142 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003143
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003144 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003145
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003146 // Make a copy, then use access chain to store the variable.
3147 statement(declare_temporary(result_type, id), to_expression(vec), ";");
3148 set<SPIRExpression>(id, to_name(id), result_type, true);
3149 auto chain = access_chain(id, &index, 1, false);
3150 statement(chain, " = ", to_expression(comp), ";");
3151 break;
3152 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003153
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003154 case OpVectorExtractDynamic:
3155 {
3156 uint32_t result_type = ops[0];
3157 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003158
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003159 auto expr = access_chain(ops[2], &ops[3], 1, false);
3160 emit_op(result_type, id, expr, should_forward(ops[2]), false);
3161 break;
3162 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003163
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003164 case OpCompositeExtract:
3165 {
3166 uint32_t result_type = ops[0];
3167 uint32_t id = ops[1];
3168 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003169
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003170 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003171
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02003172 // We can only split the expression here if our expression is forwarded as a temporary.
3173 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
3174
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003175 // Only apply this optimization if result is scalar.
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02003176 if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003177 {
3178 // We want to split the access chain from the base.
3179 // This is so we can later combine different CompositeExtract results
3180 // with CompositeConstruct without emitting code like
3181 //
3182 // vec3 temp = texture(...).xyz
3183 // vec4(temp.x, temp.y, temp.z, 1.0).
3184 //
3185 // when we actually wanted to emit this
3186 // vec4(texture(...).xyz, 1.0).
3187 //
3188 // Including the base will prevent this and would trigger multiple reads
3189 // from expression causing it to be forced to an actual temporary in GLSL.
3190 auto expr = access_chain(ops[2], &ops[3], length, true, true);
3191 auto &e = emit_op(result_type, id, expr, true, false, !expression_is_forwarded(ops[2]));
3192 e.base_expression = ops[2];
3193 }
3194 else
3195 {
3196 auto expr = access_chain(ops[2], &ops[3], length, true);
3197 emit_op(result_type, id, expr, should_forward(ops[2]), false, !expression_is_forwarded(ops[2]));
3198 }
3199 break;
3200 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003201
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003202 case OpCompositeInsert:
3203 {
3204 uint32_t result_type = ops[0];
3205 uint32_t id = ops[1];
3206 uint32_t obj = ops[2];
3207 uint32_t composite = ops[3];
3208 const auto *elems = &ops[4];
3209 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003210
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003211 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003212
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003213 auto *expr = maybe_get<SPIRExpression>(id);
3214 if ((expr && expr->used_while_invalidated) || !should_forward(composite))
3215 {
3216 // Make a copy, then use access chain to store the variable.
3217 statement(declare_temporary(result_type, id), to_expression(composite), ";");
3218 set<SPIRExpression>(id, to_name(id), result_type, true);
3219 auto chain = access_chain(id, elems, length, true);
3220 statement(chain, " = ", to_expression(obj), ";");
3221 }
3222 else
3223 {
3224 auto chain = access_chain(composite, elems, length, true);
3225 statement(chain, " = ", to_expression(obj), ";");
3226 set<SPIRExpression>(id, to_expression(composite), result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003227
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003228 register_write(composite);
3229 register_read(id, composite, true);
3230 // Invalidate the old expression we inserted into.
3231 invalid_expressions.insert(composite);
3232 }
3233 break;
3234 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003235
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003236 case OpCopyObject:
3237 {
3238 uint32_t result_type = ops[0];
3239 uint32_t id = ops[1];
3240 uint32_t rhs = ops[2];
3241 if (expression_is_lvalue(rhs))
3242 {
3243 // Need a copy.
3244 statement(declare_temporary(result_type, id), to_expression(rhs), ";");
3245 set<SPIRExpression>(id, to_name(id), result_type, true);
3246 }
3247 else
3248 {
3249 // RHS expression is immutable, so just forward it.
3250 // Copying these things really make no sense, but
3251 // seems to be allowed anyways.
3252 set<SPIRExpression>(id, to_expression(rhs), result_type, true);
3253 }
3254 break;
3255 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003257 case OpVectorShuffle:
3258 {
3259 uint32_t result_type = ops[0];
3260 uint32_t id = ops[1];
3261 uint32_t vec0 = ops[2];
3262 uint32_t vec1 = ops[3];
3263 const auto *elems = &ops[4];
3264 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003266 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003268 bool shuffle = false;
3269 for (uint32_t i = 0; i < length; i++)
3270 if (elems[i] >= type0.vecsize)
3271 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003272
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003273 string expr;
3274 bool trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003275
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003276 if (shuffle)
3277 {
3278 trivial_forward = !expression_is_forwarded(vec0) && !expression_is_forwarded(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003279
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003280 // Constructor style and shuffling from two different vectors.
3281 vector<string> args;
3282 for (uint32_t i = 0; i < length; i++)
3283 {
3284 if (elems[i] >= type0.vecsize)
3285 args.push_back(join(to_expression(vec1), ".", index_to_swizzle(elems[i] - type0.vecsize)));
3286 else
3287 args.push_back(join(to_expression(vec0), ".", index_to_swizzle(elems[i])));
3288 }
3289 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
3290 }
3291 else
3292 {
3293 trivial_forward = !expression_is_forwarded(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003294
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003295 // We only source from first vector, so can use swizzle.
3296 expr += to_expression(vec0);
3297 expr += ".";
3298 for (uint32_t i = 0; i < length; i++)
3299 expr += index_to_swizzle(elems[i]);
3300 if (backend.swizzle_is_function && length > 1)
3301 expr += "()";
3302 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003303
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003304 // A shuffle is trivial in that it doesn't actually *do* anything.
3305 // 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 +01003306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003307 emit_op(result_type, id, expr, should_forward(vec0) && should_forward(vec1), false, trivial_forward);
3308 break;
3309 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003311 // ALU
3312 case OpIsNan:
3313 UFOP(isnan);
3314 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003315
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003316 case OpIsInf:
3317 UFOP(isinf);
3318 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003320 case OpSNegate:
3321 case OpFNegate:
3322 UOP(-);
3323 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003324
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003325 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003326 {
3327 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
3328 auto type = get<SPIRType>(ops[0]).basetype;
3329 BOP_CAST(+, type, true);
3330 break;
3331 }
3332
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003333 case OpFAdd:
3334 BOP(+);
3335 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003336
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003337 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003338 {
3339 auto type = get<SPIRType>(ops[0]).basetype;
3340 BOP_CAST(-, type, true);
3341 break;
3342 }
3343
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003344 case OpFSub:
3345 BOP(-);
3346 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003347
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003348 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003349 {
3350 auto type = get<SPIRType>(ops[0]).basetype;
3351 BOP_CAST(*, type, true);
3352 break;
3353 }
3354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003355 case OpFMul:
3356 case OpMatrixTimesVector:
3357 case OpMatrixTimesScalar:
3358 case OpVectorTimesScalar:
3359 case OpVectorTimesMatrix:
3360 case OpMatrixTimesMatrix:
3361 BOP(*);
3362 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003364 case OpOuterProduct:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003365 BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003366 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003367
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003368 case OpDot:
3369 BFOP(dot);
3370 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003371
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003372 case OpTranspose:
3373 UFOP(transpose);
3374 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003375
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003376 case OpSDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003377 BOP_CAST(/, SPIRType::Int, false);
3378 break;
3379
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003380 case OpUDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003381 BOP_CAST(/, SPIRType::UInt, false);
3382 break;
3383
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003384 case OpFDiv:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003385 BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003386 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003387
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003388 case OpShiftRightLogical:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003389 BOP_CAST(>>, SPIRType::UInt, false);
3390 break;
3391
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003392 case OpShiftRightArithmetic:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003393 BOP_CAST(>>, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003394 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003395
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003396 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003397 {
3398 auto type = get<SPIRType>(ops[0]).basetype;
3399 BOP_CAST(<<, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003400 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003401 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003402
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003403 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003404 {
3405 auto type = get<SPIRType>(ops[0]).basetype;
3406 BOP_CAST(|, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003407 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003408 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003409
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003410 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003411 {
3412 auto type = get<SPIRType>(ops[0]).basetype;
3413 BOP_CAST (^, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003414 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003415 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003417 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003418 {
3419 auto type = get<SPIRType>(ops[0]).basetype;
3420 BOP_CAST(&, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003421 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003422 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003423
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003424 case OpNot:
3425 UOP(~);
3426 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003428 case OpUMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003429 BOP_CAST(%, SPIRType::UInt, false);
3430 break;
3431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003432 case OpSMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003433 BOP_CAST(%, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003434 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003435
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003436 case OpFMod:
3437 BFOP(mod);
3438 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +02003439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003440 // Relational
3441 case OpAny:
3442 UFOP(any);
3443 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003445 case OpAll:
3446 UFOP(all);
3447 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003448
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003449 case OpSelect:
3450 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
3451 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003453 case OpLogicalOr:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003454 BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003455 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003457 case OpLogicalAnd:
3458 BOP(&&);
3459 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003460
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003461 case OpLogicalNot:
3462 UOP(!);
3463 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003464
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003465 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003466 {
3467 if (expression_type(ops[2]).vecsize > 1)
3468 BFOP_CAST(equal, SPIRType::Int, true);
3469 else
3470 BOP_CAST(==, SPIRType::Int, true);
3471 break;
3472 }
3473
3474 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003475 case OpFOrdEqual:
3476 {
3477 if (expression_type(ops[2]).vecsize > 1)
3478 BFOP(equal);
3479 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003480 BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003481 break;
3482 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003483
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003484 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003485 {
3486 if (expression_type(ops[2]).vecsize > 1)
3487 BFOP_CAST(notEqual, SPIRType::Int, true);
3488 else
3489 BOP_CAST(!=, SPIRType::Int, true);
3490 break;
3491 }
3492
3493 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003494 case OpFOrdNotEqual:
3495 {
3496 if (expression_type(ops[2]).vecsize > 1)
3497 BFOP(notEqual);
3498 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003499 BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003500 break;
3501 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003503 case OpUGreaterThan:
3504 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003505 {
3506 auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
3507 if (expression_type(ops[2]).vecsize > 1)
3508 BFOP_CAST(greaterThan, type, false);
3509 else
3510 BOP_CAST(>, type, false);
3511 break;
3512 }
3513
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003514 case OpFOrdGreaterThan:
3515 {
3516 if (expression_type(ops[2]).vecsize > 1)
3517 BFOP(greaterThan);
3518 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003519 BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003520 break;
3521 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003522
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003523 case OpUGreaterThanEqual:
3524 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003525 {
3526 auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
3527 if (expression_type(ops[2]).vecsize > 1)
3528 BFOP_CAST(greaterThanEqual, type, false);
3529 else
3530 BOP_CAST(>=, type, false);
3531 break;
3532 }
3533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003534 case OpFOrdGreaterThanEqual:
3535 {
3536 if (expression_type(ops[2]).vecsize > 1)
3537 BFOP(greaterThanEqual);
3538 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003539 BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003540 break;
3541 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003542
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003543 case OpULessThan:
3544 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003545 {
3546 auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
3547 if (expression_type(ops[2]).vecsize > 1)
3548 BFOP_CAST(lessThan, type, false);
3549 else
3550 BOP_CAST(<, type, false);
3551 break;
3552 }
3553
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003554 case OpFOrdLessThan:
3555 {
3556 if (expression_type(ops[2]).vecsize > 1)
3557 BFOP(lessThan);
3558 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003559 BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003560 break;
3561 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003562
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003563 case OpULessThanEqual:
3564 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003565 {
3566 auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
3567 if (expression_type(ops[2]).vecsize > 1)
3568 BFOP_CAST(lessThanEqual, type, false);
3569 else
3570 BOP_CAST(<=, type, false);
3571 break;
3572 }
3573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003574 case OpFOrdLessThanEqual:
3575 {
3576 if (expression_type(ops[2]).vecsize > 1)
3577 BFOP(lessThanEqual);
3578 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003579 BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003580 break;
3581 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003582
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003583 // Conversion
3584 case OpConvertFToU:
3585 case OpConvertFToS:
3586 case OpConvertSToF:
3587 case OpConvertUToF:
3588 case OpUConvert:
3589 case OpSConvert:
3590 case OpFConvert:
3591 {
3592 uint32_t result_type = ops[0];
3593 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003595 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
3596 emit_unary_func_op(result_type, id, ops[2], func.c_str());
3597 break;
3598 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003599
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003600 case OpBitcast:
3601 {
3602 uint32_t result_type = ops[0];
3603 uint32_t id = ops[1];
3604 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003605
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003606 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003607 emit_unary_func_op(result_type, id, arg, op.c_str());
3608 break;
3609 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003610
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02003611 case OpQuantizeToF16:
3612 {
3613 uint32_t result_type = ops[0];
3614 uint32_t id = ops[1];
3615 uint32_t arg = ops[2];
3616
3617 string op;
3618 auto &type = get<SPIRType>(result_type);
3619
3620 switch (type.vecsize)
3621 {
3622 case 1:
3623 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
3624 break;
3625 case 2:
3626 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
3627 break;
3628 case 3:
3629 {
3630 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
3631 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
3632 op = join("vec3(", op0, ", ", op1, ")");
3633 break;
3634 }
3635 case 4:
3636 {
3637 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
3638 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
3639 op = join("vec4(", op0, ", ", op1, ")");
3640 break;
3641 }
3642 default:
3643 throw CompilerError("Illegal argument to OpQuantizeToF16.");
3644 }
3645
3646 emit_op(result_type, id, op, should_forward(arg), false);
3647 break;
3648 }
3649
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003650 // Derivatives
3651 case OpDPdx:
3652 UFOP(dFdx);
3653 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003655 case OpDPdy:
3656 UFOP(dFdy);
3657 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003658
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003659 case OpFwidth:
3660 UFOP(fwidth);
3661 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003662
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003663 // Bitfield
3664 case OpBitFieldInsert:
3665 QFOP(bitfieldInsert);
3666 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003667
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003668 case OpBitFieldSExtract:
3669 case OpBitFieldUExtract:
3670 QFOP(bitfieldExtract);
3671 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003672
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003673 case OpBitReverse:
3674 UFOP(bitfieldReverse);
3675 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003676
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003677 case OpBitCount:
3678 UFOP(bitCount);
3679 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003680
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003681 // Atomics
3682 case OpAtomicExchange:
3683 {
3684 uint32_t result_type = ops[0];
3685 uint32_t id = ops[1];
3686 uint32_t ptr = ops[2];
3687 // Ignore semantics for now, probably only relevant to CL.
3688 uint32_t val = ops[5];
3689 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
3690 forced_temporaries.insert(id);
3691 emit_binary_func_op(result_type, id, ptr, val, op);
3692 flush_all_atomic_capable_variables();
3693 break;
3694 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003695
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003696 case OpAtomicCompareExchange:
3697 {
3698 uint32_t result_type = ops[0];
3699 uint32_t id = ops[1];
3700 uint32_t ptr = ops[2];
3701 uint32_t val = ops[6];
3702 uint32_t comp = ops[7];
3703 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003705 forced_temporaries.insert(id);
3706 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
3707 flush_all_atomic_capable_variables();
3708 break;
3709 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003711 case OpAtomicLoad:
3712 flush_all_atomic_capable_variables();
3713 // FIXME: Image?
3714 UFOP(atomicCounter);
3715 register_read(ops[1], ops[2], should_forward(ops[2]));
3716 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003717
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003718 // OpAtomicStore unimplemented. Not sure what would use that.
3719 // OpAtomicLoad seems to only be relevant for atomic counters.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003720
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003721 case OpAtomicIIncrement:
3722 forced_temporaries.insert(ops[1]);
3723 // FIXME: Image?
3724 UFOP(atomicCounterIncrement);
3725 flush_all_atomic_capable_variables();
3726 register_read(ops[1], ops[2], should_forward(ops[2]));
3727 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003728
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003729 case OpAtomicIDecrement:
3730 forced_temporaries.insert(ops[1]);
3731 // FIXME: Image?
3732 UFOP(atomicCounterDecrement);
3733 flush_all_atomic_capable_variables();
3734 register_read(ops[1], ops[2], should_forward(ops[2]));
3735 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003736
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003737 case OpAtomicIAdd:
3738 {
3739 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3740 forced_temporaries.insert(ops[1]);
3741 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3742 flush_all_atomic_capable_variables();
3743 register_read(ops[1], ops[2], should_forward(ops[2]));
3744 break;
3745 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003746
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003747 case OpAtomicISub:
3748 {
3749 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3750 forced_temporaries.insert(ops[1]);
3751 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_expression(ops[5]), ")");
3752 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]), false);
3753 flush_all_atomic_capable_variables();
3754 register_read(ops[1], ops[2], should_forward(ops[2]));
3755 break;
3756 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003757
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003758 case OpAtomicSMin:
3759 case OpAtomicUMin:
3760 {
3761 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
3762 forced_temporaries.insert(ops[1]);
3763 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3764 flush_all_atomic_capable_variables();
3765 register_read(ops[1], ops[2], should_forward(ops[2]));
3766 break;
3767 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003769 case OpAtomicSMax:
3770 case OpAtomicUMax:
3771 {
3772 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
3773 forced_temporaries.insert(ops[1]);
3774 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3775 flush_all_atomic_capable_variables();
3776 register_read(ops[1], ops[2], should_forward(ops[2]));
3777 break;
3778 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003780 case OpAtomicAnd:
3781 {
3782 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
3783 forced_temporaries.insert(ops[1]);
3784 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3785 flush_all_atomic_capable_variables();
3786 register_read(ops[1], ops[2], should_forward(ops[2]));
3787 break;
3788 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003789
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003790 case OpAtomicOr:
3791 {
3792 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
3793 forced_temporaries.insert(ops[1]);
3794 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3795 flush_all_atomic_capable_variables();
3796 register_read(ops[1], ops[2], should_forward(ops[2]));
3797 break;
3798 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003799
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003800 case OpAtomicXor:
3801 {
3802 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
3803 forced_temporaries.insert(ops[1]);
3804 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3805 flush_all_atomic_capable_variables();
3806 register_read(ops[1], ops[2], should_forward(ops[2]));
3807 break;
3808 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003809
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003810 // Geometry shaders
3811 case OpEmitVertex:
3812 statement("EmitVertex();");
3813 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003814
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003815 case OpEndPrimitive:
3816 statement("EndPrimitive();");
3817 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003819 case OpEmitStreamVertex:
3820 statement("EmitStreamVertex();");
3821 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003823 case OpEndStreamPrimitive:
3824 statement("EndStreamPrimitive();");
3825 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003826
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003827 // Textures
3828 case OpImageSampleImplicitLod:
3829 case OpImageSampleExplicitLod:
3830 case OpImageSampleProjImplicitLod:
3831 case OpImageSampleProjExplicitLod:
3832 case OpImageSampleDrefImplicitLod:
3833 case OpImageSampleDrefExplicitLod:
3834 case OpImageSampleProjDrefImplicitLod:
3835 case OpImageSampleProjDrefExplicitLod:
3836 case OpImageFetch:
3837 case OpImageGather:
3838 case OpImageDrefGather:
3839 // Gets a bit hairy, so move this to a separate instruction.
3840 emit_texture_op(instruction);
3841 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003842
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003843 case OpImage:
3844 {
3845 uint32_t result_type = ops[0];
3846 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02003847 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, false);
3848
3849 // When using the image, we need to know which variable it is actually loaded from.
3850 auto *var = maybe_get_backing_variable(ops[2]);
3851 e.loaded_from = var ? var->self : 0;
3852 break;
3853 }
3854
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02003855 case OpImageQueryLod:
3856 {
3857 if (!options.es && options.version < 400)
3858 {
3859 require_extension("GL_ARB_texture_query_lod");
3860 // For some reason, the ARB spec is all-caps.
3861 BFOP(textureQueryLOD);
3862 }
3863 else if (options.es)
3864 throw CompilerError("textureQueryLod not supported in ES profile.");
3865 else
3866 BFOP(textureQueryLod);
3867 break;
3868 }
3869
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02003870 case OpImageQueryLevels:
3871 {
3872 if (!options.es && options.version < 430)
3873 require_extension("GL_ARB_texture_query_levels");
3874 if (options.es)
3875 throw CompilerError("textureQueryLevels not supported in ES profile.");
3876 UFOP(textureQueryLevels);
3877 break;
3878 }
3879
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02003880 case OpImageQuerySamples:
3881 {
3882 auto *var = maybe_get_backing_variable(ops[2]);
3883 if (!var)
3884 throw CompilerError(
3885 "Bug. OpImageQuerySamples must have a backing variable so we know if the image is sampled or not.");
3886
3887 auto &type = get<SPIRType>(var->basetype);
3888 bool image = type.image.sampled == 2;
3889 if (image)
3890 UFOP(imageSamples);
3891 else
3892 UFOP(textureSamples);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003893 break;
3894 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003895
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003896 case OpSampledImage:
3897 {
3898 uint32_t result_type = ops[0];
3899 uint32_t id = ops[1];
3900 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
3901 break;
3902 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +02003903
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003904 case OpImageQuerySizeLod:
3905 BFOP(textureSize);
3906 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003907
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003908 // Image load/store
3909 case OpImageRead:
3910 {
3911 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
3912 // not adding the proper qualifiers.
3913 // If it turns out we need to read the image after all, remove the qualifier and recompile.
3914 auto *var = maybe_get_backing_variable(ops[2]);
3915 if (var)
3916 {
3917 auto &flags = meta.at(var->self).decoration.decoration_flags;
3918 if (flags & (1ull << DecorationNonReadable))
3919 {
3920 flags &= ~(1ull << DecorationNonReadable);
3921 force_recompile = true;
3922 }
3923 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003924
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003925 uint32_t result_type = ops[0];
3926 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003927
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003928 bool pure;
3929 string imgexpr;
3930 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003931
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02003932 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003933 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02003934 if (type.image.ms)
3935 throw CompilerError("Trying to remap multisampled image to variable, this is not possible.");
3936
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003937 auto itr =
3938 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 +01003939
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003940 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02003941 {
3942 // For non-PLS inputs, we rely on subpass type remapping information to get it right
3943 // since ImageRead always returns 4-component vectors and the backing type is opaque.
3944 if (!var->remapped_components)
3945 throw CompilerError("subpassInput was remapped, but remap_components is not set correctly.");
3946 imgexpr = remap_swizzle(result_type, var->remapped_components, ops[2]);
3947 }
3948 else
3949 {
3950 // PLS input could have different number of components than what the SPIR expects, swizzle to
3951 // the appropriate vector size.
3952 uint32_t components = pls_format_to_components(itr->format);
3953 imgexpr = remap_swizzle(result_type, components, ops[2]);
3954 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003955 pure = true;
3956 }
3957 else if (type.image.dim == DimSubpassData)
3958 {
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003959 if (options.vulkan_semantics)
3960 {
3961 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02003962 if (type.image.ms)
3963 {
3964 uint32_t operands = ops[4];
3965 if (operands != ImageOperandsSampleMask || length != 6)
3966 throw CompilerError(
3967 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
3968
3969 uint32_t samples = ops[5];
3970 imgexpr = join("subpassLoad(", to_expression(ops[2]), ", ", to_expression(samples), ")");
3971 }
3972 else
3973 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003974 }
3975 else
3976 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02003977 if (type.image.ms)
3978 {
3979 uint32_t operands = ops[4];
3980 if (operands != ImageOperandsSampleMask || length != 6)
3981 throw CompilerError(
3982 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
3983
3984 uint32_t samples = ops[5];
3985 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
3986 to_expression(samples), ")");
3987 }
3988 else
3989 {
3990 // Implement subpass loads via texture barrier style sampling.
3991 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
3992 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003993 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003994 pure = true;
3995 }
3996 else
3997 {
3998 // Plain image load/store.
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02003999 if (type.image.ms)
4000 {
4001 uint32_t operands = ops[4];
4002 if (operands != ImageOperandsSampleMask || length != 6)
4003 throw CompilerError(
4004 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
4005
4006 uint32_t samples = ops[5];
4007 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
4008 to_expression(samples), ")");
4009 }
4010 else
4011 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004012 pure = false;
4013 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004014
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004015 if (var && var->forwardable)
4016 {
4017 auto &e = emit_op(result_type, id, imgexpr, true, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004018
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004019 // We only need to track dependencies if we're reading from image load/store.
4020 if (!pure)
4021 {
4022 e.loaded_from = var->self;
4023 var->dependees.push_back(id);
4024 }
4025 }
4026 else
4027 emit_op(result_type, id, imgexpr, false, false);
4028 break;
4029 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004030
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004031 case OpImageTexelPointer:
4032 {
4033 uint32_t result_type = ops[0];
4034 uint32_t id = ops[1];
4035 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 +01004036
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02004037 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004038 auto *var = maybe_get_backing_variable(ops[2]);
4039 e.loaded_from = var ? var->self : 0;
4040 break;
4041 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004043 case OpImageWrite:
4044 {
4045 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
4046 // not adding the proper qualifiers.
4047 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
4048 auto *var = maybe_get_backing_variable(ops[0]);
4049 if (var)
4050 {
4051 auto &flags = meta.at(var->self).decoration.decoration_flags;
4052 if (flags & (1ull << DecorationNonWritable))
4053 {
4054 flags &= ~(1ull << DecorationNonWritable);
4055 force_recompile = true;
4056 }
4057 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004058
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02004059 auto &type = expression_type(ops[0]);
4060 if (type.image.ms)
4061 {
4062 uint32_t operands = ops[3];
4063 if (operands != ImageOperandsSampleMask || length != 5)
4064 throw CompilerError("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
4065 uint32_t samples = ops[4];
4066 statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(samples),
4067 ", ", to_expression(ops[2]), ");");
4068 }
4069 else
4070 statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]),
4071 ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004073 if (var && variable_storage_is_aliased(*var))
4074 flush_all_aliased_variables();
4075 break;
4076 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004078 case OpImageQuerySize:
4079 {
4080 auto &type = expression_type(ops[2]);
4081 uint32_t result_type = ops[0];
4082 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004083
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004084 if (type.basetype == SPIRType::Image)
4085 {
4086 // The size of an image is always constant.
4087 emit_op(result_type, id, join("imageSize(", to_expression(ops[2]), ")"), true, false);
4088 }
4089 else
4090 throw CompilerError("Invalid type for OpImageQuerySize.");
4091 break;
4092 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004094 // Compute
4095 case OpControlBarrier:
4096 {
4097 // Ignore execution and memory scope.
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004098 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004099 {
4100 uint32_t mem = get<SPIRConstant>(ops[2]).scalar();
4101 if (mem == MemorySemanticsWorkgroupMemoryMask)
4102 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02004103 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004104 statement("memoryBarrier();");
4105 }
4106 statement("barrier();");
4107 break;
4108 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004109
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004110 case OpMemoryBarrier:
4111 {
4112 uint32_t mem = get<SPIRConstant>(ops[1]).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004113
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004114 // We cannot forward any loads beyond the memory barrier.
4115 if (mem)
4116 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004118 if (mem == MemorySemanticsWorkgroupMemoryMask)
4119 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02004120 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004121 statement("memoryBarrier();");
4122 break;
4123 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004124
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004125 case OpExtInst:
4126 {
4127 uint32_t extension_set = ops[2];
4128 if (get<SPIRExtension>(extension_set).ext != SPIRExtension::GLSL)
4129 {
4130 statement("// unimplemented ext op ", instruction.op);
4131 break;
4132 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004133
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004134 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
4135 break;
4136 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004137
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004138 default:
4139 statement("// unimplemented op ", instruction.op);
4140 break;
4141 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004142}
4143
4144string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
4145{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004146 auto &memb = meta[type.self].members;
4147 if (index < memb.size() && !memb[index].alias.empty())
4148 return memb[index].alias;
4149 else
4150 return join("_", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004151}
4152
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004153void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
4154{
4155 auto &memb = meta[type.self].members;
4156 if (index < memb.size() && !memb[index].alias.empty())
4157 {
4158 auto &name = memb[index].alias;
4159 if (name.empty())
4160 return;
4161
4162 // Reserved for temporaries.
4163 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
4164 {
4165 name.clear();
4166 return;
4167 }
4168
4169 update_name_cache(type.member_name_cache, name);
4170 }
4171}
4172
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004173string CompilerGLSL::variable_decl(const SPIRType &type, const std::string &name)
4174{
4175 return join(type_to_glsl(type), " ", name, type_to_array_glsl(type));
4176}
4177
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004178string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index)
4179{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004180 uint64_t memberflags = 0;
4181 auto &memb = meta[type.self].members;
4182 if (index < memb.size())
4183 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004184
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004185 return join(layout_for_member(type, index), flags_to_precision_qualifiers_glsl(membertype, memberflags),
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004186 variable_decl(membertype, to_member_name(type, index)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004187}
4188
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004189const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004190{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004191 if (options.es)
4192 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004193 auto &execution = get_entry_point();
4194
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004195 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004196 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
4197 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
4198 type.basetype != SPIRType::Sampler)
4199 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004200
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004201 if (flags & (1ull << DecorationRelaxedPrecision))
4202 {
4203 bool implied_fmediump = type.basetype == SPIRType::Float &&
4204 options.fragment.default_float_precision == Options::Mediump &&
4205 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004207 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
4208 options.fragment.default_int_precision == Options::Mediump &&
4209 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004210
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004211 return implied_fmediump || implied_imediump ? "" : "mediump ";
4212 }
4213 else
4214 {
4215 bool implied_fhighp =
4216 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
4217 execution.model == ExecutionModelFragment) ||
4218 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004219
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004220 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
4221 ((options.fragment.default_int_precision == Options::Highp &&
4222 execution.model == ExecutionModelFragment) ||
4223 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004224
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004225 return implied_fhighp || implied_ihighp ? "" : "highp ";
4226 }
4227 }
4228 else
4229 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004230}
4231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004232const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004233{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004234 return flags_to_precision_qualifiers_glsl(expression_type(id), meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004235}
4236
4237string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
4238{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004239 auto flags = meta[id].decoration.decoration_flags;
4240 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004241
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004242 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004243
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004244 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
4245 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004246
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004247 res += to_precision_qualifiers_glsl(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004248
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004249 //if (flags & (1ull << DecorationSmooth))
4250 // res += "smooth ";
4251 if (flags & (1ull << DecorationFlat))
4252 res += "flat ";
4253 if (flags & (1ull << DecorationNoPerspective))
4254 res += "noperspective ";
4255 if (flags & (1ull << DecorationPatch))
4256 res += "patch ";
4257 if (flags & (1ull << DecorationSample))
4258 res += "sample ";
4259 if (flags & (1ull << DecorationInvariant))
4260 res += "invariant ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004261
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004262 auto &type = expression_type(id);
4263 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
4264 {
4265 if (flags & (1ull << DecorationNonWritable))
4266 res += "readonly ";
4267 if (flags & (1ull << DecorationNonReadable))
4268 res += "writeonly ";
4269 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004270
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004271 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004272}
4273
4274string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
4275{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004276 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
4277 // Not sure if argument being pointer type should make the argument inout.
4278 auto &type = expression_type(arg.id);
4279 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004280
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004281 if (type.pointer)
4282 {
4283 if (arg.write_count && arg.read_count)
4284 direction = "inout ";
4285 else if (arg.write_count)
4286 direction = "out ";
4287 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004288
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004289 return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004290}
4291
4292string CompilerGLSL::variable_decl(const SPIRVariable &variable)
4293{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004294 // Ignore the pointer type since GLSL doesn't have pointers.
4295 auto &type = get<SPIRType>(variable.basetype);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004296 auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self)));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004297 if (variable.initializer)
4298 res += join(" = ", to_expression(variable.initializer));
4299 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004300}
4301
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004302const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004303{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004304 auto flags = meta[variable.self].decoration.decoration_flags;
4305 if (flags & (1ull << DecorationRelaxedPrecision))
4306 return "mediump ";
4307 else
4308 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004309}
4310
4311string CompilerGLSL::pls_decl(const PlsRemap &var)
4312{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004313 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004315 SPIRType type;
4316 type.vecsize = pls_format_to_components(var.format);
4317 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004318
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004319 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
4320 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004321}
4322
4323string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
4324{
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004325 if (type.array.empty())
4326 return "";
4327
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004328 string res;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004329 for (size_t i = type.array.size(); i; i--)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004330 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004331 auto &size = type.array[i - 1];
4332
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004333 res += "[";
4334 if (size)
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02004335 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004336 res += convert_to_string(size);
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02004337 }
4338 else if (!backend.flexible_member_array_supported)
4339 {
4340 // For runtime-sized arrays, we can work around
4341 // lack of standard support for this by simply having
4342 // a single element array.
4343 //
4344 // Runtime length arrays must always be the last element
4345 // in an interface block.
4346 res += '1';
4347 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004348 res += "]";
4349 }
4350 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004351}
4352
4353string CompilerGLSL::image_type_glsl(const SPIRType &type)
4354{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004355 auto &imagetype = get<SPIRType>(type.image.type);
4356 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004357
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004358 switch (imagetype.basetype)
4359 {
4360 case SPIRType::Int:
4361 res = "i";
4362 break;
4363 case SPIRType::UInt:
4364 res = "u";
4365 break;
4366 default:
4367 break;
4368 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004369
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004370 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02004371 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004372
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004373 // If we're emulating subpassInput with samplers, force sampler2D
4374 // so we don't have to specify format.
4375 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
4376 res += type.image.sampled == 2 ? "image" : "texture";
4377 else
4378 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004379
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004380 switch (type.image.dim)
4381 {
4382 case Dim1D:
4383 res += "1D";
4384 break;
4385 case Dim2D:
4386 res += "2D";
4387 break;
4388 case Dim3D:
4389 res += "3D";
4390 break;
4391 case DimCube:
4392 res += "Cube";
4393 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004394
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004395 case DimBuffer:
4396 if (options.es && options.version < 320)
4397 require_extension("GL_OES_texture_buffer");
4398 else if (!options.es && options.version < 300)
4399 require_extension("GL_EXT_texture_buffer_object");
4400 res += "Buffer";
4401 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004402
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004403 case DimSubpassData:
4404 res += "2D";
4405 break;
4406 default:
4407 throw CompilerError("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
4408 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004409
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02004410 if (type.image.ms)
4411 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004412 if (type.image.arrayed)
4413 res += "Array";
4414 if (type.image.depth)
4415 res += "Shadow";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004417 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004418}
4419
4420string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
4421{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004422 auto e = type_to_glsl(type);
4423 for (uint32_t i = 0; i < type.array.size(); i++)
4424 e += "[]";
4425 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004426}
4427
4428string CompilerGLSL::type_to_glsl(const SPIRType &type)
4429{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004430 // Ignore the pointer type since GLSL doesn't have pointers.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004431
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004432 switch (type.basetype)
4433 {
4434 case SPIRType::Struct:
4435 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004436 if (backend.explicit_struct_type)
4437 return join("struct ", to_name(type.self));
4438 else
4439 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004440
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004441 case SPIRType::Image:
4442 case SPIRType::SampledImage:
4443 return image_type_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004445 case SPIRType::Sampler:
4446 // Not really used.
4447 return "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004448
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004449 case SPIRType::Void:
4450 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004451
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004452 default:
4453 break;
4454 }
4455
4456 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
4457 {
4458 switch (type.basetype)
4459 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004460 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004461 return "bool";
4462 case SPIRType::Int:
4463 return backend.basic_int_type;
4464 case SPIRType::UInt:
4465 return backend.basic_uint_type;
4466 case SPIRType::AtomicCounter:
4467 return "atomic_uint";
4468 case SPIRType::Float:
4469 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004470 case SPIRType::Double:
4471 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004472 case SPIRType::Int64:
4473 return "int64_t";
4474 case SPIRType::UInt64:
4475 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004476 default:
4477 return "???";
4478 }
4479 }
4480 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
4481 {
4482 switch (type.basetype)
4483 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004484 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004485 return join("bvec", type.vecsize);
4486 case SPIRType::Int:
4487 return join("ivec", type.vecsize);
4488 case SPIRType::UInt:
4489 return join("uvec", type.vecsize);
4490 case SPIRType::Float:
4491 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004492 case SPIRType::Double:
4493 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004494 case SPIRType::Int64:
4495 return join("i64vec", type.vecsize);
4496 case SPIRType::UInt64:
4497 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004498 default:
4499 return "???";
4500 }
4501 }
4502 else if (type.vecsize == type.columns) // Simple Matrix builtin
4503 {
4504 switch (type.basetype)
4505 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004506 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004507 return join("bmat", type.vecsize);
4508 case SPIRType::Int:
4509 return join("imat", type.vecsize);
4510 case SPIRType::UInt:
4511 return join("umat", type.vecsize);
4512 case SPIRType::Float:
4513 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004514 case SPIRType::Double:
4515 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004516 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004517 default:
4518 return "???";
4519 }
4520 }
4521 else
4522 {
4523 switch (type.basetype)
4524 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004525 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004526 return join("bmat", type.columns, "x", type.vecsize);
4527 case SPIRType::Int:
4528 return join("imat", type.columns, "x", type.vecsize);
4529 case SPIRType::UInt:
4530 return join("umat", type.columns, "x", type.vecsize);
4531 case SPIRType::Float:
4532 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004533 case SPIRType::Double:
4534 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004535 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004536 default:
4537 return "???";
4538 }
4539 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004540}
4541
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004542void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004543{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004544 auto &name = meta[id].decoration.alias;
4545 if (name.empty())
4546 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004547
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004548 // Reserved for temporaries.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004549 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004550 {
4551 name.clear();
4552 return;
4553 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004554
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004555 update_name_cache(variables, name);
4556}
4557
4558void CompilerGLSL::add_local_variable_name(uint32_t id)
4559{
4560 add_variable(local_variable_names, id);
4561}
4562
4563void CompilerGLSL::add_resource_name(uint32_t id)
4564{
4565 add_variable(resource_names, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004566}
4567
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +02004568void CompilerGLSL::add_header_line(const std::string &line)
4569{
4570 header_lines.push_back(line);
4571}
4572
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004573void CompilerGLSL::require_extension(const string &ext)
4574{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004575 if (forced_extensions.find(ext) == end(forced_extensions))
4576 {
4577 forced_extensions.insert(ext);
4578 force_recompile = true;
4579 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004580}
4581
4582bool CompilerGLSL::check_atomic_image(uint32_t id)
4583{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004584 auto &type = expression_type(id);
4585 if (type.storage == StorageClassImage)
4586 {
4587 if (options.es && options.version < 320)
4588 require_extension("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004589
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004590 auto *var = maybe_get_backing_variable(id);
4591 if (var)
4592 {
4593 auto &flags = meta.at(var->self).decoration.decoration_flags;
4594 if (flags & ((1ull << DecorationNonWritable) | (1ull << DecorationNonReadable)))
4595 {
4596 flags &= ~(1ull << DecorationNonWritable);
4597 flags &= ~(1ull << DecorationNonReadable);
4598 force_recompile = true;
4599 }
4600 }
4601 return true;
4602 }
4603 else
4604 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004605}
4606
4607void CompilerGLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_flags)
4608{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004609 // Avoid shadow declarations.
4610 local_variable_names = resource_names;
4611
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004612 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004613
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004614 auto &type = get<SPIRType>(func.return_type);
4615 decl += flags_to_precision_qualifiers_glsl(type, return_flags);
4616 decl += type_to_glsl(type);
4617 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004618
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004619 if (func.self == entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004620 {
4621 decl += "main";
4622 processing_entry_point = true;
4623 }
4624 else
4625 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004626
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004627 decl += "(";
4628 for (auto &arg : func.arguments)
4629 {
4630 // Might change the variable name if it already exists in this function.
4631 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
4632 // to use same name for variables.
4633 // 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 +02004634 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004636 decl += argument_decl(arg);
4637 if (&arg != &func.arguments.back())
4638 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004639
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004640 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
4641 auto *var = maybe_get<SPIRVariable>(arg.id);
4642 if (var)
4643 var->parameter = &arg;
4644 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004646 decl += ")";
4647 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004648}
4649
4650void CompilerGLSL::emit_function(SPIRFunction &func, uint64_t return_flags)
4651{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004652 // Avoid potential cycles.
4653 if (func.active)
4654 return;
4655 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004657 // If we depend on a function, emit that function before we emit our own function.
4658 for (auto block : func.blocks)
4659 {
4660 auto &b = get<SPIRBlock>(block);
4661 for (auto &i : b.ops)
4662 {
4663 auto ops = stream(i);
4664 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004665
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004666 if (op == OpFunctionCall)
4667 {
4668 // Recursively emit functions which are called.
4669 uint32_t id = ops[2];
4670 emit_function(get<SPIRFunction>(id), meta[ops[1]].decoration.decoration_flags);
4671 }
4672 }
4673 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004675 emit_function_prototype(func, return_flags);
4676 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004677
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004678 current_function = &func;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004680 for (auto &v : func.local_variables)
4681 {
4682 auto &var = get<SPIRVariable>(v);
4683 if (expression_is_lvalue(v))
4684 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004685 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004687 if (var.initializer)
4688 statement(variable_decl(var), ";");
4689 else
4690 {
4691 // Don't declare variable until first use to declutter the GLSL output quite a lot.
4692 // If we don't touch the variable before first branch,
4693 // declare it then since we need variable declaration to be in top scope.
4694 var.deferred_declaration = true;
4695 }
4696 }
4697 else
4698 {
4699 // HACK: SPIRV likes to use samplers and images as local variables, but GLSL does not allow
4700 // this. For these types (non-lvalue), we enforce forwarding through a shadowed variable.
4701 // This means that when we OpStore to these variables, we just write in the expression ID directly.
4702 // This breaks any kind of branching, since the variable must be statically assigned.
4703 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
4704 var.statically_assigned = true;
4705 }
4706 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004707
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004708 auto &entry_block = get<SPIRBlock>(func.entry_block);
4709 entry_block.loop_dominator = SPIRBlock::NoDominator;
4710 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004711
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004712 end_scope();
4713 processing_entry_point = false;
4714 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004715}
4716
4717void CompilerGLSL::emit_fixup()
4718{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004719 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004720 if (execution.model == ExecutionModelVertex && options.vertex.fixup_clipspace)
4721 {
4722 const char *suffix = backend.float_literal_suffix ? "f" : "";
4723 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
4724 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004725}
4726
4727bool CompilerGLSL::flush_phi_required(uint32_t from, uint32_t to)
4728{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004729 auto &child = get<SPIRBlock>(to);
4730 for (auto &phi : child.phi_variables)
4731 if (phi.parent == from)
4732 return true;
4733 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004734}
4735
4736void CompilerGLSL::flush_phi(uint32_t from, uint32_t to)
4737{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004738 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004740 for (auto &phi : child.phi_variables)
4741 if (phi.parent == from)
4742 statement(to_expression(phi.function_variable), " = ", to_expression(phi.local_variable), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004743}
4744
4745void CompilerGLSL::branch(uint32_t from, uint32_t to)
4746{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004747 flush_phi(from, to);
4748 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004749
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004750 // This is only a continue if we branch to our loop dominator.
4751 if (loop_blocks.find(to) != end(loop_blocks) && get<SPIRBlock>(from).loop_dominator == to)
4752 {
4753 // This can happen if we had a complex continue block which was emitted.
4754 // Once the continue block tries to branch to the loop header, just emit continue;
4755 // and end the chain here.
4756 statement("continue;");
4757 }
4758 else if (is_continue(to))
4759 {
4760 auto &to_block = get<SPIRBlock>(to);
4761 if (to_block.complex_continue)
4762 {
4763 // Just emit the whole block chain as is.
4764 auto usage_counts = expression_usage_counts;
4765 auto invalid = invalid_expressions;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004766
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004767 emit_block_chain(to_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004769 // Expression usage counts and invalid expressions
4770 // are moot after returning from the continue block.
4771 // Since we emit the same block multiple times,
4772 // we don't want to invalidate ourselves.
4773 expression_usage_counts = usage_counts;
4774 invalid_expressions = invalid;
4775 }
4776 else
4777 {
4778 auto &from_block = get<SPIRBlock>(from);
4779 auto &dominator = get<SPIRBlock>(from_block.loop_dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004780
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004781 // For non-complex continue blocks, we implicitly branch to the continue block
4782 // by having the continue block be part of the loop header in for (; ; continue-block).
4783 bool outside_control_flow = block_is_outside_flow_control_from_block(dominator, from_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004784
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004785 // Some simplification for for-loops. We always end up with a useless continue;
4786 // statement since we branch to a loop block.
4787 // Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block,
4788 // we can avoid writing out an explicit continue statement.
4789 // Similar optimization to return statements if we know we're outside flow control.
4790 if (!outside_control_flow)
4791 statement("continue;");
4792 }
4793 }
4794 else if (is_break(to))
4795 statement("break;");
4796 else if (!is_conditional(to))
4797 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004798}
4799
4800void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block)
4801{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004802 // If we branch directly to a selection merge target, we don't really need a code path.
4803 bool true_sub = !is_conditional(true_block);
4804 bool false_sub = !is_conditional(false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004806 if (true_sub)
4807 {
4808 statement("if (", to_expression(cond), ")");
4809 begin_scope();
4810 branch(from, true_block);
4811 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004812
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004813 if (false_sub)
4814 {
4815 statement("else");
4816 begin_scope();
4817 branch(from, false_block);
4818 end_scope();
4819 }
4820 else if (flush_phi_required(from, false_block))
4821 {
4822 statement("else");
4823 begin_scope();
4824 flush_phi(from, false_block);
4825 end_scope();
4826 }
4827 }
4828 else if (false_sub && !true_sub)
4829 {
4830 // Only need false path, use negative conditional.
4831 statement("if (!", to_expression(cond), ")");
4832 begin_scope();
4833 branch(from, false_block);
4834 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004836 if (flush_phi_required(from, true_block))
4837 {
4838 statement("else");
4839 begin_scope();
4840 flush_phi(from, true_block);
4841 end_scope();
4842 }
4843 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004844}
4845
4846void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
4847{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004848 // Propagate down the loop dominator block, so that dominated blocks can back trace.
4849 if (block.merge == SPIRBlock::MergeLoop || block.loop_dominator)
4850 {
4851 uint32_t dominator = block.merge == SPIRBlock::MergeLoop ? block.self : block.loop_dominator;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004852
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02004853 auto set_dominator = [this](uint32_t self, uint32_t new_dominator) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004854 auto &dominated_block = this->get<SPIRBlock>(self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004855
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004856 // If we already have a loop dominator, we're trying to break out to merge targets
4857 // which should not update the loop dominator.
4858 if (!dominated_block.loop_dominator)
4859 dominated_block.loop_dominator = new_dominator;
4860 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004861
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004862 // After merging a loop, we inherit the loop dominator always.
4863 if (block.merge_block)
4864 set_dominator(block.merge_block, block.loop_dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004866 if (block.true_block)
4867 set_dominator(block.true_block, dominator);
4868 if (block.false_block)
4869 set_dominator(block.false_block, dominator);
4870 if (block.next_block)
4871 set_dominator(block.next_block, dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004872
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004873 for (auto &c : block.cases)
4874 set_dominator(c.block, dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004875
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004876 // In older glslang output continue_block can be == loop header.
4877 if (block.continue_block && block.continue_block != block.self)
4878 set_dominator(block.continue_block, dominator);
4879 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004880}
4881
4882// FIXME: This currently cannot handle complex continue blocks
4883// as in do-while.
4884// This should be seen as a "trivial" continue block.
4885string CompilerGLSL::emit_continue_block(uint32_t continue_block)
4886{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004887 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004888
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004889 // While emitting the continue block, declare_temporary will check this
4890 // if we have to emit temporaries.
4891 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004892
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004893 vector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004894
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004895 // Capture all statements into our list.
4896 auto *old = redirect_statement;
4897 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004898
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004899 // Stamp out all blocks one after each other.
4900 while (loop_blocks.find(block->self) == end(loop_blocks))
4901 {
4902 propagate_loop_dominators(*block);
4903 // Write out all instructions we have in this block.
4904 for (auto &op : block->ops)
4905 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004906
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004907 // For plain branchless for/while continue blocks.
4908 if (block->next_block)
4909 {
4910 flush_phi(continue_block, block->next_block);
4911 block = &get<SPIRBlock>(block->next_block);
4912 }
4913 // For do while blocks. The last block will be a select block.
4914 else if (block->true_block)
4915 {
4916 flush_phi(continue_block, block->true_block);
4917 block = &get<SPIRBlock>(block->true_block);
4918 }
4919 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004920
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004921 // Restore old pointer.
4922 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004923
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004924 // Somewhat ugly, strip off the last ';' since we use ',' instead.
4925 // Ideally, we should select this behavior in statement().
4926 for (auto &s : statements)
4927 {
4928 if (!s.empty() && s.back() == ';')
4929 s.pop_back();
4930 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004931
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004932 current_continue_block = nullptr;
4933 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004934}
4935
4936bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
4937{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004938 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004939
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004940 if (method == SPIRBlock::MergeToSelectForLoop)
4941 {
4942 uint32_t current_count = statement_count;
4943 // If we're trying to create a true for loop,
4944 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4945 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4946 for (auto &op : block.ops)
4947 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004948
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004949 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004950
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004951 // This can work! We only did trivial things which could be forwarded in block body!
4952 if (current_count == statement_count && condition_is_temporary)
4953 {
4954 switch (continue_type)
4955 {
4956 case SPIRBlock::ForLoop:
4957 statement("for (; ", to_expression(block.condition), "; ", emit_continue_block(block.continue_block),
4958 ")");
4959 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004960
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004961 case SPIRBlock::WhileLoop:
4962 statement("while (", to_expression(block.condition), ")");
4963 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004964
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004965 default:
4966 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
4967 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004968
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004969 begin_scope();
4970 return true;
4971 }
4972 else
4973 {
4974 block.disable_block_optimization = true;
4975 force_recompile = true;
4976 begin_scope(); // We'll see an end_scope() later.
4977 return false;
4978 }
4979 }
4980 else if (method == SPIRBlock::MergeToDirectForLoop)
4981 {
4982 uint32_t current_count = statement_count;
4983 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004985 // If we're trying to create a true for loop,
4986 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4987 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4988 for (auto &op : child.ops)
4989 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004990
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004991 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004992
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004993 if (current_count == statement_count && condition_is_temporary)
4994 {
4995 propagate_loop_dominators(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004996
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004997 switch (continue_type)
4998 {
4999 case SPIRBlock::ForLoop:
5000 statement("for (; ", to_expression(child.condition), "; ", emit_continue_block(block.continue_block),
5001 ")");
5002 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005003
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005004 case SPIRBlock::WhileLoop:
5005 statement("while (", to_expression(child.condition), ")");
5006 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005007
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005008 default:
5009 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
5010 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005011
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005012 begin_scope();
5013 branch(child.self, child.true_block);
5014 return true;
5015 }
5016 else
5017 {
5018 block.disable_block_optimization = true;
5019 force_recompile = true;
5020 begin_scope(); // We'll see an end_scope() later.
5021 return false;
5022 }
5023 }
5024 else
5025 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005026}
5027
5028void CompilerGLSL::flush_undeclared_variables()
5029{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005030 // Declare undeclared variables.
5031 if (current_function->flush_undeclared)
5032 {
5033 for (auto &v : current_function->local_variables)
5034 {
5035 auto &var = get<SPIRVariable>(v);
5036 if (var.deferred_declaration)
5037 statement(variable_decl(var), ";");
5038 var.deferred_declaration = false;
5039 }
5040 current_function->flush_undeclared = false;
5041 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005042}
5043
5044void CompilerGLSL::emit_block_chain(SPIRBlock &block)
5045{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005046 propagate_loop_dominators(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005047
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005048 bool select_branch_to_true_block = false;
5049 bool skip_direct_branch = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005050
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005051 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
5052 for (auto &tmp : block.declare_temporary)
5053 {
5054 auto flags = meta[tmp.second].decoration.decoration_flags;
5055 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02005056 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005057 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005058
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005059 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
5060 if (block.continue_block)
5061 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005062
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005063 // This is the older loop behavior in glslang which branches to loop body directly from the loop header.
5064 if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
5065 {
5066 flush_undeclared_variables();
5067 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
5068 {
5069 // The body of while, is actually just the true block, so always branch there
5070 // unconditionally.
5071 select_branch_to_true_block = true;
5072 }
5073 }
5074 // This is the newer loop behavior in glslang which branches from Loop header directly to
5075 // a new block, which in turn has a OpBranchSelection without a selection merge.
5076 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
5077 {
5078 flush_undeclared_variables();
5079 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
5080 skip_direct_branch = true;
5081 }
5082 else if (continue_type == SPIRBlock::DoWhileLoop)
5083 {
5084 statement("do");
5085 begin_scope();
5086 for (auto &op : block.ops)
5087 emit_instruction(op);
5088 }
5089 else if (block.merge == SPIRBlock::MergeLoop)
5090 {
5091 flush_undeclared_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005092
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005093 // We have a generic loop without any distinguishable pattern like for, while or do while.
5094 get<SPIRBlock>(block.continue_block).complex_continue = true;
5095 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005096
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005097 statement("for (;;)");
5098 begin_scope();
5099 for (auto &op : block.ops)
5100 emit_instruction(op);
5101 }
5102 else
5103 {
5104 for (auto &op : block.ops)
5105 emit_instruction(op);
5106 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005107
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005108 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005109
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005110 // Handle end of block.
5111 switch (block.terminator)
5112 {
5113 case SPIRBlock::Direct:
5114 // True when emitting complex continue block.
5115 if (block.loop_dominator == block.next_block)
5116 {
5117 branch(block.self, block.next_block);
5118 emit_next_block = false;
5119 }
5120 // True if MergeToDirectForLoop succeeded.
5121 else if (skip_direct_branch)
5122 emit_next_block = false;
5123 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
5124 {
5125 branch(block.self, block.next_block);
5126 emit_next_block = false;
5127 }
5128 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005129
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005130 case SPIRBlock::Select:
5131 // True if MergeToSelectForLoop succeeded.
5132 if (select_branch_to_true_block)
5133 branch(block.self, block.true_block);
5134 else
5135 {
5136 flush_undeclared_variables();
5137 branch(block.self, block.condition, block.true_block, block.false_block);
5138 }
5139 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005140
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005141 case SPIRBlock::MultiSelect:
5142 {
5143 flush_undeclared_variables();
5144 auto &type = expression_type(block.condition);
5145 bool uint32_t_case = type.basetype == SPIRType::UInt;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005146
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005147 statement("switch (", to_expression(block.condition), ")");
5148 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005149
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005150 for (auto &c : block.cases)
5151 {
5152 auto case_value =
5153 uint32_t_case ? convert_to_string(uint32_t(c.value)) : convert_to_string(int32_t(c.value));
5154 statement("case ", case_value, ":");
5155 begin_scope();
5156 branch(block.self, c.block);
5157 end_scope();
5158 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005159
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005160 if (block.default_block != block.next_block)
5161 {
5162 statement("default:");
5163 begin_scope();
5164 if (is_break(block.default_block))
5165 throw CompilerError("Cannot break; out of a switch statement and out of a loop at the same time ...");
5166 branch(block.self, block.default_block);
5167 end_scope();
5168 }
5169 else if (flush_phi_required(block.self, block.next_block))
5170 {
5171 statement("default:");
5172 begin_scope();
5173 flush_phi(block.self, block.next_block);
5174 statement("break;");
5175 end_scope();
5176 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005178 end_scope();
5179 break;
5180 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005181
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005182 case SPIRBlock::Return:
5183 if (processing_entry_point)
5184 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005185
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005186 if (block.return_value)
5187 {
5188 // OpReturnValue can return Undef, so don't emit anything for this case.
5189 if (ids.at(block.return_value).get_type() != TypeUndef)
5190 statement("return ", to_expression(block.return_value), ";");
5191 }
5192 // If this block is the very final block and not called from control flow,
5193 // we do not need an explicit return which looks out of place. Just end the function here.
5194 // In the very weird case of for(;;) { return; } executing return is unconditional,
5195 // but we actually need a return here ...
5196 else if (!block_is_outside_flow_control_from_block(get<SPIRBlock>(current_function->entry_block), block) ||
5197 block.loop_dominator != SPIRBlock::NoDominator)
5198 statement("return;");
5199 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005200
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005201 case SPIRBlock::Kill:
5202 statement("discard;");
5203 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005204
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005205 default:
5206 throw CompilerError("Unimplemented block terminator.");
5207 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005208
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005209 if (block.next_block && emit_next_block)
5210 {
5211 // If we hit this case, we're dealing with an unconditional branch, which means we will output
5212 // that block after this. If we had selection merge, we already flushed phi variables.
5213 if (block.merge != SPIRBlock::MergeSelection)
5214 flush_phi(block.self, block.next_block);
5215 emit_block_chain(get<SPIRBlock>(block.next_block));
5216 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005218 if (block.merge == SPIRBlock::MergeLoop)
5219 {
5220 if (continue_type == SPIRBlock::DoWhileLoop)
5221 {
5222 // Make sure that we run the continue block to get the expressions set, but this
5223 // should become an empty string.
5224 // We have no fallbacks if we cannot forward everything to temporaries ...
5225 auto statements = emit_continue_block(block.continue_block);
5226 if (!statements.empty())
5227 {
5228 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
5229 get<SPIRBlock>(block.continue_block).complex_continue = true;
5230 force_recompile = true;
5231 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005232
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005233 end_scope_decl(join("while (", to_expression(get<SPIRBlock>(block.continue_block).condition), ")"));
5234 }
5235 else
5236 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005238 flush_phi(block.self, block.merge_block);
5239 emit_block_chain(get<SPIRBlock>(block.merge_block));
5240 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005241}
5242
5243void CompilerGLSL::begin_scope()
5244{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005245 statement("{");
5246 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005247}
5248
5249void CompilerGLSL::end_scope()
5250{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005251 if (!indent)
5252 throw CompilerError("Popping empty indent stack.");
5253 indent--;
5254 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005255}
5256
5257void CompilerGLSL::end_scope_decl()
5258{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005259 if (!indent)
5260 throw CompilerError("Popping empty indent stack.");
5261 indent--;
5262 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005263}
5264
5265void CompilerGLSL::end_scope_decl(const string &decl)
5266{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005267 if (!indent)
5268 throw CompilerError("Popping empty indent stack.");
5269 indent--;
5270 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005271}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02005272
5273void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
5274{
5275 // If our variable is remapped, and we rely on type-remapping information as
5276 // well, then we cannot pass the variable as a function parameter.
5277 // Fixing this is non-trivial without stamping out variants of the same function,
5278 // so for now warn about this and suggest workarounds instead.
5279 for (uint32_t i = 0; i < length; i++)
5280 {
5281 auto *var = maybe_get<SPIRVariable>(args[i]);
5282 if (!var || !var->remapped_variable)
5283 continue;
5284
5285 auto &type = get<SPIRType>(var->basetype);
5286 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
5287 {
5288 throw CompilerError("Tried passing a remapped subpassInput variable to a function. "
5289 "This will not work correctly because type-remapping information is lost. "
5290 "To workaround, please consider not passing the subpass input as a function parameter, "
5291 "or use in/out variables instead which do not need type remapping information.");
5292 }
5293 }
5294}