blob: 1cee3753b61298b92b99736451fa74e25013755f [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
179string CompilerGLSL::compile()
180{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200181 uint32_t pass_count = 0;
182 do
183 {
184 if (pass_count >= 3)
185 throw CompilerError("Over 3 compilation loops detected. Must be a bug!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100186
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200187 reset();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100188
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200189 // Move constructor for this type is broken on GCC 4.9 ...
190 buffer = unique_ptr<ostringstream>(new ostringstream());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100191
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200192 emit_header();
193 emit_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100194
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200195 emit_function(get<SPIRFunction>(execution.entry_point), 0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100196
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200197 pass_count++;
198 } while (force_recompile);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100199
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200200 return buffer->str();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100201}
202
203void CompilerGLSL::emit_header()
204{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200205 statement("#version ", options.version, options.es && options.version > 100 ? " es" : "");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200207 // Needed for binding = # on UBOs, etc.
208 if (!options.es && options.version < 420)
209 {
210 statement("#ifdef GL_ARB_shading_language_420pack");
211 statement("#extension GL_ARB_shading_language_420pack : require");
212 statement("#endif");
213 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100214
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200215 for (auto &ext : forced_extensions)
216 statement("#extension ", ext, " : require");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200218 if (!pls_inputs.empty() || !pls_outputs.empty())
219 statement("#extension GL_EXT_shader_pixel_local_storage : require");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100220
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200221 vector<string> inputs;
222 vector<string> outputs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100223
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200224 switch (execution.model)
225 {
226 case ExecutionModelGeometry:
227 if (options.es && options.version < 320)
228 statement("#extension GL_EXT_geometry_shader : require");
229 if (!options.es && options.version < 320)
230 statement("#extension GL_ARB_geometry_shader4 : require");
231 outputs.push_back(join("max_vertices = ", execution.output_vertices));
232 if (execution.flags & (1ull << ExecutionModeInvocations))
233 inputs.push_back(join("invocations = ", execution.invocations));
234 if (execution.flags & (1ull << ExecutionModeInputPoints))
235 inputs.push_back("points");
236 if (execution.flags & (1ull << ExecutionModeInputLines))
237 inputs.push_back("lines");
238 if (execution.flags & (1ull << ExecutionModeInputLinesAdjacency))
239 inputs.push_back("lines_adjacency");
240 if (execution.flags & (1ull << ExecutionModeTriangles))
241 inputs.push_back("triangles");
242 if (execution.flags & (1ull << ExecutionModeInputTrianglesAdjacency))
243 inputs.push_back("triangles_adjacency");
244 if (execution.flags & (1ull << ExecutionModeOutputTriangleStrip))
245 outputs.push_back("triangle_strip");
246 if (execution.flags & (1ull << ExecutionModeOutputPoints))
247 outputs.push_back("points");
248 if (execution.flags & (1ull << ExecutionModeOutputLineStrip))
249 outputs.push_back("line_strip");
250 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200252 case ExecutionModelTessellationControl:
253 if (options.es && options.version < 320)
254 statement("#extension GL_EXT_tessellation_shader : require");
255 if (!options.es && options.version < 400)
256 statement("#extension GL_ARB_tessellation_shader : require");
257 if (execution.flags & (1ull << ExecutionModeOutputVertices))
258 outputs.push_back(join("vertices = ", execution.output_vertices));
259 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200261 case ExecutionModelTessellationEvaluation:
262 if (options.es && options.version < 320)
263 statement("#extension GL_EXT_tessellation_shader : require");
264 if (!options.es && options.version < 400)
265 statement("#extension GL_ARB_tessellation_shader : require");
266 if (execution.flags & (1ull << ExecutionModeQuads))
267 inputs.push_back("quads");
268 if (execution.flags & (1ull << ExecutionModeIsolines))
269 inputs.push_back("isolines");
270 if (execution.flags & (1ull << ExecutionModePointMode))
271 inputs.push_back("point_mode");
272 if (execution.flags & (1ull << ExecutionModeVertexOrderCw))
273 inputs.push_back("cw");
274 if (execution.flags & (1ull << ExecutionModeVertexOrderCcw))
275 inputs.push_back("ccw");
276 if (execution.flags & (1ull << ExecutionModeSpacingFractionalEven))
277 inputs.push_back("fractional_even_spacing");
278 if (execution.flags & (1ull << ExecutionModeSpacingFractionalOdd))
279 inputs.push_back("fractional_odd_spacing");
280 if (execution.flags & (1ull << ExecutionModeSpacingEqual))
281 inputs.push_back("equal_spacing");
282 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100283
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200284 case ExecutionModelGLCompute:
285 if (!options.es && options.version < 430)
286 statement("#extension GL_ARB_compute_shader : require");
287 if (options.es && options.version < 310)
288 throw CompilerError("At least ESSL 3.10 required for compute shaders.");
289 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
290 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
291 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
292 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100293
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200294 case ExecutionModelFragment:
295 if (options.es)
296 {
297 switch (options.fragment.default_float_precision)
298 {
299 case Options::Lowp:
300 statement("precision lowp float;");
301 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200303 case Options::Mediump:
304 statement("precision mediump float;");
305 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200307 case Options::Highp:
308 statement("precision highp float;");
309 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200311 default:
312 break;
313 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200315 switch (options.fragment.default_int_precision)
316 {
317 case Options::Lowp:
318 statement("precision lowp int;");
319 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100320
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200321 case Options::Mediump:
322 statement("precision mediump int;");
323 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100324
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200325 case Options::Highp:
326 statement("precision highp int;");
327 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200329 default:
330 break;
331 }
332 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200334 if (execution.flags & (1ull << ExecutionModeEarlyFragmentTests))
335 inputs.push_back("early_fragment_tests");
336 if (execution.flags & (1ull << ExecutionModeDepthGreater))
337 inputs.push_back("depth_greater");
338 if (execution.flags & (1ull << ExecutionModeDepthLess))
339 inputs.push_back("depth_less");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100342
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200343 default:
344 break;
345 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100346
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200347 if (!inputs.empty())
348 statement("layout(", merge(inputs), ") in;");
349 if (!outputs.empty())
350 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200352 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100353}
354
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200355void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100356{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200357 // Struct types can be stamped out multiple times
358 // with just different offsets, matrix layouts, etc ...
359 // Type-punning with these types is legal, which complicates things
360 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200361 if (type.type_alias != 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200362 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200363
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200364 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200365 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100366
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200367 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200368 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100369
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200370 type.member_name_cache.clear();
371
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200372 uint32_t i = 0;
373 bool emitted = false;
374 for (auto &member : type.member_types)
375 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200376 add_member_name(type, i);
377
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200378 auto &membertype = get<SPIRType>(member);
379 statement(member_decl(type, membertype, i), ";");
380 i++;
381 emitted = true;
382 }
383 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200385 if (emitted)
386 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100387}
388
389uint64_t CompilerGLSL::combined_decoration_for_member(const SPIRType &type, uint32_t index)
390{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200391 uint64_t flags = 0;
392 auto &memb = meta[type.self].members;
393 if (index >= memb.size())
394 return 0;
395 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100396
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200397 // If our type is a sturct, traverse all the members as well recursively.
398 flags |= dec.decoration_flags;
399 for (uint32_t i = 0; i < type.member_types.size(); i++)
400 flags |= combined_decoration_for_member(get<SPIRType>(type.member_types[i]), i);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100401
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200402 return flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100403}
404
405string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
406{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200407 bool is_block = (meta[type.self].decoration.decoration_flags &
408 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
409 if (!is_block)
410 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100411
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200412 auto &memb = meta[type.self].members;
413 if (index >= memb.size())
414 return 0;
415 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200417 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100418
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200419 // We can only apply layouts on members in block interfaces.
420 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
421 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
422 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
423 //
424 // We would like to go from (SPIR-V style):
425 //
426 // struct Foo { layout(row_major) mat4 matrix; };
427 // buffer UBO { Foo foo; };
428 //
429 // to
430 //
431 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
432 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
433 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100434
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200435 if (flags & (1ull << DecorationRowMajor))
436 attr.push_back("row_major");
437 // We don't emit any global layouts, so column_major is default.
438 //if (flags & (1ull << DecorationColMajor))
439 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100440
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200441 if (dec.decoration_flags & (1ull << DecorationLocation))
442 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100443
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200444 if (attr.empty())
445 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100446
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200447 string res = "layout(";
448 res += merge(attr);
449 res += ") ";
450 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100451}
452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200453const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100454{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200455 // Only handle GLES 3.1 compliant types for now ...
456 switch (format)
457 {
458 case ImageFormatRgba32f:
459 return "rgba32f";
460 case ImageFormatRgba16f:
461 return "rgba16f";
462 case ImageFormatR32f:
463 return "r32f";
464 case ImageFormatRgba8:
465 return "rgba8";
466 case ImageFormatRgba8Snorm:
467 return "rgba8_snorm";
468 case ImageFormatRg32f:
469 return "rg32f";
470 case ImageFormatRg16f:
471 return "rg16f";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100472
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200473 case ImageFormatRgba32i:
474 return "rgba32i";
475 case ImageFormatRgba16i:
476 return "rgba16i";
477 case ImageFormatR32i:
478 return "r32i";
479 case ImageFormatRgba8i:
480 return "rgba8i";
481 case ImageFormatRg32i:
482 return "rg32i";
483 case ImageFormatRg16i:
484 return "rg16i";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100485
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200486 case ImageFormatRgba32ui:
487 return "rgba32ui";
488 case ImageFormatRgba16ui:
489 return "rgba16ui";
490 case ImageFormatR32ui:
491 return "r32ui";
492 case ImageFormatRgba8ui:
493 return "rgba8ui";
494 case ImageFormatRg32ui:
495 return "rg32ui";
496 case ImageFormatRg16ui:
497 return "rg16ui";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100498
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200499 case ImageFormatUnknown:
500 return nullptr;
501 default:
502 return "UNSUPPORTED"; // TODO: Fill in rest.
503 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100504}
505
506uint32_t CompilerGLSL::type_to_std430_alignment(const SPIRType &type, uint64_t flags)
507{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200508 // float, int and uint all take 4 bytes.
509 const uint32_t base_alignment = 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100510
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200511 if (type.basetype == SPIRType::Struct)
512 {
513 // Rule 9. Structs alignments are maximum alignment of its members.
514 uint32_t alignment = 0;
515 for (uint32_t i = 0; i < type.member_types.size(); i++)
516 {
517 auto member_flags = meta[type.self].members.at(i).decoration_flags;
518 alignment = max(alignment, type_to_std430_alignment(get<SPIRType>(type.member_types[i]), member_flags));
519 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100520
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200521 return alignment;
522 }
523 else
524 {
525 // From 7.6.2.2 in GL 4.5 core spec.
526 // Rule 1
527 if (type.vecsize == 1 && type.columns == 1)
528 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100529
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200530 // Rule 2
531 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
532 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200534 // Rule 3
535 if (type.vecsize == 3 && type.columns == 1)
536 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200538 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100539
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200540 // Rule 5. Column-major matrices are stored as arrays of
541 // vectors.
542 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
543 {
544 if (type.vecsize == 3)
545 return 4 * base_alignment;
546 else
547 return type.vecsize * base_alignment;
548 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100549
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200550 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100551
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200552 // Rule 7.
553 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
554 {
555 if (type.columns == 3)
556 return 4 * base_alignment;
557 else
558 return type.columns * base_alignment;
559 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100560
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200561 // Rule 8 implied.
562 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100563
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200564 throw CompilerError("Did not find suitable std430 rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100565}
566
567uint32_t CompilerGLSL::type_to_std430_array_stride(const SPIRType &type, uint64_t flags)
568{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200569 // Array stride is equal to aligned size of the underlying type.
570 SPIRType tmp = type;
571 tmp.array.pop_back();
572 uint32_t size = type_to_std430_size(tmp, flags);
573 uint32_t alignment = type_to_std430_alignment(tmp, flags);
574 return (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100575}
576
577uint32_t CompilerGLSL::type_to_std430_size(const SPIRType &type, uint64_t flags)
578{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200579 if (!type.array.empty())
580 return type.array.back() * type_to_std430_array_stride(type, flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100581
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200582 // float, int and uint all take 4 bytes.
583 const uint32_t base_alignment = 4;
584 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100585
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200586 if (type.basetype == SPIRType::Struct)
587 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200588 uint32_t pad_alignment = 1;
589
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200590 for (uint32_t i = 0; i < type.member_types.size(); i++)
591 {
592 auto member_flags = meta[type.self].members.at(i).decoration_flags;
593 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200594
595 uint32_t std430_alignment = type_to_std430_alignment(member_type, member_flags);
596 uint32_t alignment = max(std430_alignment, pad_alignment);
597
598 // The next member following a struct member is aligned to the base alignment of the struct that came before.
599 // GL 4.5 spec, 7.6.2.2.
600 if (member_type.basetype == SPIRType::Struct)
601 pad_alignment = std430_alignment;
602 else
603 pad_alignment = 1;
604
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200605 size = (size + alignment - 1) & ~(alignment - 1);
606 size += type_to_std430_size(member_type, member_flags);
607 }
608 }
609 else
610 {
611 if (type.columns == 1)
612 size = type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100613
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200614 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
615 {
616 if (type.vecsize == 3)
617 size = type.columns * 4 * base_alignment;
618 else
619 size = type.columns * type.vecsize * base_alignment;
620 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100621
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200622 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
623 {
624 if (type.columns == 3)
625 size = type.vecsize * 4 * base_alignment;
626 else
627 size = type.vecsize * type.columns * base_alignment;
628 }
629 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100630
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200631 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100632}
633
634bool CompilerGLSL::ssbo_is_std430_packing(const SPIRType &type)
635{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200636 // This is very tricky and error prone, but try to be exhaustive and correct here.
637 // SPIR-V doesn't directly say if we're using std430 or std140.
638 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
639 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
640 // 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).
641 //
642 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
643 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
644 //
645 // The only two differences between std140 and std430 are related to padding alignment/array stride
646 // in arrays and structs. In std140 they take minimum vec4 alignment.
647 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100648
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200649 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200650 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100651
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200652 for (uint32_t i = 0; i < type.member_types.size(); i++)
653 {
654 auto &memb_type = get<SPIRType>(type.member_types[i]);
655 auto member_flags = meta[type.self].members.at(i).decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200657 // Verify alignment rules.
658 uint32_t std430_alignment = type_to_std430_alignment(memb_type, member_flags);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200659 uint32_t alignment = max(std430_alignment, pad_alignment);
660 offset = (offset + alignment - 1) & ~(alignment - 1);
661
662 // The next member following a struct member is aligned to the base alignment of the struct that came before.
663 // GL 4.5 spec, 7.6.2.2.
664 if (memb_type.basetype == SPIRType::Struct)
665 pad_alignment = std430_alignment;
666 else
667 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100668
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200669 uint32_t actual_offset = type_struct_member_offset(type, i);
670 if (actual_offset != offset) // This cannot be std430.
671 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100672
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200673 // Verify array stride rules.
674 if (!memb_type.array.empty() &&
675 type_to_std430_array_stride(memb_type, member_flags) != type_struct_member_array_stride(type, i))
676 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100677
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200678 // Verify that sub-structs also follow std430 rules.
679 if (!memb_type.member_types.empty() && !ssbo_is_std430_packing(memb_type))
680 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100681
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200682 // Bump size.
683 offset += type_to_std430_size(memb_type, member_flags);
684 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200686 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100687}
688
689string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
690{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200691 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100692
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200693 auto &dec = meta[var.self].decoration;
694 auto &type = get<SPIRType>(var.basetype);
695 auto flags = dec.decoration_flags;
696 auto typeflags = meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100697
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200698 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
699 attr.push_back("push_constant");
700
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200701 if (flags & (1ull << DecorationRowMajor))
702 attr.push_back("row_major");
703 if (flags & (1ull << DecorationColMajor))
704 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200705
706 if (options.vulkan_semantics)
707 {
708 if (flags & (1ull << DecorationInputAttachmentIndex))
709 attr.push_back(join("input_attachment_index = ", dec.input_attachment));
710 }
711
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200712 if (flags & (1ull << DecorationLocation))
713 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +0200714
715 // set = 0 is the default. Do not emit set = decoration in regular GLSL output, but
716 // we should preserve it in Vulkan GLSL mode.
717 if (var.storage != StorageClassPushConstant)
718 {
719 if ((flags & (1ull << DecorationDescriptorSet)) && (dec.set != 0 || options.vulkan_semantics))
720 attr.push_back(join("set = ", dec.set));
721 }
722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200723 if (flags & (1ull << DecorationBinding))
724 attr.push_back(join("binding = ", dec.binding));
725 if (flags & (1ull << DecorationCoherent))
726 attr.push_back("coherent");
727 if (flags & (1ull << DecorationOffset))
728 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100729
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200730 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
731 // If SPIR-V does not comply with either layout, we cannot really work around it.
732 if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBlock)))
733 attr.push_back("std140");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200734 else if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock)))
735 attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
736 else if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200737 attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100738
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200739 // For images, the type itself adds a layout qualifer.
740 if (type.basetype == SPIRType::Image)
741 {
742 const char *fmt = format_to_glsl(type.image.format);
743 if (fmt)
744 attr.push_back(fmt);
745 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100746
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200747 if (attr.empty())
748 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100749
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200750 string res = "layout(";
751 res += merge(attr);
752 res += ") ";
753 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100754}
755
756void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
757{
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200758 if (options.vulkan_semantics)
759 emit_push_constant_block_vulkan(var);
760 else
761 emit_push_constant_block_glsl(var);
762}
763
764void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
765{
766 emit_buffer_block(var);
767}
768
769void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
770{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200771 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
772 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100773
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200774 auto &flags = meta[var.self].decoration.decoration_flags;
775 flags &= ~((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100776
777#if 0
778 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
779 throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
780 "Remap to location with reflection API first or disable these decorations.");
781#endif
782
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200783 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
784 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
785 auto &block_flags = meta[type.self].decoration.decoration_flags;
786 uint64_t block_flag = block_flags & (1ull << DecorationBlock);
787 block_flags &= ~block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100788
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200789 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100790
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200791 block_flags |= block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100792
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200793 emit_uniform(var);
794 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100795}
796
797void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
798{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200799 auto &type = get<SPIRType>(var.basetype);
800 auto ssbo = meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200801
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200802 add_resource_name(var.self);
803
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200804 // Block names should never alias.
805 auto buffer_name = to_name(type.self, false);
806
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200807 // Shaders never use the block by interface name, so we don't
808 // have to track this other than updating name caches.
809 if (resource_names.find(buffer_name) != end(resource_names))
810 buffer_name = get_fallback_name(type.self);
811 else
812 resource_names.insert(buffer_name);
813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200814 statement(layout_for_variable(var) + (ssbo ? "buffer " : "uniform ") + buffer_name);
815 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100816
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200817 type.member_name_cache.clear();
818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200819 uint32_t i = 0;
820 for (auto &member : type.member_types)
821 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200822 add_member_name(type, i);
823
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200824 auto &membertype = get<SPIRType>(member);
825 statement(member_decl(type, membertype, i), ";");
826 i++;
827 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100828
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200829 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
830 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100831}
832
833void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
834{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200835 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100836
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200837 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
838 bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100839
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200840 const char *qual = nullptr;
841 if (is_legacy() && execution.model == ExecutionModelVertex)
842 qual = var.storage == StorageClassInput ? "attribute " : "varying ";
843 else if (is_legacy() && execution.model == ExecutionModelFragment)
844 qual = "varying "; // Fragment outputs are renamed so they never hit this case.
845 else
846 qual = var.storage == StorageClassInput ? "in " : "out ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100847
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200848 if (block)
849 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200850 add_resource_name(var.self);
851
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200852 // Block names should never alias.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200853 auto block_name = to_name(type.self, false);
854
855 // Shaders never use the block by interface name, so we don't
856 // have to track this other than updating name caches.
857 if (resource_names.find(block_name) != end(resource_names))
858 block_name = get_fallback_name(type.self);
859 else
860 resource_names.insert(block_name);
861
862 statement(layout_for_variable(var), qual, block_name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200863 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100864
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200865 type.member_name_cache.clear();
866
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200867 uint32_t i = 0;
868 for (auto &member : type.member_types)
869 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200870 add_member_name(type, i);
871
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200872 auto &membertype = get<SPIRType>(member);
873 statement(member_decl(type, membertype, i), ";");
874 i++;
875 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100876
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200877 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
878 statement("");
879 }
880 else
881 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200882 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200883 statement(layout_for_variable(var), qual, variable_decl(var), ";");
884 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100885}
886
887void CompilerGLSL::emit_uniform(const SPIRVariable &var)
888{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200889 auto &type = get<SPIRType>(var.basetype);
890 if (type.basetype == SPIRType::Image)
891 {
892 if (!options.es && options.version < 420)
893 require_extension("GL_ARB_shader_image_load_store");
894 else if (options.es && options.version < 310)
895 throw CompilerError("At least ESSL 3.10 required for shader image load store.");
896 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100897
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200898 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200899 statement(layout_for_variable(var), "uniform ", variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100900}
901
902void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
903{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200904 auto &m = meta[var.self].decoration;
905 uint32_t location = 0;
906 if (m.decoration_flags & (1ull << DecorationLocation))
907 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100908
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200909 m.alias = join("gl_FragData[", location, "]");
910 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 +0100911}
912
913void CompilerGLSL::replace_fragment_outputs()
914{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200915 for (auto &id : ids)
916 {
917 if (id.get_type() == TypeVariable)
918 {
919 auto &var = id.get<SPIRVariable>();
920 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100921
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200922 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
923 var.storage == StorageClassOutput)
924 replace_fragment_output(var);
925 }
926 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100927}
928
929string CompilerGLSL::remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr)
930{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200931 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100932
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200933 if (out_type.vecsize == input_components)
934 return to_expression(expr);
935 else if (input_components == 1)
936 return join(type_to_glsl(out_type), "(", to_expression(expr), ")");
937 else
938 {
939 auto e = to_expression(expr) + ".";
940 // Just clamp the swizzle index if we have more outputs than inputs.
941 for (uint32_t c = 0; c < out_type.vecsize; c++)
942 e += index_to_swizzle(min(c, input_components - 1));
943 if (backend.swizzle_is_function && out_type.vecsize > 1)
944 e += "()";
945 return e;
946 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100947}
948
949void CompilerGLSL::emit_pls()
950{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200951 if (execution.model != ExecutionModelFragment)
952 throw CompilerError("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100953
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200954 if (!options.es)
955 throw CompilerError("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100956
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200957 if (options.version < 300)
958 throw CompilerError("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100959
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200960 if (!pls_inputs.empty())
961 {
962 statement("__pixel_local_inEXT _PLSIn");
963 begin_scope();
964 for (auto &input : pls_inputs)
965 statement(pls_decl(input), ";");
966 end_scope_decl();
967 statement("");
968 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100969
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200970 if (!pls_outputs.empty())
971 {
972 statement("__pixel_local_outEXT _PLSOut");
973 begin_scope();
974 for (auto &output : pls_outputs)
975 statement(pls_decl(output), ";");
976 end_scope_decl();
977 statement("");
978 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100979}
980
981void CompilerGLSL::emit_resources()
982{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200983 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
984 // with builtins.
985 if (execution.model == ExecutionModelFragment && is_legacy())
986 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100987
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200988 // Emit PLS blocks if we have such variables.
989 if (!pls_inputs.empty() || !pls_outputs.empty())
990 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100991
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200992 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
993 // when such variables are instantiated.
994 for (auto &id : ids)
995 {
996 if (id.get_type() == TypeType)
997 {
998 auto &type = id.get<SPIRType>();
999 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
1000 (meta[type.self].decoration.decoration_flags &
1001 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
1002 {
1003 emit_struct(type);
1004 }
1005 }
1006 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001007
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001008 // Output UBOs and SSBOs
1009 for (auto &id : ids)
1010 {
1011 if (id.get_type() == TypeVariable)
1012 {
1013 auto &var = id.get<SPIRVariable>();
1014 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001016 if (type.pointer && type.storage == StorageClassUniform && !is_builtin_variable(var) &&
1017 (meta[type.self].decoration.decoration_flags &
1018 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
1019 {
1020 emit_buffer_block(var);
1021 }
1022 }
1023 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001025 // Output push constant blocks
1026 for (auto &id : ids)
1027 {
1028 if (id.get_type() == TypeVariable)
1029 {
1030 auto &var = id.get<SPIRVariable>();
1031 auto &type = get<SPIRType>(var.basetype);
1032 if (type.pointer && type.storage == StorageClassPushConstant)
1033 emit_push_constant_block(var);
1034 }
1035 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001036
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001037 bool emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001038
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001039 // Output Uniform Constants (values, samplers, images, etc).
1040 for (auto &id : ids)
1041 {
1042 if (id.get_type() == TypeVariable)
1043 {
1044 auto &var = id.get<SPIRVariable>();
1045 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001046
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001047 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
1048 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
1049 {
1050 emit_uniform(var);
1051 emitted = true;
1052 }
1053 }
1054 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001055
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001056 if (emitted)
1057 statement("");
1058 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001059
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001060 // Output in/out interfaces.
1061 for (auto &id : ids)
1062 {
1063 if (id.get_type() == TypeVariable)
1064 {
1065 auto &var = id.get<SPIRVariable>();
1066 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001067
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001068 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
1069 (var.storage == StorageClassInput || var.storage == StorageClassOutput))
1070 {
1071 emit_interface_block(var);
1072 emitted = true;
1073 }
1074 else if (is_builtin_variable(var))
1075 {
1076 // For gl_InstanceIndex emulation on GLES, the API user needs to
1077 // supply this uniform.
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001078 if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001079 {
1080 statement("uniform int SPIRV_Cross_BaseInstance;");
1081 emitted = true;
1082 }
1083 }
1084 }
1085 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001086
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001087 // Global variables.
1088 for (auto global : global_variables)
1089 {
1090 auto &var = get<SPIRVariable>(global);
1091 if (var.storage != StorageClassOutput)
1092 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001093 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001094 statement(variable_decl(var), ";");
1095 emitted = true;
1096 }
1097 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001098
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001099 if (emitted)
1100 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001101}
1102
1103string CompilerGLSL::to_expression(uint32_t id)
1104{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001105 auto itr = invalid_expressions.find(id);
1106 if (itr != end(invalid_expressions))
1107 {
1108 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001109
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001110 // This expression has been invalidated in the past.
1111 // Be careful with this expression next pass ...
1112 // Used for OpCompositeInsert forwarding atm.
1113 expr.used_while_invalidated = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001114
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001115 // We tried to read an invalidated expression.
1116 // This means we need another pass at compilation, but next time, do not try to forward
1117 // the variables which caused invalidation to happen in the first place.
1118 for (auto var : expr.invalidated_by)
1119 {
1120 //fprintf(stderr, "Expression %u was invalidated due to variable %u being invalid at read time!\n", id, var);
1121 get<SPIRVariable>(var).forwardable = false;
1122 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001123
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001124 if (expr.invalidated_by.empty() && expr.loaded_from)
1125 {
1126 //fprintf(stderr, "Expression %u was invalidated due to variable %u being invalid at read time!\n", id, expr.loaded_from);
1127 get<SPIRVariable>(expr.loaded_from).forwardable = false;
1128 }
1129 force_recompile = true;
1130 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001131
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001132 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001133
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001134 switch (ids[id].get_type())
1135 {
1136 case TypeExpression:
1137 {
1138 auto &e = get<SPIRExpression>(id);
1139 if (e.base_expression)
1140 return to_expression(e.base_expression) + e.expression;
1141 else
1142 return e.expression;
1143 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001144
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001145 case TypeConstant:
1146 return constant_expression(get<SPIRConstant>(id));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001147
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001148 case TypeVariable:
1149 {
1150 auto &var = get<SPIRVariable>(id);
1151 if (var.statically_assigned)
1152 return to_expression(var.static_expression);
1153 else if (var.deferred_declaration)
1154 {
1155 var.deferred_declaration = false;
1156 return variable_decl(var);
1157 }
1158 else
1159 {
1160 auto &dec = meta[var.self].decoration;
1161 if (dec.builtin)
1162 return builtin_to_glsl(dec.builtin_type);
1163 else
1164 return to_name(id);
1165 }
1166 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001167
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001168 default:
1169 return to_name(id);
1170 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001171}
1172
1173string CompilerGLSL::constant_expression(const SPIRConstant &c)
1174{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001175 if (!c.subconstants.empty())
1176 {
1177 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001178 string res;
1179 if (backend.use_initializer_list)
1180 res = "{ ";
1181 else
1182 res = type_to_glsl_constructor(get<SPIRType>(c.constant_type)) + "(";
1183
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001184 for (auto &elem : c.subconstants)
1185 {
1186 res += constant_expression(get<SPIRConstant>(elem));
1187 if (&elem != &c.subconstants.back())
1188 res += ", ";
1189 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001190
1191 res += backend.use_initializer_list ? " }" : ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001192 return res;
1193 }
1194 else if (c.columns() == 1)
1195 {
1196 return constant_expression_vector(c, 0);
1197 }
1198 else
1199 {
1200 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
1201 for (uint32_t col = 0; col < c.columns(); col++)
1202 {
1203 res += constant_expression_vector(c, col);
1204 if (col + 1 < c.columns())
1205 res += ", ";
1206 }
1207 res += ")";
1208 return res;
1209 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001210}
1211
1212string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
1213{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001214 auto type = get<SPIRType>(c.constant_type);
1215 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001216
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001217 string res;
1218 if (c.vector_size() > 1)
1219 res += type_to_glsl(type) + "(";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001220
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001221 bool splat = c.vector_size() > 1;
1222 if (splat)
1223 {
1224 uint32_t ident = c.scalar(vector, 0);
1225 for (uint32_t i = 1; i < c.vector_size(); i++)
1226 if (ident != c.scalar(vector, i))
1227 splat = false;
1228 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001229
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001230 switch (type.basetype)
1231 {
1232 case SPIRType::Float:
1233 if (splat)
1234 {
1235 res += convert_to_string(c.scalar_f32(vector, 0));
1236 if (backend.float_literal_suffix)
1237 res += "f";
1238 }
1239 else
1240 {
1241 for (uint32_t i = 0; i < c.vector_size(); i++)
1242 {
1243 res += convert_to_string(c.scalar_f32(vector, i));
1244 if (backend.float_literal_suffix)
1245 res += "f";
1246 if (i + 1 < c.vector_size())
1247 res += ", ";
1248 }
1249 }
1250 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001251
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001252 case SPIRType::UInt:
1253 if (splat)
1254 {
1255 res += convert_to_string(c.scalar(vector, 0));
1256 if (backend.uint32_t_literal_suffix)
1257 res += "u";
1258 }
1259 else
1260 {
1261 for (uint32_t i = 0; i < c.vector_size(); i++)
1262 {
1263 res += convert_to_string(c.scalar(vector, i));
1264 if (backend.uint32_t_literal_suffix)
1265 res += "u";
1266 if (i + 1 < c.vector_size())
1267 res += ", ";
1268 }
1269 }
1270 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001271
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001272 case SPIRType::Int:
1273 if (splat)
1274 res += convert_to_string(c.scalar_i32(vector, 0));
1275 else
1276 {
1277 for (uint32_t i = 0; i < c.vector_size(); i++)
1278 {
1279 res += convert_to_string(c.scalar_i32(vector, i));
1280 if (i + 1 < c.vector_size())
1281 res += ", ";
1282 }
1283 }
1284 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001285
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001286 case SPIRType::Bool:
1287 if (splat)
1288 res += c.scalar(vector, 0) ? "true" : "false";
1289 else
1290 {
1291 for (uint32_t i = 0; i < c.vector_size(); i++)
1292 {
1293 res += c.scalar(vector, i) ? "true" : "false";
1294 if (i + 1 < c.vector_size())
1295 res += ", ";
1296 }
1297 }
1298 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001299
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001300 default:
1301 throw CompilerError("Invalid constant expression basetype.");
1302 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001303
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001304 if (c.vector_size() > 1)
1305 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001307 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001308}
1309
1310string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
1311{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001312 auto &type = get<SPIRType>(result_type);
1313 auto flags = meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001315 // If we're declaring temporaries inside continue blocks,
1316 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
1317 if (current_continue_block)
1318 {
1319 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
1320 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001321 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001322 return tmp.first == result_type && tmp.second == result_id;
1323 }) == end(header.declare_temporary))
1324 {
1325 header.declare_temporary.emplace_back(result_type, result_id);
1326 force_recompile = true;
1327 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001329 return join(to_name(result_id), " = ");
1330 }
1331 else
1332 {
1333 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001334 return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001335 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001336}
1337
1338bool CompilerGLSL::expression_is_forwarded(uint32_t id)
1339{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001340 return forwarded_temporaries.find(id) != end(forwarded_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001341}
1342
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001343SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
1344 bool extra_parens, bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001345{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001346 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
1347 {
1348 // Just forward it without temporary.
1349 // If the forward is trivial, we do not force flushing to temporary for this expression.
1350 if (!suppress_usage_tracking)
1351 forwarded_temporaries.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001352
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001353 if (extra_parens)
1354 return set<SPIRExpression>(result_id, join("(", rhs, ")"), result_type, true);
1355 else
1356 return set<SPIRExpression>(result_id, rhs, result_type, true);
1357 }
1358 else
1359 {
1360 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
1361 statement(declare_temporary(result_type, result_id), rhs, ";");
1362 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
1363 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001364}
1365
1366void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1367{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001368 emit_op(result_type, result_id, join(op, to_expression(op0)), should_forward(op0), true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001369}
1370
1371void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
1372{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001373 emit_op(result_type, result_id, join(to_expression(op0), " ", op, " ", to_expression(op1)),
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001374 should_forward(op0) && should_forward(op1), true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001375}
1376
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001377SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
1378 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
1379{
1380 auto &type0 = expression_type(op0);
1381 auto &type1 = expression_type(op1);
1382
1383 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
1384 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
1385 // since equality test is exactly the same.
1386 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
1387
1388 // Create a fake type so we can bitcast to it.
1389 // We only deal with regular arithmetic types here like int, uints and so on.
1390 SPIRType expected_type;
1391 expected_type.basetype = input_type;
1392 expected_type.vecsize = type0.vecsize;
1393 expected_type.columns = type0.columns;
1394 expected_type.width = type0.width;
1395
1396 if (cast)
1397 {
1398 cast_op0 = bitcast_glsl(expected_type, op0);
1399 cast_op1 = bitcast_glsl(expected_type, op1);
1400 }
1401 else
1402 {
1403 // If we don't cast, our actual input type is that of the first (or second) argument.
1404 cast_op0 = to_expression(op0);
1405 cast_op1 = to_expression(op1);
1406 input_type = type0.basetype;
1407 }
1408
1409 return expected_type;
1410}
1411
1412void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1413 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1414{
1415 string cast_op0, cast_op1;
1416 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1417 auto &out_type = get<SPIRType>(result_type);
1418
1419 // We might have casted away from the result type, so bitcast again.
1420 // For example, arithmetic right shift with uint inputs.
1421 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1422 bool extra_parens = true;
1423 string expr;
1424 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Bool)
1425 {
1426 expected_type.basetype = input_type;
1427 expr = bitcast_glsl_op(out_type, expected_type);
1428 expr += '(';
1429 expr += join(cast_op0, " ", op, " ", cast_op1);
1430 expr += ')';
1431 extra_parens = false;
1432 }
1433 else
1434 {
1435 expr += join(cast_op0, " ", op, " ", cast_op1);
1436 }
1437
1438 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), extra_parens);
1439}
1440
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001441void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1442{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001443 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), should_forward(op0), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001444}
1445
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001446void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1447 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001448{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001449 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ")"),
1450 should_forward(op0) && should_forward(op1), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001451}
1452
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001453void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1454 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1455{
1456 string cast_op0, cast_op1;
1457 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1458 auto &out_type = get<SPIRType>(result_type);
1459
1460 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1461 string expr;
1462 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Bool)
1463 {
1464 expected_type.basetype = input_type;
1465 expr = bitcast_glsl_op(out_type, expected_type);
1466 expr += '(';
1467 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1468 expr += ')';
1469 }
1470 else
1471 {
1472 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1473 }
1474
1475 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), false);
1476}
1477
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001478void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1479 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001480{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001481 emit_op(result_type, result_id,
1482 join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ")"),
1483 should_forward(op0) && should_forward(op1) && should_forward(op2), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001484}
1485
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001486void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1487 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001488{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001489 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ",
1490 to_expression(op2), ", ", to_expression(op3), ")"),
1491 should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001492}
1493
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001494string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001495{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001496 const char *type;
1497 switch (imgtype.image.dim)
1498 {
1499 case spv::Dim1D:
1500 type = "1D";
1501 break;
1502 case spv::Dim2D:
1503 type = "2D";
1504 break;
1505 case spv::Dim3D:
1506 type = "3D";
1507 break;
1508 case spv::DimCube:
1509 type = "Cube";
1510 break;
1511 case spv::DimBuffer:
1512 type = "Buffer";
1513 break;
1514 case spv::DimSubpassData:
1515 type = "2D";
1516 break;
1517 default:
1518 type = "";
1519 break;
1520 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001521
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001522 if (op == "texture")
1523 return join("texture", type);
1524 else if (op == "textureLod")
1525 return join("texture", type, "Lod");
1526 else if (op == "textureProj")
1527 return join("texture", type, "Proj");
1528 else if (op == "textureProjLod")
1529 return join("texture", type, "ProjLod");
1530 else
1531 throw CompilerError(join("Unsupported legacy texture op: ", op));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001532}
1533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001534void 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 +01001535{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001536 auto &lerptype = expression_type(lerp);
1537 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001538
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001539 bool has_boolean_mix = (options.es && options.version >= 310) || (!options.es && options.version >= 450);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001540
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001541 // Boolean mix not supported on desktop without extension.
1542 // Was added in OpenGL 4.5 with ES 3.1 compat.
1543 if (!has_boolean_mix && lerptype.basetype == SPIRType::Bool)
1544 {
1545 // Could use GL_EXT_shader_integer_mix on desktop at least,
1546 // but Apple doesn't support it. :(
1547 // Just implement it as ternary expressions.
1548 string expr;
1549 if (lerptype.vecsize == 1)
1550 expr = join(to_expression(lerp), " ? ", to_expression(right), " : ", to_expression(left));
1551 else
1552 {
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001553 auto swiz = [this](uint32_t expression, uint32_t i) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001554 return join(to_expression(expression), ".", index_to_swizzle(i));
1555 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001557 expr = type_to_glsl_constructor(restype);
1558 expr += "(";
1559 for (uint32_t i = 0; i < restype.vecsize; i++)
1560 {
1561 expr += swiz(lerp, i);
1562 expr += " ? ";
1563 expr += swiz(right, i);
1564 expr += " : ";
1565 expr += swiz(left, i);
1566 if (i + 1 < restype.vecsize)
1567 expr += ", ";
1568 }
1569 expr += ")";
1570 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001571
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001572 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp), false);
1573 }
1574 else
1575 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001576}
1577
Bill Hollings5aafb282016-04-23 21:47:41 -04001578void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
1579{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001580 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 -04001581}
1582
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001583void CompilerGLSL::emit_texture_op(const Instruction &i)
1584{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001585 auto ops = stream(i);
1586 auto op = static_cast<Op>(i.op);
1587 uint32_t length = i.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001588
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001589 if (i.offset + length > spirv.size())
1590 throw CompilerError("Compiler::parse() opcode out of range.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001592 uint32_t result_type = ops[0];
1593 uint32_t id = ops[1];
1594 uint32_t img = ops[2];
1595 uint32_t coord = ops[3];
1596 uint32_t dref = 0;
1597 uint32_t comp = 0;
1598 bool gather = false;
1599 bool proj = false;
1600 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001601
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001602 switch (op)
1603 {
1604 case OpImageSampleDrefImplicitLod:
1605 case OpImageSampleDrefExplicitLod:
1606 dref = ops[4];
1607 opt = &ops[5];
1608 length -= 5;
1609 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001610
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001611 case OpImageSampleProjDrefImplicitLod:
1612 case OpImageSampleProjDrefExplicitLod:
1613 dref = ops[4];
1614 proj = true;
1615 opt = &ops[5];
1616 length -= 5;
1617 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001618
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001619 case OpImageDrefGather:
1620 dref = ops[4];
1621 opt = &ops[5];
1622 gather = true;
1623 length -= 5;
1624 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001626 case OpImageGather:
1627 comp = ops[4];
1628 opt = &ops[5];
1629 gather = true;
1630 length -= 5;
1631 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001632
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001633 case OpImageSampleProjImplicitLod:
1634 case OpImageSampleProjExplicitLod:
1635 opt = &ops[4];
1636 length -= 4;
1637 proj = true;
1638 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001639
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001640 default:
1641 opt = &ops[4];
1642 length -= 4;
1643 break;
1644 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001646 auto &imgtype = expression_type(img);
1647 uint32_t coord_components = 0;
1648 switch (imgtype.image.dim)
1649 {
1650 case spv::Dim1D:
1651 coord_components = 1;
1652 break;
1653 case spv::Dim2D:
1654 coord_components = 2;
1655 break;
1656 case spv::Dim3D:
1657 coord_components = 3;
1658 break;
1659 case spv::DimCube:
1660 coord_components = 3;
1661 break;
1662 case spv::DimBuffer:
1663 coord_components = 1;
1664 break;
1665 default:
1666 coord_components = 2;
1667 break;
1668 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001669
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001670 if (proj)
1671 coord_components++;
1672 if (imgtype.image.arrayed)
1673 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001675 uint32_t bias = 0;
1676 uint32_t lod = 0;
1677 uint32_t grad_x = 0;
1678 uint32_t grad_y = 0;
1679 uint32_t coffset = 0;
1680 uint32_t offset = 0;
1681 uint32_t coffsets = 0;
1682 uint32_t sample = 0;
1683 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001684
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001685 if (length)
1686 {
1687 flags = opt[0];
1688 opt++;
1689 length--;
1690 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001691
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001692 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001693 if (length && (flags & flag))
1694 {
1695 v = *opt++;
1696 length--;
1697 }
1698 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001699
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001700 test(bias, ImageOperandsBiasMask);
1701 test(lod, ImageOperandsLodMask);
1702 test(grad_x, ImageOperandsGradMask);
1703 test(grad_y, ImageOperandsGradMask);
1704 test(coffset, ImageOperandsConstOffsetMask);
1705 test(offset, ImageOperandsOffsetMask);
1706 test(coffsets, ImageOperandsConstOffsetsMask);
1707 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001709 string expr;
1710 string texop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001711
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001712 if (op == OpImageFetch)
1713 texop += "texelFetch";
1714 else
1715 {
1716 texop += "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001717
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001718 if (gather)
1719 texop += "Gather";
1720 if (coffsets)
1721 texop += "Offsets";
1722 if (proj)
1723 texop += "Proj";
1724 if (grad_x || grad_y)
1725 texop += "Grad";
1726 if (lod)
1727 texop += "Lod";
1728 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001729
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001730 if (coffset || offset)
1731 texop += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001732
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001733 if (is_legacy())
1734 texop = legacy_tex_op(texop, imgtype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001735
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001736 expr += texop;
1737 expr += "(";
1738 expr += to_expression(img);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001739
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001740 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001741 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001742 if (comps == in_comps)
1743 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001745 switch (comps)
1746 {
1747 case 1:
1748 return ".x";
1749 case 2:
1750 return swizz_func ? ".xy()" : ".xy";
1751 case 3:
1752 return swizz_func ? ".xyz()" : ".xyz";
1753 default:
1754 return "";
1755 }
1756 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001757
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001758 bool forward = should_forward(coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001759
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001760 // The IR can give us more components than we need, so chop them off as needed.
1761 auto coord_expr = to_expression(coord) + swizzle(coord_components, expression_type(coord).vecsize);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001762
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001763 // TODO: implement rest ... A bit intensive.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001764
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001765 if (dref)
1766 {
1767 forward = forward && should_forward(dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001769 // SPIR-V splits dref and coordinate.
1770 if (coord_components == 4) // GLSL also splits the arguments in two.
1771 {
1772 expr += ", ";
1773 expr += to_expression(coord);
1774 expr += ", ";
1775 expr += to_expression(dref);
1776 }
1777 else
1778 {
1779 // Create a composite which merges coord/dref into a single vector.
1780 auto type = expression_type(coord);
1781 type.vecsize = coord_components + 1;
1782 expr += ", ";
1783 expr += type_to_glsl_constructor(type);
1784 expr += "(";
1785 expr += coord_expr;
1786 expr += ", ";
1787 expr += to_expression(dref);
1788 expr += ")";
1789 }
1790 }
1791 else
1792 {
1793 expr += ", ";
1794 expr += coord_expr;
1795 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001796
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001797 if (grad_x || grad_y)
1798 {
1799 forward = forward && should_forward(grad_x);
1800 forward = forward && should_forward(grad_y);
1801 expr += ", ";
1802 expr += to_expression(grad_x);
1803 expr += ", ";
1804 expr += to_expression(grad_y);
1805 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001806
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001807 if (lod)
1808 {
1809 forward = forward && should_forward(lod);
1810 expr += ", ";
1811 expr += to_expression(lod);
1812 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001814 if (coffset)
1815 {
1816 forward = forward && should_forward(coffset);
1817 expr += ", ";
1818 expr += to_expression(coffset);
1819 }
1820 else if (offset)
1821 {
1822 forward = forward && should_forward(offset);
1823 expr += ", ";
1824 expr += to_expression(offset);
1825 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001826
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001827 if (bias)
1828 {
1829 forward = forward && should_forward(bias);
1830 expr += ", ";
1831 expr += to_expression(bias);
1832 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001833
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001834 if (comp)
1835 {
1836 forward = forward && should_forward(comp);
1837 expr += ", ";
1838 expr += to_expression(comp);
1839 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001840
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001841 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001842
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001843 emit_op(result_type, id, expr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001844}
1845
1846void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t)
1847{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001848 GLSLstd450 op = static_cast<GLSLstd450>(eop);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001849
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001850 switch (op)
1851 {
1852 // FP fiddling
1853 case GLSLstd450Round:
1854 case GLSLstd450RoundEven:
1855 emit_unary_func_op(result_type, id, args[0], "round");
1856 break;
1857 case GLSLstd450Trunc:
1858 emit_unary_func_op(result_type, id, args[0], "trunc");
1859 break;
1860 case GLSLstd450SAbs:
1861 case GLSLstd450FAbs:
1862 emit_unary_func_op(result_type, id, args[0], "abs");
1863 break;
1864 case GLSLstd450SSign:
1865 case GLSLstd450FSign:
1866 emit_unary_func_op(result_type, id, args[0], "sign");
1867 break;
1868 case GLSLstd450Floor:
1869 emit_unary_func_op(result_type, id, args[0], "floor");
1870 break;
1871 case GLSLstd450Ceil:
1872 emit_unary_func_op(result_type, id, args[0], "ceil");
1873 break;
1874 case GLSLstd450Fract:
1875 emit_unary_func_op(result_type, id, args[0], "fract");
1876 break;
1877 case GLSLstd450Radians:
1878 emit_unary_func_op(result_type, id, args[0], "radians");
1879 break;
1880 case GLSLstd450Degrees:
1881 emit_unary_func_op(result_type, id, args[0], "degrees");
1882 break;
1883 case GLSLstd450Fma:
1884 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
1885 break;
1886 case GLSLstd450Modf:
1887 register_call_out_argument(args[1]);
1888 forced_temporaries.insert(id);
1889 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
1890 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001891
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001892 // Minmax
1893 case GLSLstd450FMin:
1894 case GLSLstd450UMin:
1895 case GLSLstd450SMin:
1896 emit_binary_func_op(result_type, id, args[0], args[1], "min");
1897 break;
1898 case GLSLstd450FMax:
1899 case GLSLstd450UMax:
1900 case GLSLstd450SMax:
1901 emit_binary_func_op(result_type, id, args[0], args[1], "max");
1902 break;
1903 case GLSLstd450FClamp:
1904 case GLSLstd450UClamp:
1905 case GLSLstd450SClamp:
1906 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
1907 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001908
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001909 // Trig
1910 case GLSLstd450Sin:
1911 emit_unary_func_op(result_type, id, args[0], "sin");
1912 break;
1913 case GLSLstd450Cos:
1914 emit_unary_func_op(result_type, id, args[0], "cos");
1915 break;
1916 case GLSLstd450Tan:
1917 emit_unary_func_op(result_type, id, args[0], "tan");
1918 break;
1919 case GLSLstd450Asin:
1920 emit_unary_func_op(result_type, id, args[0], "asin");
1921 break;
1922 case GLSLstd450Acos:
1923 emit_unary_func_op(result_type, id, args[0], "acos");
1924 break;
1925 case GLSLstd450Atan:
1926 emit_unary_func_op(result_type, id, args[0], "atan");
1927 break;
1928 case GLSLstd450Sinh:
1929 emit_unary_func_op(result_type, id, args[0], "sinh");
1930 break;
1931 case GLSLstd450Cosh:
1932 emit_unary_func_op(result_type, id, args[0], "cosh");
1933 break;
1934 case GLSLstd450Tanh:
1935 emit_unary_func_op(result_type, id, args[0], "tanh");
1936 break;
1937 case GLSLstd450Asinh:
1938 emit_unary_func_op(result_type, id, args[0], "asinh");
1939 break;
1940 case GLSLstd450Acosh:
1941 emit_unary_func_op(result_type, id, args[0], "acosh");
1942 break;
1943 case GLSLstd450Atanh:
1944 emit_unary_func_op(result_type, id, args[0], "atanh");
1945 break;
1946 case GLSLstd450Atan2:
1947 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
1948 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001949
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001950 // Exponentials
1951 case GLSLstd450Pow:
1952 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
1953 break;
1954 case GLSLstd450Exp:
1955 emit_unary_func_op(result_type, id, args[0], "exp");
1956 break;
1957 case GLSLstd450Log:
1958 emit_unary_func_op(result_type, id, args[0], "log");
1959 break;
1960 case GLSLstd450Exp2:
1961 emit_unary_func_op(result_type, id, args[0], "exp2");
1962 break;
1963 case GLSLstd450Log2:
1964 emit_unary_func_op(result_type, id, args[0], "log2");
1965 break;
1966 case GLSLstd450Sqrt:
1967 emit_unary_func_op(result_type, id, args[0], "sqrt");
1968 break;
1969 case GLSLstd450InverseSqrt:
1970 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
1971 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001972
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001973 // Matrix math
1974 case GLSLstd450Determinant:
1975 emit_unary_func_op(result_type, id, args[0], "determinant");
1976 break;
1977 case GLSLstd450MatrixInverse:
1978 emit_unary_func_op(result_type, id, args[0], "inverse");
1979 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001980
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001981 // Lerping
1982 case GLSLstd450FMix:
1983 case GLSLstd450IMix:
1984 {
1985 emit_mix_op(result_type, id, args[0], args[1], args[2]);
1986 break;
1987 }
1988 case GLSLstd450Step:
1989 emit_binary_func_op(result_type, id, args[0], args[1], "step");
1990 break;
1991 case GLSLstd450SmoothStep:
1992 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
1993 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001994
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001995 // Packing
1996 case GLSLstd450Frexp:
1997 register_call_out_argument(args[1]);
1998 forced_temporaries.insert(id);
1999 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
2000 break;
2001 case GLSLstd450Ldexp:
2002 emit_binary_func_op(result_type, id, args[0], args[1], "ldexp");
2003 break;
2004 case GLSLstd450PackSnorm4x8:
2005 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
2006 break;
2007 case GLSLstd450PackUnorm4x8:
2008 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
2009 break;
2010 case GLSLstd450PackSnorm2x16:
2011 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
2012 break;
2013 case GLSLstd450PackUnorm2x16:
2014 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
2015 break;
2016 case GLSLstd450PackHalf2x16:
2017 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
2018 break;
2019 case GLSLstd450UnpackSnorm4x8:
2020 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
2021 break;
2022 case GLSLstd450UnpackUnorm4x8:
2023 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
2024 break;
2025 case GLSLstd450UnpackSnorm2x16:
2026 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
2027 break;
2028 case GLSLstd450UnpackUnorm2x16:
2029 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
2030 break;
2031 case GLSLstd450UnpackHalf2x16:
2032 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
2033 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002034
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002035 // Vector math
2036 case GLSLstd450Length:
2037 emit_unary_func_op(result_type, id, args[0], "length");
2038 break;
2039 case GLSLstd450Distance:
2040 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
2041 break;
2042 case GLSLstd450Cross:
2043 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
2044 break;
2045 case GLSLstd450Normalize:
2046 emit_unary_func_op(result_type, id, args[0], "normalize");
2047 break;
2048 case GLSLstd450FaceForward:
2049 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
2050 break;
2051 case GLSLstd450Reflect:
2052 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
2053 break;
2054 case GLSLstd450Refract:
2055 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
2056 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002057
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002058 // Bit-fiddling
2059 case GLSLstd450FindILsb:
2060 emit_unary_func_op(result_type, id, args[0], "findLSB");
2061 break;
2062 case GLSLstd450FindSMsb:
2063 case GLSLstd450FindUMsb:
2064 emit_unary_func_op(result_type, id, args[0], "findMSB");
2065 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002066
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002067 // Multisampled varying
2068 case GLSLstd450InterpolateAtCentroid:
2069 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
2070 break;
2071 case GLSLstd450InterpolateAtSample:
2072 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
2073 break;
2074 case GLSLstd450InterpolateAtOffset:
2075 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
2076 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002078 default:
2079 statement("// unimplemented GLSL op ", eop);
2080 break;
2081 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002082}
2083
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002084string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002085{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002086 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
2087 return type_to_glsl(out_type);
2088 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
2089 return "floatBitsToUint";
2090 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
2091 return type_to_glsl(out_type);
2092 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
2093 return "floatBitsToInt";
2094 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
2095 return "uintBitsToFloat";
2096 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
2097 return "intBitsToFloat";
2098 else
2099 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002100}
2101
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002102string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002103{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002104 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002105 if (op.empty())
2106 return to_expression(argument);
2107 else
2108 return join(op, "(", to_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002109}
2110
Bill Hollings103aabf2016-04-06 17:42:27 -04002111string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002112{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002113 switch (builtin)
2114 {
2115 case BuiltInPosition:
2116 return "gl_Position";
2117 case BuiltInPointSize:
2118 return "gl_PointSize";
2119 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002120 if (options.vulkan_semantics)
2121 throw CompilerError(
2122 "Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002123 return "gl_VertexID";
2124 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002125 if (options.vulkan_semantics)
2126 throw CompilerError(
2127 "Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002128 return "gl_InstanceID";
2129 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002130 if (options.vulkan_semantics)
2131 return "gl_VertexIndex";
2132 else
2133 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002134 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002135 if (options.vulkan_semantics)
2136 return "gl_InstanceIndex";
2137 else
2138 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002139 case BuiltInPrimitiveId:
2140 return "gl_PrimitiveID";
2141 case BuiltInInvocationId:
2142 return "gl_InvocationID";
2143 case BuiltInLayer:
2144 return "gl_Layer";
2145 case BuiltInTessLevelOuter:
2146 return "gl_TessLevelOuter";
2147 case BuiltInTessLevelInner:
2148 return "gl_TessLevelInner";
2149 case BuiltInTessCoord:
2150 return "gl_TessCoord";
2151 case BuiltInFragCoord:
2152 return "gl_FragCoord";
2153 case BuiltInPointCoord:
2154 return "gl_PointCoord";
2155 case BuiltInFrontFacing:
2156 return "gl_FrontFacing";
2157 case BuiltInFragDepth:
2158 return "gl_FragDepth";
2159 case BuiltInNumWorkgroups:
2160 return "gl_NumWorkGroups";
2161 case BuiltInWorkgroupSize:
2162 return "gl_WorkGroupSize";
2163 case BuiltInWorkgroupId:
2164 return "gl_WorkGroupID";
2165 case BuiltInLocalInvocationId:
2166 return "gl_LocalInvocationID";
2167 case BuiltInGlobalInvocationId:
2168 return "gl_GlobalInvocationID";
2169 case BuiltInLocalInvocationIndex:
2170 return "gl_LocalInvocationIndex";
2171 default:
2172 return "gl_???";
2173 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002174}
2175
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002176const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002177{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002178 switch (index)
2179 {
2180 case 0:
2181 return "x";
2182 case 1:
2183 return "y";
2184 case 2:
2185 return "z";
2186 case 3:
2187 return "w";
2188 default:
2189 throw CompilerError("Swizzle index out of range");
2190 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002191}
2192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002193string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal,
2194 bool chain_only)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002195{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002196 string expr;
2197 if (!chain_only)
2198 expr = to_expression(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002199
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002200 const auto *type = &expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002201
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002202 // For resolving array accesses, etc, keep a local copy for poking.
2203 SPIRType temp;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002204
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002205 bool access_chain_is_arrayed = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002207 for (uint32_t i = 0; i < count; i++)
2208 {
2209 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002210
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002211 // Arrays
2212 if (!type->array.empty())
2213 {
2214 expr += "[";
2215 if (index_is_literal)
2216 expr += convert_to_string(index);
2217 else
2218 expr += to_expression(index);
2219 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002220
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002221 // We have to modify the type, so keep a local copy.
2222 if (&temp != type)
2223 temp = *type;
2224 type = &temp;
2225 temp.array.pop_back();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002226
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002227 access_chain_is_arrayed = true;
2228 }
2229 // For structs, the index refers to a constant, which indexes into the members.
2230 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
2231 else if (type->basetype == SPIRType::Struct)
2232 {
2233 if (!index_is_literal)
2234 index = get<SPIRConstant>(index).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002235
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002236 if (index >= type->member_types.size())
2237 throw CompilerError("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002238
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002239 BuiltIn builtin;
2240 if (is_member_builtin(*type, index, &builtin))
2241 {
2242 // FIXME: We rely here on OpName on gl_in/gl_out to make this work properly.
2243 // To make this properly work by omitting all OpName opcodes,
2244 // we need to infer gl_in or gl_out based on the builtin, and stage.
2245 if (access_chain_is_arrayed)
2246 {
2247 expr += ".";
2248 expr += builtin_to_glsl(builtin);
2249 }
2250 else
2251 expr = builtin_to_glsl(builtin);
2252 }
2253 else
2254 {
2255 expr += ".";
2256 expr += to_member_name(*type, index);
2257 }
2258 type = &get<SPIRType>(type->member_types[index]);
2259 }
2260 // Matrix -> Vector
2261 else if (type->columns > 1)
2262 {
2263 expr += "[";
2264 if (index_is_literal)
2265 expr += convert_to_string(index);
2266 else
2267 expr += to_expression(index);
2268 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002269
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002270 // We have to modify the type, so keep a local copy.
2271 if (&temp != type)
2272 temp = *type;
2273 type = &temp;
2274 temp.columns = 1;
2275 }
2276 // Vector -> Scalar
2277 else if (type->vecsize > 1)
2278 {
2279 if (index_is_literal)
2280 {
2281 expr += ".";
2282 expr += index_to_swizzle(index);
2283 }
2284 else if (ids[index].get_type() == TypeConstant)
2285 {
2286 auto &c = get<SPIRConstant>(index);
2287 expr += ".";
2288 expr += index_to_swizzle(c.scalar());
2289 }
2290 else
2291 {
2292 expr += "[";
2293 expr += to_expression(index);
2294 expr += "]";
2295 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002296
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002297 // We have to modify the type, so keep a local copy.
2298 if (&temp != type)
2299 temp = *type;
2300 type = &temp;
2301 temp.vecsize = 1;
2302 }
2303 else
2304 throw CompilerError("Cannot subdivide a scalar value!");
2305 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002307 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002308}
2309
2310bool CompilerGLSL::should_forward(uint32_t id)
2311{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002312 return is_immutable(id) && !options.force_temporary;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002313}
2314
2315void CompilerGLSL::track_expression_read(uint32_t id)
2316{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002317 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
2318 // In this case, it's better to just bind the complex expression to the temporary and read that temporary twice.
2319 if (expression_is_forwarded(id))
2320 {
2321 auto &v = expression_usage_counts[id];
2322 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002323
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002324 if (v >= 2)
2325 {
2326 //if (v == 2)
2327 // 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 +01002328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002329 forced_temporaries.insert(id);
2330 // Force a recompile after this pass to avoid forwarding this variable.
2331 force_recompile = true;
2332 }
2333 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002334}
2335
2336bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
2337{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002338 if (forced_temporaries.find(id) != end(forced_temporaries))
2339 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002341 for (uint32_t i = 0; i < num_args; i++)
2342 if (!should_forward(args[i]))
2343 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002345 // We need to forward globals as well.
2346 if (!pure)
2347 {
2348 for (auto global : global_variables)
2349 if (!should_forward(global))
2350 return false;
2351 for (auto aliased : aliased_variables)
2352 if (!should_forward(aliased))
2353 return false;
2354 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002355
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002356 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002357}
2358
2359void CompilerGLSL::register_impure_function_call()
2360{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002361 // Impure functions can modify globals and aliased variables, so invalidate them as well.
2362 for (auto global : global_variables)
2363 flush_dependees(get<SPIRVariable>(global));
2364 for (auto aliased : aliased_variables)
2365 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002366}
2367
2368void CompilerGLSL::register_call_out_argument(uint32_t id)
2369{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002370 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002371
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002372 auto *var = maybe_get<SPIRVariable>(id);
2373 if (var)
2374 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002375}
2376
2377void CompilerGLSL::flush_variable_declaration(uint32_t id)
2378{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002379 auto *var = maybe_get<SPIRVariable>(id);
2380 if (var && var->deferred_declaration)
2381 {
2382 statement(variable_decl(*var), ";");
2383 var->deferred_declaration = false;
2384 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002385}
2386
2387bool CompilerGLSL::remove_duplicate_swizzle(string &op)
2388{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002389 auto pos = op.find_last_of('.');
2390 if (pos == string::npos || pos == 0)
2391 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002392
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002393 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002394
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002395 if (backend.swizzle_is_function)
2396 {
2397 if (final_swiz.size() < 2)
2398 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002399
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002400 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2401 final_swiz.erase(final_swiz.size() - 2, string::npos);
2402 else
2403 return false;
2404 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002405
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002406 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2407 // If so, and previous swizzle is of same length,
2408 // we can drop the final swizzle altogether.
2409 for (uint32_t i = 0; i < final_swiz.size(); i++)
2410 {
2411 static const char expected[] = { 'x', 'y', 'z', 'w' };
2412 if (i >= 4 || final_swiz[i] != expected[i])
2413 return false;
2414 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002415
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002416 auto prevpos = op.find_last_of('.', pos - 1);
2417 if (prevpos == string::npos)
2418 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002419
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002420 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002421
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002422 // Make sure there are only swizzles here ...
2423 for (auto i = prevpos; i < pos; i++)
2424 {
2425 if (op[i] < 'w' || op[i] > 'z')
2426 {
2427 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
2428 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
2429 break;
2430 return false;
2431 }
2432 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002433
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002434 // If original swizzle is large enough, just carve out the components we need.
2435 // E.g. foobar.wyx.xy will turn into foobar.wy.
2436 if (pos - prevpos >= final_swiz.size())
2437 {
2438 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002440 // Add back the function call ...
2441 if (backend.swizzle_is_function)
2442 op += "()";
2443 }
2444 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002445}
2446
2447// Optimizes away vector swizzles where we have something like
2448// vec3 foo;
2449// foo.xyz <-- swizzle expression does nothing.
2450// This is a very common pattern after OpCompositeCombine.
2451bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
2452{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002453 auto pos = op.find_last_of('.');
2454 if (pos == string::npos || pos == 0)
2455 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002457 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002458
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002459 if (backend.swizzle_is_function)
2460 {
2461 if (final_swiz.size() < 2)
2462 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002463
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002464 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2465 final_swiz.erase(final_swiz.size() - 2, string::npos);
2466 else
2467 return false;
2468 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002469
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002470 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2471 // If so, and previous swizzle is of same length,
2472 // we can drop the final swizzle altogether.
2473 for (uint32_t i = 0; i < final_swiz.size(); i++)
2474 {
2475 static const char expected[] = { 'x', 'y', 'z', 'w' };
2476 if (i >= 4 || final_swiz[i] != expected[i])
2477 return false;
2478 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002479
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002480 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002481
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002482 // Sanity checking ...
2483 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002484
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002485 if (type.vecsize == final_swiz.size())
2486 op.erase(pos, string::npos);
2487 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002488}
2489
2490string CompilerGLSL::build_composite_combiner(const uint32_t *elems, uint32_t length)
2491{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002492 uint32_t base = 0;
2493 bool swizzle_optimization = false;
2494 string op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002495
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002496 for (uint32_t i = 0; i < length; i++)
2497 {
2498 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002499
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002500 // If we're merging another scalar which belongs to the same base
2501 // object, just merge the swizzles to avoid triggering more than 1 expression read as much as possible!
2502 if (e && e->base_expression && e->base_expression == base)
2503 {
2504 // Only supposed to be used for vector swizzle -> scalar.
2505 assert(!e->expression.empty() && e->expression.front() == '.');
2506 op += e->expression.substr(1, string::npos);
2507 swizzle_optimization = true;
2508 }
2509 else
2510 {
2511 // We'll likely end up with duplicated swizzles, e.g.
2512 // foobar.xyz.xyz from patterns like
2513 // OpVectorSwizzle
2514 // OpCompositeExtract x 3
2515 // OpCompositeConstruct 3x + other scalar.
2516 // Just modify op in-place.
2517 if (swizzle_optimization)
2518 {
2519 if (backend.swizzle_is_function)
2520 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002521
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002522 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
2523 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
2524 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
2525 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
2526 // Case 1:
2527 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
2528 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
2529 // Case 2:
2530 // foo.xyz: Duplicate swizzle won't kick in.
2531 // If foo is vec3, we can remove xyz, giving just foo.
2532 if (!remove_duplicate_swizzle(op))
2533 remove_unity_swizzle(base, op);
2534 swizzle_optimization = false;
2535 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002536
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002537 if (i)
2538 op += ", ";
2539 op += to_expression(elems[i]);
2540 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002542 base = e ? e->base_expression : 0;
2543 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002545 if (swizzle_optimization)
2546 {
2547 if (backend.swizzle_is_function)
2548 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002549
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002550 if (!remove_duplicate_swizzle(op))
2551 remove_unity_swizzle(base, op);
2552 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002553
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002554 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002555}
2556
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02002557void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002558{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002559 auto ops = stream(instruction);
2560 auto opcode = static_cast<Op>(instruction.op);
2561 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002562
2563#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002564#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 +01002565#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
2566#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
2567#define TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
2568#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002569#define BFOP_CAST(op, type, skip_cast) emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
2570#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002571#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
2572
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002573 switch (opcode)
2574 {
2575 // Dealing with memory
2576 case OpLoad:
2577 {
2578 uint32_t result_type = ops[0];
2579 uint32_t id = ops[1];
2580 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002581
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002582 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002584 // If we're loading from memory that cannot be changed by the shader,
2585 // just forward the expression directly to avoid needless temporaries.
2586 if (should_forward(ptr))
2587 {
2588 set<SPIRExpression>(id, to_expression(ptr), result_type, true);
2589 register_read(id, ptr, true);
2590 }
2591 else
2592 {
2593 // If the variable can be modified after this OpLoad, we cannot just forward the expression.
2594 // We must read it now and store it in a temporary.
2595 emit_op(result_type, id, to_expression(ptr), false, false);
2596 register_read(id, ptr, false);
2597 }
2598 break;
2599 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002600
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002601 case OpInBoundsAccessChain:
2602 case OpAccessChain:
2603 {
2604 auto *var = maybe_get<SPIRVariable>(ops[2]);
2605 if (var)
2606 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002607
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002608 // If the base is immutable, the access chain pointer must also be.
2609 auto e = access_chain(ops[2], &ops[3], length - 3, false);
2610 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], is_immutable(ops[2]));
2611 expr.loaded_from = ops[2];
2612 break;
2613 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002614
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002615 case OpStore:
2616 {
2617 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002618
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002619 if (var && var->statically_assigned)
2620 var->static_expression = ops[1];
2621 else
2622 {
2623 auto lhs = to_expression(ops[0]);
2624 auto rhs = to_expression(ops[1]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002626 // It is possible with OpLoad/OpCompositeInsert/OpStore that we get <expr> = <same-expr>.
2627 // For this case, we don't need to invalidate anything and emit any opcode.
2628 if (lhs != rhs)
2629 {
2630 register_write(ops[0]);
2631 statement(lhs, " = ", rhs, ";");
2632 }
2633 }
2634 break;
2635 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002636
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002637 case OpArrayLength:
2638 {
2639 uint32_t result_type = ops[0];
2640 uint32_t id = ops[1];
2641 auto e = access_chain(ops[2], &ops[3], length - 3, true);
2642 set<SPIRExpression>(id, e + ".length()", result_type, true);
2643 break;
2644 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002646 // Function calls
2647 case OpFunctionCall:
2648 {
2649 uint32_t result_type = ops[0];
2650 uint32_t id = ops[1];
2651 uint32_t func = ops[2];
2652 const auto *arg = &ops[3];
2653 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002654
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002655 auto &callee = get<SPIRFunction>(func);
2656 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002657
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002658 bool callee_has_out_variables = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002659
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002660 // Invalidate out variables passed to functions since they can be OpStore'd to.
2661 for (uint32_t i = 0; i < length; i++)
2662 {
2663 if (callee.arguments[i].write_count)
2664 {
2665 register_call_out_argument(arg[i]);
2666 callee_has_out_variables = true;
2667 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002668
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002669 flush_variable_declaration(arg[i]);
2670 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002671
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002672 if (!pure)
2673 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002675 string funexpr;
2676 funexpr += to_name(func) + "(";
2677 for (uint32_t i = 0; i < length; i++)
2678 {
2679 funexpr += to_expression(arg[i]);
2680 if (i + 1 < length)
2681 funexpr += ", ";
2682 }
2683 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002684
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002685 if (get<SPIRType>(result_type).basetype != SPIRType::Void)
2686 {
2687 // If the function actually writes to an out variable,
2688 // take the conservative route and do not forward.
2689 // The problem is that we might not read the function
2690 // result (and emit the function) before an out variable
2691 // is read (common case when return value is ignored!
2692 // In order to avoid start tracking invalid variables,
2693 // just avoid the forwarding problem altogether.
2694 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
2695 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002696
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002697 emit_op(result_type, id, funexpr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002698
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002699 // Function calls are implicit loads from all variables in question.
2700 // Set dependencies for them.
2701 for (uint32_t i = 0; i < length; i++)
2702 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002703
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002704 // If we're going to forward the temporary result,
2705 // put dependencies on every variable that must not change.
2706 if (forward)
2707 register_global_read_dependencies(callee, id);
2708 }
2709 else
2710 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002711
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002712 break;
2713 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002714
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002715 // Composite munging
2716 case OpCompositeConstruct:
2717 {
2718 uint32_t result_type = ops[0];
2719 uint32_t id = ops[1];
2720 const auto *elems = &ops[2];
2721 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002723 if (!length)
2724 throw CompilerError("Invalid input to OpCompositeConstruct.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002725
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002726 bool forward = true;
2727 for (uint32_t i = 0; i < length; i++)
2728 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002729
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002730 auto &in_type = expression_type(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002731 auto &out_type = get<SPIRType>(result_type);
2732
2733 // Only splat if we have vector constructors.
2734 // Arrays and structs must be initialized properly in full.
2735 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
2736 bool splat = in_type.vecsize == 1 && in_type.columns == 1 && !composite;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002738 if (splat)
2739 {
2740 uint32_t input = elems[0];
2741 for (uint32_t i = 0; i < length; i++)
2742 if (input != elems[i])
2743 splat = false;
2744 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002745
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002746 string constructor_op;
2747 if (backend.use_initializer_list && composite)
2748 {
2749 // Only use this path if we are building composites.
2750 // This path cannot be used for arithmetic.
2751 constructor_op += "{ ";
2752 if (splat)
2753 constructor_op += to_expression(elems[0]);
2754 else
2755 constructor_op += build_composite_combiner(elems, length);
2756 constructor_op += " }";
2757 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002758 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002759 {
2760 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
2761 if (splat)
2762 constructor_op += to_expression(elems[0]);
2763 else
2764 constructor_op += build_composite_combiner(elems, length);
2765 constructor_op += ")";
2766 }
2767
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002768 emit_op(result_type, id, constructor_op, forward, false);
2769 break;
2770 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002771
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002772 case OpVectorInsertDynamic:
2773 {
2774 uint32_t result_type = ops[0];
2775 uint32_t id = ops[1];
2776 uint32_t vec = ops[2];
2777 uint32_t comp = ops[3];
2778 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002780 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002781
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002782 // Make a copy, then use access chain to store the variable.
2783 statement(declare_temporary(result_type, id), to_expression(vec), ";");
2784 set<SPIRExpression>(id, to_name(id), result_type, true);
2785 auto chain = access_chain(id, &index, 1, false);
2786 statement(chain, " = ", to_expression(comp), ";");
2787 break;
2788 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002789
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002790 case OpVectorExtractDynamic:
2791 {
2792 uint32_t result_type = ops[0];
2793 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002794
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002795 auto expr = access_chain(ops[2], &ops[3], 1, false);
2796 emit_op(result_type, id, expr, should_forward(ops[2]), false);
2797 break;
2798 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002799
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002800 case OpCompositeExtract:
2801 {
2802 uint32_t result_type = ops[0];
2803 uint32_t id = ops[1];
2804 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002805
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002806 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002807
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002808 // Only apply this optimization if result is scalar.
2809 if (should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
2810 {
2811 // We want to split the access chain from the base.
2812 // This is so we can later combine different CompositeExtract results
2813 // with CompositeConstruct without emitting code like
2814 //
2815 // vec3 temp = texture(...).xyz
2816 // vec4(temp.x, temp.y, temp.z, 1.0).
2817 //
2818 // when we actually wanted to emit this
2819 // vec4(texture(...).xyz, 1.0).
2820 //
2821 // Including the base will prevent this and would trigger multiple reads
2822 // from expression causing it to be forced to an actual temporary in GLSL.
2823 auto expr = access_chain(ops[2], &ops[3], length, true, true);
2824 auto &e = emit_op(result_type, id, expr, true, false, !expression_is_forwarded(ops[2]));
2825 e.base_expression = ops[2];
2826 }
2827 else
2828 {
2829 auto expr = access_chain(ops[2], &ops[3], length, true);
2830 emit_op(result_type, id, expr, should_forward(ops[2]), false, !expression_is_forwarded(ops[2]));
2831 }
2832 break;
2833 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002834
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002835 case OpCompositeInsert:
2836 {
2837 uint32_t result_type = ops[0];
2838 uint32_t id = ops[1];
2839 uint32_t obj = ops[2];
2840 uint32_t composite = ops[3];
2841 const auto *elems = &ops[4];
2842 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002843
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002844 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002845
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002846 auto *expr = maybe_get<SPIRExpression>(id);
2847 if ((expr && expr->used_while_invalidated) || !should_forward(composite))
2848 {
2849 // Make a copy, then use access chain to store the variable.
2850 statement(declare_temporary(result_type, id), to_expression(composite), ";");
2851 set<SPIRExpression>(id, to_name(id), result_type, true);
2852 auto chain = access_chain(id, elems, length, true);
2853 statement(chain, " = ", to_expression(obj), ";");
2854 }
2855 else
2856 {
2857 auto chain = access_chain(composite, elems, length, true);
2858 statement(chain, " = ", to_expression(obj), ";");
2859 set<SPIRExpression>(id, to_expression(composite), result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002861 register_write(composite);
2862 register_read(id, composite, true);
2863 // Invalidate the old expression we inserted into.
2864 invalid_expressions.insert(composite);
2865 }
2866 break;
2867 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002868
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002869 case OpCopyObject:
2870 {
2871 uint32_t result_type = ops[0];
2872 uint32_t id = ops[1];
2873 uint32_t rhs = ops[2];
2874 if (expression_is_lvalue(rhs))
2875 {
2876 // Need a copy.
2877 statement(declare_temporary(result_type, id), to_expression(rhs), ";");
2878 set<SPIRExpression>(id, to_name(id), result_type, true);
2879 }
2880 else
2881 {
2882 // RHS expression is immutable, so just forward it.
2883 // Copying these things really make no sense, but
2884 // seems to be allowed anyways.
2885 set<SPIRExpression>(id, to_expression(rhs), result_type, true);
2886 }
2887 break;
2888 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002889
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002890 case OpVectorShuffle:
2891 {
2892 uint32_t result_type = ops[0];
2893 uint32_t id = ops[1];
2894 uint32_t vec0 = ops[2];
2895 uint32_t vec1 = ops[3];
2896 const auto *elems = &ops[4];
2897 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002898
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002899 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002900
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002901 bool shuffle = false;
2902 for (uint32_t i = 0; i < length; i++)
2903 if (elems[i] >= type0.vecsize)
2904 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002905
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002906 string expr;
2907 bool trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002908
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002909 if (shuffle)
2910 {
2911 trivial_forward = !expression_is_forwarded(vec0) && !expression_is_forwarded(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002912
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002913 // Constructor style and shuffling from two different vectors.
2914 vector<string> args;
2915 for (uint32_t i = 0; i < length; i++)
2916 {
2917 if (elems[i] >= type0.vecsize)
2918 args.push_back(join(to_expression(vec1), ".", index_to_swizzle(elems[i] - type0.vecsize)));
2919 else
2920 args.push_back(join(to_expression(vec0), ".", index_to_swizzle(elems[i])));
2921 }
2922 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
2923 }
2924 else
2925 {
2926 trivial_forward = !expression_is_forwarded(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002927
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002928 // We only source from first vector, so can use swizzle.
2929 expr += to_expression(vec0);
2930 expr += ".";
2931 for (uint32_t i = 0; i < length; i++)
2932 expr += index_to_swizzle(elems[i]);
2933 if (backend.swizzle_is_function && length > 1)
2934 expr += "()";
2935 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002936
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002937 // A shuffle is trivial in that it doesn't actually *do* anything.
2938 // 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 +01002939
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002940 emit_op(result_type, id, expr, should_forward(vec0) && should_forward(vec1), false, trivial_forward);
2941 break;
2942 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002943
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002944 // ALU
2945 case OpIsNan:
2946 UFOP(isnan);
2947 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002948
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002949 case OpIsInf:
2950 UFOP(isinf);
2951 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002952
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002953 case OpSNegate:
2954 case OpFNegate:
2955 UOP(-);
2956 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002957
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002958 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002959 {
2960 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
2961 auto type = get<SPIRType>(ops[0]).basetype;
2962 BOP_CAST(+, type, true);
2963 break;
2964 }
2965
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002966 case OpFAdd:
2967 BOP(+);
2968 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002969
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002970 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002971 {
2972 auto type = get<SPIRType>(ops[0]).basetype;
2973 BOP_CAST(-, type, true);
2974 break;
2975 }
2976
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002977 case OpFSub:
2978 BOP(-);
2979 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002980
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002981 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002982 {
2983 auto type = get<SPIRType>(ops[0]).basetype;
2984 BOP_CAST(*, type, true);
2985 break;
2986 }
2987
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002988 case OpFMul:
2989 case OpMatrixTimesVector:
2990 case OpMatrixTimesScalar:
2991 case OpVectorTimesScalar:
2992 case OpVectorTimesMatrix:
2993 case OpMatrixTimesMatrix:
2994 BOP(*);
2995 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002996
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002997 case OpOuterProduct:
2998 UFOP(outerProduct);
2999 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003000
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003001 case OpDot:
3002 BFOP(dot);
3003 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003004
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003005 case OpTranspose:
3006 UFOP(transpose);
3007 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003008
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003009 case OpSDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003010 BOP_CAST(/, SPIRType::Int, false);
3011 break;
3012
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003013 case OpUDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003014 BOP_CAST(/, SPIRType::UInt, false);
3015 break;
3016
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003017 case OpFDiv:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003018 BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003019 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003020
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003021 case OpShiftRightLogical:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003022 BOP_CAST(>>, SPIRType::UInt, false);
3023 break;
3024
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003025 case OpShiftRightArithmetic:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003026 BOP_CAST(>>, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003027 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003028
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003029 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003030 {
3031 auto type = get<SPIRType>(ops[0]).basetype;
3032 BOP_CAST(<<, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003033 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003034 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003036 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003037 {
3038 auto type = get<SPIRType>(ops[0]).basetype;
3039 BOP_CAST(|, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003040 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003041 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003043 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003044 {
3045 auto type = get<SPIRType>(ops[0]).basetype;
3046 BOP_CAST (^, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003047 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003048 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003049
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003050 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003051 {
3052 auto type = get<SPIRType>(ops[0]).basetype;
3053 BOP_CAST(&, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003054 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003055 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003056
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003057 case OpNot:
3058 UOP(~);
3059 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003061 case OpUMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003062 BOP_CAST(%, SPIRType::UInt, false);
3063 break;
3064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003065 case OpSMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003066 BOP_CAST(%, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003067 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003068
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003069 case OpFMod:
3070 BFOP(mod);
3071 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +02003072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003073 // Relational
3074 case OpAny:
3075 UFOP(any);
3076 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003078 case OpAll:
3079 UFOP(all);
3080 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003081
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003082 case OpSelect:
3083 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
3084 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003085
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003086 case OpLogicalOr:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003087 BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003088 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003090 case OpLogicalAnd:
3091 BOP(&&);
3092 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003093
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003094 case OpLogicalNot:
3095 UOP(!);
3096 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003097
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003098 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003099 {
3100 if (expression_type(ops[2]).vecsize > 1)
3101 BFOP_CAST(equal, SPIRType::Int, true);
3102 else
3103 BOP_CAST(==, SPIRType::Int, true);
3104 break;
3105 }
3106
3107 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003108 case OpFOrdEqual:
3109 {
3110 if (expression_type(ops[2]).vecsize > 1)
3111 BFOP(equal);
3112 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003113 BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003114 break;
3115 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003116
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003117 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003118 {
3119 if (expression_type(ops[2]).vecsize > 1)
3120 BFOP_CAST(notEqual, SPIRType::Int, true);
3121 else
3122 BOP_CAST(!=, SPIRType::Int, true);
3123 break;
3124 }
3125
3126 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003127 case OpFOrdNotEqual:
3128 {
3129 if (expression_type(ops[2]).vecsize > 1)
3130 BFOP(notEqual);
3131 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003132 BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003133 break;
3134 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003135
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003136 case OpUGreaterThan:
3137 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003138 {
3139 auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
3140 if (expression_type(ops[2]).vecsize > 1)
3141 BFOP_CAST(greaterThan, type, false);
3142 else
3143 BOP_CAST(>, type, false);
3144 break;
3145 }
3146
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003147 case OpFOrdGreaterThan:
3148 {
3149 if (expression_type(ops[2]).vecsize > 1)
3150 BFOP(greaterThan);
3151 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003152 BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003153 break;
3154 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003156 case OpUGreaterThanEqual:
3157 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003158 {
3159 auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
3160 if (expression_type(ops[2]).vecsize > 1)
3161 BFOP_CAST(greaterThanEqual, type, false);
3162 else
3163 BOP_CAST(>=, type, false);
3164 break;
3165 }
3166
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003167 case OpFOrdGreaterThanEqual:
3168 {
3169 if (expression_type(ops[2]).vecsize > 1)
3170 BFOP(greaterThanEqual);
3171 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003172 BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003173 break;
3174 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003175
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003176 case OpULessThan:
3177 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003178 {
3179 auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
3180 if (expression_type(ops[2]).vecsize > 1)
3181 BFOP_CAST(lessThan, type, false);
3182 else
3183 BOP_CAST(<, type, false);
3184 break;
3185 }
3186
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003187 case OpFOrdLessThan:
3188 {
3189 if (expression_type(ops[2]).vecsize > 1)
3190 BFOP(lessThan);
3191 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003192 BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003193 break;
3194 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003195
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003196 case OpULessThanEqual:
3197 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003198 {
3199 auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
3200 if (expression_type(ops[2]).vecsize > 1)
3201 BFOP_CAST(lessThanEqual, type, false);
3202 else
3203 BOP_CAST(<=, type, false);
3204 break;
3205 }
3206
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003207 case OpFOrdLessThanEqual:
3208 {
3209 if (expression_type(ops[2]).vecsize > 1)
3210 BFOP(lessThanEqual);
3211 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003212 BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003213 break;
3214 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003215
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003216 // Conversion
3217 case OpConvertFToU:
3218 case OpConvertFToS:
3219 case OpConvertSToF:
3220 case OpConvertUToF:
3221 case OpUConvert:
3222 case OpSConvert:
3223 case OpFConvert:
3224 {
3225 uint32_t result_type = ops[0];
3226 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003227
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003228 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
3229 emit_unary_func_op(result_type, id, ops[2], func.c_str());
3230 break;
3231 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003232
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003233 case OpBitcast:
3234 {
3235 uint32_t result_type = ops[0];
3236 uint32_t id = ops[1];
3237 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003238
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003239 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003240 emit_unary_func_op(result_type, id, arg, op.c_str());
3241 break;
3242 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003243
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003244 // Derivatives
3245 case OpDPdx:
3246 UFOP(dFdx);
3247 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003248
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003249 case OpDPdy:
3250 UFOP(dFdy);
3251 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003252
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003253 case OpFwidth:
3254 UFOP(fwidth);
3255 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003257 // Bitfield
3258 case OpBitFieldInsert:
3259 QFOP(bitfieldInsert);
3260 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003261
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003262 case OpBitFieldSExtract:
3263 case OpBitFieldUExtract:
3264 QFOP(bitfieldExtract);
3265 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003266
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003267 case OpBitReverse:
3268 UFOP(bitfieldReverse);
3269 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003270
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003271 case OpBitCount:
3272 UFOP(bitCount);
3273 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003274
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003275 // Atomics
3276 case OpAtomicExchange:
3277 {
3278 uint32_t result_type = ops[0];
3279 uint32_t id = ops[1];
3280 uint32_t ptr = ops[2];
3281 // Ignore semantics for now, probably only relevant to CL.
3282 uint32_t val = ops[5];
3283 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
3284 forced_temporaries.insert(id);
3285 emit_binary_func_op(result_type, id, ptr, val, op);
3286 flush_all_atomic_capable_variables();
3287 break;
3288 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003289
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003290 case OpAtomicCompareExchange:
3291 {
3292 uint32_t result_type = ops[0];
3293 uint32_t id = ops[1];
3294 uint32_t ptr = ops[2];
3295 uint32_t val = ops[6];
3296 uint32_t comp = ops[7];
3297 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003298
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003299 forced_temporaries.insert(id);
3300 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
3301 flush_all_atomic_capable_variables();
3302 break;
3303 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003304
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003305 case OpAtomicLoad:
3306 flush_all_atomic_capable_variables();
3307 // FIXME: Image?
3308 UFOP(atomicCounter);
3309 register_read(ops[1], ops[2], should_forward(ops[2]));
3310 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003312 // OpAtomicStore unimplemented. Not sure what would use that.
3313 // OpAtomicLoad seems to only be relevant for atomic counters.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003314
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003315 case OpAtomicIIncrement:
3316 forced_temporaries.insert(ops[1]);
3317 // FIXME: Image?
3318 UFOP(atomicCounterIncrement);
3319 flush_all_atomic_capable_variables();
3320 register_read(ops[1], ops[2], should_forward(ops[2]));
3321 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003323 case OpAtomicIDecrement:
3324 forced_temporaries.insert(ops[1]);
3325 // FIXME: Image?
3326 UFOP(atomicCounterDecrement);
3327 flush_all_atomic_capable_variables();
3328 register_read(ops[1], ops[2], should_forward(ops[2]));
3329 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003330
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003331 case OpAtomicIAdd:
3332 {
3333 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3334 forced_temporaries.insert(ops[1]);
3335 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3336 flush_all_atomic_capable_variables();
3337 register_read(ops[1], ops[2], should_forward(ops[2]));
3338 break;
3339 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003340
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003341 case OpAtomicISub:
3342 {
3343 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3344 forced_temporaries.insert(ops[1]);
3345 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_expression(ops[5]), ")");
3346 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]), false);
3347 flush_all_atomic_capable_variables();
3348 register_read(ops[1], ops[2], should_forward(ops[2]));
3349 break;
3350 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003352 case OpAtomicSMin:
3353 case OpAtomicUMin:
3354 {
3355 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
3356 forced_temporaries.insert(ops[1]);
3357 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3358 flush_all_atomic_capable_variables();
3359 register_read(ops[1], ops[2], should_forward(ops[2]));
3360 break;
3361 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003362
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003363 case OpAtomicSMax:
3364 case OpAtomicUMax:
3365 {
3366 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
3367 forced_temporaries.insert(ops[1]);
3368 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3369 flush_all_atomic_capable_variables();
3370 register_read(ops[1], ops[2], should_forward(ops[2]));
3371 break;
3372 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003373
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003374 case OpAtomicAnd:
3375 {
3376 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
3377 forced_temporaries.insert(ops[1]);
3378 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3379 flush_all_atomic_capable_variables();
3380 register_read(ops[1], ops[2], should_forward(ops[2]));
3381 break;
3382 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003383
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003384 case OpAtomicOr:
3385 {
3386 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
3387 forced_temporaries.insert(ops[1]);
3388 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3389 flush_all_atomic_capable_variables();
3390 register_read(ops[1], ops[2], should_forward(ops[2]));
3391 break;
3392 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003393
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003394 case OpAtomicXor:
3395 {
3396 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
3397 forced_temporaries.insert(ops[1]);
3398 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3399 flush_all_atomic_capable_variables();
3400 register_read(ops[1], ops[2], should_forward(ops[2]));
3401 break;
3402 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003403
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003404 // Geometry shaders
3405 case OpEmitVertex:
3406 statement("EmitVertex();");
3407 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003408
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003409 case OpEndPrimitive:
3410 statement("EndPrimitive();");
3411 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003412
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003413 case OpEmitStreamVertex:
3414 statement("EmitStreamVertex();");
3415 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003417 case OpEndStreamPrimitive:
3418 statement("EndStreamPrimitive();");
3419 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003420
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003421 // Textures
3422 case OpImageSampleImplicitLod:
3423 case OpImageSampleExplicitLod:
3424 case OpImageSampleProjImplicitLod:
3425 case OpImageSampleProjExplicitLod:
3426 case OpImageSampleDrefImplicitLod:
3427 case OpImageSampleDrefExplicitLod:
3428 case OpImageSampleProjDrefImplicitLod:
3429 case OpImageSampleProjDrefExplicitLod:
3430 case OpImageFetch:
3431 case OpImageGather:
3432 case OpImageDrefGather:
3433 // Gets a bit hairy, so move this to a separate instruction.
3434 emit_texture_op(instruction);
3435 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003436
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003437 case OpImage:
3438 {
3439 uint32_t result_type = ops[0];
3440 uint32_t id = ops[1];
3441 emit_op(result_type, id, to_expression(ops[2]), true, false);
3442 break;
3443 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003445 case OpSampledImage:
3446 {
3447 uint32_t result_type = ops[0];
3448 uint32_t id = ops[1];
3449 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
3450 break;
3451 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +02003452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003453 case OpImageQuerySizeLod:
3454 BFOP(textureSize);
3455 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003457 // Image load/store
3458 case OpImageRead:
3459 {
3460 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
3461 // not adding the proper qualifiers.
3462 // If it turns out we need to read the image after all, remove the qualifier and recompile.
3463 auto *var = maybe_get_backing_variable(ops[2]);
3464 if (var)
3465 {
3466 auto &flags = meta.at(var->self).decoration.decoration_flags;
3467 if (flags & (1ull << DecorationNonReadable))
3468 {
3469 flags &= ~(1ull << DecorationNonReadable);
3470 force_recompile = true;
3471 }
3472 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003473
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003474 uint32_t result_type = ops[0];
3475 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003476
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003477 bool pure;
3478 string imgexpr;
3479 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003480
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003481 if (var && var->remapped_variable) // PLS input, just read as-is without any op-code
3482 {
3483 // PLS input could have different number of components than what the SPIR expects, swizzle to
3484 // the appropriate vector size.
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003485 auto itr =
3486 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 +01003487
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003488 if (itr == end(pls_inputs))
3489 throw CompilerError("Found PLS remap for OpImageRead, but ID is not a PLS input ...");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003491 uint32_t components = pls_format_to_components(itr->format);
3492 imgexpr = remap_swizzle(result_type, components, ops[2]);
3493 pure = true;
3494 }
3495 else if (type.image.dim == DimSubpassData)
3496 {
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003497 if (options.vulkan_semantics)
3498 {
3499 // With Vulkan semantics, use the proper Vulkan GLSL construct.
3500 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
3501 }
3502 else
3503 {
3504 // Implement subpass loads via texture barrier style sampling.
3505 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
3506 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003507 pure = true;
3508 }
3509 else
3510 {
3511 // Plain image load/store.
3512 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ")");
3513 pure = false;
3514 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003516 if (var && var->forwardable)
3517 {
3518 auto &e = emit_op(result_type, id, imgexpr, true, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003519
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003520 // We only need to track dependencies if we're reading from image load/store.
3521 if (!pure)
3522 {
3523 e.loaded_from = var->self;
3524 var->dependees.push_back(id);
3525 }
3526 }
3527 else
3528 emit_op(result_type, id, imgexpr, false, false);
3529 break;
3530 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003531
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003532 case OpImageTexelPointer:
3533 {
3534 uint32_t result_type = ops[0];
3535 uint32_t id = ops[1];
3536 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 +01003537
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003538 auto *var = maybe_get_backing_variable(ops[2]);
3539 e.loaded_from = var ? var->self : 0;
3540 break;
3541 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003542
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003543 case OpImageWrite:
3544 {
3545 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
3546 // not adding the proper qualifiers.
3547 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
3548 auto *var = maybe_get_backing_variable(ops[0]);
3549 if (var)
3550 {
3551 auto &flags = meta.at(var->self).decoration.decoration_flags;
3552 if (flags & (1ull << DecorationNonWritable))
3553 {
3554 flags &= ~(1ull << DecorationNonWritable);
3555 force_recompile = true;
3556 }
3557 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003558
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003559 statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003560
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003561 if (var && variable_storage_is_aliased(*var))
3562 flush_all_aliased_variables();
3563 break;
3564 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003565
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003566 case OpImageQuerySize:
3567 {
3568 auto &type = expression_type(ops[2]);
3569 uint32_t result_type = ops[0];
3570 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003571
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003572 if (type.basetype == SPIRType::Image)
3573 {
3574 // The size of an image is always constant.
3575 emit_op(result_type, id, join("imageSize(", to_expression(ops[2]), ")"), true, false);
3576 }
3577 else
3578 throw CompilerError("Invalid type for OpImageQuerySize.");
3579 break;
3580 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003581
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003582 // Compute
3583 case OpControlBarrier:
3584 {
3585 // Ignore execution and memory scope.
3586 if (execution.model == ExecutionModelGLCompute)
3587 {
3588 uint32_t mem = get<SPIRConstant>(ops[2]).scalar();
3589 if (mem == MemorySemanticsWorkgroupMemoryMask)
3590 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02003591 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003592 statement("memoryBarrier();");
3593 }
3594 statement("barrier();");
3595 break;
3596 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003597
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003598 case OpMemoryBarrier:
3599 {
3600 uint32_t mem = get<SPIRConstant>(ops[1]).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003601
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003602 // We cannot forward any loads beyond the memory barrier.
3603 if (mem)
3604 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003605
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003606 if (mem == MemorySemanticsWorkgroupMemoryMask)
3607 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02003608 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003609 statement("memoryBarrier();");
3610 break;
3611 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003613 case OpExtInst:
3614 {
3615 uint32_t extension_set = ops[2];
3616 if (get<SPIRExtension>(extension_set).ext != SPIRExtension::GLSL)
3617 {
3618 statement("// unimplemented ext op ", instruction.op);
3619 break;
3620 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003621
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003622 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
3623 break;
3624 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003626 default:
3627 statement("// unimplemented op ", instruction.op);
3628 break;
3629 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003630}
3631
3632string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
3633{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003634 auto &memb = meta[type.self].members;
3635 if (index < memb.size() && !memb[index].alias.empty())
3636 return memb[index].alias;
3637 else
3638 return join("_", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003639}
3640
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02003641void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
3642{
3643 auto &memb = meta[type.self].members;
3644 if (index < memb.size() && !memb[index].alias.empty())
3645 {
3646 auto &name = memb[index].alias;
3647 if (name.empty())
3648 return;
3649
3650 // Reserved for temporaries.
3651 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
3652 {
3653 name.clear();
3654 return;
3655 }
3656
3657 update_name_cache(type.member_name_cache, name);
3658 }
3659}
3660
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003661string CompilerGLSL::variable_decl(const SPIRType &type, const std::string &name)
3662{
3663 return join(type_to_glsl(type), " ", name, type_to_array_glsl(type));
3664}
3665
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003666string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index)
3667{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003668 uint64_t memberflags = 0;
3669 auto &memb = meta[type.self].members;
3670 if (index < memb.size())
3671 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003672
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003673 return join(layout_for_member(type, index), flags_to_precision_qualifiers_glsl(membertype, memberflags),
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003674 variable_decl(membertype, to_member_name(type, index)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003675}
3676
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003677const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003678{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003679 if (options.es)
3680 {
3681 // Structs do not have precision qualifiers.
3682 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
3683 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
3684 type.basetype != SPIRType::Sampler)
3685 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003687 if (flags & (1ull << DecorationRelaxedPrecision))
3688 {
3689 bool implied_fmediump = type.basetype == SPIRType::Float &&
3690 options.fragment.default_float_precision == Options::Mediump &&
3691 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003692
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003693 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
3694 options.fragment.default_int_precision == Options::Mediump &&
3695 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003696
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003697 return implied_fmediump || implied_imediump ? "" : "mediump ";
3698 }
3699 else
3700 {
3701 bool implied_fhighp =
3702 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
3703 execution.model == ExecutionModelFragment) ||
3704 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003705
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003706 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
3707 ((options.fragment.default_int_precision == Options::Highp &&
3708 execution.model == ExecutionModelFragment) ||
3709 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003711 return implied_fhighp || implied_ihighp ? "" : "highp ";
3712 }
3713 }
3714 else
3715 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003716}
3717
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003718const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003719{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003720 return flags_to_precision_qualifiers_glsl(expression_type(id), meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003721}
3722
3723string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
3724{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003725 auto flags = meta[id].decoration.decoration_flags;
3726 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003727
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003728 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003729
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003730 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
3731 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003732
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003733 res += to_precision_qualifiers_glsl(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003735 //if (flags & (1ull << DecorationSmooth))
3736 // res += "smooth ";
3737 if (flags & (1ull << DecorationFlat))
3738 res += "flat ";
3739 if (flags & (1ull << DecorationNoPerspective))
3740 res += "noperspective ";
3741 if (flags & (1ull << DecorationPatch))
3742 res += "patch ";
3743 if (flags & (1ull << DecorationSample))
3744 res += "sample ";
3745 if (flags & (1ull << DecorationInvariant))
3746 res += "invariant ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003747
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003748 auto &type = expression_type(id);
3749 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
3750 {
3751 if (flags & (1ull << DecorationNonWritable))
3752 res += "readonly ";
3753 if (flags & (1ull << DecorationNonReadable))
3754 res += "writeonly ";
3755 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003756
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003757 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003758}
3759
3760string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
3761{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003762 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
3763 // Not sure if argument being pointer type should make the argument inout.
3764 auto &type = expression_type(arg.id);
3765 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003766
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003767 if (type.pointer)
3768 {
3769 if (arg.write_count && arg.read_count)
3770 direction = "inout ";
3771 else if (arg.write_count)
3772 direction = "out ";
3773 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003774
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003775 return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003776}
3777
3778string CompilerGLSL::variable_decl(const SPIRVariable &variable)
3779{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003780 // Ignore the pointer type since GLSL doesn't have pointers.
3781 auto &type = get<SPIRType>(variable.basetype);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003782 auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self)));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003783 if (variable.initializer)
3784 res += join(" = ", to_expression(variable.initializer));
3785 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003786}
3787
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003788const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003789{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003790 auto flags = meta[variable.self].decoration.decoration_flags;
3791 if (flags & (1ull << DecorationRelaxedPrecision))
3792 return "mediump ";
3793 else
3794 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003795}
3796
3797string CompilerGLSL::pls_decl(const PlsRemap &var)
3798{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003799 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003800
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003801 SPIRType type;
3802 type.vecsize = pls_format_to_components(var.format);
3803 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003804
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003805 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
3806 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003807}
3808
3809string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
3810{
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003811 if (type.array.empty())
3812 return "";
3813
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003814 string res;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003815 for (size_t i = type.array.size(); i; i--)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003816 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003817 auto &size = type.array[i - 1];
3818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003819 res += "[";
3820 if (size)
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02003821 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003822 res += convert_to_string(size);
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02003823 }
3824 else if (!backend.flexible_member_array_supported)
3825 {
3826 // For runtime-sized arrays, we can work around
3827 // lack of standard support for this by simply having
3828 // a single element array.
3829 //
3830 // Runtime length arrays must always be the last element
3831 // in an interface block.
3832 res += '1';
3833 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003834 res += "]";
3835 }
3836 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003837}
3838
3839string CompilerGLSL::image_type_glsl(const SPIRType &type)
3840{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003841 auto &imagetype = get<SPIRType>(type.image.type);
3842 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003843
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003844 switch (imagetype.basetype)
3845 {
3846 case SPIRType::Int:
3847 res = "i";
3848 break;
3849 case SPIRType::UInt:
3850 res = "u";
3851 break;
3852 default:
3853 break;
3854 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003855
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003856 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
3857 return res + "subpassInput";
3858
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003859 // If we're emulating subpassInput with samplers, force sampler2D
3860 // so we don't have to specify format.
3861 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
3862 res += type.image.sampled == 2 ? "image" : "texture";
3863 else
3864 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003865
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003866 switch (type.image.dim)
3867 {
3868 case Dim1D:
3869 res += "1D";
3870 break;
3871 case Dim2D:
3872 res += "2D";
3873 break;
3874 case Dim3D:
3875 res += "3D";
3876 break;
3877 case DimCube:
3878 res += "Cube";
3879 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003880
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003881 case DimBuffer:
3882 if (options.es && options.version < 320)
3883 require_extension("GL_OES_texture_buffer");
3884 else if (!options.es && options.version < 300)
3885 require_extension("GL_EXT_texture_buffer_object");
3886 res += "Buffer";
3887 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003888
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003889 case DimSubpassData:
3890 res += "2D";
3891 break;
3892 default:
3893 throw CompilerError("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
3894 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003895
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003896 if (type.image.arrayed)
3897 res += "Array";
3898 if (type.image.depth)
3899 res += "Shadow";
3900 if (type.image.ms)
3901 res += "MS";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003902
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003903 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003904}
3905
3906string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
3907{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003908 auto e = type_to_glsl(type);
3909 for (uint32_t i = 0; i < type.array.size(); i++)
3910 e += "[]";
3911 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003912}
3913
3914string CompilerGLSL::type_to_glsl(const SPIRType &type)
3915{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003916 // Ignore the pointer type since GLSL doesn't have pointers.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003917
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003918 switch (type.basetype)
3919 {
3920 case SPIRType::Struct:
3921 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02003922 if (backend.explicit_struct_type)
3923 return join("struct ", to_name(type.self));
3924 else
3925 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003926
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003927 case SPIRType::Image:
3928 case SPIRType::SampledImage:
3929 return image_type_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003930
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003931 case SPIRType::Sampler:
3932 // Not really used.
3933 return "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003934
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003935 case SPIRType::Void:
3936 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003937
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003938 default:
3939 break;
3940 }
3941
3942 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
3943 {
3944 switch (type.basetype)
3945 {
3946 case SPIRType::Bool:
3947 return "bool";
3948 case SPIRType::Int:
3949 return backend.basic_int_type;
3950 case SPIRType::UInt:
3951 return backend.basic_uint_type;
3952 case SPIRType::AtomicCounter:
3953 return "atomic_uint";
3954 case SPIRType::Float:
3955 return "float";
3956 default:
3957 return "???";
3958 }
3959 }
3960 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
3961 {
3962 switch (type.basetype)
3963 {
3964 case SPIRType::Bool:
3965 return join("bvec", type.vecsize);
3966 case SPIRType::Int:
3967 return join("ivec", type.vecsize);
3968 case SPIRType::UInt:
3969 return join("uvec", type.vecsize);
3970 case SPIRType::Float:
3971 return join("vec", type.vecsize);
3972 default:
3973 return "???";
3974 }
3975 }
3976 else if (type.vecsize == type.columns) // Simple Matrix builtin
3977 {
3978 switch (type.basetype)
3979 {
3980 case SPIRType::Bool:
3981 return join("bmat", type.vecsize);
3982 case SPIRType::Int:
3983 return join("imat", type.vecsize);
3984 case SPIRType::UInt:
3985 return join("umat", type.vecsize);
3986 case SPIRType::Float:
3987 return join("mat", type.vecsize);
3988 default:
3989 return "???";
3990 }
3991 }
3992 else
3993 {
3994 switch (type.basetype)
3995 {
3996 case SPIRType::Bool:
3997 return join("bmat", type.columns, "x", type.vecsize);
3998 case SPIRType::Int:
3999 return join("imat", type.columns, "x", type.vecsize);
4000 case SPIRType::UInt:
4001 return join("umat", type.columns, "x", type.vecsize);
4002 case SPIRType::Float:
4003 return join("mat", type.columns, "x", type.vecsize);
4004 default:
4005 return "???";
4006 }
4007 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004008}
4009
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004010void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004011{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004012 auto &name = meta[id].decoration.alias;
4013 if (name.empty())
4014 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004016 // Reserved for temporaries.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004017 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004018 {
4019 name.clear();
4020 return;
4021 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004022
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004023 update_name_cache(variables, name);
4024}
4025
4026void CompilerGLSL::add_local_variable_name(uint32_t id)
4027{
4028 add_variable(local_variable_names, id);
4029}
4030
4031void CompilerGLSL::add_resource_name(uint32_t id)
4032{
4033 add_variable(resource_names, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004034}
4035
4036void CompilerGLSL::require_extension(const string &ext)
4037{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004038 if (forced_extensions.find(ext) == end(forced_extensions))
4039 {
4040 forced_extensions.insert(ext);
4041 force_recompile = true;
4042 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004043}
4044
4045bool CompilerGLSL::check_atomic_image(uint32_t id)
4046{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004047 auto &type = expression_type(id);
4048 if (type.storage == StorageClassImage)
4049 {
4050 if (options.es && options.version < 320)
4051 require_extension("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004052
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004053 auto *var = maybe_get_backing_variable(id);
4054 if (var)
4055 {
4056 auto &flags = meta.at(var->self).decoration.decoration_flags;
4057 if (flags & ((1ull << DecorationNonWritable) | (1ull << DecorationNonReadable)))
4058 {
4059 flags &= ~(1ull << DecorationNonWritable);
4060 flags &= ~(1ull << DecorationNonReadable);
4061 force_recompile = true;
4062 }
4063 }
4064 return true;
4065 }
4066 else
4067 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004068}
4069
4070void CompilerGLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_flags)
4071{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004072 // Avoid shadow declarations.
4073 local_variable_names = resource_names;
4074
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004075 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004076
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004077 auto &type = get<SPIRType>(func.return_type);
4078 decl += flags_to_precision_qualifiers_glsl(type, return_flags);
4079 decl += type_to_glsl(type);
4080 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004081
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004082 if (func.self == execution.entry_point)
4083 {
4084 decl += "main";
4085 processing_entry_point = true;
4086 }
4087 else
4088 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004090 decl += "(";
4091 for (auto &arg : func.arguments)
4092 {
4093 // Might change the variable name if it already exists in this function.
4094 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
4095 // to use same name for variables.
4096 // 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 +02004097 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004098
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004099 decl += argument_decl(arg);
4100 if (&arg != &func.arguments.back())
4101 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004102
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004103 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
4104 auto *var = maybe_get<SPIRVariable>(arg.id);
4105 if (var)
4106 var->parameter = &arg;
4107 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004109 decl += ")";
4110 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004111}
4112
4113void CompilerGLSL::emit_function(SPIRFunction &func, uint64_t return_flags)
4114{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004115 // Avoid potential cycles.
4116 if (func.active)
4117 return;
4118 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004119
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004120 // If we depend on a function, emit that function before we emit our own function.
4121 for (auto block : func.blocks)
4122 {
4123 auto &b = get<SPIRBlock>(block);
4124 for (auto &i : b.ops)
4125 {
4126 auto ops = stream(i);
4127 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004128
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004129 if (op == OpFunctionCall)
4130 {
4131 // Recursively emit functions which are called.
4132 uint32_t id = ops[2];
4133 emit_function(get<SPIRFunction>(id), meta[ops[1]].decoration.decoration_flags);
4134 }
4135 }
4136 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004137
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004138 emit_function_prototype(func, return_flags);
4139 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004140
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004141 current_function = &func;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004142
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004143 for (auto &v : func.local_variables)
4144 {
4145 auto &var = get<SPIRVariable>(v);
4146 if (expression_is_lvalue(v))
4147 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004148 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004149
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004150 if (var.initializer)
4151 statement(variable_decl(var), ";");
4152 else
4153 {
4154 // Don't declare variable until first use to declutter the GLSL output quite a lot.
4155 // If we don't touch the variable before first branch,
4156 // declare it then since we need variable declaration to be in top scope.
4157 var.deferred_declaration = true;
4158 }
4159 }
4160 else
4161 {
4162 // HACK: SPIRV likes to use samplers and images as local variables, but GLSL does not allow
4163 // this. For these types (non-lvalue), we enforce forwarding through a shadowed variable.
4164 // This means that when we OpStore to these variables, we just write in the expression ID directly.
4165 // This breaks any kind of branching, since the variable must be statically assigned.
4166 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
4167 var.statically_assigned = true;
4168 }
4169 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004170
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004171 auto &entry_block = get<SPIRBlock>(func.entry_block);
4172 entry_block.loop_dominator = SPIRBlock::NoDominator;
4173 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004174
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004175 end_scope();
4176 processing_entry_point = false;
4177 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004178}
4179
4180void CompilerGLSL::emit_fixup()
4181{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004182 if (execution.model == ExecutionModelVertex && options.vertex.fixup_clipspace)
4183 {
4184 const char *suffix = backend.float_literal_suffix ? "f" : "";
4185 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
4186 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004187}
4188
4189bool CompilerGLSL::flush_phi_required(uint32_t from, uint32_t to)
4190{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004191 auto &child = get<SPIRBlock>(to);
4192 for (auto &phi : child.phi_variables)
4193 if (phi.parent == from)
4194 return true;
4195 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004196}
4197
4198void CompilerGLSL::flush_phi(uint32_t from, uint32_t to)
4199{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004200 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004201
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004202 for (auto &phi : child.phi_variables)
4203 if (phi.parent == from)
4204 statement(to_expression(phi.function_variable), " = ", to_expression(phi.local_variable), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004205}
4206
4207void CompilerGLSL::branch(uint32_t from, uint32_t to)
4208{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004209 flush_phi(from, to);
4210 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004211
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004212 // This is only a continue if we branch to our loop dominator.
4213 if (loop_blocks.find(to) != end(loop_blocks) && get<SPIRBlock>(from).loop_dominator == to)
4214 {
4215 // This can happen if we had a complex continue block which was emitted.
4216 // Once the continue block tries to branch to the loop header, just emit continue;
4217 // and end the chain here.
4218 statement("continue;");
4219 }
4220 else if (is_continue(to))
4221 {
4222 auto &to_block = get<SPIRBlock>(to);
4223 if (to_block.complex_continue)
4224 {
4225 // Just emit the whole block chain as is.
4226 auto usage_counts = expression_usage_counts;
4227 auto invalid = invalid_expressions;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004228
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004229 emit_block_chain(to_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004230
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004231 // Expression usage counts and invalid expressions
4232 // are moot after returning from the continue block.
4233 // Since we emit the same block multiple times,
4234 // we don't want to invalidate ourselves.
4235 expression_usage_counts = usage_counts;
4236 invalid_expressions = invalid;
4237 }
4238 else
4239 {
4240 auto &from_block = get<SPIRBlock>(from);
4241 auto &dominator = get<SPIRBlock>(from_block.loop_dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004242
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004243 // For non-complex continue blocks, we implicitly branch to the continue block
4244 // by having the continue block be part of the loop header in for (; ; continue-block).
4245 bool outside_control_flow = block_is_outside_flow_control_from_block(dominator, from_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004246
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004247 // Some simplification for for-loops. We always end up with a useless continue;
4248 // statement since we branch to a loop block.
4249 // Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block,
4250 // we can avoid writing out an explicit continue statement.
4251 // Similar optimization to return statements if we know we're outside flow control.
4252 if (!outside_control_flow)
4253 statement("continue;");
4254 }
4255 }
4256 else if (is_break(to))
4257 statement("break;");
4258 else if (!is_conditional(to))
4259 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004260}
4261
4262void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block)
4263{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004264 // If we branch directly to a selection merge target, we don't really need a code path.
4265 bool true_sub = !is_conditional(true_block);
4266 bool false_sub = !is_conditional(false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004268 if (true_sub)
4269 {
4270 statement("if (", to_expression(cond), ")");
4271 begin_scope();
4272 branch(from, true_block);
4273 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004274
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004275 if (false_sub)
4276 {
4277 statement("else");
4278 begin_scope();
4279 branch(from, false_block);
4280 end_scope();
4281 }
4282 else if (flush_phi_required(from, false_block))
4283 {
4284 statement("else");
4285 begin_scope();
4286 flush_phi(from, false_block);
4287 end_scope();
4288 }
4289 }
4290 else if (false_sub && !true_sub)
4291 {
4292 // Only need false path, use negative conditional.
4293 statement("if (!", to_expression(cond), ")");
4294 begin_scope();
4295 branch(from, false_block);
4296 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004297
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004298 if (flush_phi_required(from, true_block))
4299 {
4300 statement("else");
4301 begin_scope();
4302 flush_phi(from, true_block);
4303 end_scope();
4304 }
4305 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004306}
4307
4308void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
4309{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004310 // Propagate down the loop dominator block, so that dominated blocks can back trace.
4311 if (block.merge == SPIRBlock::MergeLoop || block.loop_dominator)
4312 {
4313 uint32_t dominator = block.merge == SPIRBlock::MergeLoop ? block.self : block.loop_dominator;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004314
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02004315 auto set_dominator = [this](uint32_t self, uint32_t new_dominator) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004316 auto &dominated_block = this->get<SPIRBlock>(self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004318 // If we already have a loop dominator, we're trying to break out to merge targets
4319 // which should not update the loop dominator.
4320 if (!dominated_block.loop_dominator)
4321 dominated_block.loop_dominator = new_dominator;
4322 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004323
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004324 // After merging a loop, we inherit the loop dominator always.
4325 if (block.merge_block)
4326 set_dominator(block.merge_block, block.loop_dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004327
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004328 if (block.true_block)
4329 set_dominator(block.true_block, dominator);
4330 if (block.false_block)
4331 set_dominator(block.false_block, dominator);
4332 if (block.next_block)
4333 set_dominator(block.next_block, dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004335 for (auto &c : block.cases)
4336 set_dominator(c.block, dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004337
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004338 // In older glslang output continue_block can be == loop header.
4339 if (block.continue_block && block.continue_block != block.self)
4340 set_dominator(block.continue_block, dominator);
4341 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004342}
4343
4344// FIXME: This currently cannot handle complex continue blocks
4345// as in do-while.
4346// This should be seen as a "trivial" continue block.
4347string CompilerGLSL::emit_continue_block(uint32_t continue_block)
4348{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004349 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004350
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004351 // While emitting the continue block, declare_temporary will check this
4352 // if we have to emit temporaries.
4353 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004355 vector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004356
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004357 // Capture all statements into our list.
4358 auto *old = redirect_statement;
4359 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004360
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004361 // Stamp out all blocks one after each other.
4362 while (loop_blocks.find(block->self) == end(loop_blocks))
4363 {
4364 propagate_loop_dominators(*block);
4365 // Write out all instructions we have in this block.
4366 for (auto &op : block->ops)
4367 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004368
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004369 // For plain branchless for/while continue blocks.
4370 if (block->next_block)
4371 {
4372 flush_phi(continue_block, block->next_block);
4373 block = &get<SPIRBlock>(block->next_block);
4374 }
4375 // For do while blocks. The last block will be a select block.
4376 else if (block->true_block)
4377 {
4378 flush_phi(continue_block, block->true_block);
4379 block = &get<SPIRBlock>(block->true_block);
4380 }
4381 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004382
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004383 // Restore old pointer.
4384 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004385
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004386 // Somewhat ugly, strip off the last ';' since we use ',' instead.
4387 // Ideally, we should select this behavior in statement().
4388 for (auto &s : statements)
4389 {
4390 if (!s.empty() && s.back() == ';')
4391 s.pop_back();
4392 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004393
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004394 current_continue_block = nullptr;
4395 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004396}
4397
4398bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
4399{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004400 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004401
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004402 if (method == SPIRBlock::MergeToSelectForLoop)
4403 {
4404 uint32_t current_count = statement_count;
4405 // If we're trying to create a true for loop,
4406 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4407 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4408 for (auto &op : block.ops)
4409 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004410
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004411 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004412
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004413 // This can work! We only did trivial things which could be forwarded in block body!
4414 if (current_count == statement_count && condition_is_temporary)
4415 {
4416 switch (continue_type)
4417 {
4418 case SPIRBlock::ForLoop:
4419 statement("for (; ", to_expression(block.condition), "; ", emit_continue_block(block.continue_block),
4420 ")");
4421 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004422
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004423 case SPIRBlock::WhileLoop:
4424 statement("while (", to_expression(block.condition), ")");
4425 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004426
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004427 default:
4428 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
4429 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004430
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004431 begin_scope();
4432 return true;
4433 }
4434 else
4435 {
4436 block.disable_block_optimization = true;
4437 force_recompile = true;
4438 begin_scope(); // We'll see an end_scope() later.
4439 return false;
4440 }
4441 }
4442 else if (method == SPIRBlock::MergeToDirectForLoop)
4443 {
4444 uint32_t current_count = statement_count;
4445 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004446
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004447 // If we're trying to create a true for loop,
4448 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4449 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4450 for (auto &op : child.ops)
4451 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004452
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004453 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004455 if (current_count == statement_count && condition_is_temporary)
4456 {
4457 propagate_loop_dominators(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004458
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004459 switch (continue_type)
4460 {
4461 case SPIRBlock::ForLoop:
4462 statement("for (; ", to_expression(child.condition), "; ", emit_continue_block(block.continue_block),
4463 ")");
4464 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004465
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004466 case SPIRBlock::WhileLoop:
4467 statement("while (", to_expression(child.condition), ")");
4468 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004469
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004470 default:
4471 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
4472 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004473
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004474 begin_scope();
4475 branch(child.self, child.true_block);
4476 return true;
4477 }
4478 else
4479 {
4480 block.disable_block_optimization = true;
4481 force_recompile = true;
4482 begin_scope(); // We'll see an end_scope() later.
4483 return false;
4484 }
4485 }
4486 else
4487 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004488}
4489
4490void CompilerGLSL::flush_undeclared_variables()
4491{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004492 // Declare undeclared variables.
4493 if (current_function->flush_undeclared)
4494 {
4495 for (auto &v : current_function->local_variables)
4496 {
4497 auto &var = get<SPIRVariable>(v);
4498 if (var.deferred_declaration)
4499 statement(variable_decl(var), ";");
4500 var.deferred_declaration = false;
4501 }
4502 current_function->flush_undeclared = false;
4503 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004504}
4505
4506void CompilerGLSL::emit_block_chain(SPIRBlock &block)
4507{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004508 propagate_loop_dominators(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004509
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004510 bool select_branch_to_true_block = false;
4511 bool skip_direct_branch = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004512
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004513 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
4514 for (auto &tmp : block.declare_temporary)
4515 {
4516 auto flags = meta[tmp.second].decoration.decoration_flags;
4517 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004518 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004519 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004520
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004521 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
4522 if (block.continue_block)
4523 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004524
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004525 // This is the older loop behavior in glslang which branches to loop body directly from the loop header.
4526 if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
4527 {
4528 flush_undeclared_variables();
4529 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
4530 {
4531 // The body of while, is actually just the true block, so always branch there
4532 // unconditionally.
4533 select_branch_to_true_block = true;
4534 }
4535 }
4536 // This is the newer loop behavior in glslang which branches from Loop header directly to
4537 // a new block, which in turn has a OpBranchSelection without a selection merge.
4538 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
4539 {
4540 flush_undeclared_variables();
4541 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
4542 skip_direct_branch = true;
4543 }
4544 else if (continue_type == SPIRBlock::DoWhileLoop)
4545 {
4546 statement("do");
4547 begin_scope();
4548 for (auto &op : block.ops)
4549 emit_instruction(op);
4550 }
4551 else if (block.merge == SPIRBlock::MergeLoop)
4552 {
4553 flush_undeclared_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004555 // We have a generic loop without any distinguishable pattern like for, while or do while.
4556 get<SPIRBlock>(block.continue_block).complex_continue = true;
4557 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004558
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004559 statement("for (;;)");
4560 begin_scope();
4561 for (auto &op : block.ops)
4562 emit_instruction(op);
4563 }
4564 else
4565 {
4566 for (auto &op : block.ops)
4567 emit_instruction(op);
4568 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004569
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004570 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004571
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004572 // Handle end of block.
4573 switch (block.terminator)
4574 {
4575 case SPIRBlock::Direct:
4576 // True when emitting complex continue block.
4577 if (block.loop_dominator == block.next_block)
4578 {
4579 branch(block.self, block.next_block);
4580 emit_next_block = false;
4581 }
4582 // True if MergeToDirectForLoop succeeded.
4583 else if (skip_direct_branch)
4584 emit_next_block = false;
4585 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
4586 {
4587 branch(block.self, block.next_block);
4588 emit_next_block = false;
4589 }
4590 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004592 case SPIRBlock::Select:
4593 // True if MergeToSelectForLoop succeeded.
4594 if (select_branch_to_true_block)
4595 branch(block.self, block.true_block);
4596 else
4597 {
4598 flush_undeclared_variables();
4599 branch(block.self, block.condition, block.true_block, block.false_block);
4600 }
4601 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004602
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004603 case SPIRBlock::MultiSelect:
4604 {
4605 flush_undeclared_variables();
4606 auto &type = expression_type(block.condition);
4607 bool uint32_t_case = type.basetype == SPIRType::UInt;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004608
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004609 statement("switch (", to_expression(block.condition), ")");
4610 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004611
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004612 for (auto &c : block.cases)
4613 {
4614 auto case_value =
4615 uint32_t_case ? convert_to_string(uint32_t(c.value)) : convert_to_string(int32_t(c.value));
4616 statement("case ", case_value, ":");
4617 begin_scope();
4618 branch(block.self, c.block);
4619 end_scope();
4620 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004621
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004622 if (block.default_block != block.next_block)
4623 {
4624 statement("default:");
4625 begin_scope();
4626 if (is_break(block.default_block))
4627 throw CompilerError("Cannot break; out of a switch statement and out of a loop at the same time ...");
4628 branch(block.self, block.default_block);
4629 end_scope();
4630 }
4631 else if (flush_phi_required(block.self, block.next_block))
4632 {
4633 statement("default:");
4634 begin_scope();
4635 flush_phi(block.self, block.next_block);
4636 statement("break;");
4637 end_scope();
4638 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004639
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004640 end_scope();
4641 break;
4642 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004643
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004644 case SPIRBlock::Return:
4645 if (processing_entry_point)
4646 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004647
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004648 if (block.return_value)
4649 {
4650 // OpReturnValue can return Undef, so don't emit anything for this case.
4651 if (ids.at(block.return_value).get_type() != TypeUndef)
4652 statement("return ", to_expression(block.return_value), ";");
4653 }
4654 // If this block is the very final block and not called from control flow,
4655 // we do not need an explicit return which looks out of place. Just end the function here.
4656 // In the very weird case of for(;;) { return; } executing return is unconditional,
4657 // but we actually need a return here ...
4658 else if (!block_is_outside_flow_control_from_block(get<SPIRBlock>(current_function->entry_block), block) ||
4659 block.loop_dominator != SPIRBlock::NoDominator)
4660 statement("return;");
4661 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004662
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004663 case SPIRBlock::Kill:
4664 statement("discard;");
4665 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004666
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004667 default:
4668 throw CompilerError("Unimplemented block terminator.");
4669 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004671 if (block.next_block && emit_next_block)
4672 {
4673 // If we hit this case, we're dealing with an unconditional branch, which means we will output
4674 // that block after this. If we had selection merge, we already flushed phi variables.
4675 if (block.merge != SPIRBlock::MergeSelection)
4676 flush_phi(block.self, block.next_block);
4677 emit_block_chain(get<SPIRBlock>(block.next_block));
4678 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004680 if (block.merge == SPIRBlock::MergeLoop)
4681 {
4682 if (continue_type == SPIRBlock::DoWhileLoop)
4683 {
4684 // Make sure that we run the continue block to get the expressions set, but this
4685 // should become an empty string.
4686 // We have no fallbacks if we cannot forward everything to temporaries ...
4687 auto statements = emit_continue_block(block.continue_block);
4688 if (!statements.empty())
4689 {
4690 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
4691 get<SPIRBlock>(block.continue_block).complex_continue = true;
4692 force_recompile = true;
4693 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004694
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004695 end_scope_decl(join("while (", to_expression(get<SPIRBlock>(block.continue_block).condition), ")"));
4696 }
4697 else
4698 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004699
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004700 flush_phi(block.self, block.merge_block);
4701 emit_block_chain(get<SPIRBlock>(block.merge_block));
4702 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004703}
4704
4705void CompilerGLSL::begin_scope()
4706{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004707 statement("{");
4708 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004709}
4710
4711void CompilerGLSL::end_scope()
4712{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004713 if (!indent)
4714 throw CompilerError("Popping empty indent stack.");
4715 indent--;
4716 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004717}
4718
4719void CompilerGLSL::end_scope_decl()
4720{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004721 if (!indent)
4722 throw CompilerError("Popping empty indent stack.");
4723 indent--;
4724 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004725}
4726
4727void CompilerGLSL::end_scope_decl(const string &decl)
4728{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004729 if (!indent)
4730 throw CompilerError("Popping empty indent stack.");
4731 indent--;
4732 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004733}