blob: 201eb5a30dabb5fa8596a141268ae78d3379598d [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_cpp.hpp"
Bill Hollings5f2d6662016-04-11 11:31:03 -040018#include "spirv_msl.hpp"
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020019#include <algorithm>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010020#include <cstdio>
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020021#include <cstring>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010022#include <functional>
23#include <limits>
24#include <memory>
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020025#include <stdexcept>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010026#include <unordered_map>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010027#include <unordered_set>
28
29using namespace spv;
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020030using namespace spirv_cross;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010031using namespace std;
32
33struct CLIParser;
34struct CLICallbacks
35{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020036 void add(const char *cli, const function<void(CLIParser &)> &func)
37 {
38 callbacks[cli] = func;
39 }
40 unordered_map<string, function<void(CLIParser &)>> callbacks;
41 function<void()> error_handler;
42 function<void(const char *)> default_handler;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010043};
44
45struct CLIParser
46{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020047 CLIParser(CLICallbacks cbs_, int argc_, char *argv_[])
48 : cbs(move(cbs_))
49 , argc(argc_)
50 , argv(argv_)
51 {
52 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010053
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020054 bool parse()
55 {
56 try
57 {
58 while (argc && !ended_state)
59 {
60 const char *next = *argv++;
61 argc--;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010062
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020063 if (*next != '-' && cbs.default_handler)
64 {
65 cbs.default_handler(next);
66 }
67 else
68 {
69 auto itr = cbs.callbacks.find(next);
70 if (itr == ::end(cbs.callbacks))
71 {
72 throw logic_error("Invalid argument.\n");
73 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010074
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020075 itr->second(*this);
76 }
77 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010078
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020079 return true;
80 }
81 catch (...)
82 {
83 if (cbs.error_handler)
84 {
85 cbs.error_handler();
86 }
87 return false;
88 }
89 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010090
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020091 void end()
92 {
93 ended_state = true;
94 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010095
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +020096 uint32_t next_uint()
97 {
98 if (!argc)
99 {
100 throw logic_error("Tried to parse uint, but nothing left in arguments.\n");
101 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100102
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200103 uint32_t val = stoul(*argv);
104 if (val > numeric_limits<uint32_t>::max())
105 {
106 throw out_of_range("next_uint() out of range.\n");
107 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100108
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200109 argc--;
110 argv++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100111
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200112 return val;
113 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100114
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200115 double next_double()
116 {
117 if (!argc)
118 {
119 throw logic_error("Tried to parse double, but nothing left in arguments.\n");
120 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100121
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200122 double val = stod(*argv);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100123
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200124 argc--;
125 argv++;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100126
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200127 return val;
128 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100129
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200130 const char *next_string()
131 {
132 if (!argc)
133 {
134 throw logic_error("Tried to parse string, but nothing left in arguments.\n");
135 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100136
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200137 const char *ret = *argv;
138 argc--;
139 argv++;
140 return ret;
141 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100142
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200143 CLICallbacks cbs;
144 int argc;
145 char **argv;
146 bool ended_state = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100147};
148
149static vector<uint32_t> read_spirv_file(const char *path)
150{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200151 FILE *file = fopen(path, "rb");
152 if (!file)
153 {
154 fprintf(stderr, "Failed to open SPIRV file: %s\n", path);
155 return {};
156 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100157
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200158 fseek(file, 0, SEEK_END);
159 long len = ftell(file) / sizeof(uint32_t);
160 rewind(file);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100161
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200162 vector<uint32_t> spirv(len);
163 if (fread(spirv.data(), sizeof(uint32_t), len, file) != size_t(len))
164 spirv.clear();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100165
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200166 fclose(file);
167 return spirv;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100168}
169
170static bool write_string_to_file(const char *path, const char *string)
171{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200172 FILE *file = fopen(path, "w");
173 if (!file)
174 {
175 fprintf(file, "Failed to write file: %s\n", path);
176 return false;
177 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100178
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200179 fprintf(file, "%s", string);
180 fclose(file);
181 return true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100182}
183
184static void print_resources(const Compiler &compiler, const char *tag, const vector<Resource> &resources)
185{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200186 fprintf(stderr, "%s\n", tag);
187 fprintf(stderr, "=============\n\n");
188 for (auto &res : resources)
189 {
190 auto &type = compiler.get_type(res.type_id);
191 auto mask = compiler.get_decoration_mask(res.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100192
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200193 // If we don't have a name, use the fallback for the type instead of the variable
194 // for SSBOs and UBOs since those are the only meaningful names to use externally.
195 // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks.
196 bool is_push_constant = compiler.get_storage_class(res.id) == StorageClassPushConstant;
197 bool is_block = (compiler.get_decoration_mask(type.self) &
198 ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
Hans-Kristian Arntzen5c24d992016-07-12 21:20:18 +0200199 uint32_t fallback_id = !is_push_constant && is_block ? res.base_type_id : res.id;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100200
Hans-Kristian Arntzen5c24d992016-07-12 21:20:18 +0200201 string array;
202 for (auto arr : type.array)
203 array = join("[", arr ? convert_to_string(arr) : "", "]") + array;
204
205 fprintf(stderr, " ID %03u : %s%s", res.id,
206 !res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str(), array.c_str());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100207
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200208 if (mask & (1ull << DecorationLocation))
209 fprintf(stderr, " (Location : %u)", compiler.get_decoration(res.id, DecorationLocation));
210 if (mask & (1ull << DecorationDescriptorSet))
211 fprintf(stderr, " (Set : %u)", compiler.get_decoration(res.id, DecorationDescriptorSet));
212 if (mask & (1ull << DecorationBinding))
213 fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding));
214 if (mask & (1ull << DecorationInputAttachmentIndex))
215 fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex));
216 fprintf(stderr, "\n");
217 }
218 fprintf(stderr, "=============\n\n");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100219}
220
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200221static const char *execution_model_to_str(spv::ExecutionModel model)
222{
223 switch (model)
224 {
225 case spv::ExecutionModelVertex:
226 return "vertex";
227 case spv::ExecutionModelTessellationControl:
228 return "tessellation control";
229 case ExecutionModelTessellationEvaluation:
230 return "tessellation evaluation";
231 case ExecutionModelGeometry:
232 return "geometry";
233 case ExecutionModelFragment:
234 return "fragment";
235 case ExecutionModelGLCompute:
236 return "compute";
237 default:
238 return "???";
239 }
240}
241
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100242static void print_resources(const Compiler &compiler, const ShaderResources &res)
243{
Hans-Kristian Arntzen3c285a12016-07-04 13:30:05 +0200244 uint64_t modes = compiler.get_execution_mode_mask();
245
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200246 fprintf(stderr, "Entry points:\n");
247 auto entry_points = compiler.get_entry_points();
248 for (auto &e : entry_points)
249 fprintf(stderr, " %s (%s)\n", e.c_str(), execution_model_to_str(compiler.get_entry_point(e).model));
250 fprintf(stderr, "\n");
251
Hans-Kristian Arntzen3c285a12016-07-04 13:30:05 +0200252 fprintf(stderr, "Execution modes:\n");
253 for (unsigned i = 0; i < 64; i++)
254 {
255 if (!(modes & (1ull << i)))
256 continue;
257
258 auto mode = static_cast<ExecutionMode>(i);
259 uint32_t arg0 = compiler.get_execution_mode_argument(mode, 0);
260 uint32_t arg1 = compiler.get_execution_mode_argument(mode, 1);
261 uint32_t arg2 = compiler.get_execution_mode_argument(mode, 2);
262
263 switch (static_cast<ExecutionMode>(i))
264 {
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200265 case ExecutionModeInvocations:
266 fprintf(stderr, " Invocations: %u\n", arg0);
267 break;
Hans-Kristian Arntzen3c285a12016-07-04 13:30:05 +0200268
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200269 case ExecutionModeLocalSize:
270 fprintf(stderr, " LocalSize: (%u, %u, %u)\n", arg0, arg1, arg2);
271 break;
Hans-Kristian Arntzen3c285a12016-07-04 13:30:05 +0200272
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200273 case ExecutionModeOutputVertices:
274 fprintf(stderr, " OutputVertices: %u\n", arg0);
275 break;
Hans-Kristian Arntzen3c285a12016-07-04 13:30:05 +0200276
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200277#define CHECK_MODE(m) \
278 case ExecutionMode##m: \
279 fprintf(stderr, " %s\n", #m); \
280 break
281 CHECK_MODE(SpacingEqual);
282 CHECK_MODE(SpacingFractionalEven);
283 CHECK_MODE(SpacingFractionalOdd);
284 CHECK_MODE(VertexOrderCw);
285 CHECK_MODE(VertexOrderCcw);
286 CHECK_MODE(PixelCenterInteger);
287 CHECK_MODE(OriginUpperLeft);
288 CHECK_MODE(OriginLowerLeft);
289 CHECK_MODE(EarlyFragmentTests);
290 CHECK_MODE(PointMode);
291 CHECK_MODE(Xfb);
292 CHECK_MODE(DepthReplacing);
293 CHECK_MODE(DepthGreater);
294 CHECK_MODE(DepthLess);
295 CHECK_MODE(DepthUnchanged);
296 CHECK_MODE(LocalSizeHint);
297 CHECK_MODE(InputPoints);
298 CHECK_MODE(InputLines);
299 CHECK_MODE(InputLinesAdjacency);
300 CHECK_MODE(Triangles);
301 CHECK_MODE(InputTrianglesAdjacency);
302 CHECK_MODE(Quads);
303 CHECK_MODE(Isolines);
304 CHECK_MODE(OutputPoints);
305 CHECK_MODE(OutputLineStrip);
306 CHECK_MODE(OutputTriangleStrip);
307 CHECK_MODE(VecTypeHint);
308 CHECK_MODE(ContractionOff);
Hans-Kristian Arntzen3c285a12016-07-04 13:30:05 +0200309
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200310 default:
311 break;
Hans-Kristian Arntzen3c285a12016-07-04 13:30:05 +0200312 }
313 }
314 fprintf(stderr, "\n");
315
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200316 print_resources(compiler, "subpass inputs", res.subpass_inputs);
317 print_resources(compiler, "inputs", res.stage_inputs);
318 print_resources(compiler, "outputs", res.stage_outputs);
319 print_resources(compiler, "textures", res.sampled_images);
Hans-Kristian Arntzene9202082016-09-10 13:05:35 +0200320 print_resources(compiler, "separate textures", res.separate_images);
321 print_resources(compiler, "separate samplers", res.separate_samplers);
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200322 print_resources(compiler, "images", res.storage_images);
323 print_resources(compiler, "ssbos", res.storage_buffers);
324 print_resources(compiler, "ubos", res.uniform_buffers);
325 print_resources(compiler, "push", res.push_constant_buffers);
326 print_resources(compiler, "counters", res.atomic_counters);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100327}
328
329static void print_push_constant_resources(const Compiler &compiler, const vector<Resource> &res)
330{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200331 for (auto &block : res)
332 {
333 auto ranges = compiler.get_active_buffer_ranges(block.id);
334 fprintf(stderr, "Active members in buffer: %s\n",
335 !block.name.empty() ? block.name.c_str() : compiler.get_fallback_name(block.id).c_str());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100336
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200337 fprintf(stderr, "==================\n\n");
338 for (auto &range : ranges)
339 {
Hans-Kristian Arntzen5c24d992016-07-12 21:20:18 +0200340 const auto &name = compiler.get_member_name(block.base_type_id, range.index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100341
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200342 fprintf(stderr, "Member #%3u (%s): Offset: %4u, Range: %4u\n", range.index,
343 !name.empty() ? name.c_str() : compiler.get_fallback_member_name(range.index).c_str(),
344 unsigned(range.offset), unsigned(range.range));
345 }
346 fprintf(stderr, "==================\n\n");
347 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100348}
349
350struct PLSArg
351{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200352 PlsFormat format;
353 string name;
354};
355
356struct Remap
357{
358 string src_name;
359 string dst_name;
360 unsigned components;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100361};
362
363struct CLIArguments
364{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200365 const char *input = nullptr;
366 const char *output = nullptr;
367 const char *cpp_interface_name = nullptr;
368 uint32_t version = 0;
369 bool es = false;
370 bool set_version = false;
371 bool set_es = false;
372 bool dump_resources = false;
373 bool force_temporary = false;
374 bool flatten_ubo = false;
375 bool fixup = false;
376 vector<PLSArg> pls_in;
377 vector<PLSArg> pls_out;
378 vector<Remap> remaps;
379 vector<string> extensions;
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200380 string entry;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100381
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200382 uint32_t iterations = 1;
383 bool cpp = false;
384 bool metal = false;
385 bool vulkan_semantics = false;
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200386 bool remove_unused = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100387};
388
389static void print_help()
390{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200391 fprintf(stderr, "Usage: spirv-cross [--output <output path>] [SPIR-V file] [--es] [--no-es] [--version <GLSL "
392 "version>] [--dump-resources] [--help] [--force-temporary] [--cpp] [--cpp-interface-name <name>] "
393 "[--metal] [--vulkan-semantics] [--flatten-ubo] [--fixup-clipspace] [--iterations iter] [--pls-in "
394 "format input-name] [--pls-out format output-name] [--remap source_name target_name components] "
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200395 "[--extension ext] [--entry name] [--remove-unused-variables]\n");
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100396}
397
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200398static bool remap_generic(Compiler &compiler, const vector<Resource> &resources, const Remap &remap)
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100399{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200400 auto itr =
401 find_if(begin(resources), end(resources), [&remap](const Resource &res) { return res.name == remap.src_name; });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100402
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200403 if (itr != end(resources))
404 {
405 compiler.set_remapped_variable_state(itr->id, true);
406 compiler.set_name(itr->id, remap.dst_name);
407 compiler.set_subpass_input_remapped_components(itr->id, remap.components);
408 return true;
409 }
410 else
411 return false;
412}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100413
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200414static vector<PlsRemap> remap_pls(const vector<PLSArg> &pls_variables, const vector<Resource> &resources,
415 const vector<Resource> *secondary_resources)
416{
417 vector<PlsRemap> ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100418
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200419 for (auto &pls : pls_variables)
420 {
421 bool found = false;
422 for (auto &res : resources)
423 {
424 if (res.name == pls.name)
425 {
426 ret.push_back({ res.id, pls.format });
427 found = true;
428 break;
429 }
430 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100431
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200432 if (!found && secondary_resources)
433 {
434 for (auto &res : *secondary_resources)
435 {
436 if (res.name == pls.name)
437 {
438 ret.push_back({ res.id, pls.format });
439 found = true;
440 break;
441 }
442 }
443 }
444
445 if (!found)
446 fprintf(stderr, "Did not find stage input/output/target with name \"%s\".\n", pls.name.c_str());
447 }
448
449 return ret;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100450}
451
452static PlsFormat pls_format(const char *str)
453{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200454 if (!strcmp(str, "r11f_g11f_b10f"))
455 return PlsR11FG11FB10F;
456 else if (!strcmp(str, "r32f"))
457 return PlsR32F;
458 else if (!strcmp(str, "rg16f"))
459 return PlsRG16F;
460 else if (!strcmp(str, "rg16"))
461 return PlsRG16;
462 else if (!strcmp(str, "rgb10_a2"))
463 return PlsRGB10A2;
464 else if (!strcmp(str, "rgba8"))
465 return PlsRGBA8;
466 else if (!strcmp(str, "rgba8i"))
467 return PlsRGBA8I;
468 else if (!strcmp(str, "rgba8ui"))
469 return PlsRGBA8UI;
470 else if (!strcmp(str, "rg16i"))
471 return PlsRG16I;
472 else if (!strcmp(str, "rgb10_a2ui"))
473 return PlsRGB10A2UI;
474 else if (!strcmp(str, "rg16ui"))
475 return PlsRG16UI;
476 else if (!strcmp(str, "r32ui"))
477 return PlsR32UI;
478 else
479 return PlsNone;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100480}
481
482int main(int argc, char *argv[])
483{
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200484 CLIArguments args;
485 CLICallbacks cbs;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100486
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200487 cbs.add("--help", [](CLIParser &parser) {
488 print_help();
489 parser.end();
490 });
491 cbs.add("--output", [&args](CLIParser &parser) { args.output = parser.next_string(); });
492 cbs.add("--es", [&args](CLIParser &) {
493 args.es = true;
494 args.set_es = true;
495 });
496 cbs.add("--no-es", [&args](CLIParser &) {
497 args.es = false;
498 args.set_es = true;
499 });
500 cbs.add("--version", [&args](CLIParser &parser) {
501 args.version = parser.next_uint();
502 args.set_version = true;
503 });
504 cbs.add("--dump-resources", [&args](CLIParser &) { args.dump_resources = true; });
505 cbs.add("--force-temporary", [&args](CLIParser &) { args.force_temporary = true; });
506 cbs.add("--flatten-ubo", [&args](CLIParser &) { args.flatten_ubo = true; });
507 cbs.add("--fixup-clipspace", [&args](CLIParser &) { args.fixup = true; });
508 cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); });
509 cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; });
510 cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); });
511 cbs.add("--metal", [&args](CLIParser &) { args.metal = true; });
512 cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
513 cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200514 cbs.add("--entry", [&args](CLIParser &parser) { args.entry = parser.next_string(); });
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200515 cbs.add("--remap", [&args](CLIParser &parser) {
516 string src = parser.next_string();
517 string dst = parser.next_string();
518 uint32_t components = parser.next_uint();
519 args.remaps.push_back({ move(src), move(dst), components });
520 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100521
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200522 cbs.add("--pls-in", [&args](CLIParser &parser) {
523 auto fmt = pls_format(parser.next_string());
524 auto name = parser.next_string();
525 args.pls_in.push_back({ move(fmt), move(name) });
526 });
527 cbs.add("--pls-out", [&args](CLIParser &parser) {
528 auto fmt = pls_format(parser.next_string());
529 auto name = parser.next_string();
530 args.pls_out.push_back({ move(fmt), move(name) });
531 });
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100532
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200533 cbs.add("--remove-unused-variables", [&args](CLIParser &) { args.remove_unused = true; });
534
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200535 cbs.default_handler = [&args](const char *value) { args.input = value; };
536 cbs.error_handler = [] { print_help(); };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100537
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200538 CLIParser parser{ move(cbs), argc - 1, argv + 1 };
539 if (!parser.parse())
540 {
541 return EXIT_FAILURE;
542 }
543 else if (parser.ended_state)
544 {
545 return EXIT_SUCCESS;
546 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100547
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200548 if (!args.input)
549 {
550 fprintf(stderr, "Didn't specify input file.\n");
551 print_help();
552 return EXIT_FAILURE;
553 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100554
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200555 unique_ptr<CompilerGLSL> compiler;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100556
Hans-Kristian Arntzenbcb55602016-09-10 13:56:36 +0200557 bool combined_image_samplers = false;
558
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200559 if (args.cpp)
560 {
561 compiler = unique_ptr<CompilerGLSL>(new CompilerCPP(read_spirv_file(args.input)));
562 if (args.cpp_interface_name)
563 static_cast<CompilerCPP *>(compiler.get())->set_interface_name(args.cpp_interface_name);
564 }
565 else if (args.metal)
566 compiler = unique_ptr<CompilerMSL>(new CompilerMSL(read_spirv_file(args.input)));
567 else
Hans-Kristian Arntzenbcb55602016-09-10 13:56:36 +0200568 {
569 combined_image_samplers = !args.vulkan_semantics;
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200570 compiler = unique_ptr<CompilerGLSL>(new CompilerGLSL(read_spirv_file(args.input)));
Hans-Kristian Arntzenbcb55602016-09-10 13:56:36 +0200571 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100572
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200573 if (!args.entry.empty())
574 compiler->set_entry_point(args.entry);
575
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200576 if (!args.set_version && !compiler->get_options().version)
577 {
578 fprintf(stderr, "Didn't specify GLSL version and SPIR-V did not specify language.\n");
579 print_help();
580 return EXIT_FAILURE;
581 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100582
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200583 CompilerGLSL::Options opts = compiler->get_options();
584 if (args.set_version)
585 opts.version = args.version;
586 if (args.set_es)
587 opts.es = args.es;
588 opts.force_temporary = args.force_temporary;
589 opts.vulkan_semantics = args.vulkan_semantics;
590 opts.vertex.fixup_clipspace = args.fixup;
591 compiler->set_options(opts);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100592
Hans-Kristian Arntzenf61a5d12016-08-26 12:58:50 +0200593 ShaderResources res;
594 if (args.remove_unused)
595 {
596 auto active = compiler->get_active_interface_variables();
597 res = compiler->get_shader_resources(active);
598 compiler->set_enabled_interface_variables(move(active));
599 }
600 else
601 res = compiler->get_shader_resources();
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100602
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200603 if (args.flatten_ubo)
604 for (auto &ubo : res.uniform_buffers)
605 compiler->flatten_interface_block(ubo.id);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100606
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200607 auto pls_inputs = remap_pls(args.pls_in, res.stage_inputs, &res.subpass_inputs);
608 auto pls_outputs = remap_pls(args.pls_out, res.stage_outputs, nullptr);
609 compiler->remap_pixel_local_storage(move(pls_inputs), move(pls_outputs));
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100610
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200611 for (auto &ext : args.extensions)
612 compiler->require_extension(ext);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100613
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200614 for (auto &remap : args.remaps)
615 {
616 if (remap_generic(*compiler, res.stage_inputs, remap))
617 continue;
618 if (remap_generic(*compiler, res.stage_outputs, remap))
619 continue;
620 if (remap_generic(*compiler, res.subpass_inputs, remap))
621 continue;
622 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100623
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200624 if (args.dump_resources)
625 {
626 print_resources(*compiler, res);
627 print_push_constant_resources(*compiler, res.push_constant_buffers);
628 }
629
Hans-Kristian Arntzenbcb55602016-09-10 13:56:36 +0200630 if (combined_image_samplers)
631 {
632 compiler->build_combined_image_samplers();
633 // Give the remapped combined samplers new names.
634 for (auto &remap : compiler->get_combined_image_samplers())
635 {
Hans-Kristian Arntzen1b5ca8d2016-09-10 16:20:19 +0200636 compiler->set_name(remap.combined_id, join("_Combined", compiler->get_name(remap.image_id),
Hans-Kristian Arntzenbcb55602016-09-10 13:56:36 +0200637 compiler->get_name(remap.sampler_id)));
638 }
639 }
640
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200641 string glsl;
642 for (uint32_t i = 0; i < args.iterations; i++)
643 glsl = compiler->compile();
644
645 if (args.output)
646 write_string_to_file(args.output, glsl.c_str());
647 else
648 printf("%s", glsl.c_str());
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100649}