blob: d1e7522f76ec7aba0e4031d48dd1ad6ab622aad2 [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);
1008 if (type.basetype == SPIRType::Image)
1009 {
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
1020void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
1021{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001022 auto &m = meta[var.self].decoration;
1023 uint32_t location = 0;
1024 if (m.decoration_flags & (1ull << DecorationLocation))
1025 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001026
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001027 m.alias = join("gl_FragData[", location, "]");
1028 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 +01001029}
1030
1031void CompilerGLSL::replace_fragment_outputs()
1032{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001033 for (auto &id : ids)
1034 {
1035 if (id.get_type() == TypeVariable)
1036 {
1037 auto &var = id.get<SPIRVariable>();
1038 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001039
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001040 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
1041 var.storage == StorageClassOutput)
1042 replace_fragment_output(var);
1043 }
1044 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001045}
1046
1047string CompilerGLSL::remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr)
1048{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001049 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001050
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001051 if (out_type.vecsize == input_components)
1052 return to_expression(expr);
1053 else if (input_components == 1)
1054 return join(type_to_glsl(out_type), "(", to_expression(expr), ")");
1055 else
1056 {
1057 auto e = to_expression(expr) + ".";
1058 // Just clamp the swizzle index if we have more outputs than inputs.
1059 for (uint32_t c = 0; c < out_type.vecsize; c++)
1060 e += index_to_swizzle(min(c, input_components - 1));
1061 if (backend.swizzle_is_function && out_type.vecsize > 1)
1062 e += "()";
1063 return e;
1064 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001065}
1066
1067void CompilerGLSL::emit_pls()
1068{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001069 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001070 if (execution.model != ExecutionModelFragment)
1071 throw CompilerError("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001073 if (!options.es)
1074 throw CompilerError("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001076 if (options.version < 300)
1077 throw CompilerError("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001078
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001079 if (!pls_inputs.empty())
1080 {
1081 statement("__pixel_local_inEXT _PLSIn");
1082 begin_scope();
1083 for (auto &input : pls_inputs)
1084 statement(pls_decl(input), ";");
1085 end_scope_decl();
1086 statement("");
1087 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001088
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001089 if (!pls_outputs.empty())
1090 {
1091 statement("__pixel_local_outEXT _PLSOut");
1092 begin_scope();
1093 for (auto &output : pls_outputs)
1094 statement(pls_decl(output), ";");
1095 end_scope_decl();
1096 statement("");
1097 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001098}
1099
1100void CompilerGLSL::emit_resources()
1101{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001102 auto &execution = get_entry_point();
1103
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001104 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
1105 // with builtins.
1106 if (execution.model == ExecutionModelFragment && is_legacy())
1107 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001109 // Emit PLS blocks if we have such variables.
1110 if (!pls_inputs.empty() || !pls_outputs.empty())
1111 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001112
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001113 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
1114 // when such variables are instantiated.
1115 for (auto &id : ids)
1116 {
1117 if (id.get_type() == TypeType)
1118 {
1119 auto &type = id.get<SPIRType>();
1120 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
1121 (meta[type.self].decoration.decoration_flags &
1122 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
1123 {
1124 emit_struct(type);
1125 }
1126 }
1127 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001128
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001129 // Output UBOs and SSBOs
1130 for (auto &id : ids)
1131 {
1132 if (id.get_type() == TypeVariable)
1133 {
1134 auto &var = id.get<SPIRVariable>();
1135 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001136
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +02001137 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
1138 !is_builtin_variable(var) && (meta[type.self].decoration.decoration_flags &
1139 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001140 {
1141 emit_buffer_block(var);
1142 }
1143 }
1144 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001145
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001146 // Output push constant blocks
1147 for (auto &id : ids)
1148 {
1149 if (id.get_type() == TypeVariable)
1150 {
1151 auto &var = id.get<SPIRVariable>();
1152 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +02001153 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001154 emit_push_constant_block(var);
1155 }
1156 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001157
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001158 bool emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001159
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001160 // Output Uniform Constants (values, samplers, images, etc).
1161 for (auto &id : ids)
1162 {
1163 if (id.get_type() == TypeVariable)
1164 {
1165 auto &var = id.get<SPIRVariable>();
1166 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001167
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +02001168 if (var.storage != StorageClassFunction && !is_builtin_variable(var) && !var.remapped_variable &&
1169 type.pointer &&
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001170 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
1171 {
1172 emit_uniform(var);
1173 emitted = true;
1174 }
1175 }
1176 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001178 if (emitted)
1179 statement("");
1180 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001181
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001182 // Output in/out interfaces.
1183 for (auto &id : ids)
1184 {
1185 if (id.get_type() == TypeVariable)
1186 {
1187 auto &var = id.get<SPIRVariable>();
1188 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001189
Hans-Kristian Arntzend5dc5f32016-07-05 13:21:26 +02001190 if (var.storage != StorageClassFunction && !is_builtin_variable(var) && !var.remapped_variable &&
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02001191 type.pointer && (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
1192 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001193 {
1194 emit_interface_block(var);
1195 emitted = true;
1196 }
1197 else if (is_builtin_variable(var))
1198 {
1199 // For gl_InstanceIndex emulation on GLES, the API user needs to
1200 // supply this uniform.
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001201 if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001202 {
1203 statement("uniform int SPIRV_Cross_BaseInstance;");
1204 emitted = true;
1205 }
1206 }
1207 }
1208 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001209
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001210 // Global variables.
1211 for (auto global : global_variables)
1212 {
1213 auto &var = get<SPIRVariable>(global);
1214 if (var.storage != StorageClassOutput)
1215 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001216 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001217 statement(variable_decl(var), ";");
1218 emitted = true;
1219 }
1220 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001222 if (emitted)
1223 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001224}
1225
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001226void CompilerGLSL::handle_invalid_expression(uint32_t id)
1227{
1228 auto &expr = get<SPIRExpression>(id);
1229
1230 // This expression has been invalidated in the past.
1231 // Be careful with this expression next pass ...
1232 // Used for OpCompositeInsert forwarding atm.
1233 expr.used_while_invalidated = true;
1234
1235 // We tried to read an invalidated expression.
1236 // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
1237 forced_temporaries.insert(id);
1238 force_recompile = true;
1239}
1240
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001241string CompilerGLSL::to_expression(uint32_t id)
1242{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001243 auto itr = invalid_expressions.find(id);
1244 if (itr != end(invalid_expressions))
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001245 handle_invalid_expression(id);
1246
1247 if (ids[id].get_type() == TypeExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001248 {
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001249 // We might have a more complex chain of dependencies.
1250 // A possible scenario is that we
1251 //
1252 // %1 = OpLoad
1253 // %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
1254 // %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
1255 // 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.
1256 // %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
1257 //
1258 // 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,
1259 // and see that we should not forward reads of the original variable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001260 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001261 for (uint32_t dep : expr.expression_dependencies)
1262 if (invalid_expressions.find(dep) != end(invalid_expressions))
1263 handle_invalid_expression(dep);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001264 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001266 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001268 switch (ids[id].get_type())
1269 {
1270 case TypeExpression:
1271 {
1272 auto &e = get<SPIRExpression>(id);
1273 if (e.base_expression)
1274 return to_expression(e.base_expression) + e.expression;
1275 else
1276 return e.expression;
1277 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001278
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001279 case TypeConstant:
1280 return constant_expression(get<SPIRConstant>(id));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001281
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001282 case TypeVariable:
1283 {
1284 auto &var = get<SPIRVariable>(id);
1285 if (var.statically_assigned)
1286 return to_expression(var.static_expression);
1287 else if (var.deferred_declaration)
1288 {
1289 var.deferred_declaration = false;
1290 return variable_decl(var);
1291 }
1292 else
1293 {
1294 auto &dec = meta[var.self].decoration;
1295 if (dec.builtin)
1296 return builtin_to_glsl(dec.builtin_type);
1297 else
1298 return to_name(id);
1299 }
1300 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001301
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001302 default:
1303 return to_name(id);
1304 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001305}
1306
1307string CompilerGLSL::constant_expression(const SPIRConstant &c)
1308{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001309 if (!c.subconstants.empty())
1310 {
1311 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001312 string res;
1313 if (backend.use_initializer_list)
1314 res = "{ ";
1315 else
1316 res = type_to_glsl_constructor(get<SPIRType>(c.constant_type)) + "(";
1317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001318 for (auto &elem : c.subconstants)
1319 {
1320 res += constant_expression(get<SPIRConstant>(elem));
1321 if (&elem != &c.subconstants.back())
1322 res += ", ";
1323 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001324
1325 res += backend.use_initializer_list ? " }" : ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001326 return res;
1327 }
1328 else if (c.columns() == 1)
1329 {
1330 return constant_expression_vector(c, 0);
1331 }
1332 else
1333 {
1334 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
1335 for (uint32_t col = 0; col < c.columns(); col++)
1336 {
1337 res += constant_expression_vector(c, col);
1338 if (col + 1 < c.columns())
1339 res += ", ";
1340 }
1341 res += ")";
1342 return res;
1343 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001344}
1345
1346string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
1347{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001348 auto type = get<SPIRType>(c.constant_type);
1349 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001350
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001351 string res;
1352 if (c.vector_size() > 1)
1353 res += type_to_glsl(type) + "(";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001355 bool splat = c.vector_size() > 1;
1356 if (splat)
1357 {
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001358 if (type_to_std430_base_size(type) == 8)
1359 {
1360 uint64_t ident = c.scalar_u64(vector, 0);
1361 for (uint32_t i = 1; i < c.vector_size(); i++)
1362 if (ident != c.scalar_u64(vector, i))
1363 splat = false;
1364 }
1365 else
1366 {
1367 uint32_t ident = c.scalar(vector, 0);
1368 for (uint32_t i = 1; i < c.vector_size(); i++)
1369 if (ident != c.scalar(vector, i))
1370 splat = false;
1371 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001372 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001373
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001374 switch (type.basetype)
1375 {
1376 case SPIRType::Float:
1377 if (splat)
1378 {
1379 res += convert_to_string(c.scalar_f32(vector, 0));
1380 if (backend.float_literal_suffix)
1381 res += "f";
1382 }
1383 else
1384 {
1385 for (uint32_t i = 0; i < c.vector_size(); i++)
1386 {
1387 res += convert_to_string(c.scalar_f32(vector, i));
1388 if (backend.float_literal_suffix)
1389 res += "f";
1390 if (i + 1 < c.vector_size())
1391 res += ", ";
1392 }
1393 }
1394 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001395
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001396 case SPIRType::Double:
1397 if (splat)
1398 {
1399 res += convert_to_string(c.scalar_f64(vector, 0));
1400 if (backend.double_literal_suffix)
1401 res += "lf";
1402 }
1403 else
1404 {
1405 for (uint32_t i = 0; i < c.vector_size(); i++)
1406 {
1407 res += convert_to_string(c.scalar_f64(vector, i));
1408 if (backend.double_literal_suffix)
1409 res += "lf";
1410 if (i + 1 < c.vector_size())
1411 res += ", ";
1412 }
1413 }
1414 break;
1415
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02001416 case SPIRType::Int64:
1417 if (splat)
1418 {
1419 res += convert_to_string(c.scalar_i64(vector, 0));
1420 if (backend.long_long_literal_suffix)
1421 res += "ll";
1422 else
1423 res += "l";
1424 }
1425 else
1426 {
1427 for (uint32_t i = 0; i < c.vector_size(); i++)
1428 {
1429 res += convert_to_string(c.scalar_i64(vector, i));
1430 if (backend.long_long_literal_suffix)
1431 res += "ll";
1432 else
1433 res += "l";
1434 if (i + 1 < c.vector_size())
1435 res += ", ";
1436 }
1437 }
1438 break;
1439
1440 case SPIRType::UInt64:
1441 if (splat)
1442 {
1443 res += convert_to_string(c.scalar_u64(vector, 0));
1444 if (backend.long_long_literal_suffix)
1445 res += "ull";
1446 else
1447 res += "ul";
1448 }
1449 else
1450 {
1451 for (uint32_t i = 0; i < c.vector_size(); i++)
1452 {
1453 res += convert_to_string(c.scalar_u64(vector, i));
1454 if (backend.long_long_literal_suffix)
1455 res += "ull";
1456 else
1457 res += "ul";
1458 if (i + 1 < c.vector_size())
1459 res += ", ";
1460 }
1461 }
1462 break;
1463
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001464 case SPIRType::UInt:
1465 if (splat)
1466 {
1467 res += convert_to_string(c.scalar(vector, 0));
1468 if (backend.uint32_t_literal_suffix)
1469 res += "u";
1470 }
1471 else
1472 {
1473 for (uint32_t i = 0; i < c.vector_size(); i++)
1474 {
1475 res += convert_to_string(c.scalar(vector, i));
1476 if (backend.uint32_t_literal_suffix)
1477 res += "u";
1478 if (i + 1 < c.vector_size())
1479 res += ", ";
1480 }
1481 }
1482 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001483
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001484 case SPIRType::Int:
1485 if (splat)
1486 res += convert_to_string(c.scalar_i32(vector, 0));
1487 else
1488 {
1489 for (uint32_t i = 0; i < c.vector_size(); i++)
1490 {
1491 res += convert_to_string(c.scalar_i32(vector, i));
1492 if (i + 1 < c.vector_size())
1493 res += ", ";
1494 }
1495 }
1496 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001497
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001498 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001499 if (splat)
1500 res += c.scalar(vector, 0) ? "true" : "false";
1501 else
1502 {
1503 for (uint32_t i = 0; i < c.vector_size(); i++)
1504 {
1505 res += c.scalar(vector, i) ? "true" : "false";
1506 if (i + 1 < c.vector_size())
1507 res += ", ";
1508 }
1509 }
1510 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001512 default:
1513 throw CompilerError("Invalid constant expression basetype.");
1514 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001516 if (c.vector_size() > 1)
1517 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001518
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001519 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001520}
1521
1522string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
1523{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001524 auto &type = get<SPIRType>(result_type);
1525 auto flags = meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001526
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001527 // If we're declaring temporaries inside continue blocks,
1528 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
1529 if (current_continue_block)
1530 {
1531 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
1532 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001533 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001534 return tmp.first == result_type && tmp.second == result_id;
1535 }) == end(header.declare_temporary))
1536 {
1537 header.declare_temporary.emplace_back(result_type, result_id);
1538 force_recompile = true;
1539 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001540
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001541 return join(to_name(result_id), " = ");
1542 }
1543 else
1544 {
1545 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001546 return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001547 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001548}
1549
1550bool CompilerGLSL::expression_is_forwarded(uint32_t id)
1551{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001552 return forwarded_temporaries.find(id) != end(forwarded_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001553}
1554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001555SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
1556 bool extra_parens, bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001557{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001558 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
1559 {
1560 // Just forward it without temporary.
1561 // If the forward is trivial, we do not force flushing to temporary for this expression.
1562 if (!suppress_usage_tracking)
1563 forwarded_temporaries.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001565 if (extra_parens)
1566 return set<SPIRExpression>(result_id, join("(", rhs, ")"), result_type, true);
1567 else
1568 return set<SPIRExpression>(result_id, rhs, result_type, true);
1569 }
1570 else
1571 {
1572 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
1573 statement(declare_temporary(result_type, result_id), rhs, ";");
1574 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
1575 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001576}
1577
1578void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1579{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001580 bool forward = should_forward(op0);
1581 emit_op(result_type, result_id, join(op, to_expression(op0)), forward, true);
1582
1583 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1584 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001585}
1586
1587void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
1588{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001589 bool forward = should_forward(op0) && should_forward(op1);
1590 emit_op(result_type, result_id, join(to_expression(op0), " ", op, " ", to_expression(op1)), forward, true);
1591
1592 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1593 {
1594 inherit_expression_dependencies(result_id, op0);
1595 inherit_expression_dependencies(result_id, op1);
1596 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001597}
1598
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001599SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
1600 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
1601{
1602 auto &type0 = expression_type(op0);
1603 auto &type1 = expression_type(op1);
1604
1605 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
1606 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
1607 // since equality test is exactly the same.
1608 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
1609
1610 // Create a fake type so we can bitcast to it.
1611 // We only deal with regular arithmetic types here like int, uints and so on.
1612 SPIRType expected_type;
1613 expected_type.basetype = input_type;
1614 expected_type.vecsize = type0.vecsize;
1615 expected_type.columns = type0.columns;
1616 expected_type.width = type0.width;
1617
1618 if (cast)
1619 {
1620 cast_op0 = bitcast_glsl(expected_type, op0);
1621 cast_op1 = bitcast_glsl(expected_type, op1);
1622 }
1623 else
1624 {
1625 // If we don't cast, our actual input type is that of the first (or second) argument.
1626 cast_op0 = to_expression(op0);
1627 cast_op1 = to_expression(op1);
1628 input_type = type0.basetype;
1629 }
1630
1631 return expected_type;
1632}
1633
1634void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1635 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1636{
1637 string cast_op0, cast_op1;
1638 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1639 auto &out_type = get<SPIRType>(result_type);
1640
1641 // We might have casted away from the result type, so bitcast again.
1642 // For example, arithmetic right shift with uint inputs.
1643 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1644 bool extra_parens = true;
1645 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001646 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001647 {
1648 expected_type.basetype = input_type;
1649 expr = bitcast_glsl_op(out_type, expected_type);
1650 expr += '(';
1651 expr += join(cast_op0, " ", op, " ", cast_op1);
1652 expr += ')';
1653 extra_parens = false;
1654 }
1655 else
1656 {
1657 expr += join(cast_op0, " ", op, " ", cast_op1);
1658 }
1659
1660 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), extra_parens);
1661}
1662
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001663void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1664{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001665 bool forward = should_forward(op0);
1666 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), forward, false);
1667 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1668 inherit_expression_dependencies(result_id, op0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001669}
1670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001671void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1672 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001673{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001674 bool forward = should_forward(op0) && should_forward(op1);
1675 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ")"), forward, false);
1676
1677 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1678 {
1679 inherit_expression_dependencies(result_id, op0);
1680 inherit_expression_dependencies(result_id, op1);
1681 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001682}
1683
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001684void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1685 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1686{
1687 string cast_op0, cast_op1;
1688 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1689 auto &out_type = get<SPIRType>(result_type);
1690
1691 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1692 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001693 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001694 {
1695 expected_type.basetype = input_type;
1696 expr = bitcast_glsl_op(out_type, expected_type);
1697 expr += '(';
1698 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1699 expr += ')';
1700 }
1701 else
1702 {
1703 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1704 }
1705
1706 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), false);
1707}
1708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001709void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1710 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001711{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001712 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001713 emit_op(result_type, result_id,
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001714 join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ")"), forward, false);
1715
1716 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1717 {
1718 inherit_expression_dependencies(result_id, op0);
1719 inherit_expression_dependencies(result_id, op1);
1720 inherit_expression_dependencies(result_id, op2);
1721 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001722}
1723
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001724void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1725 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001726{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001727 bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001728 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ",
1729 to_expression(op2), ", ", to_expression(op3), ")"),
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02001730 forward, false);
1731
1732 if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
1733 {
1734 inherit_expression_dependencies(result_id, op0);
1735 inherit_expression_dependencies(result_id, op1);
1736 inherit_expression_dependencies(result_id, op2);
1737 inherit_expression_dependencies(result_id, op3);
1738 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001739}
1740
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001741string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001742{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001743 const char *type;
1744 switch (imgtype.image.dim)
1745 {
1746 case spv::Dim1D:
1747 type = "1D";
1748 break;
1749 case spv::Dim2D:
1750 type = "2D";
1751 break;
1752 case spv::Dim3D:
1753 type = "3D";
1754 break;
1755 case spv::DimCube:
1756 type = "Cube";
1757 break;
1758 case spv::DimBuffer:
1759 type = "Buffer";
1760 break;
1761 case spv::DimSubpassData:
1762 type = "2D";
1763 break;
1764 default:
1765 type = "";
1766 break;
1767 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001769 if (op == "texture")
1770 return join("texture", type);
1771 else if (op == "textureLod")
1772 return join("texture", type, "Lod");
1773 else if (op == "textureProj")
1774 return join("texture", type, "Proj");
1775 else if (op == "textureProjLod")
1776 return join("texture", type, "ProjLod");
1777 else
1778 throw CompilerError(join("Unsupported legacy texture op: ", op));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001779}
1780
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001781void 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 +01001782{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001783 auto &lerptype = expression_type(lerp);
1784 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001785
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001786 bool has_boolean_mix = (options.es && options.version >= 310) || (!options.es && options.version >= 450);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001787
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001788 // Boolean mix not supported on desktop without extension.
1789 // Was added in OpenGL 4.5 with ES 3.1 compat.
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001790 if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001791 {
1792 // Could use GL_EXT_shader_integer_mix on desktop at least,
1793 // but Apple doesn't support it. :(
1794 // Just implement it as ternary expressions.
1795 string expr;
1796 if (lerptype.vecsize == 1)
1797 expr = join(to_expression(lerp), " ? ", to_expression(right), " : ", to_expression(left));
1798 else
1799 {
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001800 auto swiz = [this](uint32_t expression, uint32_t i) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001801 return join(to_expression(expression), ".", index_to_swizzle(i));
1802 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001803
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001804 expr = type_to_glsl_constructor(restype);
1805 expr += "(";
1806 for (uint32_t i = 0; i < restype.vecsize; i++)
1807 {
1808 expr += swiz(lerp, i);
1809 expr += " ? ";
1810 expr += swiz(right, i);
1811 expr += " : ";
1812 expr += swiz(left, i);
1813 if (i + 1 < restype.vecsize)
1814 expr += ", ";
1815 }
1816 expr += ")";
1817 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001819 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp), false);
1820 }
1821 else
1822 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001823}
1824
Bill Hollings5aafb282016-04-23 21:47:41 -04001825void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
1826{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001827 emit_binary_func_op(result_type, result_id, image_id, samp_id, type_to_glsl(get<SPIRType>(result_type)).c_str());
Bill Hollings5aafb282016-04-23 21:47:41 -04001828}
1829
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001830void CompilerGLSL::emit_texture_op(const Instruction &i)
1831{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001832 auto ops = stream(i);
1833 auto op = static_cast<Op>(i.op);
1834 uint32_t length = i.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001835
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001836 if (i.offset + length > spirv.size())
1837 throw CompilerError("Compiler::parse() opcode out of range.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001838
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001839 uint32_t result_type = ops[0];
1840 uint32_t id = ops[1];
1841 uint32_t img = ops[2];
1842 uint32_t coord = ops[3];
1843 uint32_t dref = 0;
1844 uint32_t comp = 0;
1845 bool gather = false;
1846 bool proj = false;
1847 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001848
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001849 switch (op)
1850 {
1851 case OpImageSampleDrefImplicitLod:
1852 case OpImageSampleDrefExplicitLod:
1853 dref = ops[4];
1854 opt = &ops[5];
1855 length -= 5;
1856 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001857
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001858 case OpImageSampleProjDrefImplicitLod:
1859 case OpImageSampleProjDrefExplicitLod:
1860 dref = ops[4];
1861 proj = true;
1862 opt = &ops[5];
1863 length -= 5;
1864 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001866 case OpImageDrefGather:
1867 dref = ops[4];
1868 opt = &ops[5];
1869 gather = true;
1870 length -= 5;
1871 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001872
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001873 case OpImageGather:
1874 comp = ops[4];
1875 opt = &ops[5];
1876 gather = true;
1877 length -= 5;
1878 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001879
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001880 case OpImageSampleProjImplicitLod:
1881 case OpImageSampleProjExplicitLod:
1882 opt = &ops[4];
1883 length -= 4;
1884 proj = true;
1885 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001886
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001887 default:
1888 opt = &ops[4];
1889 length -= 4;
1890 break;
1891 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001892
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001893 auto &imgtype = expression_type(img);
1894 uint32_t coord_components = 0;
1895 switch (imgtype.image.dim)
1896 {
1897 case spv::Dim1D:
1898 coord_components = 1;
1899 break;
1900 case spv::Dim2D:
1901 coord_components = 2;
1902 break;
1903 case spv::Dim3D:
1904 coord_components = 3;
1905 break;
1906 case spv::DimCube:
1907 coord_components = 3;
1908 break;
1909 case spv::DimBuffer:
1910 coord_components = 1;
1911 break;
1912 default:
1913 coord_components = 2;
1914 break;
1915 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001916
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001917 if (proj)
1918 coord_components++;
1919 if (imgtype.image.arrayed)
1920 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001921
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001922 uint32_t bias = 0;
1923 uint32_t lod = 0;
1924 uint32_t grad_x = 0;
1925 uint32_t grad_y = 0;
1926 uint32_t coffset = 0;
1927 uint32_t offset = 0;
1928 uint32_t coffsets = 0;
1929 uint32_t sample = 0;
1930 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001931
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001932 if (length)
1933 {
1934 flags = opt[0];
1935 opt++;
1936 length--;
1937 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001938
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001939 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001940 if (length && (flags & flag))
1941 {
1942 v = *opt++;
1943 length--;
1944 }
1945 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001946
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001947 test(bias, ImageOperandsBiasMask);
1948 test(lod, ImageOperandsLodMask);
1949 test(grad_x, ImageOperandsGradMask);
1950 test(grad_y, ImageOperandsGradMask);
1951 test(coffset, ImageOperandsConstOffsetMask);
1952 test(offset, ImageOperandsOffsetMask);
1953 test(coffsets, ImageOperandsConstOffsetsMask);
1954 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001955
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001956 string expr;
1957 string texop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001958
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001959 if (op == OpImageFetch)
1960 texop += "texelFetch";
1961 else
1962 {
1963 texop += "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001964
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001965 if (gather)
1966 texop += "Gather";
1967 if (coffsets)
1968 texop += "Offsets";
1969 if (proj)
1970 texop += "Proj";
1971 if (grad_x || grad_y)
1972 texop += "Grad";
1973 if (lod)
1974 texop += "Lod";
1975 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001976
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001977 if (coffset || offset)
1978 texop += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001979
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001980 if (is_legacy())
1981 texop = legacy_tex_op(texop, imgtype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001982
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001983 expr += texop;
1984 expr += "(";
1985 expr += to_expression(img);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001986
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001987 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001988 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001989 if (comps == in_comps)
1990 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001991
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001992 switch (comps)
1993 {
1994 case 1:
1995 return ".x";
1996 case 2:
1997 return swizz_func ? ".xy()" : ".xy";
1998 case 3:
1999 return swizz_func ? ".xyz()" : ".xyz";
2000 default:
2001 return "";
2002 }
2003 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002004
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002005 bool forward = should_forward(coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002006
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002007 // The IR can give us more components than we need, so chop them off as needed.
2008 auto coord_expr = to_expression(coord) + swizzle(coord_components, expression_type(coord).vecsize);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002009
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002010 // TODO: implement rest ... A bit intensive.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002011
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002012 if (dref)
2013 {
2014 forward = forward && should_forward(dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002016 // SPIR-V splits dref and coordinate.
2017 if (coord_components == 4) // GLSL also splits the arguments in two.
2018 {
2019 expr += ", ";
2020 expr += to_expression(coord);
2021 expr += ", ";
2022 expr += to_expression(dref);
2023 }
2024 else
2025 {
2026 // Create a composite which merges coord/dref into a single vector.
2027 auto type = expression_type(coord);
2028 type.vecsize = coord_components + 1;
2029 expr += ", ";
2030 expr += type_to_glsl_constructor(type);
2031 expr += "(";
2032 expr += coord_expr;
2033 expr += ", ";
2034 expr += to_expression(dref);
2035 expr += ")";
2036 }
2037 }
2038 else
2039 {
2040 expr += ", ";
2041 expr += coord_expr;
2042 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002043
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002044 if (grad_x || grad_y)
2045 {
2046 forward = forward && should_forward(grad_x);
2047 forward = forward && should_forward(grad_y);
2048 expr += ", ";
2049 expr += to_expression(grad_x);
2050 expr += ", ";
2051 expr += to_expression(grad_y);
2052 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002053
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002054 if (lod)
2055 {
2056 forward = forward && should_forward(lod);
2057 expr += ", ";
2058 expr += to_expression(lod);
2059 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002061 if (coffset)
2062 {
2063 forward = forward && should_forward(coffset);
2064 expr += ", ";
2065 expr += to_expression(coffset);
2066 }
2067 else if (offset)
2068 {
2069 forward = forward && should_forward(offset);
2070 expr += ", ";
2071 expr += to_expression(offset);
2072 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002073
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002074 if (bias)
2075 {
2076 forward = forward && should_forward(bias);
2077 expr += ", ";
2078 expr += to_expression(bias);
2079 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002080
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002081 if (comp)
2082 {
2083 forward = forward && should_forward(comp);
2084 expr += ", ";
2085 expr += to_expression(comp);
2086 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002087
Hans-Kristian Arntzen9d4360f2016-06-22 12:35:58 +02002088 if (sample)
2089 {
2090 expr += ", ";
2091 expr += to_expression(sample);
2092 }
2093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002094 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002095
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002096 emit_op(result_type, id, expr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002097}
2098
2099void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t)
2100{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002101 GLSLstd450 op = static_cast<GLSLstd450>(eop);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002102
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002103 switch (op)
2104 {
2105 // FP fiddling
2106 case GLSLstd450Round:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002107 emit_unary_func_op(result_type, id, args[0], "round");
2108 break;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02002109
2110 case GLSLstd450RoundEven:
2111 if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
2112 emit_unary_func_op(result_type, id, args[0], "roundEven");
2113 else
2114 throw CompilerError("roundEven supported only in ESSL 300 and GLSL 130 and up.");
2115 break;
2116
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002117 case GLSLstd450Trunc:
2118 emit_unary_func_op(result_type, id, args[0], "trunc");
2119 break;
2120 case GLSLstd450SAbs:
2121 case GLSLstd450FAbs:
2122 emit_unary_func_op(result_type, id, args[0], "abs");
2123 break;
2124 case GLSLstd450SSign:
2125 case GLSLstd450FSign:
2126 emit_unary_func_op(result_type, id, args[0], "sign");
2127 break;
2128 case GLSLstd450Floor:
2129 emit_unary_func_op(result_type, id, args[0], "floor");
2130 break;
2131 case GLSLstd450Ceil:
2132 emit_unary_func_op(result_type, id, args[0], "ceil");
2133 break;
2134 case GLSLstd450Fract:
2135 emit_unary_func_op(result_type, id, args[0], "fract");
2136 break;
2137 case GLSLstd450Radians:
2138 emit_unary_func_op(result_type, id, args[0], "radians");
2139 break;
2140 case GLSLstd450Degrees:
2141 emit_unary_func_op(result_type, id, args[0], "degrees");
2142 break;
2143 case GLSLstd450Fma:
2144 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
2145 break;
2146 case GLSLstd450Modf:
2147 register_call_out_argument(args[1]);
2148 forced_temporaries.insert(id);
2149 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
2150 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002151
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002152 // Minmax
2153 case GLSLstd450FMin:
2154 case GLSLstd450UMin:
2155 case GLSLstd450SMin:
2156 emit_binary_func_op(result_type, id, args[0], args[1], "min");
2157 break;
2158 case GLSLstd450FMax:
2159 case GLSLstd450UMax:
2160 case GLSLstd450SMax:
2161 emit_binary_func_op(result_type, id, args[0], args[1], "max");
2162 break;
2163 case GLSLstd450FClamp:
2164 case GLSLstd450UClamp:
2165 case GLSLstd450SClamp:
2166 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
2167 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002168
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002169 // Trig
2170 case GLSLstd450Sin:
2171 emit_unary_func_op(result_type, id, args[0], "sin");
2172 break;
2173 case GLSLstd450Cos:
2174 emit_unary_func_op(result_type, id, args[0], "cos");
2175 break;
2176 case GLSLstd450Tan:
2177 emit_unary_func_op(result_type, id, args[0], "tan");
2178 break;
2179 case GLSLstd450Asin:
2180 emit_unary_func_op(result_type, id, args[0], "asin");
2181 break;
2182 case GLSLstd450Acos:
2183 emit_unary_func_op(result_type, id, args[0], "acos");
2184 break;
2185 case GLSLstd450Atan:
2186 emit_unary_func_op(result_type, id, args[0], "atan");
2187 break;
2188 case GLSLstd450Sinh:
2189 emit_unary_func_op(result_type, id, args[0], "sinh");
2190 break;
2191 case GLSLstd450Cosh:
2192 emit_unary_func_op(result_type, id, args[0], "cosh");
2193 break;
2194 case GLSLstd450Tanh:
2195 emit_unary_func_op(result_type, id, args[0], "tanh");
2196 break;
2197 case GLSLstd450Asinh:
2198 emit_unary_func_op(result_type, id, args[0], "asinh");
2199 break;
2200 case GLSLstd450Acosh:
2201 emit_unary_func_op(result_type, id, args[0], "acosh");
2202 break;
2203 case GLSLstd450Atanh:
2204 emit_unary_func_op(result_type, id, args[0], "atanh");
2205 break;
2206 case GLSLstd450Atan2:
2207 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
2208 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002209
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002210 // Exponentials
2211 case GLSLstd450Pow:
2212 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
2213 break;
2214 case GLSLstd450Exp:
2215 emit_unary_func_op(result_type, id, args[0], "exp");
2216 break;
2217 case GLSLstd450Log:
2218 emit_unary_func_op(result_type, id, args[0], "log");
2219 break;
2220 case GLSLstd450Exp2:
2221 emit_unary_func_op(result_type, id, args[0], "exp2");
2222 break;
2223 case GLSLstd450Log2:
2224 emit_unary_func_op(result_type, id, args[0], "log2");
2225 break;
2226 case GLSLstd450Sqrt:
2227 emit_unary_func_op(result_type, id, args[0], "sqrt");
2228 break;
2229 case GLSLstd450InverseSqrt:
2230 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
2231 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002232
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002233 // Matrix math
2234 case GLSLstd450Determinant:
2235 emit_unary_func_op(result_type, id, args[0], "determinant");
2236 break;
2237 case GLSLstd450MatrixInverse:
2238 emit_unary_func_op(result_type, id, args[0], "inverse");
2239 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002240
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002241 // Lerping
2242 case GLSLstd450FMix:
2243 case GLSLstd450IMix:
2244 {
2245 emit_mix_op(result_type, id, args[0], args[1], args[2]);
2246 break;
2247 }
2248 case GLSLstd450Step:
2249 emit_binary_func_op(result_type, id, args[0], args[1], "step");
2250 break;
2251 case GLSLstd450SmoothStep:
2252 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
2253 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002254
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002255 // Packing
2256 case GLSLstd450Frexp:
2257 register_call_out_argument(args[1]);
2258 forced_temporaries.insert(id);
2259 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
2260 break;
2261 case GLSLstd450Ldexp:
2262 emit_binary_func_op(result_type, id, args[0], args[1], "ldexp");
2263 break;
2264 case GLSLstd450PackSnorm4x8:
2265 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
2266 break;
2267 case GLSLstd450PackUnorm4x8:
2268 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
2269 break;
2270 case GLSLstd450PackSnorm2x16:
2271 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
2272 break;
2273 case GLSLstd450PackUnorm2x16:
2274 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
2275 break;
2276 case GLSLstd450PackHalf2x16:
2277 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
2278 break;
2279 case GLSLstd450UnpackSnorm4x8:
2280 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
2281 break;
2282 case GLSLstd450UnpackUnorm4x8:
2283 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
2284 break;
2285 case GLSLstd450UnpackSnorm2x16:
2286 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
2287 break;
2288 case GLSLstd450UnpackUnorm2x16:
2289 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
2290 break;
2291 case GLSLstd450UnpackHalf2x16:
2292 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
2293 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002294
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02002295 case GLSLstd450PackDouble2x32:
2296 emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
2297 break;
2298 case GLSLstd450UnpackDouble2x32:
2299 emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
2300 break;
2301
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002302 // Vector math
2303 case GLSLstd450Length:
2304 emit_unary_func_op(result_type, id, args[0], "length");
2305 break;
2306 case GLSLstd450Distance:
2307 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
2308 break;
2309 case GLSLstd450Cross:
2310 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
2311 break;
2312 case GLSLstd450Normalize:
2313 emit_unary_func_op(result_type, id, args[0], "normalize");
2314 break;
2315 case GLSLstd450FaceForward:
2316 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
2317 break;
2318 case GLSLstd450Reflect:
2319 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
2320 break;
2321 case GLSLstd450Refract:
2322 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
2323 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002324
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002325 // Bit-fiddling
2326 case GLSLstd450FindILsb:
2327 emit_unary_func_op(result_type, id, args[0], "findLSB");
2328 break;
2329 case GLSLstd450FindSMsb:
2330 case GLSLstd450FindUMsb:
2331 emit_unary_func_op(result_type, id, args[0], "findMSB");
2332 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002334 // Multisampled varying
2335 case GLSLstd450InterpolateAtCentroid:
2336 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
2337 break;
2338 case GLSLstd450InterpolateAtSample:
2339 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
2340 break;
2341 case GLSLstd450InterpolateAtOffset:
2342 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
2343 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002345 default:
2346 statement("// unimplemented GLSL op ", eop);
2347 break;
2348 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002349}
2350
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002351string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002352{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002353 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
2354 return type_to_glsl(out_type);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002355 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Int64)
2356 return type_to_glsl(out_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002357 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
2358 return "floatBitsToUint";
2359 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
2360 return type_to_glsl(out_type);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002361 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::UInt64)
2362 return type_to_glsl(out_type);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002363 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
2364 return "floatBitsToInt";
2365 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
2366 return "uintBitsToFloat";
2367 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
2368 return "intBitsToFloat";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02002369 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
2370 return "doubleBitsToInt64";
2371 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
2372 return "doubleBitsToUint64";
2373 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
2374 return "int64BitsToDouble";
2375 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
2376 return "uint64BitsToDouble";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002377 else
2378 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002379}
2380
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002381string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002382{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002383 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002384 if (op.empty())
2385 return to_expression(argument);
2386 else
2387 return join(op, "(", to_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002388}
2389
Bill Hollings103aabf2016-04-06 17:42:27 -04002390string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002391{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002392 switch (builtin)
2393 {
2394 case BuiltInPosition:
2395 return "gl_Position";
2396 case BuiltInPointSize:
2397 return "gl_PointSize";
2398 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002399 if (options.vulkan_semantics)
2400 throw CompilerError(
2401 "Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002402 return "gl_VertexID";
2403 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002404 if (options.vulkan_semantics)
2405 throw CompilerError(
2406 "Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002407 return "gl_InstanceID";
2408 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002409 if (options.vulkan_semantics)
2410 return "gl_VertexIndex";
2411 else
2412 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002413 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002414 if (options.vulkan_semantics)
2415 return "gl_InstanceIndex";
2416 else
2417 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002418 case BuiltInPrimitiveId:
2419 return "gl_PrimitiveID";
2420 case BuiltInInvocationId:
2421 return "gl_InvocationID";
2422 case BuiltInLayer:
2423 return "gl_Layer";
2424 case BuiltInTessLevelOuter:
2425 return "gl_TessLevelOuter";
2426 case BuiltInTessLevelInner:
2427 return "gl_TessLevelInner";
2428 case BuiltInTessCoord:
2429 return "gl_TessCoord";
2430 case BuiltInFragCoord:
2431 return "gl_FragCoord";
2432 case BuiltInPointCoord:
2433 return "gl_PointCoord";
2434 case BuiltInFrontFacing:
2435 return "gl_FrontFacing";
2436 case BuiltInFragDepth:
2437 return "gl_FragDepth";
2438 case BuiltInNumWorkgroups:
2439 return "gl_NumWorkGroups";
2440 case BuiltInWorkgroupSize:
2441 return "gl_WorkGroupSize";
2442 case BuiltInWorkgroupId:
2443 return "gl_WorkGroupID";
2444 case BuiltInLocalInvocationId:
2445 return "gl_LocalInvocationID";
2446 case BuiltInGlobalInvocationId:
2447 return "gl_GlobalInvocationID";
2448 case BuiltInLocalInvocationIndex:
2449 return "gl_LocalInvocationIndex";
2450 default:
2451 return "gl_???";
2452 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002453}
2454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002455const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002456{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002457 switch (index)
2458 {
2459 case 0:
2460 return "x";
2461 case 1:
2462 return "y";
2463 case 2:
2464 return "z";
2465 case 3:
2466 return "w";
2467 default:
2468 throw CompilerError("Swizzle index out of range");
2469 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002470}
2471
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002472string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal,
2473 bool chain_only)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002474{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002475 string expr;
2476 if (!chain_only)
2477 expr = to_expression(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002479 const auto *type = &expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002480
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002481 // For resolving array accesses, etc, keep a local copy for poking.
2482 SPIRType temp;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002483
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002484 bool access_chain_is_arrayed = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002485
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002486 for (uint32_t i = 0; i < count; i++)
2487 {
2488 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002489
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002490 // Arrays
2491 if (!type->array.empty())
2492 {
2493 expr += "[";
2494 if (index_is_literal)
2495 expr += convert_to_string(index);
2496 else
2497 expr += to_expression(index);
2498 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002499
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002500 // We have to modify the type, so keep a local copy.
2501 if (&temp != type)
2502 temp = *type;
2503 type = &temp;
2504 temp.array.pop_back();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002505
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002506 access_chain_is_arrayed = true;
2507 }
2508 // For structs, the index refers to a constant, which indexes into the members.
2509 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
2510 else if (type->basetype == SPIRType::Struct)
2511 {
2512 if (!index_is_literal)
2513 index = get<SPIRConstant>(index).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002514
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002515 if (index >= type->member_types.size())
2516 throw CompilerError("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002517
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002518 BuiltIn builtin;
2519 if (is_member_builtin(*type, index, &builtin))
2520 {
2521 // FIXME: We rely here on OpName on gl_in/gl_out to make this work properly.
2522 // To make this properly work by omitting all OpName opcodes,
2523 // we need to infer gl_in or gl_out based on the builtin, and stage.
2524 if (access_chain_is_arrayed)
2525 {
2526 expr += ".";
2527 expr += builtin_to_glsl(builtin);
2528 }
2529 else
2530 expr = builtin_to_glsl(builtin);
2531 }
2532 else
2533 {
2534 expr += ".";
2535 expr += to_member_name(*type, index);
2536 }
2537 type = &get<SPIRType>(type->member_types[index]);
2538 }
2539 // Matrix -> Vector
2540 else if (type->columns > 1)
2541 {
2542 expr += "[";
2543 if (index_is_literal)
2544 expr += convert_to_string(index);
2545 else
2546 expr += to_expression(index);
2547 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002548
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002549 // We have to modify the type, so keep a local copy.
2550 if (&temp != type)
2551 temp = *type;
2552 type = &temp;
2553 temp.columns = 1;
2554 }
2555 // Vector -> Scalar
2556 else if (type->vecsize > 1)
2557 {
2558 if (index_is_literal)
2559 {
2560 expr += ".";
2561 expr += index_to_swizzle(index);
2562 }
2563 else if (ids[index].get_type() == TypeConstant)
2564 {
2565 auto &c = get<SPIRConstant>(index);
2566 expr += ".";
2567 expr += index_to_swizzle(c.scalar());
2568 }
2569 else
2570 {
2571 expr += "[";
2572 expr += to_expression(index);
2573 expr += "]";
2574 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002576 // We have to modify the type, so keep a local copy.
2577 if (&temp != type)
2578 temp = *type;
2579 type = &temp;
2580 temp.vecsize = 1;
2581 }
2582 else
2583 throw CompilerError("Cannot subdivide a scalar value!");
2584 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002585
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002586 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002587}
2588
2589bool CompilerGLSL::should_forward(uint32_t id)
2590{
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002591 // Immutable expression can always be forwarded.
2592 // If not immutable, we can speculate about it by forwarding potentially mutable variables.
2593 auto *var = maybe_get<SPIRVariable>(id);
2594 bool forward = var ? var->forwardable : false;
2595 return (is_immutable(id) || forward) && !options.force_temporary;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002596}
2597
2598void CompilerGLSL::track_expression_read(uint32_t id)
2599{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002600 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
2601 // In this case, it's better to just bind the complex expression to the temporary and read that temporary twice.
2602 if (expression_is_forwarded(id))
2603 {
2604 auto &v = expression_usage_counts[id];
2605 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002606
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002607 if (v >= 2)
2608 {
2609 //if (v == 2)
2610 // 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 +01002611
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002612 forced_temporaries.insert(id);
2613 // Force a recompile after this pass to avoid forwarding this variable.
2614 force_recompile = true;
2615 }
2616 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002617}
2618
2619bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
2620{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002621 if (forced_temporaries.find(id) != end(forced_temporaries))
2622 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002623
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002624 for (uint32_t i = 0; i < num_args; i++)
2625 if (!should_forward(args[i]))
2626 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002628 // We need to forward globals as well.
2629 if (!pure)
2630 {
2631 for (auto global : global_variables)
2632 if (!should_forward(global))
2633 return false;
2634 for (auto aliased : aliased_variables)
2635 if (!should_forward(aliased))
2636 return false;
2637 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002638
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002639 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002640}
2641
2642void CompilerGLSL::register_impure_function_call()
2643{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002644 // Impure functions can modify globals and aliased variables, so invalidate them as well.
2645 for (auto global : global_variables)
2646 flush_dependees(get<SPIRVariable>(global));
2647 for (auto aliased : aliased_variables)
2648 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002649}
2650
2651void CompilerGLSL::register_call_out_argument(uint32_t id)
2652{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002653 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002655 auto *var = maybe_get<SPIRVariable>(id);
2656 if (var)
2657 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002658}
2659
2660void CompilerGLSL::flush_variable_declaration(uint32_t id)
2661{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002662 auto *var = maybe_get<SPIRVariable>(id);
2663 if (var && var->deferred_declaration)
2664 {
2665 statement(variable_decl(*var), ";");
2666 var->deferred_declaration = false;
2667 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002668}
2669
2670bool CompilerGLSL::remove_duplicate_swizzle(string &op)
2671{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002672 auto pos = op.find_last_of('.');
2673 if (pos == string::npos || pos == 0)
2674 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002675
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002676 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002677
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002678 if (backend.swizzle_is_function)
2679 {
2680 if (final_swiz.size() < 2)
2681 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002683 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2684 final_swiz.erase(final_swiz.size() - 2, string::npos);
2685 else
2686 return false;
2687 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002688
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002689 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2690 // If so, and previous swizzle is of same length,
2691 // we can drop the final swizzle altogether.
2692 for (uint32_t i = 0; i < final_swiz.size(); i++)
2693 {
2694 static const char expected[] = { 'x', 'y', 'z', 'w' };
2695 if (i >= 4 || final_swiz[i] != expected[i])
2696 return false;
2697 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002698
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002699 auto prevpos = op.find_last_of('.', pos - 1);
2700 if (prevpos == string::npos)
2701 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002702
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002703 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002705 // Make sure there are only swizzles here ...
2706 for (auto i = prevpos; i < pos; i++)
2707 {
2708 if (op[i] < 'w' || op[i] > 'z')
2709 {
2710 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
2711 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
2712 break;
2713 return false;
2714 }
2715 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002717 // If original swizzle is large enough, just carve out the components we need.
2718 // E.g. foobar.wyx.xy will turn into foobar.wy.
2719 if (pos - prevpos >= final_swiz.size())
2720 {
2721 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002723 // Add back the function call ...
2724 if (backend.swizzle_is_function)
2725 op += "()";
2726 }
2727 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002728}
2729
2730// Optimizes away vector swizzles where we have something like
2731// vec3 foo;
2732// foo.xyz <-- swizzle expression does nothing.
2733// This is a very common pattern after OpCompositeCombine.
2734bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
2735{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002736 auto pos = op.find_last_of('.');
2737 if (pos == string::npos || pos == 0)
2738 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002740 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002741
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002742 if (backend.swizzle_is_function)
2743 {
2744 if (final_swiz.size() < 2)
2745 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002746
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002747 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2748 final_swiz.erase(final_swiz.size() - 2, string::npos);
2749 else
2750 return false;
2751 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002752
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002753 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2754 // If so, and previous swizzle is of same length,
2755 // we can drop the final swizzle altogether.
2756 for (uint32_t i = 0; i < final_swiz.size(); i++)
2757 {
2758 static const char expected[] = { 'x', 'y', 'z', 'w' };
2759 if (i >= 4 || final_swiz[i] != expected[i])
2760 return false;
2761 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002762
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002763 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002764
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002765 // Sanity checking ...
2766 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002767
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002768 if (type.vecsize == final_swiz.size())
2769 op.erase(pos, string::npos);
2770 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002771}
2772
2773string CompilerGLSL::build_composite_combiner(const uint32_t *elems, uint32_t length)
2774{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002775 uint32_t base = 0;
2776 bool swizzle_optimization = false;
2777 string op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002778
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002779 for (uint32_t i = 0; i < length; i++)
2780 {
2781 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002782
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002783 // If we're merging another scalar which belongs to the same base
2784 // object, just merge the swizzles to avoid triggering more than 1 expression read as much as possible!
2785 if (e && e->base_expression && e->base_expression == base)
2786 {
2787 // Only supposed to be used for vector swizzle -> scalar.
2788 assert(!e->expression.empty() && e->expression.front() == '.');
2789 op += e->expression.substr(1, string::npos);
2790 swizzle_optimization = true;
2791 }
2792 else
2793 {
2794 // We'll likely end up with duplicated swizzles, e.g.
2795 // foobar.xyz.xyz from patterns like
2796 // OpVectorSwizzle
2797 // OpCompositeExtract x 3
2798 // OpCompositeConstruct 3x + other scalar.
2799 // Just modify op in-place.
2800 if (swizzle_optimization)
2801 {
2802 if (backend.swizzle_is_function)
2803 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002804
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002805 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
2806 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
2807 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
2808 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
2809 // Case 1:
2810 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
2811 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
2812 // Case 2:
2813 // foo.xyz: Duplicate swizzle won't kick in.
2814 // If foo is vec3, we can remove xyz, giving just foo.
2815 if (!remove_duplicate_swizzle(op))
2816 remove_unity_swizzle(base, op);
2817 swizzle_optimization = false;
2818 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002819
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002820 if (i)
2821 op += ", ";
2822 op += to_expression(elems[i]);
2823 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002824
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002825 base = e ? e->base_expression : 0;
2826 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002827
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002828 if (swizzle_optimization)
2829 {
2830 if (backend.swizzle_is_function)
2831 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002832
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002833 if (!remove_duplicate_swizzle(op))
2834 remove_unity_swizzle(base, op);
2835 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002836
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002837 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002838}
2839
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02002840void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002841{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002842 auto ops = stream(instruction);
2843 auto opcode = static_cast<Op>(instruction.op);
2844 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002845
2846#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002847#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 +01002848#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
2849#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
2850#define TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
2851#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002852#define BFOP_CAST(op, type, skip_cast) emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
2853#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002854#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
2855
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002856 switch (opcode)
2857 {
2858 // Dealing with memory
2859 case OpLoad:
2860 {
2861 uint32_t result_type = ops[0];
2862 uint32_t id = ops[1];
2863 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002864
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002865 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002866
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002867 // If we're loading from memory that cannot be changed by the shader,
2868 // just forward the expression directly to avoid needless temporaries.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002869 // If an expression is mutable and forwardable, we speculate that it is immutable.
2870 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
2871
2872 // Suppress usage tracking since using same expression multiple times does not imply any extra work.
2873 emit_op(result_type, id, to_expression(ptr), forward, false, true);
2874 register_read(id, ptr, forward);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002875 break;
2876 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002877
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002878 case OpInBoundsAccessChain:
2879 case OpAccessChain:
2880 {
2881 auto *var = maybe_get<SPIRVariable>(ops[2]);
2882 if (var)
2883 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002884
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002885 // If the base is immutable, the access chain pointer must also be.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002886 // If an expression is mutable and forwardable, we speculate that it is immutable.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002887 auto e = access_chain(ops[2], &ops[3], length - 3, false);
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002888 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002889 expr.loaded_from = ops[2];
2890 break;
2891 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002892
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002893 case OpStore:
2894 {
2895 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002896
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002897 if (var && var->statically_assigned)
2898 var->static_expression = ops[1];
2899 else
2900 {
2901 auto lhs = to_expression(ops[0]);
2902 auto rhs = to_expression(ops[1]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002903
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002904 // It is possible with OpLoad/OpCompositeInsert/OpStore that we get <expr> = <same-expr>.
2905 // For this case, we don't need to invalidate anything and emit any opcode.
2906 if (lhs != rhs)
2907 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002908 statement(lhs, " = ", rhs, ";");
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +02002909 register_write(ops[0]);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002910 }
2911 }
2912 break;
2913 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002914
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002915 case OpArrayLength:
2916 {
2917 uint32_t result_type = ops[0];
2918 uint32_t id = ops[1];
2919 auto e = access_chain(ops[2], &ops[3], length - 3, true);
2920 set<SPIRExpression>(id, e + ".length()", result_type, true);
2921 break;
2922 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002923
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002924 // Function calls
2925 case OpFunctionCall:
2926 {
2927 uint32_t result_type = ops[0];
2928 uint32_t id = ops[1];
2929 uint32_t func = ops[2];
2930 const auto *arg = &ops[3];
2931 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002932
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002933 auto &callee = get<SPIRFunction>(func);
2934 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002935
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002936 bool callee_has_out_variables = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002937
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002938 // Invalidate out variables passed to functions since they can be OpStore'd to.
2939 for (uint32_t i = 0; i < length; i++)
2940 {
2941 if (callee.arguments[i].write_count)
2942 {
2943 register_call_out_argument(arg[i]);
2944 callee_has_out_variables = true;
2945 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002946
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002947 flush_variable_declaration(arg[i]);
2948 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002949
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002950 if (!pure)
2951 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002952
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002953 string funexpr;
2954 funexpr += to_name(func) + "(";
2955 for (uint32_t i = 0; i < length; i++)
2956 {
2957 funexpr += to_expression(arg[i]);
2958 if (i + 1 < length)
2959 funexpr += ", ";
2960 }
2961 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002962
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02002963 // Check for function call constraints.
2964 check_function_call_constraints(arg, length);
2965
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002966 if (get<SPIRType>(result_type).basetype != SPIRType::Void)
2967 {
2968 // If the function actually writes to an out variable,
2969 // take the conservative route and do not forward.
2970 // The problem is that we might not read the function
2971 // result (and emit the function) before an out variable
2972 // is read (common case when return value is ignored!
2973 // In order to avoid start tracking invalid variables,
2974 // just avoid the forwarding problem altogether.
2975 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
2976 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002977
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002978 emit_op(result_type, id, funexpr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002979
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002980 // Function calls are implicit loads from all variables in question.
2981 // Set dependencies for them.
2982 for (uint32_t i = 0; i < length; i++)
2983 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002985 // If we're going to forward the temporary result,
2986 // put dependencies on every variable that must not change.
2987 if (forward)
2988 register_global_read_dependencies(callee, id);
2989 }
2990 else
2991 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002992
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002993 break;
2994 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002995
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002996 // Composite munging
2997 case OpCompositeConstruct:
2998 {
2999 uint32_t result_type = ops[0];
3000 uint32_t id = ops[1];
3001 const auto *elems = &ops[2];
3002 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003003
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003004 if (!length)
3005 throw CompilerError("Invalid input to OpCompositeConstruct.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003006
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003007 bool forward = true;
3008 for (uint32_t i = 0; i < length; i++)
3009 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003010
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003011 auto &in_type = expression_type(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003012 auto &out_type = get<SPIRType>(result_type);
3013
3014 // Only splat if we have vector constructors.
3015 // Arrays and structs must be initialized properly in full.
3016 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
3017 bool splat = in_type.vecsize == 1 && in_type.columns == 1 && !composite;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003018
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003019 if (splat)
3020 {
3021 uint32_t input = elems[0];
3022 for (uint32_t i = 0; i < length; i++)
3023 if (input != elems[i])
3024 splat = false;
3025 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003026
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003027 string constructor_op;
3028 if (backend.use_initializer_list && composite)
3029 {
3030 // Only use this path if we are building composites.
3031 // This path cannot be used for arithmetic.
3032 constructor_op += "{ ";
3033 if (splat)
3034 constructor_op += to_expression(elems[0]);
3035 else
3036 constructor_op += build_composite_combiner(elems, length);
3037 constructor_op += " }";
3038 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003039 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003040 {
3041 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
3042 if (splat)
3043 constructor_op += to_expression(elems[0]);
3044 else
3045 constructor_op += build_composite_combiner(elems, length);
3046 constructor_op += ")";
3047 }
3048
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003049 emit_op(result_type, id, constructor_op, forward, false);
3050 break;
3051 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003052
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003053 case OpVectorInsertDynamic:
3054 {
3055 uint32_t result_type = ops[0];
3056 uint32_t id = ops[1];
3057 uint32_t vec = ops[2];
3058 uint32_t comp = ops[3];
3059 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003061 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003062
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003063 // Make a copy, then use access chain to store the variable.
3064 statement(declare_temporary(result_type, id), to_expression(vec), ";");
3065 set<SPIRExpression>(id, to_name(id), result_type, true);
3066 auto chain = access_chain(id, &index, 1, false);
3067 statement(chain, " = ", to_expression(comp), ";");
3068 break;
3069 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003070
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003071 case OpVectorExtractDynamic:
3072 {
3073 uint32_t result_type = ops[0];
3074 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003076 auto expr = access_chain(ops[2], &ops[3], 1, false);
3077 emit_op(result_type, id, expr, should_forward(ops[2]), false);
3078 break;
3079 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003080
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003081 case OpCompositeExtract:
3082 {
3083 uint32_t result_type = ops[0];
3084 uint32_t id = ops[1];
3085 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003087 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003088
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02003089 // We can only split the expression here if our expression is forwarded as a temporary.
3090 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
3091
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003092 // Only apply this optimization if result is scalar.
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02003093 if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003094 {
3095 // We want to split the access chain from the base.
3096 // This is so we can later combine different CompositeExtract results
3097 // with CompositeConstruct without emitting code like
3098 //
3099 // vec3 temp = texture(...).xyz
3100 // vec4(temp.x, temp.y, temp.z, 1.0).
3101 //
3102 // when we actually wanted to emit this
3103 // vec4(texture(...).xyz, 1.0).
3104 //
3105 // Including the base will prevent this and would trigger multiple reads
3106 // from expression causing it to be forced to an actual temporary in GLSL.
3107 auto expr = access_chain(ops[2], &ops[3], length, true, true);
3108 auto &e = emit_op(result_type, id, expr, true, false, !expression_is_forwarded(ops[2]));
3109 e.base_expression = ops[2];
3110 }
3111 else
3112 {
3113 auto expr = access_chain(ops[2], &ops[3], length, true);
3114 emit_op(result_type, id, expr, should_forward(ops[2]), false, !expression_is_forwarded(ops[2]));
3115 }
3116 break;
3117 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003118
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003119 case OpCompositeInsert:
3120 {
3121 uint32_t result_type = ops[0];
3122 uint32_t id = ops[1];
3123 uint32_t obj = ops[2];
3124 uint32_t composite = ops[3];
3125 const auto *elems = &ops[4];
3126 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003128 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003129
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003130 auto *expr = maybe_get<SPIRExpression>(id);
3131 if ((expr && expr->used_while_invalidated) || !should_forward(composite))
3132 {
3133 // Make a copy, then use access chain to store the variable.
3134 statement(declare_temporary(result_type, id), to_expression(composite), ";");
3135 set<SPIRExpression>(id, to_name(id), result_type, true);
3136 auto chain = access_chain(id, elems, length, true);
3137 statement(chain, " = ", to_expression(obj), ";");
3138 }
3139 else
3140 {
3141 auto chain = access_chain(composite, elems, length, true);
3142 statement(chain, " = ", to_expression(obj), ";");
3143 set<SPIRExpression>(id, to_expression(composite), result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003144
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003145 register_write(composite);
3146 register_read(id, composite, true);
3147 // Invalidate the old expression we inserted into.
3148 invalid_expressions.insert(composite);
3149 }
3150 break;
3151 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003152
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003153 case OpCopyObject:
3154 {
3155 uint32_t result_type = ops[0];
3156 uint32_t id = ops[1];
3157 uint32_t rhs = ops[2];
3158 if (expression_is_lvalue(rhs))
3159 {
3160 // Need a copy.
3161 statement(declare_temporary(result_type, id), to_expression(rhs), ";");
3162 set<SPIRExpression>(id, to_name(id), result_type, true);
3163 }
3164 else
3165 {
3166 // RHS expression is immutable, so just forward it.
3167 // Copying these things really make no sense, but
3168 // seems to be allowed anyways.
3169 set<SPIRExpression>(id, to_expression(rhs), result_type, true);
3170 }
3171 break;
3172 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003173
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003174 case OpVectorShuffle:
3175 {
3176 uint32_t result_type = ops[0];
3177 uint32_t id = ops[1];
3178 uint32_t vec0 = ops[2];
3179 uint32_t vec1 = ops[3];
3180 const auto *elems = &ops[4];
3181 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003182
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003183 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003184
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003185 bool shuffle = false;
3186 for (uint32_t i = 0; i < length; i++)
3187 if (elems[i] >= type0.vecsize)
3188 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003189
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003190 string expr;
3191 bool trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003193 if (shuffle)
3194 {
3195 trivial_forward = !expression_is_forwarded(vec0) && !expression_is_forwarded(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003196
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003197 // Constructor style and shuffling from two different vectors.
3198 vector<string> args;
3199 for (uint32_t i = 0; i < length; i++)
3200 {
3201 if (elems[i] >= type0.vecsize)
3202 args.push_back(join(to_expression(vec1), ".", index_to_swizzle(elems[i] - type0.vecsize)));
3203 else
3204 args.push_back(join(to_expression(vec0), ".", index_to_swizzle(elems[i])));
3205 }
3206 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
3207 }
3208 else
3209 {
3210 trivial_forward = !expression_is_forwarded(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003211
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003212 // We only source from first vector, so can use swizzle.
3213 expr += to_expression(vec0);
3214 expr += ".";
3215 for (uint32_t i = 0; i < length; i++)
3216 expr += index_to_swizzle(elems[i]);
3217 if (backend.swizzle_is_function && length > 1)
3218 expr += "()";
3219 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003220
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003221 // A shuffle is trivial in that it doesn't actually *do* anything.
3222 // 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 +01003223
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003224 emit_op(result_type, id, expr, should_forward(vec0) && should_forward(vec1), false, trivial_forward);
3225 break;
3226 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003227
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003228 // ALU
3229 case OpIsNan:
3230 UFOP(isnan);
3231 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003232
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003233 case OpIsInf:
3234 UFOP(isinf);
3235 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003236
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003237 case OpSNegate:
3238 case OpFNegate:
3239 UOP(-);
3240 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003241
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003242 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003243 {
3244 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
3245 auto type = get<SPIRType>(ops[0]).basetype;
3246 BOP_CAST(+, type, true);
3247 break;
3248 }
3249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003250 case OpFAdd:
3251 BOP(+);
3252 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003253
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003254 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003255 {
3256 auto type = get<SPIRType>(ops[0]).basetype;
3257 BOP_CAST(-, type, true);
3258 break;
3259 }
3260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003261 case OpFSub:
3262 BOP(-);
3263 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003264
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003265 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003266 {
3267 auto type = get<SPIRType>(ops[0]).basetype;
3268 BOP_CAST(*, type, true);
3269 break;
3270 }
3271
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003272 case OpFMul:
3273 case OpMatrixTimesVector:
3274 case OpMatrixTimesScalar:
3275 case OpVectorTimesScalar:
3276 case OpVectorTimesMatrix:
3277 case OpMatrixTimesMatrix:
3278 BOP(*);
3279 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003280
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003281 case OpOuterProduct:
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02003282 BFOP(outerProduct);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003283 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003284
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003285 case OpDot:
3286 BFOP(dot);
3287 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003289 case OpTranspose:
3290 UFOP(transpose);
3291 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003292
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003293 case OpSDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003294 BOP_CAST(/, SPIRType::Int, false);
3295 break;
3296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003297 case OpUDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003298 BOP_CAST(/, SPIRType::UInt, false);
3299 break;
3300
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003301 case OpFDiv:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003302 BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003303 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003304
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003305 case OpShiftRightLogical:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003306 BOP_CAST(>>, SPIRType::UInt, false);
3307 break;
3308
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003309 case OpShiftRightArithmetic:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003310 BOP_CAST(>>, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003311 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003312
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003313 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003314 {
3315 auto type = get<SPIRType>(ops[0]).basetype;
3316 BOP_CAST(<<, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003317 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003318 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003320 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003321 {
3322 auto type = get<SPIRType>(ops[0]).basetype;
3323 BOP_CAST(|, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003324 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003325 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003326
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003327 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003328 {
3329 auto type = get<SPIRType>(ops[0]).basetype;
3330 BOP_CAST (^, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003331 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003332 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003334 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003335 {
3336 auto type = get<SPIRType>(ops[0]).basetype;
3337 BOP_CAST(&, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003338 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003339 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003341 case OpNot:
3342 UOP(~);
3343 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003345 case OpUMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003346 BOP_CAST(%, SPIRType::UInt, false);
3347 break;
3348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003349 case OpSMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003350 BOP_CAST(%, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003351 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003352
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003353 case OpFMod:
3354 BFOP(mod);
3355 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +02003356
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003357 // Relational
3358 case OpAny:
3359 UFOP(any);
3360 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003361
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003362 case OpAll:
3363 UFOP(all);
3364 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003365
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003366 case OpSelect:
3367 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
3368 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003369
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003370 case OpLogicalOr:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003371 BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003372 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003373
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003374 case OpLogicalAnd:
3375 BOP(&&);
3376 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003377
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003378 case OpLogicalNot:
3379 UOP(!);
3380 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003381
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003382 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003383 {
3384 if (expression_type(ops[2]).vecsize > 1)
3385 BFOP_CAST(equal, SPIRType::Int, true);
3386 else
3387 BOP_CAST(==, SPIRType::Int, true);
3388 break;
3389 }
3390
3391 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003392 case OpFOrdEqual:
3393 {
3394 if (expression_type(ops[2]).vecsize > 1)
3395 BFOP(equal);
3396 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003397 BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003398 break;
3399 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003400
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003401 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003402 {
3403 if (expression_type(ops[2]).vecsize > 1)
3404 BFOP_CAST(notEqual, SPIRType::Int, true);
3405 else
3406 BOP_CAST(!=, SPIRType::Int, true);
3407 break;
3408 }
3409
3410 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003411 case OpFOrdNotEqual:
3412 {
3413 if (expression_type(ops[2]).vecsize > 1)
3414 BFOP(notEqual);
3415 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003416 BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003417 break;
3418 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003419
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003420 case OpUGreaterThan:
3421 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003422 {
3423 auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
3424 if (expression_type(ops[2]).vecsize > 1)
3425 BFOP_CAST(greaterThan, type, false);
3426 else
3427 BOP_CAST(>, type, false);
3428 break;
3429 }
3430
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003431 case OpFOrdGreaterThan:
3432 {
3433 if (expression_type(ops[2]).vecsize > 1)
3434 BFOP(greaterThan);
3435 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003436 BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003437 break;
3438 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003440 case OpUGreaterThanEqual:
3441 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003442 {
3443 auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
3444 if (expression_type(ops[2]).vecsize > 1)
3445 BFOP_CAST(greaterThanEqual, type, false);
3446 else
3447 BOP_CAST(>=, type, false);
3448 break;
3449 }
3450
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003451 case OpFOrdGreaterThanEqual:
3452 {
3453 if (expression_type(ops[2]).vecsize > 1)
3454 BFOP(greaterThanEqual);
3455 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003456 BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003457 break;
3458 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003459
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003460 case OpULessThan:
3461 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003462 {
3463 auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
3464 if (expression_type(ops[2]).vecsize > 1)
3465 BFOP_CAST(lessThan, type, false);
3466 else
3467 BOP_CAST(<, type, false);
3468 break;
3469 }
3470
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003471 case OpFOrdLessThan:
3472 {
3473 if (expression_type(ops[2]).vecsize > 1)
3474 BFOP(lessThan);
3475 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003476 BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003477 break;
3478 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003479
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003480 case OpULessThanEqual:
3481 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003482 {
3483 auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
3484 if (expression_type(ops[2]).vecsize > 1)
3485 BFOP_CAST(lessThanEqual, type, false);
3486 else
3487 BOP_CAST(<=, type, false);
3488 break;
3489 }
3490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003491 case OpFOrdLessThanEqual:
3492 {
3493 if (expression_type(ops[2]).vecsize > 1)
3494 BFOP(lessThanEqual);
3495 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003496 BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003497 break;
3498 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003499
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003500 // Conversion
3501 case OpConvertFToU:
3502 case OpConvertFToS:
3503 case OpConvertSToF:
3504 case OpConvertUToF:
3505 case OpUConvert:
3506 case OpSConvert:
3507 case OpFConvert:
3508 {
3509 uint32_t result_type = ops[0];
3510 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003511
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003512 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
3513 emit_unary_func_op(result_type, id, ops[2], func.c_str());
3514 break;
3515 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003516
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003517 case OpBitcast:
3518 {
3519 uint32_t result_type = ops[0];
3520 uint32_t id = ops[1];
3521 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003522
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003523 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003524 emit_unary_func_op(result_type, id, arg, op.c_str());
3525 break;
3526 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003527
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02003528 case OpQuantizeToF16:
3529 {
3530 uint32_t result_type = ops[0];
3531 uint32_t id = ops[1];
3532 uint32_t arg = ops[2];
3533
3534 string op;
3535 auto &type = get<SPIRType>(result_type);
3536
3537 switch (type.vecsize)
3538 {
3539 case 1:
3540 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
3541 break;
3542 case 2:
3543 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
3544 break;
3545 case 3:
3546 {
3547 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
3548 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
3549 op = join("vec3(", op0, ", ", op1, ")");
3550 break;
3551 }
3552 case 4:
3553 {
3554 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
3555 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
3556 op = join("vec4(", op0, ", ", op1, ")");
3557 break;
3558 }
3559 default:
3560 throw CompilerError("Illegal argument to OpQuantizeToF16.");
3561 }
3562
3563 emit_op(result_type, id, op, should_forward(arg), false);
3564 break;
3565 }
3566
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003567 // Derivatives
3568 case OpDPdx:
3569 UFOP(dFdx);
3570 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003571
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003572 case OpDPdy:
3573 UFOP(dFdy);
3574 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003575
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003576 case OpFwidth:
3577 UFOP(fwidth);
3578 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003579
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003580 // Bitfield
3581 case OpBitFieldInsert:
3582 QFOP(bitfieldInsert);
3583 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003584
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003585 case OpBitFieldSExtract:
3586 case OpBitFieldUExtract:
3587 QFOP(bitfieldExtract);
3588 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003589
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003590 case OpBitReverse:
3591 UFOP(bitfieldReverse);
3592 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003593
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003594 case OpBitCount:
3595 UFOP(bitCount);
3596 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003597
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003598 // Atomics
3599 case OpAtomicExchange:
3600 {
3601 uint32_t result_type = ops[0];
3602 uint32_t id = ops[1];
3603 uint32_t ptr = ops[2];
3604 // Ignore semantics for now, probably only relevant to CL.
3605 uint32_t val = ops[5];
3606 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
3607 forced_temporaries.insert(id);
3608 emit_binary_func_op(result_type, id, ptr, val, op);
3609 flush_all_atomic_capable_variables();
3610 break;
3611 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003613 case OpAtomicCompareExchange:
3614 {
3615 uint32_t result_type = ops[0];
3616 uint32_t id = ops[1];
3617 uint32_t ptr = ops[2];
3618 uint32_t val = ops[6];
3619 uint32_t comp = ops[7];
3620 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003621
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003622 forced_temporaries.insert(id);
3623 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
3624 flush_all_atomic_capable_variables();
3625 break;
3626 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003627
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003628 case OpAtomicLoad:
3629 flush_all_atomic_capable_variables();
3630 // FIXME: Image?
3631 UFOP(atomicCounter);
3632 register_read(ops[1], ops[2], should_forward(ops[2]));
3633 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003634
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003635 // OpAtomicStore unimplemented. Not sure what would use that.
3636 // OpAtomicLoad seems to only be relevant for atomic counters.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003637
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003638 case OpAtomicIIncrement:
3639 forced_temporaries.insert(ops[1]);
3640 // FIXME: Image?
3641 UFOP(atomicCounterIncrement);
3642 flush_all_atomic_capable_variables();
3643 register_read(ops[1], ops[2], should_forward(ops[2]));
3644 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003646 case OpAtomicIDecrement:
3647 forced_temporaries.insert(ops[1]);
3648 // FIXME: Image?
3649 UFOP(atomicCounterDecrement);
3650 flush_all_atomic_capable_variables();
3651 register_read(ops[1], ops[2], should_forward(ops[2]));
3652 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003653
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003654 case OpAtomicIAdd:
3655 {
3656 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3657 forced_temporaries.insert(ops[1]);
3658 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3659 flush_all_atomic_capable_variables();
3660 register_read(ops[1], ops[2], should_forward(ops[2]));
3661 break;
3662 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003663
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003664 case OpAtomicISub:
3665 {
3666 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3667 forced_temporaries.insert(ops[1]);
3668 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_expression(ops[5]), ")");
3669 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]), false);
3670 flush_all_atomic_capable_variables();
3671 register_read(ops[1], ops[2], should_forward(ops[2]));
3672 break;
3673 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003675 case OpAtomicSMin:
3676 case OpAtomicUMin:
3677 {
3678 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
3679 forced_temporaries.insert(ops[1]);
3680 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3681 flush_all_atomic_capable_variables();
3682 register_read(ops[1], ops[2], should_forward(ops[2]));
3683 break;
3684 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003686 case OpAtomicSMax:
3687 case OpAtomicUMax:
3688 {
3689 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
3690 forced_temporaries.insert(ops[1]);
3691 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3692 flush_all_atomic_capable_variables();
3693 register_read(ops[1], ops[2], should_forward(ops[2]));
3694 break;
3695 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003696
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003697 case OpAtomicAnd:
3698 {
3699 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
3700 forced_temporaries.insert(ops[1]);
3701 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3702 flush_all_atomic_capable_variables();
3703 register_read(ops[1], ops[2], should_forward(ops[2]));
3704 break;
3705 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003706
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003707 case OpAtomicOr:
3708 {
3709 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
3710 forced_temporaries.insert(ops[1]);
3711 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3712 flush_all_atomic_capable_variables();
3713 register_read(ops[1], ops[2], should_forward(ops[2]));
3714 break;
3715 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003717 case OpAtomicXor:
3718 {
3719 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
3720 forced_temporaries.insert(ops[1]);
3721 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3722 flush_all_atomic_capable_variables();
3723 register_read(ops[1], ops[2], should_forward(ops[2]));
3724 break;
3725 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003726
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003727 // Geometry shaders
3728 case OpEmitVertex:
3729 statement("EmitVertex();");
3730 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003731
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003732 case OpEndPrimitive:
3733 statement("EndPrimitive();");
3734 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003735
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003736 case OpEmitStreamVertex:
3737 statement("EmitStreamVertex();");
3738 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003740 case OpEndStreamPrimitive:
3741 statement("EndStreamPrimitive();");
3742 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003743
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003744 // Textures
3745 case OpImageSampleImplicitLod:
3746 case OpImageSampleExplicitLod:
3747 case OpImageSampleProjImplicitLod:
3748 case OpImageSampleProjExplicitLod:
3749 case OpImageSampleDrefImplicitLod:
3750 case OpImageSampleDrefExplicitLod:
3751 case OpImageSampleProjDrefImplicitLod:
3752 case OpImageSampleProjDrefExplicitLod:
3753 case OpImageFetch:
3754 case OpImageGather:
3755 case OpImageDrefGather:
3756 // Gets a bit hairy, so move this to a separate instruction.
3757 emit_texture_op(instruction);
3758 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003759
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003760 case OpImage:
3761 {
3762 uint32_t result_type = ops[0];
3763 uint32_t id = ops[1];
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02003764 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, false);
3765
3766 // When using the image, we need to know which variable it is actually loaded from.
3767 auto *var = maybe_get_backing_variable(ops[2]);
3768 e.loaded_from = var ? var->self : 0;
3769 break;
3770 }
3771
Hans-Kristian Arntzen1b4f7662016-07-19 09:22:54 +02003772 case OpImageQueryLod:
3773 {
3774 if (!options.es && options.version < 400)
3775 {
3776 require_extension("GL_ARB_texture_query_lod");
3777 // For some reason, the ARB spec is all-caps.
3778 BFOP(textureQueryLOD);
3779 }
3780 else if (options.es)
3781 throw CompilerError("textureQueryLod not supported in ES profile.");
3782 else
3783 BFOP(textureQueryLod);
3784 break;
3785 }
3786
Hans-Kristian Arntzen81d00da2016-07-19 09:28:32 +02003787 case OpImageQueryLevels:
3788 {
3789 if (!options.es && options.version < 430)
3790 require_extension("GL_ARB_texture_query_levels");
3791 if (options.es)
3792 throw CompilerError("textureQueryLevels not supported in ES profile.");
3793 UFOP(textureQueryLevels);
3794 break;
3795 }
3796
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02003797 case OpImageQuerySamples:
3798 {
3799 auto *var = maybe_get_backing_variable(ops[2]);
3800 if (!var)
3801 throw CompilerError(
3802 "Bug. OpImageQuerySamples must have a backing variable so we know if the image is sampled or not.");
3803
3804 auto &type = get<SPIRType>(var->basetype);
3805 bool image = type.image.sampled == 2;
3806 if (image)
3807 UFOP(imageSamples);
3808 else
3809 UFOP(textureSamples);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003810 break;
3811 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003812
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003813 case OpSampledImage:
3814 {
3815 uint32_t result_type = ops[0];
3816 uint32_t id = ops[1];
3817 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
3818 break;
3819 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +02003820
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003821 case OpImageQuerySizeLod:
3822 BFOP(textureSize);
3823 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003824
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003825 // Image load/store
3826 case OpImageRead:
3827 {
3828 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
3829 // not adding the proper qualifiers.
3830 // If it turns out we need to read the image after all, remove the qualifier and recompile.
3831 auto *var = maybe_get_backing_variable(ops[2]);
3832 if (var)
3833 {
3834 auto &flags = meta.at(var->self).decoration.decoration_flags;
3835 if (flags & (1ull << DecorationNonReadable))
3836 {
3837 flags &= ~(1ull << DecorationNonReadable);
3838 force_recompile = true;
3839 }
3840 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003841
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003842 uint32_t result_type = ops[0];
3843 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003845 bool pure;
3846 string imgexpr;
3847 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003848
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02003849 if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003850 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02003851 if (type.image.ms)
3852 throw CompilerError("Trying to remap multisampled image to variable, this is not possible.");
3853
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003854 auto itr =
3855 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 +01003856
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003857 if (itr == end(pls_inputs))
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02003858 {
3859 // For non-PLS inputs, we rely on subpass type remapping information to get it right
3860 // since ImageRead always returns 4-component vectors and the backing type is opaque.
3861 if (!var->remapped_components)
3862 throw CompilerError("subpassInput was remapped, but remap_components is not set correctly.");
3863 imgexpr = remap_swizzle(result_type, var->remapped_components, ops[2]);
3864 }
3865 else
3866 {
3867 // PLS input could have different number of components than what the SPIR expects, swizzle to
3868 // the appropriate vector size.
3869 uint32_t components = pls_format_to_components(itr->format);
3870 imgexpr = remap_swizzle(result_type, components, ops[2]);
3871 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003872 pure = true;
3873 }
3874 else if (type.image.dim == DimSubpassData)
3875 {
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003876 if (options.vulkan_semantics)
3877 {
3878 // With Vulkan semantics, use the proper Vulkan GLSL construct.
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02003879 if (type.image.ms)
3880 {
3881 uint32_t operands = ops[4];
3882 if (operands != ImageOperandsSampleMask || length != 6)
3883 throw CompilerError(
3884 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
3885
3886 uint32_t samples = ops[5];
3887 imgexpr = join("subpassLoad(", to_expression(ops[2]), ", ", to_expression(samples), ")");
3888 }
3889 else
3890 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003891 }
3892 else
3893 {
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02003894 if (type.image.ms)
3895 {
3896 uint32_t operands = ops[4];
3897 if (operands != ImageOperandsSampleMask || length != 6)
3898 throw CompilerError(
3899 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
3900
3901 uint32_t samples = ops[5];
3902 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
3903 to_expression(samples), ")");
3904 }
3905 else
3906 {
3907 // Implement subpass loads via texture barrier style sampling.
3908 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
3909 }
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003910 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003911 pure = true;
3912 }
3913 else
3914 {
3915 // Plain image load/store.
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02003916 if (type.image.ms)
3917 {
3918 uint32_t operands = ops[4];
3919 if (operands != ImageOperandsSampleMask || length != 6)
3920 throw CompilerError(
3921 "Multisampled image used in OpImageRead, but unexpected operand mask was used.");
3922
3923 uint32_t samples = ops[5];
3924 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
3925 to_expression(samples), ")");
3926 }
3927 else
3928 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ")");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003929 pure = false;
3930 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003931
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003932 if (var && var->forwardable)
3933 {
3934 auto &e = emit_op(result_type, id, imgexpr, true, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003935
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003936 // We only need to track dependencies if we're reading from image load/store.
3937 if (!pure)
3938 {
3939 e.loaded_from = var->self;
3940 var->dependees.push_back(id);
3941 }
3942 }
3943 else
3944 emit_op(result_type, id, imgexpr, false, false);
3945 break;
3946 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003947
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003948 case OpImageTexelPointer:
3949 {
3950 uint32_t result_type = ops[0];
3951 uint32_t id = ops[1];
3952 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 +01003953
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02003954 // When using the pointer, we need to know which variable it is actually loaded from.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003955 auto *var = maybe_get_backing_variable(ops[2]);
3956 e.loaded_from = var ? var->self : 0;
3957 break;
3958 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003959
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003960 case OpImageWrite:
3961 {
3962 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
3963 // not adding the proper qualifiers.
3964 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
3965 auto *var = maybe_get_backing_variable(ops[0]);
3966 if (var)
3967 {
3968 auto &flags = meta.at(var->self).decoration.decoration_flags;
3969 if (flags & (1ull << DecorationNonWritable))
3970 {
3971 flags &= ~(1ull << DecorationNonWritable);
3972 force_recompile = true;
3973 }
3974 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003975
Hans-Kristian Arntzen7af13b62016-07-11 13:25:37 +02003976 auto &type = expression_type(ops[0]);
3977 if (type.image.ms)
3978 {
3979 uint32_t operands = ops[3];
3980 if (operands != ImageOperandsSampleMask || length != 5)
3981 throw CompilerError("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
3982 uint32_t samples = ops[4];
3983 statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(samples),
3984 ", ", to_expression(ops[2]), ");");
3985 }
3986 else
3987 statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]),
3988 ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003989
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003990 if (var && variable_storage_is_aliased(*var))
3991 flush_all_aliased_variables();
3992 break;
3993 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003994
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003995 case OpImageQuerySize:
3996 {
3997 auto &type = expression_type(ops[2]);
3998 uint32_t result_type = ops[0];
3999 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004000
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004001 if (type.basetype == SPIRType::Image)
4002 {
4003 // The size of an image is always constant.
4004 emit_op(result_type, id, join("imageSize(", to_expression(ops[2]), ")"), true, false);
4005 }
4006 else
4007 throw CompilerError("Invalid type for OpImageQuerySize.");
4008 break;
4009 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004010
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004011 // Compute
4012 case OpControlBarrier:
4013 {
4014 // Ignore execution and memory scope.
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004015 if (get_entry_point().model == ExecutionModelGLCompute)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004016 {
4017 uint32_t mem = get<SPIRConstant>(ops[2]).scalar();
4018 if (mem == MemorySemanticsWorkgroupMemoryMask)
4019 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02004020 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004021 statement("memoryBarrier();");
4022 }
4023 statement("barrier();");
4024 break;
4025 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004026
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004027 case OpMemoryBarrier:
4028 {
4029 uint32_t mem = get<SPIRConstant>(ops[1]).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004030
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004031 // We cannot forward any loads beyond the memory barrier.
4032 if (mem)
4033 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004034
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004035 if (mem == MemorySemanticsWorkgroupMemoryMask)
4036 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02004037 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004038 statement("memoryBarrier();");
4039 break;
4040 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004042 case OpExtInst:
4043 {
4044 uint32_t extension_set = ops[2];
4045 if (get<SPIRExtension>(extension_set).ext != SPIRExtension::GLSL)
4046 {
4047 statement("// unimplemented ext op ", instruction.op);
4048 break;
4049 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004050
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004051 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
4052 break;
4053 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004054
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004055 default:
4056 statement("// unimplemented op ", instruction.op);
4057 break;
4058 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004059}
4060
4061string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
4062{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004063 auto &memb = meta[type.self].members;
4064 if (index < memb.size() && !memb[index].alias.empty())
4065 return memb[index].alias;
4066 else
4067 return join("_", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004068}
4069
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004070void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
4071{
4072 auto &memb = meta[type.self].members;
4073 if (index < memb.size() && !memb[index].alias.empty())
4074 {
4075 auto &name = memb[index].alias;
4076 if (name.empty())
4077 return;
4078
4079 // Reserved for temporaries.
4080 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
4081 {
4082 name.clear();
4083 return;
4084 }
4085
4086 update_name_cache(type.member_name_cache, name);
4087 }
4088}
4089
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004090string CompilerGLSL::variable_decl(const SPIRType &type, const std::string &name)
4091{
4092 return join(type_to_glsl(type), " ", name, type_to_array_glsl(type));
4093}
4094
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004095string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index)
4096{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004097 uint64_t memberflags = 0;
4098 auto &memb = meta[type.self].members;
4099 if (index < memb.size())
4100 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004101
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004102 return join(layout_for_member(type, index), flags_to_precision_qualifiers_glsl(membertype, memberflags),
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004103 variable_decl(membertype, to_member_name(type, index)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004104}
4105
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004106const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004107{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004108 if (options.es)
4109 {
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004110 auto &execution = get_entry_point();
4111
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004112 // Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004113 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
4114 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
4115 type.basetype != SPIRType::Sampler)
4116 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004118 if (flags & (1ull << DecorationRelaxedPrecision))
4119 {
4120 bool implied_fmediump = type.basetype == SPIRType::Float &&
4121 options.fragment.default_float_precision == Options::Mediump &&
4122 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004123
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004124 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
4125 options.fragment.default_int_precision == Options::Mediump &&
4126 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004127
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004128 return implied_fmediump || implied_imediump ? "" : "mediump ";
4129 }
4130 else
4131 {
4132 bool implied_fhighp =
4133 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
4134 execution.model == ExecutionModelFragment) ||
4135 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004136
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004137 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
4138 ((options.fragment.default_int_precision == Options::Highp &&
4139 execution.model == ExecutionModelFragment) ||
4140 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004141
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004142 return implied_fhighp || implied_ihighp ? "" : "highp ";
4143 }
4144 }
4145 else
4146 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004147}
4148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004149const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004150{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004151 return flags_to_precision_qualifiers_glsl(expression_type(id), meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004152}
4153
4154string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
4155{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004156 auto flags = meta[id].decoration.decoration_flags;
4157 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004158
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004159 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004160
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004161 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
4162 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004163
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004164 res += to_precision_qualifiers_glsl(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004165
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004166 //if (flags & (1ull << DecorationSmooth))
4167 // res += "smooth ";
4168 if (flags & (1ull << DecorationFlat))
4169 res += "flat ";
4170 if (flags & (1ull << DecorationNoPerspective))
4171 res += "noperspective ";
4172 if (flags & (1ull << DecorationPatch))
4173 res += "patch ";
4174 if (flags & (1ull << DecorationSample))
4175 res += "sample ";
4176 if (flags & (1ull << DecorationInvariant))
4177 res += "invariant ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004178
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004179 auto &type = expression_type(id);
4180 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
4181 {
4182 if (flags & (1ull << DecorationNonWritable))
4183 res += "readonly ";
4184 if (flags & (1ull << DecorationNonReadable))
4185 res += "writeonly ";
4186 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004187
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004188 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004189}
4190
4191string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
4192{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004193 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
4194 // Not sure if argument being pointer type should make the argument inout.
4195 auto &type = expression_type(arg.id);
4196 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004197
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004198 if (type.pointer)
4199 {
4200 if (arg.write_count && arg.read_count)
4201 direction = "inout ";
4202 else if (arg.write_count)
4203 direction = "out ";
4204 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004205
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004206 return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004207}
4208
4209string CompilerGLSL::variable_decl(const SPIRVariable &variable)
4210{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004211 // Ignore the pointer type since GLSL doesn't have pointers.
4212 auto &type = get<SPIRType>(variable.basetype);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004213 auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self)));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004214 if (variable.initializer)
4215 res += join(" = ", to_expression(variable.initializer));
4216 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004217}
4218
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004219const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004220{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004221 auto flags = meta[variable.self].decoration.decoration_flags;
4222 if (flags & (1ull << DecorationRelaxedPrecision))
4223 return "mediump ";
4224 else
4225 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004226}
4227
4228string CompilerGLSL::pls_decl(const PlsRemap &var)
4229{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004230 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004232 SPIRType type;
4233 type.vecsize = pls_format_to_components(var.format);
4234 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004235
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004236 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
4237 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004238}
4239
4240string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
4241{
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004242 if (type.array.empty())
4243 return "";
4244
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004245 string res;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004246 for (size_t i = type.array.size(); i; i--)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004247 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004248 auto &size = type.array[i - 1];
4249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004250 res += "[";
4251 if (size)
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02004252 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004253 res += convert_to_string(size);
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02004254 }
4255 else if (!backend.flexible_member_array_supported)
4256 {
4257 // For runtime-sized arrays, we can work around
4258 // lack of standard support for this by simply having
4259 // a single element array.
4260 //
4261 // Runtime length arrays must always be the last element
4262 // in an interface block.
4263 res += '1';
4264 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004265 res += "]";
4266 }
4267 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004268}
4269
4270string CompilerGLSL::image_type_glsl(const SPIRType &type)
4271{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004272 auto &imagetype = get<SPIRType>(type.image.type);
4273 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004274
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004275 switch (imagetype.basetype)
4276 {
4277 case SPIRType::Int:
4278 res = "i";
4279 break;
4280 case SPIRType::UInt:
4281 res = "u";
4282 break;
4283 default:
4284 break;
4285 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004286
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004287 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
Hans-Kristian Arntzen3265e1f2016-07-11 13:36:11 +02004288 return res + "subpassInput" + (type.image.ms ? "MS" : "");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02004289
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004290 // If we're emulating subpassInput with samplers, force sampler2D
4291 // so we don't have to specify format.
4292 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
4293 res += type.image.sampled == 2 ? "image" : "texture";
4294 else
4295 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004297 switch (type.image.dim)
4298 {
4299 case Dim1D:
4300 res += "1D";
4301 break;
4302 case Dim2D:
4303 res += "2D";
4304 break;
4305 case Dim3D:
4306 res += "3D";
4307 break;
4308 case DimCube:
4309 res += "Cube";
4310 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004312 case DimBuffer:
4313 if (options.es && options.version < 320)
4314 require_extension("GL_OES_texture_buffer");
4315 else if (!options.es && options.version < 300)
4316 require_extension("GL_EXT_texture_buffer_object");
4317 res += "Buffer";
4318 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004320 case DimSubpassData:
4321 res += "2D";
4322 break;
4323 default:
4324 throw CompilerError("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
4325 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004326
Hans-Kristian Arntzen2c7d2e42016-07-11 12:47:46 +02004327 if (type.image.ms)
4328 res += "MS";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004329 if (type.image.arrayed)
4330 res += "Array";
4331 if (type.image.depth)
4332 res += "Shadow";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004334 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004335}
4336
4337string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
4338{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004339 auto e = type_to_glsl(type);
4340 for (uint32_t i = 0; i < type.array.size(); i++)
4341 e += "[]";
4342 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004343}
4344
4345string CompilerGLSL::type_to_glsl(const SPIRType &type)
4346{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004347 // Ignore the pointer type since GLSL doesn't have pointers.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004349 switch (type.basetype)
4350 {
4351 case SPIRType::Struct:
4352 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004353 if (backend.explicit_struct_type)
4354 return join("struct ", to_name(type.self));
4355 else
4356 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004357
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004358 case SPIRType::Image:
4359 case SPIRType::SampledImage:
4360 return image_type_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004361
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004362 case SPIRType::Sampler:
4363 // Not really used.
4364 return "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004365
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004366 case SPIRType::Void:
4367 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004368
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004369 default:
4370 break;
4371 }
4372
4373 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
4374 {
4375 switch (type.basetype)
4376 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004377 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004378 return "bool";
4379 case SPIRType::Int:
4380 return backend.basic_int_type;
4381 case SPIRType::UInt:
4382 return backend.basic_uint_type;
4383 case SPIRType::AtomicCounter:
4384 return "atomic_uint";
4385 case SPIRType::Float:
4386 return "float";
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004387 case SPIRType::Double:
4388 return "double";
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004389 case SPIRType::Int64:
4390 return "int64_t";
4391 case SPIRType::UInt64:
4392 return "uint64_t";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004393 default:
4394 return "???";
4395 }
4396 }
4397 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
4398 {
4399 switch (type.basetype)
4400 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004401 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004402 return join("bvec", type.vecsize);
4403 case SPIRType::Int:
4404 return join("ivec", type.vecsize);
4405 case SPIRType::UInt:
4406 return join("uvec", type.vecsize);
4407 case SPIRType::Float:
4408 return join("vec", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004409 case SPIRType::Double:
4410 return join("dvec", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004411 case SPIRType::Int64:
4412 return join("i64vec", type.vecsize);
4413 case SPIRType::UInt64:
4414 return join("u64vec", type.vecsize);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004415 default:
4416 return "???";
4417 }
4418 }
4419 else if (type.vecsize == type.columns) // Simple Matrix builtin
4420 {
4421 switch (type.basetype)
4422 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004423 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004424 return join("bmat", type.vecsize);
4425 case SPIRType::Int:
4426 return join("imat", type.vecsize);
4427 case SPIRType::UInt:
4428 return join("umat", type.vecsize);
4429 case SPIRType::Float:
4430 return join("mat", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004431 case SPIRType::Double:
4432 return join("dmat", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004433 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004434 default:
4435 return "???";
4436 }
4437 }
4438 else
4439 {
4440 switch (type.basetype)
4441 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004442 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004443 return join("bmat", type.columns, "x", type.vecsize);
4444 case SPIRType::Int:
4445 return join("imat", type.columns, "x", type.vecsize);
4446 case SPIRType::UInt:
4447 return join("umat", type.columns, "x", type.vecsize);
4448 case SPIRType::Float:
4449 return join("mat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02004450 case SPIRType::Double:
4451 return join("dmat", type.columns, "x", type.vecsize);
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +02004452 // Matrix types not supported for int64/uint64.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004453 default:
4454 return "???";
4455 }
4456 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004457}
4458
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004459void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004460{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004461 auto &name = meta[id].decoration.alias;
4462 if (name.empty())
4463 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004464
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004465 // Reserved for temporaries.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004466 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004467 {
4468 name.clear();
4469 return;
4470 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004471
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004472 update_name_cache(variables, name);
4473}
4474
4475void CompilerGLSL::add_local_variable_name(uint32_t id)
4476{
4477 add_variable(local_variable_names, id);
4478}
4479
4480void CompilerGLSL::add_resource_name(uint32_t id)
4481{
4482 add_variable(resource_names, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004483}
4484
Hans-Kristian Arntzen8e63c772016-07-06 09:58:01 +02004485void CompilerGLSL::add_header_line(const std::string &line)
4486{
4487 header_lines.push_back(line);
4488}
4489
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004490void CompilerGLSL::require_extension(const string &ext)
4491{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004492 if (forced_extensions.find(ext) == end(forced_extensions))
4493 {
4494 forced_extensions.insert(ext);
4495 force_recompile = true;
4496 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004497}
4498
4499bool CompilerGLSL::check_atomic_image(uint32_t id)
4500{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004501 auto &type = expression_type(id);
4502 if (type.storage == StorageClassImage)
4503 {
4504 if (options.es && options.version < 320)
4505 require_extension("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004506
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004507 auto *var = maybe_get_backing_variable(id);
4508 if (var)
4509 {
4510 auto &flags = meta.at(var->self).decoration.decoration_flags;
4511 if (flags & ((1ull << DecorationNonWritable) | (1ull << DecorationNonReadable)))
4512 {
4513 flags &= ~(1ull << DecorationNonWritable);
4514 flags &= ~(1ull << DecorationNonReadable);
4515 force_recompile = true;
4516 }
4517 }
4518 return true;
4519 }
4520 else
4521 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004522}
4523
4524void CompilerGLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_flags)
4525{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004526 // Avoid shadow declarations.
4527 local_variable_names = resource_names;
4528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004529 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004530
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004531 auto &type = get<SPIRType>(func.return_type);
4532 decl += flags_to_precision_qualifiers_glsl(type, return_flags);
4533 decl += type_to_glsl(type);
4534 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004535
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004536 if (func.self == entry_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004537 {
4538 decl += "main";
4539 processing_entry_point = true;
4540 }
4541 else
4542 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004543
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004544 decl += "(";
4545 for (auto &arg : func.arguments)
4546 {
4547 // Might change the variable name if it already exists in this function.
4548 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
4549 // to use same name for variables.
4550 // 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 +02004551 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004552
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004553 decl += argument_decl(arg);
4554 if (&arg != &func.arguments.back())
4555 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004557 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
4558 auto *var = maybe_get<SPIRVariable>(arg.id);
4559 if (var)
4560 var->parameter = &arg;
4561 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004562
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004563 decl += ")";
4564 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004565}
4566
4567void CompilerGLSL::emit_function(SPIRFunction &func, uint64_t return_flags)
4568{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004569 // Avoid potential cycles.
4570 if (func.active)
4571 return;
4572 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004574 // If we depend on a function, emit that function before we emit our own function.
4575 for (auto block : func.blocks)
4576 {
4577 auto &b = get<SPIRBlock>(block);
4578 for (auto &i : b.ops)
4579 {
4580 auto ops = stream(i);
4581 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004582
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004583 if (op == OpFunctionCall)
4584 {
4585 // Recursively emit functions which are called.
4586 uint32_t id = ops[2];
4587 emit_function(get<SPIRFunction>(id), meta[ops[1]].decoration.decoration_flags);
4588 }
4589 }
4590 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004592 emit_function_prototype(func, return_flags);
4593 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004595 current_function = &func;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004596
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004597 for (auto &v : func.local_variables)
4598 {
4599 auto &var = get<SPIRVariable>(v);
4600 if (expression_is_lvalue(v))
4601 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004602 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004603
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004604 if (var.initializer)
4605 statement(variable_decl(var), ";");
4606 else
4607 {
4608 // Don't declare variable until first use to declutter the GLSL output quite a lot.
4609 // If we don't touch the variable before first branch,
4610 // declare it then since we need variable declaration to be in top scope.
4611 var.deferred_declaration = true;
4612 }
4613 }
4614 else
4615 {
4616 // HACK: SPIRV likes to use samplers and images as local variables, but GLSL does not allow
4617 // this. For these types (non-lvalue), we enforce forwarding through a shadowed variable.
4618 // This means that when we OpStore to these variables, we just write in the expression ID directly.
4619 // This breaks any kind of branching, since the variable must be statically assigned.
4620 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
4621 var.statically_assigned = true;
4622 }
4623 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004624
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004625 auto &entry_block = get<SPIRBlock>(func.entry_block);
4626 entry_block.loop_dominator = SPIRBlock::NoDominator;
4627 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004628
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004629 end_scope();
4630 processing_entry_point = false;
4631 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004632}
4633
4634void CompilerGLSL::emit_fixup()
4635{
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +02004636 auto &execution = get_entry_point();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004637 if (execution.model == ExecutionModelVertex && options.vertex.fixup_clipspace)
4638 {
4639 const char *suffix = backend.float_literal_suffix ? "f" : "";
4640 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
4641 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004642}
4643
4644bool CompilerGLSL::flush_phi_required(uint32_t from, uint32_t to)
4645{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004646 auto &child = get<SPIRBlock>(to);
4647 for (auto &phi : child.phi_variables)
4648 if (phi.parent == from)
4649 return true;
4650 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004651}
4652
4653void CompilerGLSL::flush_phi(uint32_t from, uint32_t to)
4654{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004655 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004657 for (auto &phi : child.phi_variables)
4658 if (phi.parent == from)
4659 statement(to_expression(phi.function_variable), " = ", to_expression(phi.local_variable), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004660}
4661
4662void CompilerGLSL::branch(uint32_t from, uint32_t to)
4663{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004664 flush_phi(from, to);
4665 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004666
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004667 // This is only a continue if we branch to our loop dominator.
4668 if (loop_blocks.find(to) != end(loop_blocks) && get<SPIRBlock>(from).loop_dominator == to)
4669 {
4670 // This can happen if we had a complex continue block which was emitted.
4671 // Once the continue block tries to branch to the loop header, just emit continue;
4672 // and end the chain here.
4673 statement("continue;");
4674 }
4675 else if (is_continue(to))
4676 {
4677 auto &to_block = get<SPIRBlock>(to);
4678 if (to_block.complex_continue)
4679 {
4680 // Just emit the whole block chain as is.
4681 auto usage_counts = expression_usage_counts;
4682 auto invalid = invalid_expressions;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004683
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004684 emit_block_chain(to_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004686 // Expression usage counts and invalid expressions
4687 // are moot after returning from the continue block.
4688 // Since we emit the same block multiple times,
4689 // we don't want to invalidate ourselves.
4690 expression_usage_counts = usage_counts;
4691 invalid_expressions = invalid;
4692 }
4693 else
4694 {
4695 auto &from_block = get<SPIRBlock>(from);
4696 auto &dominator = get<SPIRBlock>(from_block.loop_dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004697
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004698 // For non-complex continue blocks, we implicitly branch to the continue block
4699 // by having the continue block be part of the loop header in for (; ; continue-block).
4700 bool outside_control_flow = block_is_outside_flow_control_from_block(dominator, from_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004701
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004702 // Some simplification for for-loops. We always end up with a useless continue;
4703 // statement since we branch to a loop block.
4704 // Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block,
4705 // we can avoid writing out an explicit continue statement.
4706 // Similar optimization to return statements if we know we're outside flow control.
4707 if (!outside_control_flow)
4708 statement("continue;");
4709 }
4710 }
4711 else if (is_break(to))
4712 statement("break;");
4713 else if (!is_conditional(to))
4714 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004715}
4716
4717void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block)
4718{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004719 // If we branch directly to a selection merge target, we don't really need a code path.
4720 bool true_sub = !is_conditional(true_block);
4721 bool false_sub = !is_conditional(false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004723 if (true_sub)
4724 {
4725 statement("if (", to_expression(cond), ")");
4726 begin_scope();
4727 branch(from, true_block);
4728 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004729
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004730 if (false_sub)
4731 {
4732 statement("else");
4733 begin_scope();
4734 branch(from, false_block);
4735 end_scope();
4736 }
4737 else if (flush_phi_required(from, false_block))
4738 {
4739 statement("else");
4740 begin_scope();
4741 flush_phi(from, false_block);
4742 end_scope();
4743 }
4744 }
4745 else if (false_sub && !true_sub)
4746 {
4747 // Only need false path, use negative conditional.
4748 statement("if (!", to_expression(cond), ")");
4749 begin_scope();
4750 branch(from, false_block);
4751 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004752
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004753 if (flush_phi_required(from, true_block))
4754 {
4755 statement("else");
4756 begin_scope();
4757 flush_phi(from, true_block);
4758 end_scope();
4759 }
4760 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004761}
4762
4763void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
4764{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004765 // Propagate down the loop dominator block, so that dominated blocks can back trace.
4766 if (block.merge == SPIRBlock::MergeLoop || block.loop_dominator)
4767 {
4768 uint32_t dominator = block.merge == SPIRBlock::MergeLoop ? block.self : block.loop_dominator;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004769
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02004770 auto set_dominator = [this](uint32_t self, uint32_t new_dominator) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004771 auto &dominated_block = this->get<SPIRBlock>(self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004772
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004773 // If we already have a loop dominator, we're trying to break out to merge targets
4774 // which should not update the loop dominator.
4775 if (!dominated_block.loop_dominator)
4776 dominated_block.loop_dominator = new_dominator;
4777 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004778
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004779 // After merging a loop, we inherit the loop dominator always.
4780 if (block.merge_block)
4781 set_dominator(block.merge_block, block.loop_dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004782
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004783 if (block.true_block)
4784 set_dominator(block.true_block, dominator);
4785 if (block.false_block)
4786 set_dominator(block.false_block, dominator);
4787 if (block.next_block)
4788 set_dominator(block.next_block, dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004789
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004790 for (auto &c : block.cases)
4791 set_dominator(c.block, dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004792
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004793 // In older glslang output continue_block can be == loop header.
4794 if (block.continue_block && block.continue_block != block.self)
4795 set_dominator(block.continue_block, dominator);
4796 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004797}
4798
4799// FIXME: This currently cannot handle complex continue blocks
4800// as in do-while.
4801// This should be seen as a "trivial" continue block.
4802string CompilerGLSL::emit_continue_block(uint32_t continue_block)
4803{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004804 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004806 // While emitting the continue block, declare_temporary will check this
4807 // if we have to emit temporaries.
4808 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004809
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004810 vector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004811
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004812 // Capture all statements into our list.
4813 auto *old = redirect_statement;
4814 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004815
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004816 // Stamp out all blocks one after each other.
4817 while (loop_blocks.find(block->self) == end(loop_blocks))
4818 {
4819 propagate_loop_dominators(*block);
4820 // Write out all instructions we have in this block.
4821 for (auto &op : block->ops)
4822 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004823
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004824 // For plain branchless for/while continue blocks.
4825 if (block->next_block)
4826 {
4827 flush_phi(continue_block, block->next_block);
4828 block = &get<SPIRBlock>(block->next_block);
4829 }
4830 // For do while blocks. The last block will be a select block.
4831 else if (block->true_block)
4832 {
4833 flush_phi(continue_block, block->true_block);
4834 block = &get<SPIRBlock>(block->true_block);
4835 }
4836 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004837
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004838 // Restore old pointer.
4839 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004840
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004841 // Somewhat ugly, strip off the last ';' since we use ',' instead.
4842 // Ideally, we should select this behavior in statement().
4843 for (auto &s : statements)
4844 {
4845 if (!s.empty() && s.back() == ';')
4846 s.pop_back();
4847 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004848
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004849 current_continue_block = nullptr;
4850 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004851}
4852
4853bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
4854{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004855 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004856
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004857 if (method == SPIRBlock::MergeToSelectForLoop)
4858 {
4859 uint32_t current_count = statement_count;
4860 // If we're trying to create a true for loop,
4861 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4862 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4863 for (auto &op : block.ops)
4864 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004866 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004867
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004868 // This can work! We only did trivial things which could be forwarded in block body!
4869 if (current_count == statement_count && condition_is_temporary)
4870 {
4871 switch (continue_type)
4872 {
4873 case SPIRBlock::ForLoop:
4874 statement("for (; ", to_expression(block.condition), "; ", emit_continue_block(block.continue_block),
4875 ")");
4876 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004877
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004878 case SPIRBlock::WhileLoop:
4879 statement("while (", to_expression(block.condition), ")");
4880 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004881
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004882 default:
4883 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
4884 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004885
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004886 begin_scope();
4887 return true;
4888 }
4889 else
4890 {
4891 block.disable_block_optimization = true;
4892 force_recompile = true;
4893 begin_scope(); // We'll see an end_scope() later.
4894 return false;
4895 }
4896 }
4897 else if (method == SPIRBlock::MergeToDirectForLoop)
4898 {
4899 uint32_t current_count = statement_count;
4900 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004901
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004902 // If we're trying to create a true for loop,
4903 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4904 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4905 for (auto &op : child.ops)
4906 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004907
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004908 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004909
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004910 if (current_count == statement_count && condition_is_temporary)
4911 {
4912 propagate_loop_dominators(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004913
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004914 switch (continue_type)
4915 {
4916 case SPIRBlock::ForLoop:
4917 statement("for (; ", to_expression(child.condition), "; ", emit_continue_block(block.continue_block),
4918 ")");
4919 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004920
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004921 case SPIRBlock::WhileLoop:
4922 statement("while (", to_expression(child.condition), ")");
4923 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004924
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004925 default:
4926 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
4927 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004928
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004929 begin_scope();
4930 branch(child.self, child.true_block);
4931 return true;
4932 }
4933 else
4934 {
4935 block.disable_block_optimization = true;
4936 force_recompile = true;
4937 begin_scope(); // We'll see an end_scope() later.
4938 return false;
4939 }
4940 }
4941 else
4942 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004943}
4944
4945void CompilerGLSL::flush_undeclared_variables()
4946{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004947 // Declare undeclared variables.
4948 if (current_function->flush_undeclared)
4949 {
4950 for (auto &v : current_function->local_variables)
4951 {
4952 auto &var = get<SPIRVariable>(v);
4953 if (var.deferred_declaration)
4954 statement(variable_decl(var), ";");
4955 var.deferred_declaration = false;
4956 }
4957 current_function->flush_undeclared = false;
4958 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004959}
4960
4961void CompilerGLSL::emit_block_chain(SPIRBlock &block)
4962{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004963 propagate_loop_dominators(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004964
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004965 bool select_branch_to_true_block = false;
4966 bool skip_direct_branch = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004967
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004968 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
4969 for (auto &tmp : block.declare_temporary)
4970 {
4971 auto flags = meta[tmp.second].decoration.decoration_flags;
4972 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004973 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004974 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004975
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004976 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
4977 if (block.continue_block)
4978 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004979
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004980 // This is the older loop behavior in glslang which branches to loop body directly from the loop header.
4981 if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
4982 {
4983 flush_undeclared_variables();
4984 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
4985 {
4986 // The body of while, is actually just the true block, so always branch there
4987 // unconditionally.
4988 select_branch_to_true_block = true;
4989 }
4990 }
4991 // This is the newer loop behavior in glslang which branches from Loop header directly to
4992 // a new block, which in turn has a OpBranchSelection without a selection merge.
4993 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
4994 {
4995 flush_undeclared_variables();
4996 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
4997 skip_direct_branch = true;
4998 }
4999 else if (continue_type == SPIRBlock::DoWhileLoop)
5000 {
5001 statement("do");
5002 begin_scope();
5003 for (auto &op : block.ops)
5004 emit_instruction(op);
5005 }
5006 else if (block.merge == SPIRBlock::MergeLoop)
5007 {
5008 flush_undeclared_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005009
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005010 // We have a generic loop without any distinguishable pattern like for, while or do while.
5011 get<SPIRBlock>(block.continue_block).complex_continue = true;
5012 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005013
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005014 statement("for (;;)");
5015 begin_scope();
5016 for (auto &op : block.ops)
5017 emit_instruction(op);
5018 }
5019 else
5020 {
5021 for (auto &op : block.ops)
5022 emit_instruction(op);
5023 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005025 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005026
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005027 // Handle end of block.
5028 switch (block.terminator)
5029 {
5030 case SPIRBlock::Direct:
5031 // True when emitting complex continue block.
5032 if (block.loop_dominator == block.next_block)
5033 {
5034 branch(block.self, block.next_block);
5035 emit_next_block = false;
5036 }
5037 // True if MergeToDirectForLoop succeeded.
5038 else if (skip_direct_branch)
5039 emit_next_block = false;
5040 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
5041 {
5042 branch(block.self, block.next_block);
5043 emit_next_block = false;
5044 }
5045 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005046
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005047 case SPIRBlock::Select:
5048 // True if MergeToSelectForLoop succeeded.
5049 if (select_branch_to_true_block)
5050 branch(block.self, block.true_block);
5051 else
5052 {
5053 flush_undeclared_variables();
5054 branch(block.self, block.condition, block.true_block, block.false_block);
5055 }
5056 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005057
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005058 case SPIRBlock::MultiSelect:
5059 {
5060 flush_undeclared_variables();
5061 auto &type = expression_type(block.condition);
5062 bool uint32_t_case = type.basetype == SPIRType::UInt;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005063
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005064 statement("switch (", to_expression(block.condition), ")");
5065 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005066
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005067 for (auto &c : block.cases)
5068 {
5069 auto case_value =
5070 uint32_t_case ? convert_to_string(uint32_t(c.value)) : convert_to_string(int32_t(c.value));
5071 statement("case ", case_value, ":");
5072 begin_scope();
5073 branch(block.self, c.block);
5074 end_scope();
5075 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005076
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005077 if (block.default_block != block.next_block)
5078 {
5079 statement("default:");
5080 begin_scope();
5081 if (is_break(block.default_block))
5082 throw CompilerError("Cannot break; out of a switch statement and out of a loop at the same time ...");
5083 branch(block.self, block.default_block);
5084 end_scope();
5085 }
5086 else if (flush_phi_required(block.self, block.next_block))
5087 {
5088 statement("default:");
5089 begin_scope();
5090 flush_phi(block.self, block.next_block);
5091 statement("break;");
5092 end_scope();
5093 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005094
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005095 end_scope();
5096 break;
5097 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005098
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005099 case SPIRBlock::Return:
5100 if (processing_entry_point)
5101 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005102
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005103 if (block.return_value)
5104 {
5105 // OpReturnValue can return Undef, so don't emit anything for this case.
5106 if (ids.at(block.return_value).get_type() != TypeUndef)
5107 statement("return ", to_expression(block.return_value), ";");
5108 }
5109 // If this block is the very final block and not called from control flow,
5110 // we do not need an explicit return which looks out of place. Just end the function here.
5111 // In the very weird case of for(;;) { return; } executing return is unconditional,
5112 // but we actually need a return here ...
5113 else if (!block_is_outside_flow_control_from_block(get<SPIRBlock>(current_function->entry_block), block) ||
5114 block.loop_dominator != SPIRBlock::NoDominator)
5115 statement("return;");
5116 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005118 case SPIRBlock::Kill:
5119 statement("discard;");
5120 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005121
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005122 default:
5123 throw CompilerError("Unimplemented block terminator.");
5124 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005125
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005126 if (block.next_block && emit_next_block)
5127 {
5128 // If we hit this case, we're dealing with an unconditional branch, which means we will output
5129 // that block after this. If we had selection merge, we already flushed phi variables.
5130 if (block.merge != SPIRBlock::MergeSelection)
5131 flush_phi(block.self, block.next_block);
5132 emit_block_chain(get<SPIRBlock>(block.next_block));
5133 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005134
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005135 if (block.merge == SPIRBlock::MergeLoop)
5136 {
5137 if (continue_type == SPIRBlock::DoWhileLoop)
5138 {
5139 // Make sure that we run the continue block to get the expressions set, but this
5140 // should become an empty string.
5141 // We have no fallbacks if we cannot forward everything to temporaries ...
5142 auto statements = emit_continue_block(block.continue_block);
5143 if (!statements.empty())
5144 {
5145 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
5146 get<SPIRBlock>(block.continue_block).complex_continue = true;
5147 force_recompile = true;
5148 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005149
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005150 end_scope_decl(join("while (", to_expression(get<SPIRBlock>(block.continue_block).condition), ")"));
5151 }
5152 else
5153 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005154
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005155 flush_phi(block.self, block.merge_block);
5156 emit_block_chain(get<SPIRBlock>(block.merge_block));
5157 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005158}
5159
5160void CompilerGLSL::begin_scope()
5161{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005162 statement("{");
5163 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005164}
5165
5166void CompilerGLSL::end_scope()
5167{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005168 if (!indent)
5169 throw CompilerError("Popping empty indent stack.");
5170 indent--;
5171 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005172}
5173
5174void CompilerGLSL::end_scope_decl()
5175{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005176 if (!indent)
5177 throw CompilerError("Popping empty indent stack.");
5178 indent--;
5179 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005180}
5181
5182void CompilerGLSL::end_scope_decl(const string &decl)
5183{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02005184 if (!indent)
5185 throw CompilerError("Popping empty indent stack.");
5186 indent--;
5187 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01005188}
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02005189
5190void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length)
5191{
5192 // If our variable is remapped, and we rely on type-remapping information as
5193 // well, then we cannot pass the variable as a function parameter.
5194 // Fixing this is non-trivial without stamping out variants of the same function,
5195 // so for now warn about this and suggest workarounds instead.
5196 for (uint32_t i = 0; i < length; i++)
5197 {
5198 auto *var = maybe_get<SPIRVariable>(args[i]);
5199 if (!var || !var->remapped_variable)
5200 continue;
5201
5202 auto &type = get<SPIRType>(var->basetype);
5203 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
5204 {
5205 throw CompilerError("Tried passing a remapped subpassInput variable to a function. "
5206 "This will not work correctly because type-remapping information is lost. "
5207 "To workaround, please consider not passing the subpass input as a function parameter, "
5208 "or use in/out variables instead which do not need type remapping information.");
5209 }
5210 }
5211}