blob: 9a9bc44e4c676a4addb798316318e7502be87dc9 [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));
Hans-Kristian Arntzen05a97882016-06-23 13:42:59 +0200232 if ((execution.flags & (1ull << ExecutionModeInvocations)) && execution.invocations != 1)
233 {
234 // Instanced GS is part of 400 core or this extension.
235 if (!options.es && options.version < 400)
236 statement("#extension GL_ARB_gpu_shader5 : require");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200237 inputs.push_back(join("invocations = ", execution.invocations));
Hans-Kristian Arntzen05a97882016-06-23 13:42:59 +0200238 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200239 if (execution.flags & (1ull << ExecutionModeInputPoints))
240 inputs.push_back("points");
241 if (execution.flags & (1ull << ExecutionModeInputLines))
242 inputs.push_back("lines");
243 if (execution.flags & (1ull << ExecutionModeInputLinesAdjacency))
244 inputs.push_back("lines_adjacency");
245 if (execution.flags & (1ull << ExecutionModeTriangles))
246 inputs.push_back("triangles");
247 if (execution.flags & (1ull << ExecutionModeInputTrianglesAdjacency))
248 inputs.push_back("triangles_adjacency");
249 if (execution.flags & (1ull << ExecutionModeOutputTriangleStrip))
250 outputs.push_back("triangle_strip");
251 if (execution.flags & (1ull << ExecutionModeOutputPoints))
252 outputs.push_back("points");
253 if (execution.flags & (1ull << ExecutionModeOutputLineStrip))
254 outputs.push_back("line_strip");
255 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200257 case ExecutionModelTessellationControl:
258 if (options.es && options.version < 320)
259 statement("#extension GL_EXT_tessellation_shader : require");
260 if (!options.es && options.version < 400)
261 statement("#extension GL_ARB_tessellation_shader : require");
262 if (execution.flags & (1ull << ExecutionModeOutputVertices))
263 outputs.push_back(join("vertices = ", execution.output_vertices));
264 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200266 case ExecutionModelTessellationEvaluation:
267 if (options.es && options.version < 320)
268 statement("#extension GL_EXT_tessellation_shader : require");
269 if (!options.es && options.version < 400)
270 statement("#extension GL_ARB_tessellation_shader : require");
271 if (execution.flags & (1ull << ExecutionModeQuads))
272 inputs.push_back("quads");
273 if (execution.flags & (1ull << ExecutionModeIsolines))
274 inputs.push_back("isolines");
275 if (execution.flags & (1ull << ExecutionModePointMode))
276 inputs.push_back("point_mode");
277 if (execution.flags & (1ull << ExecutionModeVertexOrderCw))
278 inputs.push_back("cw");
279 if (execution.flags & (1ull << ExecutionModeVertexOrderCcw))
280 inputs.push_back("ccw");
281 if (execution.flags & (1ull << ExecutionModeSpacingFractionalEven))
282 inputs.push_back("fractional_even_spacing");
283 if (execution.flags & (1ull << ExecutionModeSpacingFractionalOdd))
284 inputs.push_back("fractional_odd_spacing");
285 if (execution.flags & (1ull << ExecutionModeSpacingEqual))
286 inputs.push_back("equal_spacing");
287 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100288
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200289 case ExecutionModelGLCompute:
290 if (!options.es && options.version < 430)
291 statement("#extension GL_ARB_compute_shader : require");
292 if (options.es && options.version < 310)
293 throw CompilerError("At least ESSL 3.10 required for compute shaders.");
294 inputs.push_back(join("local_size_x = ", execution.workgroup_size.x));
295 inputs.push_back(join("local_size_y = ", execution.workgroup_size.y));
296 inputs.push_back(join("local_size_z = ", execution.workgroup_size.z));
297 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100298
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200299 case ExecutionModelFragment:
300 if (options.es)
301 {
302 switch (options.fragment.default_float_precision)
303 {
304 case Options::Lowp:
305 statement("precision lowp float;");
306 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100307
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200308 case Options::Mediump:
309 statement("precision mediump float;");
310 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200312 case Options::Highp:
313 statement("precision highp float;");
314 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100315
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200316 default:
317 break;
318 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200320 switch (options.fragment.default_int_precision)
321 {
322 case Options::Lowp:
323 statement("precision lowp int;");
324 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100325
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200326 case Options::Mediump:
327 statement("precision mediump int;");
328 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100329
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200330 case Options::Highp:
331 statement("precision highp int;");
332 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200334 default:
335 break;
336 }
337 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100338
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200339 if (execution.flags & (1ull << ExecutionModeEarlyFragmentTests))
340 inputs.push_back("early_fragment_tests");
341 if (execution.flags & (1ull << ExecutionModeDepthGreater))
342 inputs.push_back("depth_greater");
343 if (execution.flags & (1ull << ExecutionModeDepthLess))
344 inputs.push_back("depth_less");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100345
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200346 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100347
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200348 default:
349 break;
350 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200352 if (!inputs.empty())
353 statement("layout(", merge(inputs), ") in;");
354 if (!outputs.empty())
355 statement("layout(", merge(outputs), ") out;");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100356
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200357 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100358}
359
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200360void CompilerGLSL::emit_struct(SPIRType &type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100361{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200362 // Struct types can be stamped out multiple times
363 // with just different offsets, matrix layouts, etc ...
364 // Type-punning with these types is legal, which complicates things
365 // when we are storing struct and array types in an SSBO for example.
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200366 if (type.type_alias != 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200367 return;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200368
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200369 add_resource_name(type.self);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200370 auto name = type_to_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100371
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200372 statement(!backend.explicit_struct_type ? "struct " : "", name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200373 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100374
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200375 type.member_name_cache.clear();
376
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200377 uint32_t i = 0;
378 bool emitted = false;
379 for (auto &member : type.member_types)
380 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200381 add_member_name(type, i);
382
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200383 auto &membertype = get<SPIRType>(member);
384 statement(member_decl(type, membertype, i), ";");
385 i++;
386 emitted = true;
387 }
388 end_scope_decl();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100389
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200390 if (emitted)
391 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100392}
393
394uint64_t CompilerGLSL::combined_decoration_for_member(const SPIRType &type, uint32_t index)
395{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200396 uint64_t flags = 0;
397 auto &memb = meta[type.self].members;
398 if (index >= memb.size())
399 return 0;
400 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100401
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200402 // If our type is a sturct, traverse all the members as well recursively.
403 flags |= dec.decoration_flags;
404 for (uint32_t i = 0; i < type.member_types.size(); i++)
405 flags |= combined_decoration_for_member(get<SPIRType>(type.member_types[i]), i);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100406
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200407 return flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100408}
409
410string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
411{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200412 bool is_block = (meta[type.self].decoration.decoration_flags &
413 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
414 if (!is_block)
415 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200417 auto &memb = meta[type.self].members;
418 if (index >= memb.size())
419 return 0;
420 auto &dec = memb[index];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100421
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200422 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100423
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200424 // We can only apply layouts on members in block interfaces.
425 // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
426 // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct
427 // has a decoration, it was originally caused by a top-level layout() qualifier in GLSL.
428 //
429 // We would like to go from (SPIR-V style):
430 //
431 // struct Foo { layout(row_major) mat4 matrix; };
432 // buffer UBO { Foo foo; };
433 //
434 // to
435 //
436 // struct Foo { mat4 matrix; }; // GLSL doesn't support any layout shenanigans in raw struct declarations.
437 // buffer UBO { layout(row_major) Foo foo; }; // Apply the layout on top-level.
438 auto flags = combined_decoration_for_member(type, index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100439
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200440 if (flags & (1ull << DecorationRowMajor))
441 attr.push_back("row_major");
442 // We don't emit any global layouts, so column_major is default.
443 //if (flags & (1ull << DecorationColMajor))
444 // attr.push_back("column_major");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100445
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200446 if (dec.decoration_flags & (1ull << DecorationLocation))
447 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100448
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200449 if (attr.empty())
450 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100451
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200452 string res = "layout(";
453 res += merge(attr);
454 res += ") ";
455 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100456}
457
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200458const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100459{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200460 // Only handle GLES 3.1 compliant types for now ...
461 switch (format)
462 {
463 case ImageFormatRgba32f:
464 return "rgba32f";
465 case ImageFormatRgba16f:
466 return "rgba16f";
467 case ImageFormatR32f:
468 return "r32f";
469 case ImageFormatRgba8:
470 return "rgba8";
471 case ImageFormatRgba8Snorm:
472 return "rgba8_snorm";
473 case ImageFormatRg32f:
474 return "rg32f";
475 case ImageFormatRg16f:
476 return "rg16f";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100477
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200478 case ImageFormatRgba32i:
479 return "rgba32i";
480 case ImageFormatRgba16i:
481 return "rgba16i";
482 case ImageFormatR32i:
483 return "r32i";
484 case ImageFormatRgba8i:
485 return "rgba8i";
486 case ImageFormatRg32i:
487 return "rg32i";
488 case ImageFormatRg16i:
489 return "rg16i";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200491 case ImageFormatRgba32ui:
492 return "rgba32ui";
493 case ImageFormatRgba16ui:
494 return "rgba16ui";
495 case ImageFormatR32ui:
496 return "r32ui";
497 case ImageFormatRgba8ui:
498 return "rgba8ui";
499 case ImageFormatRg32ui:
500 return "rg32ui";
501 case ImageFormatRg16ui:
502 return "rg16ui";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100503
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200504 case ImageFormatUnknown:
505 return nullptr;
506 default:
507 return "UNSUPPORTED"; // TODO: Fill in rest.
508 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100509}
510
511uint32_t CompilerGLSL::type_to_std430_alignment(const SPIRType &type, uint64_t flags)
512{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200513 // float, int and uint all take 4 bytes.
514 const uint32_t base_alignment = 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200516 if (type.basetype == SPIRType::Struct)
517 {
518 // Rule 9. Structs alignments are maximum alignment of its members.
519 uint32_t alignment = 0;
520 for (uint32_t i = 0; i < type.member_types.size(); i++)
521 {
522 auto member_flags = meta[type.self].members.at(i).decoration_flags;
523 alignment = max(alignment, type_to_std430_alignment(get<SPIRType>(type.member_types[i]), member_flags));
524 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100525
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200526 return alignment;
527 }
528 else
529 {
530 // From 7.6.2.2 in GL 4.5 core spec.
531 // Rule 1
532 if (type.vecsize == 1 && type.columns == 1)
533 return base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100534
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200535 // Rule 2
536 if ((type.vecsize == 2 || type.vecsize == 4) && type.columns == 1)
537 return type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100538
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200539 // Rule 3
540 if (type.vecsize == 3 && type.columns == 1)
541 return 4 * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100542
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200543 // Rule 4 implied. Alignment does not change in std430.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200545 // Rule 5. Column-major matrices are stored as arrays of
546 // vectors.
547 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
548 {
549 if (type.vecsize == 3)
550 return 4 * base_alignment;
551 else
552 return type.vecsize * base_alignment;
553 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100554
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200555 // Rule 6 implied.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100556
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200557 // Rule 7.
558 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
559 {
560 if (type.columns == 3)
561 return 4 * base_alignment;
562 else
563 return type.columns * base_alignment;
564 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100565
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200566 // Rule 8 implied.
567 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100568
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200569 throw CompilerError("Did not find suitable std430 rule for type. Bogus decorations?");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100570}
571
572uint32_t CompilerGLSL::type_to_std430_array_stride(const SPIRType &type, uint64_t flags)
573{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200574 // Array stride is equal to aligned size of the underlying type.
575 SPIRType tmp = type;
576 tmp.array.pop_back();
577 uint32_t size = type_to_std430_size(tmp, flags);
578 uint32_t alignment = type_to_std430_alignment(tmp, flags);
579 return (size + alignment - 1) & ~(alignment - 1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100580}
581
582uint32_t CompilerGLSL::type_to_std430_size(const SPIRType &type, uint64_t flags)
583{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200584 if (!type.array.empty())
585 return type.array.back() * type_to_std430_array_stride(type, flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100586
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200587 // float, int and uint all take 4 bytes.
588 const uint32_t base_alignment = 4;
589 uint32_t size = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100590
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200591 if (type.basetype == SPIRType::Struct)
592 {
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200593 uint32_t pad_alignment = 1;
594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200595 for (uint32_t i = 0; i < type.member_types.size(); i++)
596 {
597 auto member_flags = meta[type.self].members.at(i).decoration_flags;
598 auto &member_type = get<SPIRType>(type.member_types[i]);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200599
600 uint32_t std430_alignment = type_to_std430_alignment(member_type, member_flags);
601 uint32_t alignment = max(std430_alignment, pad_alignment);
602
603 // The next member following a struct member is aligned to the base alignment of the struct that came before.
604 // GL 4.5 spec, 7.6.2.2.
605 if (member_type.basetype == SPIRType::Struct)
606 pad_alignment = std430_alignment;
607 else
608 pad_alignment = 1;
609
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200610 size = (size + alignment - 1) & ~(alignment - 1);
611 size += type_to_std430_size(member_type, member_flags);
612 }
613 }
614 else
615 {
616 if (type.columns == 1)
617 size = type.vecsize * base_alignment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100618
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200619 if ((flags & (1ull << DecorationColMajor)) && type.columns > 1)
620 {
621 if (type.vecsize == 3)
622 size = type.columns * 4 * base_alignment;
623 else
624 size = type.columns * type.vecsize * base_alignment;
625 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100626
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200627 if ((flags & (1ull << DecorationRowMajor)) && type.vecsize > 1)
628 {
629 if (type.columns == 3)
630 size = type.vecsize * 4 * base_alignment;
631 else
632 size = type.vecsize * type.columns * base_alignment;
633 }
634 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200636 return size;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100637}
638
639bool CompilerGLSL::ssbo_is_std430_packing(const SPIRType &type)
640{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200641 // This is very tricky and error prone, but try to be exhaustive and correct here.
642 // SPIR-V doesn't directly say if we're using std430 or std140.
643 // SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
644 // so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
645 // 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).
646 //
647 // It is almost certain that we're using std430, but it gets tricky with arrays in particular.
648 // We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
649 //
650 // The only two differences between std140 and std430 are related to padding alignment/array stride
651 // in arrays and structs. In std140 they take minimum vec4 alignment.
652 // std430 only removes the vec4 requirement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100653
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200654 uint32_t offset = 0;
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200655 uint32_t pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200657 for (uint32_t i = 0; i < type.member_types.size(); i++)
658 {
659 auto &memb_type = get<SPIRType>(type.member_types[i]);
660 auto member_flags = meta[type.self].members.at(i).decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100661
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200662 // Verify alignment rules.
663 uint32_t std430_alignment = type_to_std430_alignment(memb_type, member_flags);
Hans-Kristian Arntzen44ef3672016-05-05 16:32:15 +0200664 uint32_t alignment = max(std430_alignment, pad_alignment);
665 offset = (offset + alignment - 1) & ~(alignment - 1);
666
667 // The next member following a struct member is aligned to the base alignment of the struct that came before.
668 // GL 4.5 spec, 7.6.2.2.
669 if (memb_type.basetype == SPIRType::Struct)
670 pad_alignment = std430_alignment;
671 else
672 pad_alignment = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100673
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200674 uint32_t actual_offset = type_struct_member_offset(type, i);
675 if (actual_offset != offset) // This cannot be std430.
676 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100677
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200678 // Verify array stride rules.
679 if (!memb_type.array.empty() &&
680 type_to_std430_array_stride(memb_type, member_flags) != type_struct_member_array_stride(type, i))
681 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200683 // Verify that sub-structs also follow std430 rules.
684 if (!memb_type.member_types.empty() && !ssbo_is_std430_packing(memb_type))
685 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100686
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200687 // Bump size.
688 offset += type_to_std430_size(memb_type, member_flags);
689 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100690
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200691 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100692}
693
694string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
695{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200696 vector<string> attr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100697
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200698 auto &dec = meta[var.self].decoration;
699 auto &type = get<SPIRType>(var.basetype);
700 auto flags = dec.decoration_flags;
701 auto typeflags = meta[type.self].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100702
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200703 if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
704 attr.push_back("push_constant");
705
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200706 if (flags & (1ull << DecorationRowMajor))
707 attr.push_back("row_major");
708 if (flags & (1ull << DecorationColMajor))
709 attr.push_back("column_major");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200710
711 if (options.vulkan_semantics)
712 {
713 if (flags & (1ull << DecorationInputAttachmentIndex))
714 attr.push_back(join("input_attachment_index = ", dec.input_attachment));
715 }
716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200717 if (flags & (1ull << DecorationLocation))
718 attr.push_back(join("location = ", dec.location));
Hans-Kristian Arntzenf144b762016-05-05 11:51:18 +0200719
720 // set = 0 is the default. Do not emit set = decoration in regular GLSL output, but
721 // we should preserve it in Vulkan GLSL mode.
722 if (var.storage != StorageClassPushConstant)
723 {
724 if ((flags & (1ull << DecorationDescriptorSet)) && (dec.set != 0 || options.vulkan_semantics))
725 attr.push_back(join("set = ", dec.set));
726 }
727
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200728 if (flags & (1ull << DecorationBinding))
729 attr.push_back(join("binding = ", dec.binding));
730 if (flags & (1ull << DecorationCoherent))
731 attr.push_back("coherent");
732 if (flags & (1ull << DecorationOffset))
733 attr.push_back(join("offset = ", dec.offset));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200735 // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430.
736 // If SPIR-V does not comply with either layout, we cannot really work around it.
737 if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBlock)))
738 attr.push_back("std140");
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200739 else if (var.storage == StorageClassUniform && (typeflags & (1ull << DecorationBufferBlock)))
740 attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
741 else if (options.vulkan_semantics && var.storage == StorageClassPushConstant)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200742 attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100743
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200744 // For images, the type itself adds a layout qualifer.
745 if (type.basetype == SPIRType::Image)
746 {
747 const char *fmt = format_to_glsl(type.image.format);
748 if (fmt)
749 attr.push_back(fmt);
750 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100751
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200752 if (attr.empty())
753 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100754
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200755 string res = "layout(";
756 res += merge(attr);
757 res += ") ";
758 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100759}
760
761void CompilerGLSL::emit_push_constant_block(const SPIRVariable &var)
762{
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +0200763 if (options.vulkan_semantics)
764 emit_push_constant_block_vulkan(var);
765 else
766 emit_push_constant_block_glsl(var);
767}
768
769void CompilerGLSL::emit_push_constant_block_vulkan(const SPIRVariable &var)
770{
771 emit_buffer_block(var);
772}
773
774void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
775{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200776 // OpenGL has no concept of push constant blocks, implement it as a uniform struct.
777 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100778
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200779 auto &flags = meta[var.self].decoration.decoration_flags;
780 flags &= ~((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100781
782#if 0
783 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet)))
784 throw CompilerError("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
785 "Remap to location with reflection API first or disable these decorations.");
786#endif
787
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200788 // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily.
789 // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed.
790 auto &block_flags = meta[type.self].decoration.decoration_flags;
791 uint64_t block_flag = block_flags & (1ull << DecorationBlock);
792 block_flags &= ~block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100793
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200794 emit_struct(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100795
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200796 block_flags |= block_flag;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100797
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200798 emit_uniform(var);
799 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100800}
801
802void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
803{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200804 auto &type = get<SPIRType>(var.basetype);
805 auto ssbo = meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock);
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200806
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200807 add_resource_name(var.self);
808
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200809 // Block names should never alias.
810 auto buffer_name = to_name(type.self, false);
811
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200812 // Shaders never use the block by interface name, so we don't
813 // have to track this other than updating name caches.
814 if (resource_names.find(buffer_name) != end(resource_names))
815 buffer_name = get_fallback_name(type.self);
816 else
817 resource_names.insert(buffer_name);
818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200819 statement(layout_for_variable(var) + (ssbo ? "buffer " : "uniform ") + buffer_name);
820 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100821
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200822 type.member_name_cache.clear();
823
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200824 uint32_t i = 0;
825 for (auto &member : type.member_types)
826 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200827 add_member_name(type, i);
828
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200829 auto &membertype = get<SPIRType>(member);
830 statement(member_decl(type, membertype, i), ";");
831 i++;
832 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100833
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200834 end_scope_decl(to_name(var.self) + type_to_array_glsl(type));
835 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100836}
837
838void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
839{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200840 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100841
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200842 // Either make it plain in/out or in/out blocks depending on what shader is doing ...
843 bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200845 const char *qual = nullptr;
846 if (is_legacy() && execution.model == ExecutionModelVertex)
847 qual = var.storage == StorageClassInput ? "attribute " : "varying ";
848 else if (is_legacy() && execution.model == ExecutionModelFragment)
849 qual = "varying "; // Fragment outputs are renamed so they never hit this case.
850 else
851 qual = var.storage == StorageClassInput ? "in " : "out ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100852
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200853 if (block)
854 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200855 add_resource_name(var.self);
856
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200857 // Block names should never alias.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200858 auto block_name = to_name(type.self, false);
859
860 // Shaders never use the block by interface name, so we don't
861 // have to track this other than updating name caches.
862 if (resource_names.find(block_name) != end(resource_names))
863 block_name = get_fallback_name(type.self);
864 else
865 resource_names.insert(block_name);
866
867 statement(layout_for_variable(var), qual, block_name);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200868 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100869
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200870 type.member_name_cache.clear();
871
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200872 uint32_t i = 0;
873 for (auto &member : type.member_types)
874 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200875 add_member_name(type, i);
876
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200877 auto &membertype = get<SPIRType>(member);
878 statement(member_decl(type, membertype, i), ";");
879 i++;
880 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100881
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200882 end_scope_decl(join(to_name(var.self), type_to_array_glsl(type)));
883 statement("");
884 }
885 else
886 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200887 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200888 statement(layout_for_variable(var), qual, variable_decl(var), ";");
889 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100890}
891
892void CompilerGLSL::emit_uniform(const SPIRVariable &var)
893{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200894 auto &type = get<SPIRType>(var.basetype);
895 if (type.basetype == SPIRType::Image)
896 {
897 if (!options.es && options.version < 420)
898 require_extension("GL_ARB_shader_image_load_store");
899 else if (options.es && options.version < 310)
900 throw CompilerError("At least ESSL 3.10 required for shader image load store.");
901 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100902
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200903 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200904 statement(layout_for_variable(var), "uniform ", variable_decl(var), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100905}
906
907void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
908{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200909 auto &m = meta[var.self].decoration;
910 uint32_t location = 0;
911 if (m.decoration_flags & (1ull << DecorationLocation))
912 location = m.location;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100913
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200914 m.alias = join("gl_FragData[", location, "]");
915 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 +0100916}
917
918void CompilerGLSL::replace_fragment_outputs()
919{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200920 for (auto &id : ids)
921 {
922 if (id.get_type() == TypeVariable)
923 {
924 auto &var = id.get<SPIRVariable>();
925 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100926
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200927 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
928 var.storage == StorageClassOutput)
929 replace_fragment_output(var);
930 }
931 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100932}
933
934string CompilerGLSL::remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr)
935{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200936 auto &out_type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100937
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200938 if (out_type.vecsize == input_components)
939 return to_expression(expr);
940 else if (input_components == 1)
941 return join(type_to_glsl(out_type), "(", to_expression(expr), ")");
942 else
943 {
944 auto e = to_expression(expr) + ".";
945 // Just clamp the swizzle index if we have more outputs than inputs.
946 for (uint32_t c = 0; c < out_type.vecsize; c++)
947 e += index_to_swizzle(min(c, input_components - 1));
948 if (backend.swizzle_is_function && out_type.vecsize > 1)
949 e += "()";
950 return e;
951 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100952}
953
954void CompilerGLSL::emit_pls()
955{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200956 if (execution.model != ExecutionModelFragment)
957 throw CompilerError("Pixel local storage only supported in fragment shaders.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100958
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200959 if (!options.es)
960 throw CompilerError("Pixel local storage only supported in OpenGL ES.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100961
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200962 if (options.version < 300)
963 throw CompilerError("Pixel local storage only supported in ESSL 3.0 and above.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100964
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200965 if (!pls_inputs.empty())
966 {
967 statement("__pixel_local_inEXT _PLSIn");
968 begin_scope();
969 for (auto &input : pls_inputs)
970 statement(pls_decl(input), ";");
971 end_scope_decl();
972 statement("");
973 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100974
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200975 if (!pls_outputs.empty())
976 {
977 statement("__pixel_local_outEXT _PLSOut");
978 begin_scope();
979 for (auto &output : pls_outputs)
980 statement(pls_decl(output), ";");
981 end_scope_decl();
982 statement("");
983 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100984}
985
986void CompilerGLSL::emit_resources()
987{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200988 // Legacy GL uses gl_FragData[], redeclare all fragment outputs
989 // with builtins.
990 if (execution.model == ExecutionModelFragment && is_legacy())
991 replace_fragment_outputs();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100992
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200993 // Emit PLS blocks if we have such variables.
994 if (!pls_inputs.empty() || !pls_outputs.empty())
995 emit_pls();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100996
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200997 // Output all basic struct types which are not Block or BufferBlock as these are declared inplace
998 // when such variables are instantiated.
999 for (auto &id : ids)
1000 {
1001 if (id.get_type() == TypeType)
1002 {
1003 auto &type = id.get<SPIRType>();
1004 if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
1005 (meta[type.self].decoration.decoration_flags &
1006 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) == 0)
1007 {
1008 emit_struct(type);
1009 }
1010 }
1011 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001012
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001013 // Output UBOs and SSBOs
1014 for (auto &id : ids)
1015 {
1016 if (id.get_type() == TypeVariable)
1017 {
1018 auto &var = id.get<SPIRVariable>();
1019 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001020
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001021 if (type.pointer && type.storage == StorageClassUniform && !is_builtin_variable(var) &&
1022 (meta[type.self].decoration.decoration_flags &
1023 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
1024 {
1025 emit_buffer_block(var);
1026 }
1027 }
1028 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001029
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001030 // Output push constant blocks
1031 for (auto &id : ids)
1032 {
1033 if (id.get_type() == TypeVariable)
1034 {
1035 auto &var = id.get<SPIRVariable>();
1036 auto &type = get<SPIRType>(var.basetype);
1037 if (type.pointer && type.storage == StorageClassPushConstant)
1038 emit_push_constant_block(var);
1039 }
1040 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001041
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001042 bool emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001043
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001044 // Output Uniform Constants (values, samplers, images, etc).
1045 for (auto &id : ids)
1046 {
1047 if (id.get_type() == TypeVariable)
1048 {
1049 auto &var = id.get<SPIRVariable>();
1050 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001051
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001052 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
1053 (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
1054 {
1055 emit_uniform(var);
1056 emitted = true;
1057 }
1058 }
1059 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001060
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001061 if (emitted)
1062 statement("");
1063 emitted = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001065 // Output in/out interfaces.
1066 for (auto &id : ids)
1067 {
1068 if (id.get_type() == TypeVariable)
1069 {
1070 auto &var = id.get<SPIRVariable>();
1071 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001073 if (!is_builtin_variable(var) && !var.remapped_variable && type.pointer &&
1074 (var.storage == StorageClassInput || var.storage == StorageClassOutput))
1075 {
1076 emit_interface_block(var);
1077 emitted = true;
1078 }
1079 else if (is_builtin_variable(var))
1080 {
1081 // For gl_InstanceIndex emulation on GLES, the API user needs to
1082 // supply this uniform.
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02001083 if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001084 {
1085 statement("uniform int SPIRV_Cross_BaseInstance;");
1086 emitted = true;
1087 }
1088 }
1089 }
1090 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001091
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001092 // Global variables.
1093 for (auto global : global_variables)
1094 {
1095 auto &var = get<SPIRVariable>(global);
1096 if (var.storage != StorageClassOutput)
1097 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02001098 add_resource_name(var.self);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001099 statement(variable_decl(var), ";");
1100 emitted = true;
1101 }
1102 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001103
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001104 if (emitted)
1105 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001106}
1107
1108string CompilerGLSL::to_expression(uint32_t id)
1109{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001110 auto itr = invalid_expressions.find(id);
1111 if (itr != end(invalid_expressions))
1112 {
1113 auto &expr = get<SPIRExpression>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001114
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001115 // This expression has been invalidated in the past.
1116 // Be careful with this expression next pass ...
1117 // Used for OpCompositeInsert forwarding atm.
1118 expr.used_while_invalidated = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001119
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001120 // We tried to read an invalidated expression.
1121 // This means we need another pass at compilation, but next time, do not try to forward
1122 // the variables which caused invalidation to happen in the first place.
1123 for (auto var : expr.invalidated_by)
1124 {
1125 //fprintf(stderr, "Expression %u was invalidated due to variable %u being invalid at read time!\n", id, var);
1126 get<SPIRVariable>(var).forwardable = false;
1127 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001128
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001129 if (expr.invalidated_by.empty() && expr.loaded_from)
1130 {
1131 //fprintf(stderr, "Expression %u was invalidated due to variable %u being invalid at read time!\n", id, expr.loaded_from);
1132 get<SPIRVariable>(expr.loaded_from).forwardable = false;
1133 }
1134 force_recompile = true;
1135 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001136
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001137 track_expression_read(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001138
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001139 switch (ids[id].get_type())
1140 {
1141 case TypeExpression:
1142 {
1143 auto &e = get<SPIRExpression>(id);
1144 if (e.base_expression)
1145 return to_expression(e.base_expression) + e.expression;
1146 else
1147 return e.expression;
1148 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001149
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001150 case TypeConstant:
1151 return constant_expression(get<SPIRConstant>(id));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001152
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001153 case TypeVariable:
1154 {
1155 auto &var = get<SPIRVariable>(id);
1156 if (var.statically_assigned)
1157 return to_expression(var.static_expression);
1158 else if (var.deferred_declaration)
1159 {
1160 var.deferred_declaration = false;
1161 return variable_decl(var);
1162 }
1163 else
1164 {
1165 auto &dec = meta[var.self].decoration;
1166 if (dec.builtin)
1167 return builtin_to_glsl(dec.builtin_type);
1168 else
1169 return to_name(id);
1170 }
1171 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001172
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001173 default:
1174 return to_name(id);
1175 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001176}
1177
1178string CompilerGLSL::constant_expression(const SPIRConstant &c)
1179{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001180 if (!c.subconstants.empty())
1181 {
1182 // Handles Arrays and structures.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001183 string res;
1184 if (backend.use_initializer_list)
1185 res = "{ ";
1186 else
1187 res = type_to_glsl_constructor(get<SPIRType>(c.constant_type)) + "(";
1188
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001189 for (auto &elem : c.subconstants)
1190 {
1191 res += constant_expression(get<SPIRConstant>(elem));
1192 if (&elem != &c.subconstants.back())
1193 res += ", ";
1194 }
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001195
1196 res += backend.use_initializer_list ? " }" : ")";
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001197 return res;
1198 }
1199 else if (c.columns() == 1)
1200 {
1201 return constant_expression_vector(c, 0);
1202 }
1203 else
1204 {
1205 string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
1206 for (uint32_t col = 0; col < c.columns(); col++)
1207 {
1208 res += constant_expression_vector(c, col);
1209 if (col + 1 < c.columns())
1210 res += ", ";
1211 }
1212 res += ")";
1213 return res;
1214 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001215}
1216
1217string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
1218{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001219 auto type = get<SPIRType>(c.constant_type);
1220 type.columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001222 string res;
1223 if (c.vector_size() > 1)
1224 res += type_to_glsl(type) + "(";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001225
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001226 bool splat = c.vector_size() > 1;
1227 if (splat)
1228 {
1229 uint32_t ident = c.scalar(vector, 0);
1230 for (uint32_t i = 1; i < c.vector_size(); i++)
1231 if (ident != c.scalar(vector, i))
1232 splat = false;
1233 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001234
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001235 switch (type.basetype)
1236 {
1237 case SPIRType::Float:
1238 if (splat)
1239 {
1240 res += convert_to_string(c.scalar_f32(vector, 0));
1241 if (backend.float_literal_suffix)
1242 res += "f";
1243 }
1244 else
1245 {
1246 for (uint32_t i = 0; i < c.vector_size(); i++)
1247 {
1248 res += convert_to_string(c.scalar_f32(vector, i));
1249 if (backend.float_literal_suffix)
1250 res += "f";
1251 if (i + 1 < c.vector_size())
1252 res += ", ";
1253 }
1254 }
1255 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001256
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001257 case SPIRType::UInt:
1258 if (splat)
1259 {
1260 res += convert_to_string(c.scalar(vector, 0));
1261 if (backend.uint32_t_literal_suffix)
1262 res += "u";
1263 }
1264 else
1265 {
1266 for (uint32_t i = 0; i < c.vector_size(); i++)
1267 {
1268 res += convert_to_string(c.scalar(vector, i));
1269 if (backend.uint32_t_literal_suffix)
1270 res += "u";
1271 if (i + 1 < c.vector_size())
1272 res += ", ";
1273 }
1274 }
1275 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001276
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001277 case SPIRType::Int:
1278 if (splat)
1279 res += convert_to_string(c.scalar_i32(vector, 0));
1280 else
1281 {
1282 for (uint32_t i = 0; i < c.vector_size(); i++)
1283 {
1284 res += convert_to_string(c.scalar_i32(vector, i));
1285 if (i + 1 < c.vector_size())
1286 res += ", ";
1287 }
1288 }
1289 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001290
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001291 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001292 if (splat)
1293 res += c.scalar(vector, 0) ? "true" : "false";
1294 else
1295 {
1296 for (uint32_t i = 0; i < c.vector_size(); i++)
1297 {
1298 res += c.scalar(vector, i) ? "true" : "false";
1299 if (i + 1 < c.vector_size())
1300 res += ", ";
1301 }
1302 }
1303 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001304
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001305 default:
1306 throw CompilerError("Invalid constant expression basetype.");
1307 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001308
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001309 if (c.vector_size() > 1)
1310 res += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001311
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001312 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001313}
1314
1315string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
1316{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001317 auto &type = get<SPIRType>(result_type);
1318 auto flags = meta[result_id].decoration.decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001319
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001320 // If we're declaring temporaries inside continue blocks,
1321 // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
1322 if (current_continue_block)
1323 {
1324 auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
1325 if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001326 [result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001327 return tmp.first == result_type && tmp.second == result_id;
1328 }) == end(header.declare_temporary))
1329 {
1330 header.declare_temporary.emplace_back(result_type, result_id);
1331 force_recompile = true;
1332 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001333
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001334 return join(to_name(result_id), " = ");
1335 }
1336 else
1337 {
1338 // The result_id has not been made into an expression yet, so use flags interface.
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02001339 return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001340 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001341}
1342
1343bool CompilerGLSL::expression_is_forwarded(uint32_t id)
1344{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001345 return forwarded_temporaries.find(id) != end(forwarded_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001346}
1347
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001348SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
1349 bool extra_parens, bool suppress_usage_tracking)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001350{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001351 if (forwarding && (forced_temporaries.find(result_id) == end(forced_temporaries)))
1352 {
1353 // Just forward it without temporary.
1354 // If the forward is trivial, we do not force flushing to temporary for this expression.
1355 if (!suppress_usage_tracking)
1356 forwarded_temporaries.insert(result_id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001357
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001358 if (extra_parens)
1359 return set<SPIRExpression>(result_id, join("(", rhs, ")"), result_type, true);
1360 else
1361 return set<SPIRExpression>(result_id, rhs, result_type, true);
1362 }
1363 else
1364 {
1365 // If expression isn't immutable, bind it to a temporary and make the new temporary immutable (they always are).
1366 statement(declare_temporary(result_type, result_id), rhs, ";");
1367 return set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
1368 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001369}
1370
1371void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1372{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001373 emit_op(result_type, result_id, join(op, to_expression(op0)), should_forward(op0), true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001374}
1375
1376void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
1377{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001378 emit_op(result_type, result_id, join(to_expression(op0), " ", op, " ", to_expression(op1)),
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001379 should_forward(op0) && should_forward(op1), true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001380}
1381
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001382SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
1383 uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
1384{
1385 auto &type0 = expression_type(op0);
1386 auto &type1 = expression_type(op1);
1387
1388 // We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
1389 // For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
1390 // since equality test is exactly the same.
1391 bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
1392
1393 // Create a fake type so we can bitcast to it.
1394 // We only deal with regular arithmetic types here like int, uints and so on.
1395 SPIRType expected_type;
1396 expected_type.basetype = input_type;
1397 expected_type.vecsize = type0.vecsize;
1398 expected_type.columns = type0.columns;
1399 expected_type.width = type0.width;
1400
1401 if (cast)
1402 {
1403 cast_op0 = bitcast_glsl(expected_type, op0);
1404 cast_op1 = bitcast_glsl(expected_type, op1);
1405 }
1406 else
1407 {
1408 // If we don't cast, our actual input type is that of the first (or second) argument.
1409 cast_op0 = to_expression(op0);
1410 cast_op1 = to_expression(op1);
1411 input_type = type0.basetype;
1412 }
1413
1414 return expected_type;
1415}
1416
1417void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1418 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1419{
1420 string cast_op0, cast_op1;
1421 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1422 auto &out_type = get<SPIRType>(result_type);
1423
1424 // We might have casted away from the result type, so bitcast again.
1425 // For example, arithmetic right shift with uint inputs.
1426 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1427 bool extra_parens = true;
1428 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001429 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001430 {
1431 expected_type.basetype = input_type;
1432 expr = bitcast_glsl_op(out_type, expected_type);
1433 expr += '(';
1434 expr += join(cast_op0, " ", op, " ", cast_op1);
1435 expr += ')';
1436 extra_parens = false;
1437 }
1438 else
1439 {
1440 expr += join(cast_op0, " ", op, " ", cast_op1);
1441 }
1442
1443 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), extra_parens);
1444}
1445
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001446void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
1447{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001448 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), should_forward(op0), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001449}
1450
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001451void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1452 const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001453{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001454 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ")"),
1455 should_forward(op0) && should_forward(op1), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001456}
1457
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001458void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1459 const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
1460{
1461 string cast_op0, cast_op1;
1462 auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
1463 auto &out_type = get<SPIRType>(result_type);
1464
1465 // Special case boolean outputs since relational opcodes output booleans instead of int/uint.
1466 string expr;
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001467 if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02001468 {
1469 expected_type.basetype = input_type;
1470 expr = bitcast_glsl_op(out_type, expected_type);
1471 expr += '(';
1472 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1473 expr += ')';
1474 }
1475 else
1476 {
1477 expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
1478 }
1479
1480 emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), false);
1481}
1482
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001483void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1484 uint32_t op2, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001485{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001486 emit_op(result_type, result_id,
1487 join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ")"),
1488 should_forward(op0) && should_forward(op1) && should_forward(op2), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001489}
1490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001491void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
1492 uint32_t op2, uint32_t op3, const char *op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001493{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001494 emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ",
1495 to_expression(op2), ", ", to_expression(op3), ")"),
1496 should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3), false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001497}
1498
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001499string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001500{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001501 const char *type;
1502 switch (imgtype.image.dim)
1503 {
1504 case spv::Dim1D:
1505 type = "1D";
1506 break;
1507 case spv::Dim2D:
1508 type = "2D";
1509 break;
1510 case spv::Dim3D:
1511 type = "3D";
1512 break;
1513 case spv::DimCube:
1514 type = "Cube";
1515 break;
1516 case spv::DimBuffer:
1517 type = "Buffer";
1518 break;
1519 case spv::DimSubpassData:
1520 type = "2D";
1521 break;
1522 default:
1523 type = "";
1524 break;
1525 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001526
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001527 if (op == "texture")
1528 return join("texture", type);
1529 else if (op == "textureLod")
1530 return join("texture", type, "Lod");
1531 else if (op == "textureProj")
1532 return join("texture", type, "Proj");
1533 else if (op == "textureProjLod")
1534 return join("texture", type, "ProjLod");
1535 else
1536 throw CompilerError(join("Unsupported legacy texture op: ", op));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001537}
1538
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001539void 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 +01001540{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001541 auto &lerptype = expression_type(lerp);
1542 auto &restype = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001543
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001544 bool has_boolean_mix = (options.es && options.version >= 310) || (!options.es && options.version >= 450);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001545
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001546 // Boolean mix not supported on desktop without extension.
1547 // Was added in OpenGL 4.5 with ES 3.1 compat.
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02001548 if (!has_boolean_mix && lerptype.basetype == SPIRType::Boolean)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001549 {
1550 // Could use GL_EXT_shader_integer_mix on desktop at least,
1551 // but Apple doesn't support it. :(
1552 // Just implement it as ternary expressions.
1553 string expr;
1554 if (lerptype.vecsize == 1)
1555 expr = join(to_expression(lerp), " ? ", to_expression(right), " : ", to_expression(left));
1556 else
1557 {
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001558 auto swiz = [this](uint32_t expression, uint32_t i) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001559 return join(to_expression(expression), ".", index_to_swizzle(i));
1560 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001561
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001562 expr = type_to_glsl_constructor(restype);
1563 expr += "(";
1564 for (uint32_t i = 0; i < restype.vecsize; i++)
1565 {
1566 expr += swiz(lerp, i);
1567 expr += " ? ";
1568 expr += swiz(right, i);
1569 expr += " : ";
1570 expr += swiz(left, i);
1571 if (i + 1 < restype.vecsize)
1572 expr += ", ";
1573 }
1574 expr += ")";
1575 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001576
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001577 emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp), false);
1578 }
1579 else
1580 emit_trinary_func_op(result_type, id, left, right, lerp, "mix");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001581}
1582
Bill Hollings5aafb282016-04-23 21:47:41 -04001583void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
1584{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001585 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 -04001586}
1587
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001588void CompilerGLSL::emit_texture_op(const Instruction &i)
1589{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001590 auto ops = stream(i);
1591 auto op = static_cast<Op>(i.op);
1592 uint32_t length = i.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001593
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001594 if (i.offset + length > spirv.size())
1595 throw CompilerError("Compiler::parse() opcode out of range.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001596
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001597 uint32_t result_type = ops[0];
1598 uint32_t id = ops[1];
1599 uint32_t img = ops[2];
1600 uint32_t coord = ops[3];
1601 uint32_t dref = 0;
1602 uint32_t comp = 0;
1603 bool gather = false;
1604 bool proj = false;
1605 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001606
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001607 switch (op)
1608 {
1609 case OpImageSampleDrefImplicitLod:
1610 case OpImageSampleDrefExplicitLod:
1611 dref = ops[4];
1612 opt = &ops[5];
1613 length -= 5;
1614 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001615
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001616 case OpImageSampleProjDrefImplicitLod:
1617 case OpImageSampleProjDrefExplicitLod:
1618 dref = ops[4];
1619 proj = true;
1620 opt = &ops[5];
1621 length -= 5;
1622 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001623
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001624 case OpImageDrefGather:
1625 dref = ops[4];
1626 opt = &ops[5];
1627 gather = true;
1628 length -= 5;
1629 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001630
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001631 case OpImageGather:
1632 comp = ops[4];
1633 opt = &ops[5];
1634 gather = true;
1635 length -= 5;
1636 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001637
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001638 case OpImageSampleProjImplicitLod:
1639 case OpImageSampleProjExplicitLod:
1640 opt = &ops[4];
1641 length -= 4;
1642 proj = true;
1643 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001644
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001645 default:
1646 opt = &ops[4];
1647 length -= 4;
1648 break;
1649 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001650
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001651 auto &imgtype = expression_type(img);
1652 uint32_t coord_components = 0;
1653 switch (imgtype.image.dim)
1654 {
1655 case spv::Dim1D:
1656 coord_components = 1;
1657 break;
1658 case spv::Dim2D:
1659 coord_components = 2;
1660 break;
1661 case spv::Dim3D:
1662 coord_components = 3;
1663 break;
1664 case spv::DimCube:
1665 coord_components = 3;
1666 break;
1667 case spv::DimBuffer:
1668 coord_components = 1;
1669 break;
1670 default:
1671 coord_components = 2;
1672 break;
1673 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001675 if (proj)
1676 coord_components++;
1677 if (imgtype.image.arrayed)
1678 coord_components++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001680 uint32_t bias = 0;
1681 uint32_t lod = 0;
1682 uint32_t grad_x = 0;
1683 uint32_t grad_y = 0;
1684 uint32_t coffset = 0;
1685 uint32_t offset = 0;
1686 uint32_t coffsets = 0;
1687 uint32_t sample = 0;
1688 uint32_t flags = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001689
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001690 if (length)
1691 {
1692 flags = opt[0];
1693 opt++;
1694 length--;
1695 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001696
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001697 auto test = [&](uint32_t &v, uint32_t flag) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001698 if (length && (flags & flag))
1699 {
1700 v = *opt++;
1701 length--;
1702 }
1703 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001704
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001705 test(bias, ImageOperandsBiasMask);
1706 test(lod, ImageOperandsLodMask);
1707 test(grad_x, ImageOperandsGradMask);
1708 test(grad_y, ImageOperandsGradMask);
1709 test(coffset, ImageOperandsConstOffsetMask);
1710 test(offset, ImageOperandsOffsetMask);
1711 test(coffsets, ImageOperandsConstOffsetsMask);
1712 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001713
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001714 string expr;
1715 string texop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001716
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001717 if (op == OpImageFetch)
1718 texop += "texelFetch";
1719 else
1720 {
1721 texop += "texture";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001722
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001723 if (gather)
1724 texop += "Gather";
1725 if (coffsets)
1726 texop += "Offsets";
1727 if (proj)
1728 texop += "Proj";
1729 if (grad_x || grad_y)
1730 texop += "Grad";
1731 if (lod)
1732 texop += "Lod";
1733 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001735 if (coffset || offset)
1736 texop += "Offset";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001738 if (is_legacy())
1739 texop = legacy_tex_op(texop, imgtype);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001740
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001741 expr += texop;
1742 expr += "(";
1743 expr += to_expression(img);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001745 bool swizz_func = backend.swizzle_is_function;
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02001746 auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001747 if (comps == in_comps)
1748 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001749
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001750 switch (comps)
1751 {
1752 case 1:
1753 return ".x";
1754 case 2:
1755 return swizz_func ? ".xy()" : ".xy";
1756 case 3:
1757 return swizz_func ? ".xyz()" : ".xyz";
1758 default:
1759 return "";
1760 }
1761 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001762
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001763 bool forward = should_forward(coord);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001764
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001765 // The IR can give us more components than we need, so chop them off as needed.
1766 auto coord_expr = to_expression(coord) + swizzle(coord_components, expression_type(coord).vecsize);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001767
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001768 // TODO: implement rest ... A bit intensive.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001769
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001770 if (dref)
1771 {
1772 forward = forward && should_forward(dref);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001773
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001774 // SPIR-V splits dref and coordinate.
1775 if (coord_components == 4) // GLSL also splits the arguments in two.
1776 {
1777 expr += ", ";
1778 expr += to_expression(coord);
1779 expr += ", ";
1780 expr += to_expression(dref);
1781 }
1782 else
1783 {
1784 // Create a composite which merges coord/dref into a single vector.
1785 auto type = expression_type(coord);
1786 type.vecsize = coord_components + 1;
1787 expr += ", ";
1788 expr += type_to_glsl_constructor(type);
1789 expr += "(";
1790 expr += coord_expr;
1791 expr += ", ";
1792 expr += to_expression(dref);
1793 expr += ")";
1794 }
1795 }
1796 else
1797 {
1798 expr += ", ";
1799 expr += coord_expr;
1800 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001801
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001802 if (grad_x || grad_y)
1803 {
1804 forward = forward && should_forward(grad_x);
1805 forward = forward && should_forward(grad_y);
1806 expr += ", ";
1807 expr += to_expression(grad_x);
1808 expr += ", ";
1809 expr += to_expression(grad_y);
1810 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001811
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001812 if (lod)
1813 {
1814 forward = forward && should_forward(lod);
1815 expr += ", ";
1816 expr += to_expression(lod);
1817 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001818
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001819 if (coffset)
1820 {
1821 forward = forward && should_forward(coffset);
1822 expr += ", ";
1823 expr += to_expression(coffset);
1824 }
1825 else if (offset)
1826 {
1827 forward = forward && should_forward(offset);
1828 expr += ", ";
1829 expr += to_expression(offset);
1830 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001831
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001832 if (bias)
1833 {
1834 forward = forward && should_forward(bias);
1835 expr += ", ";
1836 expr += to_expression(bias);
1837 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001838
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001839 if (comp)
1840 {
1841 forward = forward && should_forward(comp);
1842 expr += ", ";
1843 expr += to_expression(comp);
1844 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001845
Hans-Kristian Arntzen9d4360f2016-06-22 12:35:58 +02001846 if (sample)
1847 {
1848 expr += ", ";
1849 expr += to_expression(sample);
1850 }
1851
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001852 expr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001853
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001854 emit_op(result_type, id, expr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001855}
1856
1857void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t)
1858{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001859 GLSLstd450 op = static_cast<GLSLstd450>(eop);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001861 switch (op)
1862 {
1863 // FP fiddling
1864 case GLSLstd450Round:
1865 case GLSLstd450RoundEven:
1866 emit_unary_func_op(result_type, id, args[0], "round");
1867 break;
1868 case GLSLstd450Trunc:
1869 emit_unary_func_op(result_type, id, args[0], "trunc");
1870 break;
1871 case GLSLstd450SAbs:
1872 case GLSLstd450FAbs:
1873 emit_unary_func_op(result_type, id, args[0], "abs");
1874 break;
1875 case GLSLstd450SSign:
1876 case GLSLstd450FSign:
1877 emit_unary_func_op(result_type, id, args[0], "sign");
1878 break;
1879 case GLSLstd450Floor:
1880 emit_unary_func_op(result_type, id, args[0], "floor");
1881 break;
1882 case GLSLstd450Ceil:
1883 emit_unary_func_op(result_type, id, args[0], "ceil");
1884 break;
1885 case GLSLstd450Fract:
1886 emit_unary_func_op(result_type, id, args[0], "fract");
1887 break;
1888 case GLSLstd450Radians:
1889 emit_unary_func_op(result_type, id, args[0], "radians");
1890 break;
1891 case GLSLstd450Degrees:
1892 emit_unary_func_op(result_type, id, args[0], "degrees");
1893 break;
1894 case GLSLstd450Fma:
1895 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
1896 break;
1897 case GLSLstd450Modf:
1898 register_call_out_argument(args[1]);
1899 forced_temporaries.insert(id);
1900 emit_binary_func_op(result_type, id, args[0], args[1], "modf");
1901 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001902
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001903 // Minmax
1904 case GLSLstd450FMin:
1905 case GLSLstd450UMin:
1906 case GLSLstd450SMin:
1907 emit_binary_func_op(result_type, id, args[0], args[1], "min");
1908 break;
1909 case GLSLstd450FMax:
1910 case GLSLstd450UMax:
1911 case GLSLstd450SMax:
1912 emit_binary_func_op(result_type, id, args[0], args[1], "max");
1913 break;
1914 case GLSLstd450FClamp:
1915 case GLSLstd450UClamp:
1916 case GLSLstd450SClamp:
1917 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "clamp");
1918 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001919
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001920 // Trig
1921 case GLSLstd450Sin:
1922 emit_unary_func_op(result_type, id, args[0], "sin");
1923 break;
1924 case GLSLstd450Cos:
1925 emit_unary_func_op(result_type, id, args[0], "cos");
1926 break;
1927 case GLSLstd450Tan:
1928 emit_unary_func_op(result_type, id, args[0], "tan");
1929 break;
1930 case GLSLstd450Asin:
1931 emit_unary_func_op(result_type, id, args[0], "asin");
1932 break;
1933 case GLSLstd450Acos:
1934 emit_unary_func_op(result_type, id, args[0], "acos");
1935 break;
1936 case GLSLstd450Atan:
1937 emit_unary_func_op(result_type, id, args[0], "atan");
1938 break;
1939 case GLSLstd450Sinh:
1940 emit_unary_func_op(result_type, id, args[0], "sinh");
1941 break;
1942 case GLSLstd450Cosh:
1943 emit_unary_func_op(result_type, id, args[0], "cosh");
1944 break;
1945 case GLSLstd450Tanh:
1946 emit_unary_func_op(result_type, id, args[0], "tanh");
1947 break;
1948 case GLSLstd450Asinh:
1949 emit_unary_func_op(result_type, id, args[0], "asinh");
1950 break;
1951 case GLSLstd450Acosh:
1952 emit_unary_func_op(result_type, id, args[0], "acosh");
1953 break;
1954 case GLSLstd450Atanh:
1955 emit_unary_func_op(result_type, id, args[0], "atanh");
1956 break;
1957 case GLSLstd450Atan2:
1958 emit_binary_func_op(result_type, id, args[0], args[1], "atan");
1959 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001960
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001961 // Exponentials
1962 case GLSLstd450Pow:
1963 emit_binary_func_op(result_type, id, args[0], args[1], "pow");
1964 break;
1965 case GLSLstd450Exp:
1966 emit_unary_func_op(result_type, id, args[0], "exp");
1967 break;
1968 case GLSLstd450Log:
1969 emit_unary_func_op(result_type, id, args[0], "log");
1970 break;
1971 case GLSLstd450Exp2:
1972 emit_unary_func_op(result_type, id, args[0], "exp2");
1973 break;
1974 case GLSLstd450Log2:
1975 emit_unary_func_op(result_type, id, args[0], "log2");
1976 break;
1977 case GLSLstd450Sqrt:
1978 emit_unary_func_op(result_type, id, args[0], "sqrt");
1979 break;
1980 case GLSLstd450InverseSqrt:
1981 emit_unary_func_op(result_type, id, args[0], "inversesqrt");
1982 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001983
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001984 // Matrix math
1985 case GLSLstd450Determinant:
1986 emit_unary_func_op(result_type, id, args[0], "determinant");
1987 break;
1988 case GLSLstd450MatrixInverse:
1989 emit_unary_func_op(result_type, id, args[0], "inverse");
1990 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001991
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001992 // Lerping
1993 case GLSLstd450FMix:
1994 case GLSLstd450IMix:
1995 {
1996 emit_mix_op(result_type, id, args[0], args[1], args[2]);
1997 break;
1998 }
1999 case GLSLstd450Step:
2000 emit_binary_func_op(result_type, id, args[0], args[1], "step");
2001 break;
2002 case GLSLstd450SmoothStep:
2003 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "smoothstep");
2004 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002005
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002006 // Packing
2007 case GLSLstd450Frexp:
2008 register_call_out_argument(args[1]);
2009 forced_temporaries.insert(id);
2010 emit_binary_func_op(result_type, id, args[0], args[1], "frexp");
2011 break;
2012 case GLSLstd450Ldexp:
2013 emit_binary_func_op(result_type, id, args[0], args[1], "ldexp");
2014 break;
2015 case GLSLstd450PackSnorm4x8:
2016 emit_unary_func_op(result_type, id, args[0], "packSnorm4x8");
2017 break;
2018 case GLSLstd450PackUnorm4x8:
2019 emit_unary_func_op(result_type, id, args[0], "packUnorm4x8");
2020 break;
2021 case GLSLstd450PackSnorm2x16:
2022 emit_unary_func_op(result_type, id, args[0], "packSnorm2x16");
2023 break;
2024 case GLSLstd450PackUnorm2x16:
2025 emit_unary_func_op(result_type, id, args[0], "packUnorm2x16");
2026 break;
2027 case GLSLstd450PackHalf2x16:
2028 emit_unary_func_op(result_type, id, args[0], "packHalf2x16");
2029 break;
2030 case GLSLstd450UnpackSnorm4x8:
2031 emit_unary_func_op(result_type, id, args[0], "unpackSnorm4x8");
2032 break;
2033 case GLSLstd450UnpackUnorm4x8:
2034 emit_unary_func_op(result_type, id, args[0], "unpackUnorm4x8");
2035 break;
2036 case GLSLstd450UnpackSnorm2x16:
2037 emit_unary_func_op(result_type, id, args[0], "unpackSnorm2x16");
2038 break;
2039 case GLSLstd450UnpackUnorm2x16:
2040 emit_unary_func_op(result_type, id, args[0], "unpackUnorm2x16");
2041 break;
2042 case GLSLstd450UnpackHalf2x16:
2043 emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
2044 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002045
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002046 // Vector math
2047 case GLSLstd450Length:
2048 emit_unary_func_op(result_type, id, args[0], "length");
2049 break;
2050 case GLSLstd450Distance:
2051 emit_binary_func_op(result_type, id, args[0], args[1], "distance");
2052 break;
2053 case GLSLstd450Cross:
2054 emit_binary_func_op(result_type, id, args[0], args[1], "cross");
2055 break;
2056 case GLSLstd450Normalize:
2057 emit_unary_func_op(result_type, id, args[0], "normalize");
2058 break;
2059 case GLSLstd450FaceForward:
2060 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "faceforward");
2061 break;
2062 case GLSLstd450Reflect:
2063 emit_binary_func_op(result_type, id, args[0], args[1], "reflect");
2064 break;
2065 case GLSLstd450Refract:
2066 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "refract");
2067 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002068
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002069 // Bit-fiddling
2070 case GLSLstd450FindILsb:
2071 emit_unary_func_op(result_type, id, args[0], "findLSB");
2072 break;
2073 case GLSLstd450FindSMsb:
2074 case GLSLstd450FindUMsb:
2075 emit_unary_func_op(result_type, id, args[0], "findMSB");
2076 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002078 // Multisampled varying
2079 case GLSLstd450InterpolateAtCentroid:
2080 emit_unary_func_op(result_type, id, args[0], "interpolateAtCentroid");
2081 break;
2082 case GLSLstd450InterpolateAtSample:
2083 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtSample");
2084 break;
2085 case GLSLstd450InterpolateAtOffset:
2086 emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
2087 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002088
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002089 default:
2090 statement("// unimplemented GLSL op ", eop);
2091 break;
2092 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002093}
2094
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002095string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002096{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002097 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
2098 return type_to_glsl(out_type);
2099 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
2100 return "floatBitsToUint";
2101 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
2102 return type_to_glsl(out_type);
2103 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
2104 return "floatBitsToInt";
2105 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
2106 return "uintBitsToFloat";
2107 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
2108 return "intBitsToFloat";
2109 else
2110 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002111}
2112
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002113string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002114{
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002115 auto op = bitcast_glsl_op(result_type, expression_type(argument));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002116 if (op.empty())
2117 return to_expression(argument);
2118 else
2119 return join(op, "(", to_expression(argument), ")");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002120}
2121
Bill Hollings103aabf2016-04-06 17:42:27 -04002122string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002123{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002124 switch (builtin)
2125 {
2126 case BuiltInPosition:
2127 return "gl_Position";
2128 case BuiltInPointSize:
2129 return "gl_PointSize";
2130 case BuiltInVertexId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002131 if (options.vulkan_semantics)
2132 throw CompilerError(
2133 "Cannot implement gl_VertexID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002134 return "gl_VertexID";
2135 case BuiltInInstanceId:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002136 if (options.vulkan_semantics)
2137 throw CompilerError(
2138 "Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002139 return "gl_InstanceID";
2140 case BuiltInVertexIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002141 if (options.vulkan_semantics)
2142 return "gl_VertexIndex";
2143 else
2144 return "gl_VertexID"; // gl_VertexID already has the base offset applied.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002145 case BuiltInInstanceIndex:
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02002146 if (options.vulkan_semantics)
2147 return "gl_InstanceIndex";
2148 else
2149 return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002150 case BuiltInPrimitiveId:
2151 return "gl_PrimitiveID";
2152 case BuiltInInvocationId:
2153 return "gl_InvocationID";
2154 case BuiltInLayer:
2155 return "gl_Layer";
2156 case BuiltInTessLevelOuter:
2157 return "gl_TessLevelOuter";
2158 case BuiltInTessLevelInner:
2159 return "gl_TessLevelInner";
2160 case BuiltInTessCoord:
2161 return "gl_TessCoord";
2162 case BuiltInFragCoord:
2163 return "gl_FragCoord";
2164 case BuiltInPointCoord:
2165 return "gl_PointCoord";
2166 case BuiltInFrontFacing:
2167 return "gl_FrontFacing";
2168 case BuiltInFragDepth:
2169 return "gl_FragDepth";
2170 case BuiltInNumWorkgroups:
2171 return "gl_NumWorkGroups";
2172 case BuiltInWorkgroupSize:
2173 return "gl_WorkGroupSize";
2174 case BuiltInWorkgroupId:
2175 return "gl_WorkGroupID";
2176 case BuiltInLocalInvocationId:
2177 return "gl_LocalInvocationID";
2178 case BuiltInGlobalInvocationId:
2179 return "gl_GlobalInvocationID";
2180 case BuiltInLocalInvocationIndex:
2181 return "gl_LocalInvocationIndex";
2182 default:
2183 return "gl_???";
2184 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002185}
2186
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002187const char *CompilerGLSL::index_to_swizzle(uint32_t index)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002188{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002189 switch (index)
2190 {
2191 case 0:
2192 return "x";
2193 case 1:
2194 return "y";
2195 case 2:
2196 return "z";
2197 case 3:
2198 return "w";
2199 default:
2200 throw CompilerError("Swizzle index out of range");
2201 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002202}
2203
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002204string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal,
2205 bool chain_only)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002206{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002207 string expr;
2208 if (!chain_only)
2209 expr = to_expression(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002210
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002211 const auto *type = &expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002212
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002213 // For resolving array accesses, etc, keep a local copy for poking.
2214 SPIRType temp;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002215
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002216 bool access_chain_is_arrayed = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002217
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002218 for (uint32_t i = 0; i < count; i++)
2219 {
2220 uint32_t index = indices[i];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002222 // Arrays
2223 if (!type->array.empty())
2224 {
2225 expr += "[";
2226 if (index_is_literal)
2227 expr += convert_to_string(index);
2228 else
2229 expr += to_expression(index);
2230 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002232 // We have to modify the type, so keep a local copy.
2233 if (&temp != type)
2234 temp = *type;
2235 type = &temp;
2236 temp.array.pop_back();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002237
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002238 access_chain_is_arrayed = true;
2239 }
2240 // For structs, the index refers to a constant, which indexes into the members.
2241 // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
2242 else if (type->basetype == SPIRType::Struct)
2243 {
2244 if (!index_is_literal)
2245 index = get<SPIRConstant>(index).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002246
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002247 if (index >= type->member_types.size())
2248 throw CompilerError("Member index is out of bounds!");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002249
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002250 BuiltIn builtin;
2251 if (is_member_builtin(*type, index, &builtin))
2252 {
2253 // FIXME: We rely here on OpName on gl_in/gl_out to make this work properly.
2254 // To make this properly work by omitting all OpName opcodes,
2255 // we need to infer gl_in or gl_out based on the builtin, and stage.
2256 if (access_chain_is_arrayed)
2257 {
2258 expr += ".";
2259 expr += builtin_to_glsl(builtin);
2260 }
2261 else
2262 expr = builtin_to_glsl(builtin);
2263 }
2264 else
2265 {
2266 expr += ".";
2267 expr += to_member_name(*type, index);
2268 }
2269 type = &get<SPIRType>(type->member_types[index]);
2270 }
2271 // Matrix -> Vector
2272 else if (type->columns > 1)
2273 {
2274 expr += "[";
2275 if (index_is_literal)
2276 expr += convert_to_string(index);
2277 else
2278 expr += to_expression(index);
2279 expr += "]";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002280
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002281 // We have to modify the type, so keep a local copy.
2282 if (&temp != type)
2283 temp = *type;
2284 type = &temp;
2285 temp.columns = 1;
2286 }
2287 // Vector -> Scalar
2288 else if (type->vecsize > 1)
2289 {
2290 if (index_is_literal)
2291 {
2292 expr += ".";
2293 expr += index_to_swizzle(index);
2294 }
2295 else if (ids[index].get_type() == TypeConstant)
2296 {
2297 auto &c = get<SPIRConstant>(index);
2298 expr += ".";
2299 expr += index_to_swizzle(c.scalar());
2300 }
2301 else
2302 {
2303 expr += "[";
2304 expr += to_expression(index);
2305 expr += "]";
2306 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002307
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002308 // We have to modify the type, so keep a local copy.
2309 if (&temp != type)
2310 temp = *type;
2311 type = &temp;
2312 temp.vecsize = 1;
2313 }
2314 else
2315 throw CompilerError("Cannot subdivide a scalar value!");
2316 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002317
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002318 return expr;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002319}
2320
2321bool CompilerGLSL::should_forward(uint32_t id)
2322{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002323 return is_immutable(id) && !options.force_temporary;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002324}
2325
2326void CompilerGLSL::track_expression_read(uint32_t id)
2327{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002328 // If we try to read a forwarded temporary more than once we will stamp out possibly complex code twice.
2329 // In this case, it's better to just bind the complex expression to the temporary and read that temporary twice.
2330 if (expression_is_forwarded(id))
2331 {
2332 auto &v = expression_usage_counts[id];
2333 v++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002334
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002335 if (v >= 2)
2336 {
2337 //if (v == 2)
2338 // 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 +01002339
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002340 forced_temporaries.insert(id);
2341 // Force a recompile after this pass to avoid forwarding this variable.
2342 force_recompile = true;
2343 }
2344 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002345}
2346
2347bool CompilerGLSL::args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure)
2348{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002349 if (forced_temporaries.find(id) != end(forced_temporaries))
2350 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002351
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002352 for (uint32_t i = 0; i < num_args; i++)
2353 if (!should_forward(args[i]))
2354 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002355
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002356 // We need to forward globals as well.
2357 if (!pure)
2358 {
2359 for (auto global : global_variables)
2360 if (!should_forward(global))
2361 return false;
2362 for (auto aliased : aliased_variables)
2363 if (!should_forward(aliased))
2364 return false;
2365 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002366
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002367 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002368}
2369
2370void CompilerGLSL::register_impure_function_call()
2371{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002372 // Impure functions can modify globals and aliased variables, so invalidate them as well.
2373 for (auto global : global_variables)
2374 flush_dependees(get<SPIRVariable>(global));
2375 for (auto aliased : aliased_variables)
2376 flush_dependees(get<SPIRVariable>(aliased));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002377}
2378
2379void CompilerGLSL::register_call_out_argument(uint32_t id)
2380{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002381 register_write(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002382
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002383 auto *var = maybe_get<SPIRVariable>(id);
2384 if (var)
2385 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002386}
2387
2388void CompilerGLSL::flush_variable_declaration(uint32_t id)
2389{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002390 auto *var = maybe_get<SPIRVariable>(id);
2391 if (var && var->deferred_declaration)
2392 {
2393 statement(variable_decl(*var), ";");
2394 var->deferred_declaration = false;
2395 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002396}
2397
2398bool CompilerGLSL::remove_duplicate_swizzle(string &op)
2399{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002400 auto pos = op.find_last_of('.');
2401 if (pos == string::npos || pos == 0)
2402 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002403
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002404 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002405
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002406 if (backend.swizzle_is_function)
2407 {
2408 if (final_swiz.size() < 2)
2409 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002410
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002411 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2412 final_swiz.erase(final_swiz.size() - 2, string::npos);
2413 else
2414 return false;
2415 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002417 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2418 // If so, and previous swizzle is of same length,
2419 // we can drop the final swizzle altogether.
2420 for (uint32_t i = 0; i < final_swiz.size(); i++)
2421 {
2422 static const char expected[] = { 'x', 'y', 'z', 'w' };
2423 if (i >= 4 || final_swiz[i] != expected[i])
2424 return false;
2425 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002426
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002427 auto prevpos = op.find_last_of('.', pos - 1);
2428 if (prevpos == string::npos)
2429 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002430
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002431 prevpos++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002432
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002433 // Make sure there are only swizzles here ...
2434 for (auto i = prevpos; i < pos; i++)
2435 {
2436 if (op[i] < 'w' || op[i] > 'z')
2437 {
2438 // If swizzles are foo.xyz() like in C++ backend for example, check for that.
2439 if (backend.swizzle_is_function && i + 2 == pos && op[i] == '(' && op[i + 1] == ')')
2440 break;
2441 return false;
2442 }
2443 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002444
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002445 // If original swizzle is large enough, just carve out the components we need.
2446 // E.g. foobar.wyx.xy will turn into foobar.wy.
2447 if (pos - prevpos >= final_swiz.size())
2448 {
2449 op.erase(prevpos + final_swiz.size(), string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002450
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002451 // Add back the function call ...
2452 if (backend.swizzle_is_function)
2453 op += "()";
2454 }
2455 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002456}
2457
2458// Optimizes away vector swizzles where we have something like
2459// vec3 foo;
2460// foo.xyz <-- swizzle expression does nothing.
2461// This is a very common pattern after OpCompositeCombine.
2462bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op)
2463{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002464 auto pos = op.find_last_of('.');
2465 if (pos == string::npos || pos == 0)
2466 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002467
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002468 string final_swiz = op.substr(pos + 1, string::npos);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002469
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002470 if (backend.swizzle_is_function)
2471 {
2472 if (final_swiz.size() < 2)
2473 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002474
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002475 if (final_swiz.substr(final_swiz.size() - 2, string::npos) == "()")
2476 final_swiz.erase(final_swiz.size() - 2, string::npos);
2477 else
2478 return false;
2479 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002480
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002481 // Check if final swizzle is of form .x, .xy, .xyz, .xyzw or similar.
2482 // If so, and previous swizzle is of same length,
2483 // we can drop the final swizzle altogether.
2484 for (uint32_t i = 0; i < final_swiz.size(); i++)
2485 {
2486 static const char expected[] = { 'x', 'y', 'z', 'w' };
2487 if (i >= 4 || final_swiz[i] != expected[i])
2488 return false;
2489 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002491 auto &type = expression_type(base);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002492
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002493 // Sanity checking ...
2494 assert(type.columns == 1 && type.array.empty());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002495
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002496 if (type.vecsize == final_swiz.size())
2497 op.erase(pos, string::npos);
2498 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002499}
2500
2501string CompilerGLSL::build_composite_combiner(const uint32_t *elems, uint32_t length)
2502{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002503 uint32_t base = 0;
2504 bool swizzle_optimization = false;
2505 string op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002506
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002507 for (uint32_t i = 0; i < length; i++)
2508 {
2509 auto *e = maybe_get<SPIRExpression>(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002510
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002511 // If we're merging another scalar which belongs to the same base
2512 // object, just merge the swizzles to avoid triggering more than 1 expression read as much as possible!
2513 if (e && e->base_expression && e->base_expression == base)
2514 {
2515 // Only supposed to be used for vector swizzle -> scalar.
2516 assert(!e->expression.empty() && e->expression.front() == '.');
2517 op += e->expression.substr(1, string::npos);
2518 swizzle_optimization = true;
2519 }
2520 else
2521 {
2522 // We'll likely end up with duplicated swizzles, e.g.
2523 // foobar.xyz.xyz from patterns like
2524 // OpVectorSwizzle
2525 // OpCompositeExtract x 3
2526 // OpCompositeConstruct 3x + other scalar.
2527 // Just modify op in-place.
2528 if (swizzle_optimization)
2529 {
2530 if (backend.swizzle_is_function)
2531 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002532
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002533 // Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
2534 // The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
2535 // We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
2536 // Essentially, we can only remove one set of swizzles, since that's what we have control over ...
2537 // Case 1:
2538 // foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
2539 // foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
2540 // Case 2:
2541 // foo.xyz: Duplicate swizzle won't kick in.
2542 // If foo is vec3, we can remove xyz, giving just foo.
2543 if (!remove_duplicate_swizzle(op))
2544 remove_unity_swizzle(base, op);
2545 swizzle_optimization = false;
2546 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002547
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002548 if (i)
2549 op += ", ";
2550 op += to_expression(elems[i]);
2551 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002552
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002553 base = e ? e->base_expression : 0;
2554 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002555
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002556 if (swizzle_optimization)
2557 {
2558 if (backend.swizzle_is_function)
2559 op += "()";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002560
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002561 if (!remove_duplicate_swizzle(op))
2562 remove_unity_swizzle(base, op);
2563 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002565 return op;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002566}
2567
Hans-Kristian Arntzen926916d2016-05-05 09:15:25 +02002568void CompilerGLSL::emit_instruction(const Instruction &instruction)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002569{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002570 auto ops = stream(instruction);
2571 auto opcode = static_cast<Op>(instruction.op);
2572 uint32_t length = instruction.length;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002573
2574#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002575#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 +01002576#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
2577#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
2578#define TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
2579#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002580#define BFOP_CAST(op, type, skip_cast) emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
2581#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002582#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
2583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002584 switch (opcode)
2585 {
2586 // Dealing with memory
2587 case OpLoad:
2588 {
2589 uint32_t result_type = ops[0];
2590 uint32_t id = ops[1];
2591 uint32_t ptr = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002592
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002593 flush_variable_declaration(ptr);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002595 // If we're loading from memory that cannot be changed by the shader,
2596 // just forward the expression directly to avoid needless temporaries.
2597 if (should_forward(ptr))
2598 {
2599 set<SPIRExpression>(id, to_expression(ptr), result_type, true);
2600 register_read(id, ptr, true);
2601 }
2602 else
2603 {
2604 // If the variable can be modified after this OpLoad, we cannot just forward the expression.
2605 // We must read it now and store it in a temporary.
2606 emit_op(result_type, id, to_expression(ptr), false, false);
2607 register_read(id, ptr, false);
2608 }
2609 break;
2610 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002611
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002612 case OpInBoundsAccessChain:
2613 case OpAccessChain:
2614 {
2615 auto *var = maybe_get<SPIRVariable>(ops[2]);
2616 if (var)
2617 flush_variable_declaration(var->self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002618
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002619 // If the base is immutable, the access chain pointer must also be.
2620 auto e = access_chain(ops[2], &ops[3], length - 3, false);
2621 auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], is_immutable(ops[2]));
2622 expr.loaded_from = ops[2];
2623 break;
2624 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002626 case OpStore:
2627 {
2628 auto *var = maybe_get<SPIRVariable>(ops[0]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002629
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002630 if (var && var->statically_assigned)
2631 var->static_expression = ops[1];
2632 else
2633 {
2634 auto lhs = to_expression(ops[0]);
2635 auto rhs = to_expression(ops[1]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002636
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002637 // It is possible with OpLoad/OpCompositeInsert/OpStore that we get <expr> = <same-expr>.
2638 // For this case, we don't need to invalidate anything and emit any opcode.
2639 if (lhs != rhs)
2640 {
2641 register_write(ops[0]);
2642 statement(lhs, " = ", rhs, ";");
2643 }
2644 }
2645 break;
2646 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002647
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002648 case OpArrayLength:
2649 {
2650 uint32_t result_type = ops[0];
2651 uint32_t id = ops[1];
2652 auto e = access_chain(ops[2], &ops[3], length - 3, true);
2653 set<SPIRExpression>(id, e + ".length()", result_type, true);
2654 break;
2655 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002656
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002657 // Function calls
2658 case OpFunctionCall:
2659 {
2660 uint32_t result_type = ops[0];
2661 uint32_t id = ops[1];
2662 uint32_t func = ops[2];
2663 const auto *arg = &ops[3];
2664 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002665
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002666 auto &callee = get<SPIRFunction>(func);
2667 bool pure = function_is_pure(callee);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002668
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002669 bool callee_has_out_variables = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002670
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002671 // Invalidate out variables passed to functions since they can be OpStore'd to.
2672 for (uint32_t i = 0; i < length; i++)
2673 {
2674 if (callee.arguments[i].write_count)
2675 {
2676 register_call_out_argument(arg[i]);
2677 callee_has_out_variables = true;
2678 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002680 flush_variable_declaration(arg[i]);
2681 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002683 if (!pure)
2684 register_impure_function_call();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002686 string funexpr;
2687 funexpr += to_name(func) + "(";
2688 for (uint32_t i = 0; i < length; i++)
2689 {
2690 funexpr += to_expression(arg[i]);
2691 if (i + 1 < length)
2692 funexpr += ", ";
2693 }
Bill Hollingsfe8b8602016-07-06 16:55:45 -04002694 funexpr += static_func_args(callee, length);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002695 funexpr += ")";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002696
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002697 if (get<SPIRType>(result_type).basetype != SPIRType::Void)
2698 {
2699 // If the function actually writes to an out variable,
2700 // take the conservative route and do not forward.
2701 // The problem is that we might not read the function
2702 // result (and emit the function) before an out variable
2703 // is read (common case when return value is ignored!
2704 // In order to avoid start tracking invalid variables,
2705 // just avoid the forwarding problem altogether.
2706 bool forward = args_will_forward(id, arg, length, pure) && !callee_has_out_variables && pure &&
2707 (forced_temporaries.find(id) == end(forced_temporaries));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002708
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002709 emit_op(result_type, id, funexpr, forward, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002711 // Function calls are implicit loads from all variables in question.
2712 // Set dependencies for them.
2713 for (uint32_t i = 0; i < length; i++)
2714 register_read(id, arg[i], forward);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002715
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002716 // If we're going to forward the temporary result,
2717 // put dependencies on every variable that must not change.
2718 if (forward)
2719 register_global_read_dependencies(callee, id);
2720 }
2721 else
2722 statement(funexpr, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002723
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002724 break;
2725 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002726
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002727 // Composite munging
2728 case OpCompositeConstruct:
2729 {
2730 uint32_t result_type = ops[0];
2731 uint32_t id = ops[1];
2732 const auto *elems = &ops[2];
2733 length -= 2;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002734
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002735 if (!length)
2736 throw CompilerError("Invalid input to OpCompositeConstruct.");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002737
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002738 bool forward = true;
2739 for (uint32_t i = 0; i < length; i++)
2740 forward = forward && should_forward(elems[i]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002741
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002742 auto &in_type = expression_type(elems[0]);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002743 auto &out_type = get<SPIRType>(result_type);
2744
2745 // Only splat if we have vector constructors.
2746 // Arrays and structs must be initialized properly in full.
2747 bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
2748 bool splat = in_type.vecsize == 1 && in_type.columns == 1 && !composite;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002749
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002750 if (splat)
2751 {
2752 uint32_t input = elems[0];
2753 for (uint32_t i = 0; i < length; i++)
2754 if (input != elems[i])
2755 splat = false;
2756 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002757
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002758 string constructor_op;
2759 if (backend.use_initializer_list && composite)
2760 {
2761 // Only use this path if we are building composites.
2762 // This path cannot be used for arithmetic.
2763 constructor_op += "{ ";
2764 if (splat)
2765 constructor_op += to_expression(elems[0]);
2766 else
2767 constructor_op += build_composite_combiner(elems, length);
2768 constructor_op += " }";
2769 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002770 else
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02002771 {
2772 constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
2773 if (splat)
2774 constructor_op += to_expression(elems[0]);
2775 else
2776 constructor_op += build_composite_combiner(elems, length);
2777 constructor_op += ")";
2778 }
2779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002780 emit_op(result_type, id, constructor_op, forward, false);
2781 break;
2782 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002783
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002784 case OpVectorInsertDynamic:
2785 {
2786 uint32_t result_type = ops[0];
2787 uint32_t id = ops[1];
2788 uint32_t vec = ops[2];
2789 uint32_t comp = ops[3];
2790 uint32_t index = ops[4];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002791
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002792 flush_variable_declaration(vec);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002793
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002794 // Make a copy, then use access chain to store the variable.
2795 statement(declare_temporary(result_type, id), to_expression(vec), ";");
2796 set<SPIRExpression>(id, to_name(id), result_type, true);
2797 auto chain = access_chain(id, &index, 1, false);
2798 statement(chain, " = ", to_expression(comp), ";");
2799 break;
2800 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002801
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002802 case OpVectorExtractDynamic:
2803 {
2804 uint32_t result_type = ops[0];
2805 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002806
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002807 auto expr = access_chain(ops[2], &ops[3], 1, false);
2808 emit_op(result_type, id, expr, should_forward(ops[2]), false);
2809 break;
2810 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002811
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002812 case OpCompositeExtract:
2813 {
2814 uint32_t result_type = ops[0];
2815 uint32_t id = ops[1];
2816 length -= 3;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002817
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002818 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002819
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02002820 // We can only split the expression here if our expression is forwarded as a temporary.
2821 bool allow_base_expression = forced_temporaries.find(id) == end(forced_temporaries);
2822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002823 // Only apply this optimization if result is scalar.
Hans-Kristian Arntzen4bb9f092016-06-23 12:11:36 +02002824 if (allow_base_expression && should_forward(ops[2]) && type.vecsize == 1 && type.columns == 1 && length == 1)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002825 {
2826 // We want to split the access chain from the base.
2827 // This is so we can later combine different CompositeExtract results
2828 // with CompositeConstruct without emitting code like
2829 //
2830 // vec3 temp = texture(...).xyz
2831 // vec4(temp.x, temp.y, temp.z, 1.0).
2832 //
2833 // when we actually wanted to emit this
2834 // vec4(texture(...).xyz, 1.0).
2835 //
2836 // Including the base will prevent this and would trigger multiple reads
2837 // from expression causing it to be forced to an actual temporary in GLSL.
2838 auto expr = access_chain(ops[2], &ops[3], length, true, true);
2839 auto &e = emit_op(result_type, id, expr, true, false, !expression_is_forwarded(ops[2]));
2840 e.base_expression = ops[2];
2841 }
2842 else
2843 {
2844 auto expr = access_chain(ops[2], &ops[3], length, true);
2845 emit_op(result_type, id, expr, should_forward(ops[2]), false, !expression_is_forwarded(ops[2]));
2846 }
2847 break;
2848 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002849
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002850 case OpCompositeInsert:
2851 {
2852 uint32_t result_type = ops[0];
2853 uint32_t id = ops[1];
2854 uint32_t obj = ops[2];
2855 uint32_t composite = ops[3];
2856 const auto *elems = &ops[4];
2857 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002858
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002859 flush_variable_declaration(composite);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002860
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002861 auto *expr = maybe_get<SPIRExpression>(id);
2862 if ((expr && expr->used_while_invalidated) || !should_forward(composite))
2863 {
2864 // Make a copy, then use access chain to store the variable.
2865 statement(declare_temporary(result_type, id), to_expression(composite), ";");
2866 set<SPIRExpression>(id, to_name(id), result_type, true);
2867 auto chain = access_chain(id, elems, length, true);
2868 statement(chain, " = ", to_expression(obj), ";");
2869 }
2870 else
2871 {
2872 auto chain = access_chain(composite, elems, length, true);
2873 statement(chain, " = ", to_expression(obj), ";");
2874 set<SPIRExpression>(id, to_expression(composite), result_type, true);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002875
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002876 register_write(composite);
2877 register_read(id, composite, true);
2878 // Invalidate the old expression we inserted into.
2879 invalid_expressions.insert(composite);
2880 }
2881 break;
2882 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002883
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002884 case OpCopyObject:
2885 {
2886 uint32_t result_type = ops[0];
2887 uint32_t id = ops[1];
2888 uint32_t rhs = ops[2];
2889 if (expression_is_lvalue(rhs))
2890 {
2891 // Need a copy.
2892 statement(declare_temporary(result_type, id), to_expression(rhs), ";");
2893 set<SPIRExpression>(id, to_name(id), result_type, true);
2894 }
2895 else
2896 {
2897 // RHS expression is immutable, so just forward it.
2898 // Copying these things really make no sense, but
2899 // seems to be allowed anyways.
2900 set<SPIRExpression>(id, to_expression(rhs), result_type, true);
2901 }
2902 break;
2903 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002904
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002905 case OpVectorShuffle:
2906 {
2907 uint32_t result_type = ops[0];
2908 uint32_t id = ops[1];
2909 uint32_t vec0 = ops[2];
2910 uint32_t vec1 = ops[3];
2911 const auto *elems = &ops[4];
2912 length -= 4;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002913
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002914 auto &type0 = expression_type(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002915
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002916 bool shuffle = false;
2917 for (uint32_t i = 0; i < length; i++)
2918 if (elems[i] >= type0.vecsize)
2919 shuffle = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002920
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002921 string expr;
2922 bool trivial_forward;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002923
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002924 if (shuffle)
2925 {
2926 trivial_forward = !expression_is_forwarded(vec0) && !expression_is_forwarded(vec1);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002927
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002928 // Constructor style and shuffling from two different vectors.
2929 vector<string> args;
2930 for (uint32_t i = 0; i < length; i++)
2931 {
2932 if (elems[i] >= type0.vecsize)
2933 args.push_back(join(to_expression(vec1), ".", index_to_swizzle(elems[i] - type0.vecsize)));
2934 else
2935 args.push_back(join(to_expression(vec0), ".", index_to_swizzle(elems[i])));
2936 }
2937 expr += join(type_to_glsl_constructor(get<SPIRType>(result_type)), "(", merge(args), ")");
2938 }
2939 else
2940 {
2941 trivial_forward = !expression_is_forwarded(vec0);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002942
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002943 // We only source from first vector, so can use swizzle.
2944 expr += to_expression(vec0);
2945 expr += ".";
2946 for (uint32_t i = 0; i < length; i++)
2947 expr += index_to_swizzle(elems[i]);
2948 if (backend.swizzle_is_function && length > 1)
2949 expr += "()";
2950 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002951
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002952 // A shuffle is trivial in that it doesn't actually *do* anything.
2953 // 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 +01002954
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002955 emit_op(result_type, id, expr, should_forward(vec0) && should_forward(vec1), false, trivial_forward);
2956 break;
2957 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002958
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002959 // ALU
2960 case OpIsNan:
2961 UFOP(isnan);
2962 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002963
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002964 case OpIsInf:
2965 UFOP(isinf);
2966 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002967
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002968 case OpSNegate:
2969 case OpFNegate:
2970 UOP(-);
2971 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002972
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002973 case OpIAdd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002974 {
2975 // For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
2976 auto type = get<SPIRType>(ops[0]).basetype;
2977 BOP_CAST(+, type, true);
2978 break;
2979 }
2980
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002981 case OpFAdd:
2982 BOP(+);
2983 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002984
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002985 case OpISub:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002986 {
2987 auto type = get<SPIRType>(ops[0]).basetype;
2988 BOP_CAST(-, type, true);
2989 break;
2990 }
2991
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002992 case OpFSub:
2993 BOP(-);
2994 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01002995
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02002996 case OpIMul:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02002997 {
2998 auto type = get<SPIRType>(ops[0]).basetype;
2999 BOP_CAST(*, type, true);
3000 break;
3001 }
3002
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003003 case OpFMul:
3004 case OpMatrixTimesVector:
3005 case OpMatrixTimesScalar:
3006 case OpVectorTimesScalar:
3007 case OpVectorTimesMatrix:
3008 case OpMatrixTimesMatrix:
3009 BOP(*);
3010 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003011
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003012 case OpOuterProduct:
3013 UFOP(outerProduct);
3014 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003015
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003016 case OpDot:
3017 BFOP(dot);
3018 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003019
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003020 case OpTranspose:
3021 UFOP(transpose);
3022 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003023
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003024 case OpSDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003025 BOP_CAST(/, SPIRType::Int, false);
3026 break;
3027
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003028 case OpUDiv:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003029 BOP_CAST(/, SPIRType::UInt, false);
3030 break;
3031
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003032 case OpFDiv:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003033 BOP(/);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003034 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003035
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003036 case OpShiftRightLogical:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003037 BOP_CAST(>>, SPIRType::UInt, false);
3038 break;
3039
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003040 case OpShiftRightArithmetic:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003041 BOP_CAST(>>, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003042 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003043
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003044 case OpShiftLeftLogical:
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003045 {
3046 auto type = get<SPIRType>(ops[0]).basetype;
3047 BOP_CAST(<<, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003048 break;
Hans-Kristian Arntzenffc55442016-05-13 15:30:40 +02003049 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003050
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003051 case OpBitwiseOr:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003052 {
3053 auto type = get<SPIRType>(ops[0]).basetype;
3054 BOP_CAST(|, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003055 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003056 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003057
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003058 case OpBitwiseXor:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003059 {
3060 auto type = get<SPIRType>(ops[0]).basetype;
3061 BOP_CAST (^, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003062 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003063 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003064
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003065 case OpBitwiseAnd:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003066 {
3067 auto type = get<SPIRType>(ops[0]).basetype;
3068 BOP_CAST(&, type, true);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003069 break;
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003070 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003072 case OpNot:
3073 UOP(~);
3074 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003075
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003076 case OpUMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003077 BOP_CAST(%, SPIRType::UInt, false);
3078 break;
3079
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003080 case OpSMod:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003081 BOP_CAST(%, SPIRType::Int, false);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003082 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003083
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003084 case OpFMod:
3085 BFOP(mod);
3086 break;
Hans-Kristian Arntzenb4248512016-04-16 09:25:14 +02003087
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003088 // Relational
3089 case OpAny:
3090 UFOP(any);
3091 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003092
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003093 case OpAll:
3094 UFOP(all);
3095 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003096
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003097 case OpSelect:
3098 emit_mix_op(ops[0], ops[1], ops[4], ops[3], ops[2]);
3099 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003100
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003101 case OpLogicalOr:
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003102 BOP(||);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003103 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003104
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003105 case OpLogicalAnd:
3106 BOP(&&);
3107 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003108
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003109 case OpLogicalNot:
3110 UOP(!);
3111 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003112
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003113 case OpIEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003114 {
3115 if (expression_type(ops[2]).vecsize > 1)
3116 BFOP_CAST(equal, SPIRType::Int, true);
3117 else
3118 BOP_CAST(==, SPIRType::Int, true);
3119 break;
3120 }
3121
3122 case OpLogicalEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003123 case OpFOrdEqual:
3124 {
3125 if (expression_type(ops[2]).vecsize > 1)
3126 BFOP(equal);
3127 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003128 BOP(==);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003129 break;
3130 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003131
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003132 case OpINotEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003133 {
3134 if (expression_type(ops[2]).vecsize > 1)
3135 BFOP_CAST(notEqual, SPIRType::Int, true);
3136 else
3137 BOP_CAST(!=, SPIRType::Int, true);
3138 break;
3139 }
3140
3141 case OpLogicalNotEqual:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003142 case OpFOrdNotEqual:
3143 {
3144 if (expression_type(ops[2]).vecsize > 1)
3145 BFOP(notEqual);
3146 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003147 BOP(!=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003148 break;
3149 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003150
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003151 case OpUGreaterThan:
3152 case OpSGreaterThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003153 {
3154 auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
3155 if (expression_type(ops[2]).vecsize > 1)
3156 BFOP_CAST(greaterThan, type, false);
3157 else
3158 BOP_CAST(>, type, false);
3159 break;
3160 }
3161
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003162 case OpFOrdGreaterThan:
3163 {
3164 if (expression_type(ops[2]).vecsize > 1)
3165 BFOP(greaterThan);
3166 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003167 BOP(>);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003168 break;
3169 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003170
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003171 case OpUGreaterThanEqual:
3172 case OpSGreaterThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003173 {
3174 auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
3175 if (expression_type(ops[2]).vecsize > 1)
3176 BFOP_CAST(greaterThanEqual, type, false);
3177 else
3178 BOP_CAST(>=, type, false);
3179 break;
3180 }
3181
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003182 case OpFOrdGreaterThanEqual:
3183 {
3184 if (expression_type(ops[2]).vecsize > 1)
3185 BFOP(greaterThanEqual);
3186 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003187 BOP(>=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003188 break;
3189 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003190
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003191 case OpULessThan:
3192 case OpSLessThan:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003193 {
3194 auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
3195 if (expression_type(ops[2]).vecsize > 1)
3196 BFOP_CAST(lessThan, type, false);
3197 else
3198 BOP_CAST(<, type, false);
3199 break;
3200 }
3201
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003202 case OpFOrdLessThan:
3203 {
3204 if (expression_type(ops[2]).vecsize > 1)
3205 BFOP(lessThan);
3206 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003207 BOP(<);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003208 break;
3209 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003210
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003211 case OpULessThanEqual:
3212 case OpSLessThanEqual:
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003213 {
3214 auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
3215 if (expression_type(ops[2]).vecsize > 1)
3216 BFOP_CAST(lessThanEqual, type, false);
3217 else
3218 BOP_CAST(<=, type, false);
3219 break;
3220 }
3221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003222 case OpFOrdLessThanEqual:
3223 {
3224 if (expression_type(ops[2]).vecsize > 1)
3225 BFOP(lessThanEqual);
3226 else
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003227 BOP(<=);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003228 break;
3229 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003230
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003231 // Conversion
3232 case OpConvertFToU:
3233 case OpConvertFToS:
3234 case OpConvertSToF:
3235 case OpConvertUToF:
3236 case OpUConvert:
3237 case OpSConvert:
3238 case OpFConvert:
3239 {
3240 uint32_t result_type = ops[0];
3241 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003242
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003243 auto func = type_to_glsl_constructor(get<SPIRType>(result_type));
3244 emit_unary_func_op(result_type, id, ops[2], func.c_str());
3245 break;
3246 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003247
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003248 case OpBitcast:
3249 {
3250 uint32_t result_type = ops[0];
3251 uint32_t id = ops[1];
3252 uint32_t arg = ops[2];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003253
Hans-Kristian Arntzen45ad58a2016-05-10 23:39:41 +02003254 auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003255 emit_unary_func_op(result_type, id, arg, op.c_str());
3256 break;
3257 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003258
Hans-Kristian Arntzen81a8fc12016-05-31 16:56:15 +02003259 case OpQuantizeToF16:
3260 {
3261 uint32_t result_type = ops[0];
3262 uint32_t id = ops[1];
3263 uint32_t arg = ops[2];
3264
3265 string op;
3266 auto &type = get<SPIRType>(result_type);
3267
3268 switch (type.vecsize)
3269 {
3270 case 1:
3271 op = join("unpackHalf2x16(packHalf2x16(vec2(", to_expression(arg), "))).x");
3272 break;
3273 case 2:
3274 op = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), "))");
3275 break;
3276 case 3:
3277 {
3278 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
3279 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zz)).x");
3280 op = join("vec3(", op0, ", ", op1, ")");
3281 break;
3282 }
3283 case 4:
3284 {
3285 auto op0 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".xy))");
3286 auto op1 = join("unpackHalf2x16(packHalf2x16(", to_expression(arg), ".zw))");
3287 op = join("vec4(", op0, ", ", op1, ")");
3288 break;
3289 }
3290 default:
3291 throw CompilerError("Illegal argument to OpQuantizeToF16.");
3292 }
3293
3294 emit_op(result_type, id, op, should_forward(arg), false);
3295 break;
3296 }
3297
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003298 // Derivatives
3299 case OpDPdx:
3300 UFOP(dFdx);
3301 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003303 case OpDPdy:
3304 UFOP(dFdy);
3305 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003306
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003307 case OpFwidth:
3308 UFOP(fwidth);
3309 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003310
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003311 // Bitfield
3312 case OpBitFieldInsert:
3313 QFOP(bitfieldInsert);
3314 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003315
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003316 case OpBitFieldSExtract:
3317 case OpBitFieldUExtract:
3318 QFOP(bitfieldExtract);
3319 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003320
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003321 case OpBitReverse:
3322 UFOP(bitfieldReverse);
3323 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003324
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003325 case OpBitCount:
3326 UFOP(bitCount);
3327 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003329 // Atomics
3330 case OpAtomicExchange:
3331 {
3332 uint32_t result_type = ops[0];
3333 uint32_t id = ops[1];
3334 uint32_t ptr = ops[2];
3335 // Ignore semantics for now, probably only relevant to CL.
3336 uint32_t val = ops[5];
3337 const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
3338 forced_temporaries.insert(id);
3339 emit_binary_func_op(result_type, id, ptr, val, op);
3340 flush_all_atomic_capable_variables();
3341 break;
3342 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003343
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003344 case OpAtomicCompareExchange:
3345 {
3346 uint32_t result_type = ops[0];
3347 uint32_t id = ops[1];
3348 uint32_t ptr = ops[2];
3349 uint32_t val = ops[6];
3350 uint32_t comp = ops[7];
3351 const char *op = check_atomic_image(ptr) ? "imageAtomicCompSwap" : "atomicCompSwap";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003352
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003353 forced_temporaries.insert(id);
3354 emit_trinary_func_op(result_type, id, ptr, comp, val, op);
3355 flush_all_atomic_capable_variables();
3356 break;
3357 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003358
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003359 case OpAtomicLoad:
3360 flush_all_atomic_capable_variables();
3361 // FIXME: Image?
3362 UFOP(atomicCounter);
3363 register_read(ops[1], ops[2], should_forward(ops[2]));
3364 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003365
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003366 // OpAtomicStore unimplemented. Not sure what would use that.
3367 // OpAtomicLoad seems to only be relevant for atomic counters.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003368
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003369 case OpAtomicIIncrement:
3370 forced_temporaries.insert(ops[1]);
3371 // FIXME: Image?
3372 UFOP(atomicCounterIncrement);
3373 flush_all_atomic_capable_variables();
3374 register_read(ops[1], ops[2], should_forward(ops[2]));
3375 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003376
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003377 case OpAtomicIDecrement:
3378 forced_temporaries.insert(ops[1]);
3379 // FIXME: Image?
3380 UFOP(atomicCounterDecrement);
3381 flush_all_atomic_capable_variables();
3382 register_read(ops[1], ops[2], should_forward(ops[2]));
3383 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003384
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003385 case OpAtomicIAdd:
3386 {
3387 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3388 forced_temporaries.insert(ops[1]);
3389 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3390 flush_all_atomic_capable_variables();
3391 register_read(ops[1], ops[2], should_forward(ops[2]));
3392 break;
3393 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003394
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003395 case OpAtomicISub:
3396 {
3397 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd";
3398 forced_temporaries.insert(ops[1]);
3399 auto expr = join(op, "(", to_expression(ops[2]), ", -", to_expression(ops[5]), ")");
3400 emit_op(ops[0], ops[1], expr, should_forward(ops[2]) && should_forward(ops[5]), false);
3401 flush_all_atomic_capable_variables();
3402 register_read(ops[1], ops[2], should_forward(ops[2]));
3403 break;
3404 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003405
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003406 case OpAtomicSMin:
3407 case OpAtomicUMin:
3408 {
3409 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMin" : "atomicMin";
3410 forced_temporaries.insert(ops[1]);
3411 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3412 flush_all_atomic_capable_variables();
3413 register_read(ops[1], ops[2], should_forward(ops[2]));
3414 break;
3415 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003416
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003417 case OpAtomicSMax:
3418 case OpAtomicUMax:
3419 {
3420 const char *op = check_atomic_image(ops[2]) ? "imageAtomicMax" : "atomicMax";
3421 forced_temporaries.insert(ops[1]);
3422 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3423 flush_all_atomic_capable_variables();
3424 register_read(ops[1], ops[2], should_forward(ops[2]));
3425 break;
3426 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003428 case OpAtomicAnd:
3429 {
3430 const char *op = check_atomic_image(ops[2]) ? "imageAtomicAnd" : "atomicAnd";
3431 forced_temporaries.insert(ops[1]);
3432 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3433 flush_all_atomic_capable_variables();
3434 register_read(ops[1], ops[2], should_forward(ops[2]));
3435 break;
3436 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003437
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003438 case OpAtomicOr:
3439 {
3440 const char *op = check_atomic_image(ops[2]) ? "imageAtomicOr" : "atomicOr";
3441 forced_temporaries.insert(ops[1]);
3442 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3443 flush_all_atomic_capable_variables();
3444 register_read(ops[1], ops[2], should_forward(ops[2]));
3445 break;
3446 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003447
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003448 case OpAtomicXor:
3449 {
3450 const char *op = check_atomic_image(ops[2]) ? "imageAtomicXor" : "atomicXor";
3451 forced_temporaries.insert(ops[1]);
3452 emit_binary_func_op(ops[0], ops[1], ops[2], ops[5], op);
3453 flush_all_atomic_capable_variables();
3454 register_read(ops[1], ops[2], should_forward(ops[2]));
3455 break;
3456 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003457
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003458 // Geometry shaders
3459 case OpEmitVertex:
3460 statement("EmitVertex();");
3461 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003462
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003463 case OpEndPrimitive:
3464 statement("EndPrimitive();");
3465 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003466
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003467 case OpEmitStreamVertex:
3468 statement("EmitStreamVertex();");
3469 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003470
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003471 case OpEndStreamPrimitive:
3472 statement("EndStreamPrimitive();");
3473 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003474
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003475 // Textures
3476 case OpImageSampleImplicitLod:
3477 case OpImageSampleExplicitLod:
3478 case OpImageSampleProjImplicitLod:
3479 case OpImageSampleProjExplicitLod:
3480 case OpImageSampleDrefImplicitLod:
3481 case OpImageSampleDrefExplicitLod:
3482 case OpImageSampleProjDrefImplicitLod:
3483 case OpImageSampleProjDrefExplicitLod:
3484 case OpImageFetch:
3485 case OpImageGather:
3486 case OpImageDrefGather:
3487 // Gets a bit hairy, so move this to a separate instruction.
3488 emit_texture_op(instruction);
3489 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003490
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003491 case OpImage:
3492 {
3493 uint32_t result_type = ops[0];
3494 uint32_t id = ops[1];
3495 emit_op(result_type, id, to_expression(ops[2]), true, false);
3496 break;
3497 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003498
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003499 case OpSampledImage:
3500 {
3501 uint32_t result_type = ops[0];
3502 uint32_t id = ops[1];
3503 emit_sampled_image_op(result_type, id, ops[2], ops[3]);
3504 break;
3505 }
Hans-Kristian Arntzen7652c902016-04-19 11:13:47 +02003506
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003507 case OpImageQuerySizeLod:
3508 BFOP(textureSize);
3509 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003510
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003511 // Image load/store
3512 case OpImageRead:
3513 {
3514 // We added Nonreadable speculatively to the OpImage variable due to glslangValidator
3515 // not adding the proper qualifiers.
3516 // If it turns out we need to read the image after all, remove the qualifier and recompile.
3517 auto *var = maybe_get_backing_variable(ops[2]);
3518 if (var)
3519 {
3520 auto &flags = meta.at(var->self).decoration.decoration_flags;
3521 if (flags & (1ull << DecorationNonReadable))
3522 {
3523 flags &= ~(1ull << DecorationNonReadable);
3524 force_recompile = true;
3525 }
3526 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003527
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003528 uint32_t result_type = ops[0];
3529 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003530
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003531 bool pure;
3532 string imgexpr;
3533 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003534
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003535 if (var && var->remapped_variable) // PLS input, just read as-is without any op-code
3536 {
3537 // PLS input could have different number of components than what the SPIR expects, swizzle to
3538 // the appropriate vector size.
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02003539 auto itr =
3540 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 +01003541
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003542 if (itr == end(pls_inputs))
3543 throw CompilerError("Found PLS remap for OpImageRead, but ID is not a PLS input ...");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003544
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003545 uint32_t components = pls_format_to_components(itr->format);
3546 imgexpr = remap_swizzle(result_type, components, ops[2]);
3547 pure = true;
3548 }
3549 else if (type.image.dim == DimSubpassData)
3550 {
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003551 if (options.vulkan_semantics)
3552 {
3553 // With Vulkan semantics, use the proper Vulkan GLSL construct.
3554 imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
3555 }
3556 else
3557 {
3558 // Implement subpass loads via texture barrier style sampling.
3559 imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
3560 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003561 pure = true;
3562 }
3563 else
3564 {
3565 // Plain image load/store.
3566 imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ")");
3567 pure = false;
3568 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003569
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003570 if (var && var->forwardable)
3571 {
3572 auto &e = emit_op(result_type, id, imgexpr, true, false);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003573
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003574 // We only need to track dependencies if we're reading from image load/store.
3575 if (!pure)
3576 {
3577 e.loaded_from = var->self;
3578 var->dependees.push_back(id);
3579 }
3580 }
3581 else
3582 emit_op(result_type, id, imgexpr, false, false);
3583 break;
3584 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003585
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003586 case OpImageTexelPointer:
3587 {
3588 uint32_t result_type = ops[0];
3589 uint32_t id = ops[1];
3590 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 +01003591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003592 auto *var = maybe_get_backing_variable(ops[2]);
3593 e.loaded_from = var ? var->self : 0;
3594 break;
3595 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003596
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003597 case OpImageWrite:
3598 {
3599 // We added Nonwritable speculatively to the OpImage variable due to glslangValidator
3600 // not adding the proper qualifiers.
3601 // If it turns out we need to write to the image after all, remove the qualifier and recompile.
3602 auto *var = maybe_get_backing_variable(ops[0]);
3603 if (var)
3604 {
3605 auto &flags = meta.at(var->self).decoration.decoration_flags;
3606 if (flags & (1ull << DecorationNonWritable))
3607 {
3608 flags &= ~(1ull << DecorationNonWritable);
3609 force_recompile = true;
3610 }
3611 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003612
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003613 statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ");");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003614
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003615 if (var && variable_storage_is_aliased(*var))
3616 flush_all_aliased_variables();
3617 break;
3618 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003619
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003620 case OpImageQuerySize:
3621 {
3622 auto &type = expression_type(ops[2]);
3623 uint32_t result_type = ops[0];
3624 uint32_t id = ops[1];
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003626 if (type.basetype == SPIRType::Image)
3627 {
3628 // The size of an image is always constant.
3629 emit_op(result_type, id, join("imageSize(", to_expression(ops[2]), ")"), true, false);
3630 }
3631 else
3632 throw CompilerError("Invalid type for OpImageQuerySize.");
3633 break;
3634 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003635
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003636 // Compute
3637 case OpControlBarrier:
3638 {
3639 // Ignore execution and memory scope.
3640 if (execution.model == ExecutionModelGLCompute)
3641 {
3642 uint32_t mem = get<SPIRConstant>(ops[2]).scalar();
3643 if (mem == MemorySemanticsWorkgroupMemoryMask)
3644 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02003645 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003646 statement("memoryBarrier();");
3647 }
3648 statement("barrier();");
3649 break;
3650 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003651
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003652 case OpMemoryBarrier:
3653 {
3654 uint32_t mem = get<SPIRConstant>(ops[1]).scalar();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003655
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003656 // We cannot forward any loads beyond the memory barrier.
3657 if (mem)
3658 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003659
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003660 if (mem == MemorySemanticsWorkgroupMemoryMask)
3661 statement("memoryBarrierShared();");
Hans-Kristian Arntzen4739d162016-05-28 11:46:33 +02003662 else if (mem)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003663 statement("memoryBarrier();");
3664 break;
3665 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003666
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003667 case OpExtInst:
3668 {
3669 uint32_t extension_set = ops[2];
3670 if (get<SPIRExtension>(extension_set).ext != SPIRExtension::GLSL)
3671 {
3672 statement("// unimplemented ext op ", instruction.op);
3673 break;
3674 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003675
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003676 emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4);
3677 break;
3678 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003679
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003680 default:
3681 statement("// unimplemented op ", instruction.op);
3682 break;
3683 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003684}
3685
Bill Hollingsfe8b8602016-07-06 16:55:45 -04003686// Returns a string expression of function arguments beyond the specified index.
3687// This is used when a function call uses fewer arguments than the function defines.
3688// This situation may occur if the function signature has been dynamically modified
3689// to extract static global variables referenced from within the function and convert
3690// them to function arguments. This is necessary for shader languages that do not
3691// support global access to shader input content from within a function (eg. Metal).
3692// Each additional function args uses the name of the global var. Function nesting
3693// will modify the functions and calls all the way up the nesting chain.
3694string CompilerGLSL::static_func_args(const SPIRFunction &func, uint32_t index)
3695{
3696 string static_args;
3697 auto& args = func.arguments;
3698 uint32_t arg_cnt = (uint32_t)args.size();
3699 for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++) {
3700 if (arg_idx > 0) static_args += ", ";
3701 static_args += to_expression(args[arg_idx].id);
3702 }
3703 return static_args;
3704}
3705
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003706string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
3707{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003708 auto &memb = meta[type.self].members;
3709 if (index < memb.size() && !memb[index].alias.empty())
3710 return memb[index].alias;
3711 else
3712 return join("_", index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003713}
3714
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02003715void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index)
3716{
3717 auto &memb = meta[type.self].members;
3718 if (index < memb.size() && !memb[index].alias.empty())
3719 {
3720 auto &name = memb[index].alias;
3721 if (name.empty())
3722 return;
3723
3724 // Reserved for temporaries.
3725 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
3726 {
3727 name.clear();
3728 return;
3729 }
3730
3731 update_name_cache(type.member_name_cache, name);
3732 }
3733}
3734
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003735string CompilerGLSL::variable_decl(const SPIRType &type, const std::string &name)
3736{
3737 return join(type_to_glsl(type), " ", name, type_to_array_glsl(type));
3738}
3739
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003740string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index)
3741{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003742 uint64_t memberflags = 0;
3743 auto &memb = meta[type.self].members;
3744 if (index < memb.size())
3745 memberflags = memb[index].decoration_flags;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003746
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003747 return join(layout_for_member(type, index), flags_to_precision_qualifiers_glsl(membertype, memberflags),
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003748 variable_decl(membertype, to_member_name(type, index)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003749}
3750
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003751const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003752{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003753 if (options.es)
3754 {
3755 // Structs do not have precision qualifiers.
3756 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
3757 type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
3758 type.basetype != SPIRType::Sampler)
3759 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003760
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003761 if (flags & (1ull << DecorationRelaxedPrecision))
3762 {
3763 bool implied_fmediump = type.basetype == SPIRType::Float &&
3764 options.fragment.default_float_precision == Options::Mediump &&
3765 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003766
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003767 bool implied_imediump = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
3768 options.fragment.default_int_precision == Options::Mediump &&
3769 execution.model == ExecutionModelFragment;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003770
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003771 return implied_fmediump || implied_imediump ? "" : "mediump ";
3772 }
3773 else
3774 {
3775 bool implied_fhighp =
3776 type.basetype == SPIRType::Float && ((options.fragment.default_float_precision == Options::Highp &&
3777 execution.model == ExecutionModelFragment) ||
3778 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003779
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003780 bool implied_ihighp = (type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt) &&
3781 ((options.fragment.default_int_precision == Options::Highp &&
3782 execution.model == ExecutionModelFragment) ||
3783 (execution.model != ExecutionModelFragment));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003784
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003785 return implied_fhighp || implied_ihighp ? "" : "highp ";
3786 }
3787 }
3788 else
3789 return "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003790}
3791
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003792const char *CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003793{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003794 return flags_to_precision_qualifiers_glsl(expression_type(id), meta[id].decoration.decoration_flags);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003795}
3796
3797string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
3798{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003799 auto flags = meta[id].decoration.decoration_flags;
3800 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003801
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003802 auto *var = maybe_get<SPIRVariable>(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003803
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003804 if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied)
3805 res += "shared ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003806
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003807 res += to_precision_qualifiers_glsl(id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003808
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003809 //if (flags & (1ull << DecorationSmooth))
3810 // res += "smooth ";
3811 if (flags & (1ull << DecorationFlat))
3812 res += "flat ";
3813 if (flags & (1ull << DecorationNoPerspective))
3814 res += "noperspective ";
3815 if (flags & (1ull << DecorationPatch))
3816 res += "patch ";
3817 if (flags & (1ull << DecorationSample))
3818 res += "sample ";
3819 if (flags & (1ull << DecorationInvariant))
3820 res += "invariant ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003821
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003822 auto &type = expression_type(id);
3823 if (type.image.dim != DimSubpassData && type.image.sampled == 2)
3824 {
3825 if (flags & (1ull << DecorationNonWritable))
3826 res += "readonly ";
3827 if (flags & (1ull << DecorationNonReadable))
3828 res += "writeonly ";
3829 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003830
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003831 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003832}
3833
3834string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
3835{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003836 // glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
3837 // Not sure if argument being pointer type should make the argument inout.
3838 auto &type = expression_type(arg.id);
3839 const char *direction = "";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003840
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003841 if (type.pointer)
3842 {
3843 if (arg.write_count && arg.read_count)
3844 direction = "inout ";
3845 else if (arg.write_count)
3846 direction = "out ";
3847 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003848
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003849 return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id)));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003850}
3851
3852string CompilerGLSL::variable_decl(const SPIRVariable &variable)
3853{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003854 // Ignore the pointer type since GLSL doesn't have pointers.
3855 auto &type = get<SPIRType>(variable.basetype);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003856 auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self)));
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003857 if (variable.initializer)
3858 res += join(" = ", to_expression(variable.initializer));
3859 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003860}
3861
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003862const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003863{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003864 auto flags = meta[variable.self].decoration.decoration_flags;
3865 if (flags & (1ull << DecorationRelaxedPrecision))
3866 return "mediump ";
3867 else
3868 return "highp ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003869}
3870
3871string CompilerGLSL::pls_decl(const PlsRemap &var)
3872{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003873 auto &variable = get<SPIRVariable>(var.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003874
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003875 SPIRType type;
3876 type.vecsize = pls_format_to_components(var.format);
3877 type.basetype = pls_format_to_basetype(var.format);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003878
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003879 return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ",
3880 to_name(variable.self));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003881}
3882
3883string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
3884{
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003885 if (type.array.empty())
3886 return "";
3887
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003888 string res;
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003889 for (size_t i = type.array.size(); i; i--)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003890 {
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02003891 auto &size = type.array[i - 1];
3892
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003893 res += "[";
3894 if (size)
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02003895 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003896 res += convert_to_string(size);
Hans-Kristian Arntzen78e76152016-05-23 09:15:49 +02003897 }
3898 else if (!backend.flexible_member_array_supported)
3899 {
3900 // For runtime-sized arrays, we can work around
3901 // lack of standard support for this by simply having
3902 // a single element array.
3903 //
3904 // Runtime length arrays must always be the last element
3905 // in an interface block.
3906 res += '1';
3907 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003908 res += "]";
3909 }
3910 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003911}
3912
3913string CompilerGLSL::image_type_glsl(const SPIRType &type)
3914{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003915 auto &imagetype = get<SPIRType>(type.image.type);
3916 string res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003917
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003918 switch (imagetype.basetype)
3919 {
3920 case SPIRType::Int:
3921 res = "i";
3922 break;
3923 case SPIRType::UInt:
3924 res = "u";
3925 break;
3926 default:
3927 break;
3928 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003929
Hans-Kristian Arntzendbee4e42016-05-05 10:16:22 +02003930 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
3931 return res + "subpassInput";
3932
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003933 // If we're emulating subpassInput with samplers, force sampler2D
3934 // so we don't have to specify format.
3935 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
3936 res += type.image.sampled == 2 ? "image" : "texture";
3937 else
3938 res += "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003939
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003940 switch (type.image.dim)
3941 {
3942 case Dim1D:
3943 res += "1D";
3944 break;
3945 case Dim2D:
3946 res += "2D";
3947 break;
3948 case Dim3D:
3949 res += "3D";
3950 break;
3951 case DimCube:
3952 res += "Cube";
3953 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003954
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003955 case DimBuffer:
3956 if (options.es && options.version < 320)
3957 require_extension("GL_OES_texture_buffer");
3958 else if (!options.es && options.version < 300)
3959 require_extension("GL_EXT_texture_buffer_object");
3960 res += "Buffer";
3961 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003962
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003963 case DimSubpassData:
3964 res += "2D";
3965 break;
3966 default:
3967 throw CompilerError("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
3968 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003969
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003970 if (type.image.arrayed)
3971 res += "Array";
3972 if (type.image.depth)
3973 res += "Shadow";
3974 if (type.image.ms)
3975 res += "MS";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003976
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003977 return res;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003978}
3979
3980string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
3981{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003982 auto e = type_to_glsl(type);
3983 for (uint32_t i = 0; i < type.array.size(); i++)
3984 e += "[]";
3985 return e;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003986}
3987
3988string CompilerGLSL::type_to_glsl(const SPIRType &type)
3989{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003990 // Ignore the pointer type since GLSL doesn't have pointers.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01003991
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02003992 switch (type.basetype)
3993 {
3994 case SPIRType::Struct:
3995 // Need OpName lookup here to get a "sensible" name for a struct.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02003996 if (backend.explicit_struct_type)
3997 return join("struct ", to_name(type.self));
3998 else
3999 return to_name(type.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004000
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004001 case SPIRType::Image:
4002 case SPIRType::SampledImage:
4003 return image_type_glsl(type);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004004
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004005 case SPIRType::Sampler:
4006 // Not really used.
4007 return "sampler";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004008
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004009 case SPIRType::Void:
4010 return "void";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004011
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004012 default:
4013 break;
4014 }
4015
4016 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
4017 {
4018 switch (type.basetype)
4019 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004020 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004021 return "bool";
4022 case SPIRType::Int:
4023 return backend.basic_int_type;
4024 case SPIRType::UInt:
4025 return backend.basic_uint_type;
4026 case SPIRType::AtomicCounter:
4027 return "atomic_uint";
4028 case SPIRType::Float:
4029 return "float";
4030 default:
4031 return "???";
4032 }
4033 }
4034 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
4035 {
4036 switch (type.basetype)
4037 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004038 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004039 return join("bvec", type.vecsize);
4040 case SPIRType::Int:
4041 return join("ivec", type.vecsize);
4042 case SPIRType::UInt:
4043 return join("uvec", type.vecsize);
4044 case SPIRType::Float:
4045 return join("vec", type.vecsize);
4046 default:
4047 return "???";
4048 }
4049 }
4050 else if (type.vecsize == type.columns) // Simple Matrix builtin
4051 {
4052 switch (type.basetype)
4053 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004054 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004055 return join("bmat", type.vecsize);
4056 case SPIRType::Int:
4057 return join("imat", type.vecsize);
4058 case SPIRType::UInt:
4059 return join("umat", type.vecsize);
4060 case SPIRType::Float:
4061 return join("mat", type.vecsize);
4062 default:
4063 return "???";
4064 }
4065 }
4066 else
4067 {
4068 switch (type.basetype)
4069 {
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +02004070 case SPIRType::Boolean:
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004071 return join("bmat", type.columns, "x", type.vecsize);
4072 case SPIRType::Int:
4073 return join("imat", type.columns, "x", type.vecsize);
4074 case SPIRType::UInt:
4075 return join("umat", type.columns, "x", type.vecsize);
4076 case SPIRType::Float:
4077 return join("mat", type.columns, "x", type.vecsize);
4078 default:
4079 return "???";
4080 }
4081 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004082}
4083
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004084void CompilerGLSL::add_variable(unordered_set<string> &variables, uint32_t id)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004085{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004086 auto &name = meta[id].decoration.alias;
4087 if (name.empty())
4088 return;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004089
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004090 // Reserved for temporaries.
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004091 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004092 {
4093 name.clear();
4094 return;
4095 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004096
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004097 update_name_cache(variables, name);
4098}
4099
4100void CompilerGLSL::add_local_variable_name(uint32_t id)
4101{
4102 add_variable(local_variable_names, id);
4103}
4104
4105void CompilerGLSL::add_resource_name(uint32_t id)
4106{
4107 add_variable(resource_names, id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004108}
4109
4110void CompilerGLSL::require_extension(const string &ext)
4111{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004112 if (forced_extensions.find(ext) == end(forced_extensions))
4113 {
4114 forced_extensions.insert(ext);
4115 force_recompile = true;
4116 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004117}
4118
4119bool CompilerGLSL::check_atomic_image(uint32_t id)
4120{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004121 auto &type = expression_type(id);
4122 if (type.storage == StorageClassImage)
4123 {
4124 if (options.es && options.version < 320)
4125 require_extension("GL_OES_shader_image_atomic");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004126
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004127 auto *var = maybe_get_backing_variable(id);
4128 if (var)
4129 {
4130 auto &flags = meta.at(var->self).decoration.decoration_flags;
4131 if (flags & ((1ull << DecorationNonWritable) | (1ull << DecorationNonReadable)))
4132 {
4133 flags &= ~(1ull << DecorationNonWritable);
4134 flags &= ~(1ull << DecorationNonReadable);
4135 force_recompile = true;
4136 }
4137 }
4138 return true;
4139 }
4140 else
4141 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004142}
4143
4144void CompilerGLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_flags)
4145{
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004146 // Avoid shadow declarations.
4147 local_variable_names = resource_names;
4148
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004149 string decl;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004150
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004151 auto &type = get<SPIRType>(func.return_type);
4152 decl += flags_to_precision_qualifiers_glsl(type, return_flags);
4153 decl += type_to_glsl(type);
4154 decl += " ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004155
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004156 if (func.self == execution.entry_point)
4157 {
4158 decl += "main";
4159 processing_entry_point = true;
4160 }
4161 else
4162 decl += to_name(func.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004163
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004164 decl += "(";
4165 for (auto &arg : func.arguments)
4166 {
4167 // Might change the variable name if it already exists in this function.
4168 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
4169 // to use same name for variables.
4170 // 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 +02004171 add_local_variable_name(arg.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004172
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004173 decl += argument_decl(arg);
4174 if (&arg != &func.arguments.back())
4175 decl += ", ";
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004176
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004177 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
4178 auto *var = maybe_get<SPIRVariable>(arg.id);
4179 if (var)
4180 var->parameter = &arg;
4181 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004182
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004183 decl += ")";
4184 statement(decl);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004185}
4186
4187void CompilerGLSL::emit_function(SPIRFunction &func, uint64_t return_flags)
4188{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004189 // Avoid potential cycles.
4190 if (func.active)
4191 return;
4192 func.active = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004193
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004194 // If we depend on a function, emit that function before we emit our own function.
4195 for (auto block : func.blocks)
4196 {
4197 auto &b = get<SPIRBlock>(block);
4198 for (auto &i : b.ops)
4199 {
4200 auto ops = stream(i);
4201 auto op = static_cast<Op>(i.op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004202
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004203 if (op == OpFunctionCall)
4204 {
4205 // Recursively emit functions which are called.
4206 uint32_t id = ops[2];
4207 emit_function(get<SPIRFunction>(id), meta[ops[1]].decoration.decoration_flags);
4208 }
4209 }
4210 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004211
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004212 emit_function_prototype(func, return_flags);
4213 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004214
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004215 current_function = &func;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004216
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004217 for (auto &v : func.local_variables)
4218 {
4219 auto &var = get<SPIRVariable>(v);
4220 if (expression_is_lvalue(v))
4221 {
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +02004222 add_local_variable_name(var.self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004223
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004224 if (var.initializer)
4225 statement(variable_decl(var), ";");
4226 else
4227 {
4228 // Don't declare variable until first use to declutter the GLSL output quite a lot.
4229 // If we don't touch the variable before first branch,
4230 // declare it then since we need variable declaration to be in top scope.
4231 var.deferred_declaration = true;
4232 }
4233 }
4234 else
4235 {
4236 // HACK: SPIRV likes to use samplers and images as local variables, but GLSL does not allow
4237 // this. For these types (non-lvalue), we enforce forwarding through a shadowed variable.
4238 // This means that when we OpStore to these variables, we just write in the expression ID directly.
4239 // This breaks any kind of branching, since the variable must be statically assigned.
4240 // Branching on samplers and images would be pretty much impossible to fake in GLSL.
4241 var.statically_assigned = true;
4242 }
4243 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004244
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004245 auto &entry_block = get<SPIRBlock>(func.entry_block);
4246 entry_block.loop_dominator = SPIRBlock::NoDominator;
4247 emit_block_chain(entry_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004248
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004249 end_scope();
4250 processing_entry_point = false;
4251 statement("");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004252}
4253
4254void CompilerGLSL::emit_fixup()
4255{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004256 if (execution.model == ExecutionModelVertex && options.vertex.fixup_clipspace)
4257 {
4258 const char *suffix = backend.float_literal_suffix ? "f" : "";
4259 statement("gl_Position.z = 2.0", suffix, " * gl_Position.z - gl_Position.w;");
4260 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004261}
4262
4263bool CompilerGLSL::flush_phi_required(uint32_t from, uint32_t to)
4264{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004265 auto &child = get<SPIRBlock>(to);
4266 for (auto &phi : child.phi_variables)
4267 if (phi.parent == from)
4268 return true;
4269 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004270}
4271
4272void CompilerGLSL::flush_phi(uint32_t from, uint32_t to)
4273{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004274 auto &child = get<SPIRBlock>(to);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004275
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004276 for (auto &phi : child.phi_variables)
4277 if (phi.parent == from)
4278 statement(to_expression(phi.function_variable), " = ", to_expression(phi.local_variable), ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004279}
4280
4281void CompilerGLSL::branch(uint32_t from, uint32_t to)
4282{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004283 flush_phi(from, to);
4284 flush_all_active_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004285
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004286 // This is only a continue if we branch to our loop dominator.
4287 if (loop_blocks.find(to) != end(loop_blocks) && get<SPIRBlock>(from).loop_dominator == to)
4288 {
4289 // This can happen if we had a complex continue block which was emitted.
4290 // Once the continue block tries to branch to the loop header, just emit continue;
4291 // and end the chain here.
4292 statement("continue;");
4293 }
4294 else if (is_continue(to))
4295 {
4296 auto &to_block = get<SPIRBlock>(to);
4297 if (to_block.complex_continue)
4298 {
4299 // Just emit the whole block chain as is.
4300 auto usage_counts = expression_usage_counts;
4301 auto invalid = invalid_expressions;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004302
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004303 emit_block_chain(to_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004304
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004305 // Expression usage counts and invalid expressions
4306 // are moot after returning from the continue block.
4307 // Since we emit the same block multiple times,
4308 // we don't want to invalidate ourselves.
4309 expression_usage_counts = usage_counts;
4310 invalid_expressions = invalid;
4311 }
4312 else
4313 {
4314 auto &from_block = get<SPIRBlock>(from);
4315 auto &dominator = get<SPIRBlock>(from_block.loop_dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004316
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004317 // For non-complex continue blocks, we implicitly branch to the continue block
4318 // by having the continue block be part of the loop header in for (; ; continue-block).
4319 bool outside_control_flow = block_is_outside_flow_control_from_block(dominator, from_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004320
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004321 // Some simplification for for-loops. We always end up with a useless continue;
4322 // statement since we branch to a loop block.
4323 // Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block,
4324 // we can avoid writing out an explicit continue statement.
4325 // Similar optimization to return statements if we know we're outside flow control.
4326 if (!outside_control_flow)
4327 statement("continue;");
4328 }
4329 }
4330 else if (is_break(to))
4331 statement("break;");
4332 else if (!is_conditional(to))
4333 emit_block_chain(get<SPIRBlock>(to));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004334}
4335
4336void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block)
4337{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004338 // If we branch directly to a selection merge target, we don't really need a code path.
4339 bool true_sub = !is_conditional(true_block);
4340 bool false_sub = !is_conditional(false_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004341
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004342 if (true_sub)
4343 {
4344 statement("if (", to_expression(cond), ")");
4345 begin_scope();
4346 branch(from, true_block);
4347 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004348
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004349 if (false_sub)
4350 {
4351 statement("else");
4352 begin_scope();
4353 branch(from, false_block);
4354 end_scope();
4355 }
4356 else if (flush_phi_required(from, false_block))
4357 {
4358 statement("else");
4359 begin_scope();
4360 flush_phi(from, false_block);
4361 end_scope();
4362 }
4363 }
4364 else if (false_sub && !true_sub)
4365 {
4366 // Only need false path, use negative conditional.
4367 statement("if (!", to_expression(cond), ")");
4368 begin_scope();
4369 branch(from, false_block);
4370 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004371
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004372 if (flush_phi_required(from, true_block))
4373 {
4374 statement("else");
4375 begin_scope();
4376 flush_phi(from, true_block);
4377 end_scope();
4378 }
4379 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004380}
4381
4382void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
4383{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004384 // Propagate down the loop dominator block, so that dominated blocks can back trace.
4385 if (block.merge == SPIRBlock::MergeLoop || block.loop_dominator)
4386 {
4387 uint32_t dominator = block.merge == SPIRBlock::MergeLoop ? block.self : block.loop_dominator;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004388
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +02004389 auto set_dominator = [this](uint32_t self, uint32_t new_dominator) {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004390 auto &dominated_block = this->get<SPIRBlock>(self);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004391
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004392 // If we already have a loop dominator, we're trying to break out to merge targets
4393 // which should not update the loop dominator.
4394 if (!dominated_block.loop_dominator)
4395 dominated_block.loop_dominator = new_dominator;
4396 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004397
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004398 // After merging a loop, we inherit the loop dominator always.
4399 if (block.merge_block)
4400 set_dominator(block.merge_block, block.loop_dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004401
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004402 if (block.true_block)
4403 set_dominator(block.true_block, dominator);
4404 if (block.false_block)
4405 set_dominator(block.false_block, dominator);
4406 if (block.next_block)
4407 set_dominator(block.next_block, dominator);
Hans-Kristian Arntzenba0ab872016-04-04 08:53:37 +02004408
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004409 for (auto &c : block.cases)
4410 set_dominator(c.block, dominator);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004411
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004412 // In older glslang output continue_block can be == loop header.
4413 if (block.continue_block && block.continue_block != block.self)
4414 set_dominator(block.continue_block, dominator);
4415 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004416}
4417
4418// FIXME: This currently cannot handle complex continue blocks
4419// as in do-while.
4420// This should be seen as a "trivial" continue block.
4421string CompilerGLSL::emit_continue_block(uint32_t continue_block)
4422{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004423 auto *block = &get<SPIRBlock>(continue_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004424
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004425 // While emitting the continue block, declare_temporary will check this
4426 // if we have to emit temporaries.
4427 current_continue_block = block;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004428
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004429 vector<string> statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004430
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004431 // Capture all statements into our list.
4432 auto *old = redirect_statement;
4433 redirect_statement = &statements;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004434
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004435 // Stamp out all blocks one after each other.
4436 while (loop_blocks.find(block->self) == end(loop_blocks))
4437 {
4438 propagate_loop_dominators(*block);
4439 // Write out all instructions we have in this block.
4440 for (auto &op : block->ops)
4441 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004442
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004443 // For plain branchless for/while continue blocks.
4444 if (block->next_block)
4445 {
4446 flush_phi(continue_block, block->next_block);
4447 block = &get<SPIRBlock>(block->next_block);
4448 }
4449 // For do while blocks. The last block will be a select block.
4450 else if (block->true_block)
4451 {
4452 flush_phi(continue_block, block->true_block);
4453 block = &get<SPIRBlock>(block->true_block);
4454 }
4455 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004456
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004457 // Restore old pointer.
4458 redirect_statement = old;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004459
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004460 // Somewhat ugly, strip off the last ';' since we use ',' instead.
4461 // Ideally, we should select this behavior in statement().
4462 for (auto &s : statements)
4463 {
4464 if (!s.empty() && s.back() == ';')
4465 s.pop_back();
4466 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004467
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004468 current_continue_block = nullptr;
4469 return merge(statements);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004470}
4471
4472bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
4473{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004474 SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004475
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004476 if (method == SPIRBlock::MergeToSelectForLoop)
4477 {
4478 uint32_t current_count = statement_count;
4479 // If we're trying to create a true for loop,
4480 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4481 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4482 for (auto &op : block.ops)
4483 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004484
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004485 bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004486
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004487 // This can work! We only did trivial things which could be forwarded in block body!
4488 if (current_count == statement_count && condition_is_temporary)
4489 {
4490 switch (continue_type)
4491 {
4492 case SPIRBlock::ForLoop:
4493 statement("for (; ", to_expression(block.condition), "; ", emit_continue_block(block.continue_block),
4494 ")");
4495 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004496
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004497 case SPIRBlock::WhileLoop:
4498 statement("while (", to_expression(block.condition), ")");
4499 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004500
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004501 default:
4502 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
4503 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004504
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004505 begin_scope();
4506 return true;
4507 }
4508 else
4509 {
4510 block.disable_block_optimization = true;
4511 force_recompile = true;
4512 begin_scope(); // We'll see an end_scope() later.
4513 return false;
4514 }
4515 }
4516 else if (method == SPIRBlock::MergeToDirectForLoop)
4517 {
4518 uint32_t current_count = statement_count;
4519 auto &child = get<SPIRBlock>(block.next_block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004520
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004521 // If we're trying to create a true for loop,
4522 // we need to make sure that all opcodes before branch statement do not actually emit any code.
4523 // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
4524 for (auto &op : child.ops)
4525 emit_instruction(op);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004526
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004527 bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004529 if (current_count == statement_count && condition_is_temporary)
4530 {
4531 propagate_loop_dominators(child);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004532
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004533 switch (continue_type)
4534 {
4535 case SPIRBlock::ForLoop:
4536 statement("for (; ", to_expression(child.condition), "; ", emit_continue_block(block.continue_block),
4537 ")");
4538 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004539
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004540 case SPIRBlock::WhileLoop:
4541 statement("while (", to_expression(child.condition), ")");
4542 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004543
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004544 default:
4545 throw CompilerError("For/while loop detected, but need while/for loop semantics.");
4546 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004547
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004548 begin_scope();
4549 branch(child.self, child.true_block);
4550 return true;
4551 }
4552 else
4553 {
4554 block.disable_block_optimization = true;
4555 force_recompile = true;
4556 begin_scope(); // We'll see an end_scope() later.
4557 return false;
4558 }
4559 }
4560 else
4561 return false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004562}
4563
4564void CompilerGLSL::flush_undeclared_variables()
4565{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004566 // Declare undeclared variables.
4567 if (current_function->flush_undeclared)
4568 {
4569 for (auto &v : current_function->local_variables)
4570 {
4571 auto &var = get<SPIRVariable>(v);
4572 if (var.deferred_declaration)
4573 statement(variable_decl(var), ";");
4574 var.deferred_declaration = false;
4575 }
4576 current_function->flush_undeclared = false;
4577 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004578}
4579
4580void CompilerGLSL::emit_block_chain(SPIRBlock &block)
4581{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004582 propagate_loop_dominators(block);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004584 bool select_branch_to_true_block = false;
4585 bool skip_direct_branch = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004586
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004587 // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
4588 for (auto &tmp : block.declare_temporary)
4589 {
4590 auto flags = meta[tmp.second].decoration.decoration_flags;
4591 auto &type = get<SPIRType>(tmp.first);
Hans-Kristian Arntzen168e46f2016-05-28 13:09:26 +02004592 statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";");
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004593 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004594
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004595 SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
4596 if (block.continue_block)
4597 continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004598
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004599 // This is the older loop behavior in glslang which branches to loop body directly from the loop header.
4600 if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
4601 {
4602 flush_undeclared_variables();
4603 if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
4604 {
4605 // The body of while, is actually just the true block, so always branch there
4606 // unconditionally.
4607 select_branch_to_true_block = true;
4608 }
4609 }
4610 // This is the newer loop behavior in glslang which branches from Loop header directly to
4611 // a new block, which in turn has a OpBranchSelection without a selection merge.
4612 else if (block_is_loop_candidate(block, SPIRBlock::MergeToDirectForLoop))
4613 {
4614 flush_undeclared_variables();
4615 if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
4616 skip_direct_branch = true;
4617 }
4618 else if (continue_type == SPIRBlock::DoWhileLoop)
4619 {
4620 statement("do");
4621 begin_scope();
4622 for (auto &op : block.ops)
4623 emit_instruction(op);
4624 }
4625 else if (block.merge == SPIRBlock::MergeLoop)
4626 {
4627 flush_undeclared_variables();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004628
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004629 // We have a generic loop without any distinguishable pattern like for, while or do while.
4630 get<SPIRBlock>(block.continue_block).complex_continue = true;
4631 continue_type = SPIRBlock::ComplexLoop;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004632
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004633 statement("for (;;)");
4634 begin_scope();
4635 for (auto &op : block.ops)
4636 emit_instruction(op);
4637 }
4638 else
4639 {
4640 for (auto &op : block.ops)
4641 emit_instruction(op);
4642 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004643
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004644 bool emit_next_block = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004645
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004646 // Handle end of block.
4647 switch (block.terminator)
4648 {
4649 case SPIRBlock::Direct:
4650 // True when emitting complex continue block.
4651 if (block.loop_dominator == block.next_block)
4652 {
4653 branch(block.self, block.next_block);
4654 emit_next_block = false;
4655 }
4656 // True if MergeToDirectForLoop succeeded.
4657 else if (skip_direct_branch)
4658 emit_next_block = false;
4659 else if (is_continue(block.next_block) || is_break(block.next_block) || is_conditional(block.next_block))
4660 {
4661 branch(block.self, block.next_block);
4662 emit_next_block = false;
4663 }
4664 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004665
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004666 case SPIRBlock::Select:
4667 // True if MergeToSelectForLoop succeeded.
4668 if (select_branch_to_true_block)
4669 branch(block.self, block.true_block);
4670 else
4671 {
4672 flush_undeclared_variables();
4673 branch(block.self, block.condition, block.true_block, block.false_block);
4674 }
4675 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004676
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004677 case SPIRBlock::MultiSelect:
4678 {
4679 flush_undeclared_variables();
4680 auto &type = expression_type(block.condition);
4681 bool uint32_t_case = type.basetype == SPIRType::UInt;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004682
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004683 statement("switch (", to_expression(block.condition), ")");
4684 begin_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004685
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004686 for (auto &c : block.cases)
4687 {
4688 auto case_value =
4689 uint32_t_case ? convert_to_string(uint32_t(c.value)) : convert_to_string(int32_t(c.value));
4690 statement("case ", case_value, ":");
4691 begin_scope();
4692 branch(block.self, c.block);
4693 end_scope();
4694 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004695
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004696 if (block.default_block != block.next_block)
4697 {
4698 statement("default:");
4699 begin_scope();
4700 if (is_break(block.default_block))
4701 throw CompilerError("Cannot break; out of a switch statement and out of a loop at the same time ...");
4702 branch(block.self, block.default_block);
4703 end_scope();
4704 }
4705 else if (flush_phi_required(block.self, block.next_block))
4706 {
4707 statement("default:");
4708 begin_scope();
4709 flush_phi(block.self, block.next_block);
4710 statement("break;");
4711 end_scope();
4712 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004713
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004714 end_scope();
4715 break;
4716 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004717
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004718 case SPIRBlock::Return:
4719 if (processing_entry_point)
4720 emit_fixup();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004721
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004722 if (block.return_value)
4723 {
4724 // OpReturnValue can return Undef, so don't emit anything for this case.
4725 if (ids.at(block.return_value).get_type() != TypeUndef)
4726 statement("return ", to_expression(block.return_value), ";");
4727 }
4728 // If this block is the very final block and not called from control flow,
4729 // we do not need an explicit return which looks out of place. Just end the function here.
4730 // In the very weird case of for(;;) { return; } executing return is unconditional,
4731 // but we actually need a return here ...
4732 else if (!block_is_outside_flow_control_from_block(get<SPIRBlock>(current_function->entry_block), block) ||
4733 block.loop_dominator != SPIRBlock::NoDominator)
4734 statement("return;");
4735 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004736
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004737 case SPIRBlock::Kill:
4738 statement("discard;");
4739 break;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004740
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004741 default:
4742 throw CompilerError("Unimplemented block terminator.");
4743 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004744
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004745 if (block.next_block && emit_next_block)
4746 {
4747 // If we hit this case, we're dealing with an unconditional branch, which means we will output
4748 // that block after this. If we had selection merge, we already flushed phi variables.
4749 if (block.merge != SPIRBlock::MergeSelection)
4750 flush_phi(block.self, block.next_block);
4751 emit_block_chain(get<SPIRBlock>(block.next_block));
4752 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004753
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004754 if (block.merge == SPIRBlock::MergeLoop)
4755 {
4756 if (continue_type == SPIRBlock::DoWhileLoop)
4757 {
4758 // Make sure that we run the continue block to get the expressions set, but this
4759 // should become an empty string.
4760 // We have no fallbacks if we cannot forward everything to temporaries ...
4761 auto statements = emit_continue_block(block.continue_block);
4762 if (!statements.empty())
4763 {
4764 // The DoWhile block has side effects, force ComplexLoop pattern next pass.
4765 get<SPIRBlock>(block.continue_block).complex_continue = true;
4766 force_recompile = true;
4767 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004768
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004769 end_scope_decl(join("while (", to_expression(get<SPIRBlock>(block.continue_block).condition), ")"));
4770 }
4771 else
4772 end_scope();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004773
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004774 flush_phi(block.self, block.merge_block);
4775 emit_block_chain(get<SPIRBlock>(block.merge_block));
4776 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004777}
4778
4779void CompilerGLSL::begin_scope()
4780{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004781 statement("{");
4782 indent++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004783}
4784
4785void CompilerGLSL::end_scope()
4786{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004787 if (!indent)
4788 throw CompilerError("Popping empty indent stack.");
4789 indent--;
4790 statement("}");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004791}
4792
4793void CompilerGLSL::end_scope_decl()
4794{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004795 if (!indent)
4796 throw CompilerError("Popping empty indent stack.");
4797 indent--;
4798 statement("};");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004799}
4800
4801void CompilerGLSL::end_scope_decl(const string &decl)
4802{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02004803 if (!indent)
4804 throw CompilerError("Popping empty indent stack.");
4805 indent--;
4806 statement("} ", decl, ";");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004807}