main.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286
  1. /*
  2. * Copyright 2015-2019 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. #include "spirv_cpp.hpp"
  17. #include "spirv_cross_util.hpp"
  18. #include "spirv_glsl.hpp"
  19. #include "spirv_hlsl.hpp"
  20. #include "spirv_msl.hpp"
  21. #include "spirv_parser.hpp"
  22. #include "spirv_reflect.hpp"
  23. #include <algorithm>
  24. #include <cstdio>
  25. #include <cstring>
  26. #include <functional>
  27. #include <limits>
  28. #include <memory>
  29. #include <stdexcept>
  30. #include <unordered_map>
  31. #include <unordered_set>
  32. #ifdef HAVE_SPIRV_CROSS_GIT_VERSION
  33. #include "gitversion.h"
  34. #endif
  35. #ifdef _MSC_VER
  36. #pragma warning(disable : 4996)
  37. #endif
  38. using namespace spv;
  39. using namespace SPIRV_CROSS_NAMESPACE;
  40. using namespace std;
  41. #ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
  42. static inline void THROW(const char *str)
  43. {
  44. fprintf(stderr, "SPIRV-Cross will abort: %s\n", str);
  45. fflush(stderr);
  46. abort();
  47. }
  48. #else
  49. #define THROW(x) throw runtime_error(x)
  50. #endif
  51. struct CLIParser;
  52. struct CLICallbacks
  53. {
  54. void add(const char *cli, const function<void(CLIParser &)> &func)
  55. {
  56. callbacks[cli] = func;
  57. }
  58. unordered_map<string, function<void(CLIParser &)>> callbacks;
  59. function<void()> error_handler;
  60. function<void(const char *)> default_handler;
  61. };
  62. struct CLIParser
  63. {
  64. CLIParser(CLICallbacks cbs_, int argc_, char *argv_[])
  65. : cbs(move(cbs_))
  66. , argc(argc_)
  67. , argv(argv_)
  68. {
  69. }
  70. bool parse()
  71. {
  72. #ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
  73. try
  74. #endif
  75. {
  76. while (argc && !ended_state)
  77. {
  78. const char *next = *argv++;
  79. argc--;
  80. if (*next != '-' && cbs.default_handler)
  81. {
  82. cbs.default_handler(next);
  83. }
  84. else
  85. {
  86. auto itr = cbs.callbacks.find(next);
  87. if (itr == ::end(cbs.callbacks))
  88. {
  89. THROW("Invalid argument");
  90. }
  91. itr->second(*this);
  92. }
  93. }
  94. return true;
  95. }
  96. #ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
  97. catch (...)
  98. {
  99. if (cbs.error_handler)
  100. {
  101. cbs.error_handler();
  102. }
  103. return false;
  104. }
  105. #endif
  106. }
  107. void end()
  108. {
  109. ended_state = true;
  110. }
  111. uint32_t next_uint()
  112. {
  113. if (!argc)
  114. {
  115. THROW("Tried to parse uint, but nothing left in arguments");
  116. }
  117. uint64_t val = stoul(*argv);
  118. if (val > numeric_limits<uint32_t>::max())
  119. {
  120. THROW("next_uint() out of range");
  121. }
  122. argc--;
  123. argv++;
  124. return uint32_t(val);
  125. }
  126. double next_double()
  127. {
  128. if (!argc)
  129. {
  130. THROW("Tried to parse double, but nothing left in arguments");
  131. }
  132. double val = stod(*argv);
  133. argc--;
  134. argv++;
  135. return val;
  136. }
  137. // Return a string only if it's not prefixed with `--`, otherwise return the default value
  138. const char *next_value_string(const char *default_value)
  139. {
  140. if (!argc)
  141. {
  142. return default_value;
  143. }
  144. if (0 == strncmp("--", *argv, 2))
  145. {
  146. return default_value;
  147. }
  148. return next_string();
  149. }
  150. const char *next_string()
  151. {
  152. if (!argc)
  153. {
  154. THROW("Tried to parse string, but nothing left in arguments");
  155. }
  156. const char *ret = *argv;
  157. argc--;
  158. argv++;
  159. return ret;
  160. }
  161. CLICallbacks cbs;
  162. int argc;
  163. char **argv;
  164. bool ended_state = false;
  165. };
  166. static vector<uint32_t> read_spirv_file(const char *path)
  167. {
  168. FILE *file = fopen(path, "rb");
  169. if (!file)
  170. {
  171. fprintf(stderr, "Failed to open SPIR-V file: %s\n", path);
  172. return {};
  173. }
  174. fseek(file, 0, SEEK_END);
  175. long len = ftell(file) / sizeof(uint32_t);
  176. rewind(file);
  177. vector<uint32_t> spirv(len);
  178. if (fread(spirv.data(), sizeof(uint32_t), len, file) != size_t(len))
  179. spirv.clear();
  180. fclose(file);
  181. return spirv;
  182. }
  183. static bool write_string_to_file(const char *path, const char *string)
  184. {
  185. FILE *file = fopen(path, "w");
  186. if (!file)
  187. {
  188. fprintf(stderr, "Failed to write file: %s\n", path);
  189. return false;
  190. }
  191. fprintf(file, "%s", string);
  192. fclose(file);
  193. return true;
  194. }
  195. static void print_resources(const Compiler &compiler, const char *tag, const SmallVector<Resource> &resources)
  196. {
  197. fprintf(stderr, "%s\n", tag);
  198. fprintf(stderr, "=============\n\n");
  199. bool print_ssbo = !strcmp(tag, "ssbos");
  200. for (auto &res : resources)
  201. {
  202. auto &type = compiler.get_type(res.type_id);
  203. if (print_ssbo && compiler.buffer_is_hlsl_counter_buffer(res.id))
  204. continue;
  205. // If we don't have a name, use the fallback for the type instead of the variable
  206. // for SSBOs and UBOs since those are the only meaningful names to use externally.
  207. // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks.
  208. bool is_push_constant = compiler.get_storage_class(res.id) == StorageClassPushConstant;
  209. bool is_block = compiler.get_decoration_bitset(type.self).get(DecorationBlock) ||
  210. compiler.get_decoration_bitset(type.self).get(DecorationBufferBlock);
  211. bool is_sized_block = is_block && (compiler.get_storage_class(res.id) == StorageClassUniform ||
  212. compiler.get_storage_class(res.id) == StorageClassUniformConstant);
  213. ID fallback_id = !is_push_constant && is_block ? ID(res.base_type_id) : ID(res.id);
  214. uint32_t block_size = 0;
  215. uint32_t runtime_array_stride = 0;
  216. if (is_sized_block)
  217. {
  218. auto &base_type = compiler.get_type(res.base_type_id);
  219. block_size = uint32_t(compiler.get_declared_struct_size(base_type));
  220. runtime_array_stride = uint32_t(compiler.get_declared_struct_size_runtime_array(base_type, 1) -
  221. compiler.get_declared_struct_size_runtime_array(base_type, 0));
  222. }
  223. Bitset mask;
  224. if (print_ssbo)
  225. mask = compiler.get_buffer_block_flags(res.id);
  226. else
  227. mask = compiler.get_decoration_bitset(res.id);
  228. string array;
  229. for (auto arr : type.array)
  230. array = join("[", arr ? convert_to_string(arr) : "", "]") + array;
  231. fprintf(stderr, " ID %03u : %s%s", uint32_t(res.id),
  232. !res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str(), array.c_str());
  233. if (mask.get(DecorationLocation))
  234. fprintf(stderr, " (Location : %u)", compiler.get_decoration(res.id, DecorationLocation));
  235. if (mask.get(DecorationDescriptorSet))
  236. fprintf(stderr, " (Set : %u)", compiler.get_decoration(res.id, DecorationDescriptorSet));
  237. if (mask.get(DecorationBinding))
  238. fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding));
  239. if (mask.get(DecorationInputAttachmentIndex))
  240. fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex));
  241. if (mask.get(DecorationNonReadable))
  242. fprintf(stderr, " writeonly");
  243. if (mask.get(DecorationNonWritable))
  244. fprintf(stderr, " readonly");
  245. if (is_sized_block)
  246. {
  247. fprintf(stderr, " (BlockSize : %u bytes)", block_size);
  248. if (runtime_array_stride)
  249. fprintf(stderr, " (Unsized array stride: %u bytes)", runtime_array_stride);
  250. }
  251. uint32_t counter_id = 0;
  252. if (print_ssbo && compiler.buffer_get_hlsl_counter_buffer(res.id, counter_id))
  253. fprintf(stderr, " (HLSL counter buffer ID: %u)", counter_id);
  254. fprintf(stderr, "\n");
  255. }
  256. fprintf(stderr, "=============\n\n");
  257. }
  258. static const char *execution_model_to_str(spv::ExecutionModel model)
  259. {
  260. switch (model)
  261. {
  262. case spv::ExecutionModelVertex:
  263. return "vertex";
  264. case spv::ExecutionModelTessellationControl:
  265. return "tessellation control";
  266. case ExecutionModelTessellationEvaluation:
  267. return "tessellation evaluation";
  268. case ExecutionModelGeometry:
  269. return "geometry";
  270. case ExecutionModelFragment:
  271. return "fragment";
  272. case ExecutionModelGLCompute:
  273. return "compute";
  274. case ExecutionModelRayGenerationNV:
  275. return "raygenNV";
  276. case ExecutionModelIntersectionNV:
  277. return "intersectionNV";
  278. case ExecutionModelCallableNV:
  279. return "callableNV";
  280. case ExecutionModelAnyHitNV:
  281. return "anyhitNV";
  282. case ExecutionModelClosestHitNV:
  283. return "closesthitNV";
  284. case ExecutionModelMissNV:
  285. return "missNV";
  286. default:
  287. return "???";
  288. }
  289. }
  290. static void print_resources(const Compiler &compiler, const ShaderResources &res)
  291. {
  292. auto &modes = compiler.get_execution_mode_bitset();
  293. fprintf(stderr, "Entry points:\n");
  294. auto entry_points = compiler.get_entry_points_and_stages();
  295. for (auto &e : entry_points)
  296. fprintf(stderr, " %s (%s)\n", e.name.c_str(), execution_model_to_str(e.execution_model));
  297. fprintf(stderr, "\n");
  298. fprintf(stderr, "Execution modes:\n");
  299. modes.for_each_bit([&](uint32_t i) {
  300. auto mode = static_cast<ExecutionMode>(i);
  301. uint32_t arg0 = compiler.get_execution_mode_argument(mode, 0);
  302. uint32_t arg1 = compiler.get_execution_mode_argument(mode, 1);
  303. uint32_t arg2 = compiler.get_execution_mode_argument(mode, 2);
  304. switch (static_cast<ExecutionMode>(i))
  305. {
  306. case ExecutionModeInvocations:
  307. fprintf(stderr, " Invocations: %u\n", arg0);
  308. break;
  309. case ExecutionModeLocalSize:
  310. fprintf(stderr, " LocalSize: (%u, %u, %u)\n", arg0, arg1, arg2);
  311. break;
  312. case ExecutionModeOutputVertices:
  313. fprintf(stderr, " OutputVertices: %u\n", arg0);
  314. break;
  315. #define CHECK_MODE(m) \
  316. case ExecutionMode##m: \
  317. fprintf(stderr, " %s\n", #m); \
  318. break
  319. CHECK_MODE(SpacingEqual);
  320. CHECK_MODE(SpacingFractionalEven);
  321. CHECK_MODE(SpacingFractionalOdd);
  322. CHECK_MODE(VertexOrderCw);
  323. CHECK_MODE(VertexOrderCcw);
  324. CHECK_MODE(PixelCenterInteger);
  325. CHECK_MODE(OriginUpperLeft);
  326. CHECK_MODE(OriginLowerLeft);
  327. CHECK_MODE(EarlyFragmentTests);
  328. CHECK_MODE(PointMode);
  329. CHECK_MODE(Xfb);
  330. CHECK_MODE(DepthReplacing);
  331. CHECK_MODE(DepthGreater);
  332. CHECK_MODE(DepthLess);
  333. CHECK_MODE(DepthUnchanged);
  334. CHECK_MODE(LocalSizeHint);
  335. CHECK_MODE(InputPoints);
  336. CHECK_MODE(InputLines);
  337. CHECK_MODE(InputLinesAdjacency);
  338. CHECK_MODE(Triangles);
  339. CHECK_MODE(InputTrianglesAdjacency);
  340. CHECK_MODE(Quads);
  341. CHECK_MODE(Isolines);
  342. CHECK_MODE(OutputPoints);
  343. CHECK_MODE(OutputLineStrip);
  344. CHECK_MODE(OutputTriangleStrip);
  345. CHECK_MODE(VecTypeHint);
  346. CHECK_MODE(ContractionOff);
  347. default:
  348. break;
  349. }
  350. });
  351. fprintf(stderr, "\n");
  352. print_resources(compiler, "subpass inputs", res.subpass_inputs);
  353. print_resources(compiler, "inputs", res.stage_inputs);
  354. print_resources(compiler, "outputs", res.stage_outputs);
  355. print_resources(compiler, "textures", res.sampled_images);
  356. print_resources(compiler, "separate images", res.separate_images);
  357. print_resources(compiler, "separate samplers", res.separate_samplers);
  358. print_resources(compiler, "images", res.storage_images);
  359. print_resources(compiler, "ssbos", res.storage_buffers);
  360. print_resources(compiler, "ubos", res.uniform_buffers);
  361. print_resources(compiler, "push", res.push_constant_buffers);
  362. print_resources(compiler, "counters", res.atomic_counters);
  363. print_resources(compiler, "acceleration structures", res.acceleration_structures);
  364. }
  365. static void print_push_constant_resources(const Compiler &compiler, const SmallVector<Resource> &res)
  366. {
  367. for (auto &block : res)
  368. {
  369. auto ranges = compiler.get_active_buffer_ranges(block.id);
  370. fprintf(stderr, "Active members in buffer: %s\n",
  371. !block.name.empty() ? block.name.c_str() : compiler.get_fallback_name(block.id).c_str());
  372. fprintf(stderr, "==================\n\n");
  373. for (auto &range : ranges)
  374. {
  375. const auto &name = compiler.get_member_name(block.base_type_id, range.index);
  376. fprintf(stderr, "Member #%3u (%s): Offset: %4u, Range: %4u\n", range.index,
  377. !name.empty() ? name.c_str() : compiler.get_fallback_member_name(range.index).c_str(),
  378. unsigned(range.offset), unsigned(range.range));
  379. }
  380. fprintf(stderr, "==================\n\n");
  381. }
  382. }
  383. static void print_spec_constants(const Compiler &compiler)
  384. {
  385. auto spec_constants = compiler.get_specialization_constants();
  386. fprintf(stderr, "Specialization constants\n");
  387. fprintf(stderr, "==================\n\n");
  388. for (auto &c : spec_constants)
  389. fprintf(stderr, "ID: %u, Spec ID: %u\n", uint32_t(c.id), c.constant_id);
  390. fprintf(stderr, "==================\n\n");
  391. }
  392. static void print_capabilities_and_extensions(const Compiler &compiler)
  393. {
  394. fprintf(stderr, "Capabilities\n");
  395. fprintf(stderr, "============\n");
  396. for (auto &capability : compiler.get_declared_capabilities())
  397. fprintf(stderr, "Capability: %u\n", static_cast<unsigned>(capability));
  398. fprintf(stderr, "============\n\n");
  399. fprintf(stderr, "Extensions\n");
  400. fprintf(stderr, "============\n");
  401. for (auto &ext : compiler.get_declared_extensions())
  402. fprintf(stderr, "Extension: %s\n", ext.c_str());
  403. fprintf(stderr, "============\n\n");
  404. }
  405. struct PLSArg
  406. {
  407. PlsFormat format;
  408. string name;
  409. };
  410. struct Remap
  411. {
  412. string src_name;
  413. string dst_name;
  414. unsigned components;
  415. };
  416. struct VariableTypeRemap
  417. {
  418. string variable_name;
  419. string new_variable_type;
  420. };
  421. struct InterfaceVariableRename
  422. {
  423. StorageClass storageClass;
  424. uint32_t location;
  425. string variable_name;
  426. };
  427. struct CLIArguments
  428. {
  429. const char *input = nullptr;
  430. const char *output = nullptr;
  431. const char *cpp_interface_name = nullptr;
  432. uint32_t version = 0;
  433. uint32_t shader_model = 0;
  434. uint32_t msl_version = 0;
  435. bool es = false;
  436. bool set_version = false;
  437. bool set_shader_model = false;
  438. bool set_msl_version = false;
  439. bool set_es = false;
  440. bool dump_resources = false;
  441. bool force_temporary = false;
  442. bool flatten_ubo = false;
  443. bool fixup = false;
  444. bool yflip = false;
  445. bool sso = false;
  446. bool support_nonzero_baseinstance = true;
  447. bool msl_capture_output_to_buffer = false;
  448. bool msl_swizzle_texture_samples = false;
  449. bool msl_ios = false;
  450. bool msl_pad_fragment_output = false;
  451. bool msl_domain_lower_left = false;
  452. bool msl_argument_buffers = false;
  453. bool msl_texture_buffer_native = false;
  454. bool msl_framebuffer_fetch = false;
  455. bool msl_invariant_float_math = false;
  456. bool msl_emulate_cube_array = false;
  457. bool msl_multiview = false;
  458. bool msl_view_index_from_device_index = false;
  459. bool msl_dispatch_base = false;
  460. bool glsl_emit_push_constant_as_ubo = false;
  461. bool glsl_emit_ubo_as_plain_uniforms = false;
  462. bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
  463. bool emit_line_directives = false;
  464. SmallVector<uint32_t> msl_discrete_descriptor_sets;
  465. SmallVector<uint32_t> msl_device_argument_buffers;
  466. SmallVector<pair<uint32_t, uint32_t>> msl_dynamic_buffers;
  467. SmallVector<PLSArg> pls_in;
  468. SmallVector<PLSArg> pls_out;
  469. SmallVector<Remap> remaps;
  470. SmallVector<string> extensions;
  471. SmallVector<VariableTypeRemap> variable_type_remaps;
  472. SmallVector<InterfaceVariableRename> interface_variable_renames;
  473. SmallVector<HLSLVertexAttributeRemap> hlsl_attr_remap;
  474. string entry;
  475. string entry_stage;
  476. struct Rename
  477. {
  478. string old_name;
  479. string new_name;
  480. ExecutionModel execution_model;
  481. };
  482. SmallVector<Rename> entry_point_rename;
  483. uint32_t iterations = 1;
  484. bool cpp = false;
  485. string reflect;
  486. bool msl = false;
  487. bool hlsl = false;
  488. bool hlsl_compat = false;
  489. bool hlsl_support_nonzero_base = false;
  490. HLSLBindingFlags hlsl_binding_flags = 0;
  491. bool vulkan_semantics = false;
  492. bool flatten_multidimensional_arrays = false;
  493. bool use_420pack_extension = true;
  494. bool remove_unused = false;
  495. bool combined_samplers_inherit_bindings = false;
  496. };
  497. static void print_version()
  498. {
  499. #ifdef HAVE_SPIRV_CROSS_GIT_VERSION
  500. fprintf(stderr, "%s\n", SPIRV_CROSS_GIT_REVISION);
  501. #else
  502. fprintf(stderr, "Git revision unknown. Build with CMake to create timestamp and revision info.\n");
  503. #endif
  504. }
  505. static void print_help()
  506. {
  507. print_version();
  508. fprintf(stderr, "Usage: spirv-cross\n"
  509. "\t[--output <output path>]\n"
  510. "\t[SPIR-V file]\n"
  511. "\t[--es]\n"
  512. "\t[--no-es]\n"
  513. "\t[--version <GLSL version>]\n"
  514. "\t[--dump-resources]\n"
  515. "\t[--help]\n"
  516. "\t[--revision]\n"
  517. "\t[--force-temporary]\n"
  518. "\t[--vulkan-semantics]\n"
  519. "\t[--flatten-ubo]\n"
  520. "\t[--fixup-clipspace]\n"
  521. "\t[--flip-vert-y]\n"
  522. "\t[--iterations iter]\n"
  523. "\t[--cpp]\n"
  524. "\t[--cpp-interface-name <name>]\n"
  525. "\t[--glsl-emit-push-constant-as-ubo]\n"
  526. "\t[--glsl-emit-ubo-as-plain-uniforms]\n"
  527. "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]\n"
  528. "\t[--msl]\n"
  529. "\t[--msl-version <MMmmpp>]\n"
  530. "\t[--msl-capture-output]\n"
  531. "\t[--msl-swizzle-texture-samples]\n"
  532. "\t[--msl-ios]\n"
  533. "\t[--msl-pad-fragment-output]\n"
  534. "\t[--msl-domain-lower-left]\n"
  535. "\t[--msl-argument-buffers]\n"
  536. "\t[--msl-texture-buffer-native]\n"
  537. "\t[--msl-framebuffer-fetch]\n"
  538. "\t[--msl-emulate-cube-array]\n"
  539. "\t[--msl-discrete-descriptor-set <index>]\n"
  540. "\t[--msl-device-argument-buffer <index>]\n"
  541. "\t[--msl-multiview]\n"
  542. "\t[--msl-view-index-from-device-index]\n"
  543. "\t[--msl-dispatch-base]\n"
  544. "\t[--msl-dynamic-buffer <set index> <binding>]\n"
  545. "\t[--hlsl]\n"
  546. "\t[--reflect]\n"
  547. "\t[--shader-model]\n"
  548. "\t[--hlsl-enable-compat]\n"
  549. "\t[--hlsl-support-nonzero-basevertex-baseinstance]\n"
  550. "\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n"
  551. "\t[--separate-shader-objects]\n"
  552. "\t[--pls-in format input-name]\n"
  553. "\t[--pls-out format output-name]\n"
  554. "\t[--remap source_name target_name components]\n"
  555. "\t[--extension ext]\n"
  556. "\t[--entry name]\n"
  557. "\t[--stage <stage (vert, frag, geom, tesc, tese comp)>]\n"
  558. "\t[--remove-unused-variables]\n"
  559. "\t[--flatten-multidimensional-arrays]\n"
  560. "\t[--no-420pack-extension]\n"
  561. "\t[--remap-variable-type <variable_name> <new_variable_type>]\n"
  562. "\t[--rename-interface-variable <in|out> <location> <new_variable_name>]\n"
  563. "\t[--set-hlsl-vertex-input-semantic <location> <semantic>]\n"
  564. "\t[--rename-entry-point <old> <new> <stage>]\n"
  565. "\t[--combined-samplers-inherit-bindings]\n"
  566. "\t[--no-support-nonzero-baseinstance]\n"
  567. "\t[--emit-line-directives]\n"
  568. "\n");
  569. }
  570. static bool remap_generic(Compiler &compiler, const SmallVector<Resource> &resources, const Remap &remap)
  571. {
  572. auto itr =
  573. find_if(begin(resources), end(resources), [&remap](const Resource &res) { return res.name == remap.src_name; });
  574. if (itr != end(resources))
  575. {
  576. compiler.set_remapped_variable_state(itr->id, true);
  577. compiler.set_name(itr->id, remap.dst_name);
  578. compiler.set_subpass_input_remapped_components(itr->id, remap.components);
  579. return true;
  580. }
  581. else
  582. return false;
  583. }
  584. static vector<PlsRemap> remap_pls(const SmallVector<PLSArg> &pls_variables, const SmallVector<Resource> &resources,
  585. const SmallVector<Resource> *secondary_resources)
  586. {
  587. vector<PlsRemap> ret;
  588. for (auto &pls : pls_variables)
  589. {
  590. bool found = false;
  591. for (auto &res : resources)
  592. {
  593. if (res.name == pls.name)
  594. {
  595. ret.push_back({ res.id, pls.format });
  596. found = true;
  597. break;
  598. }
  599. }
  600. if (!found && secondary_resources)
  601. {
  602. for (auto &res : *secondary_resources)
  603. {
  604. if (res.name == pls.name)
  605. {
  606. ret.push_back({ res.id, pls.format });
  607. found = true;
  608. break;
  609. }
  610. }
  611. }
  612. if (!found)
  613. fprintf(stderr, "Did not find stage input/output/target with name \"%s\".\n", pls.name.c_str());
  614. }
  615. return ret;
  616. }
  617. static PlsFormat pls_format(const char *str)
  618. {
  619. if (!strcmp(str, "r11f_g11f_b10f"))
  620. return PlsR11FG11FB10F;
  621. else if (!strcmp(str, "r32f"))
  622. return PlsR32F;
  623. else if (!strcmp(str, "rg16f"))
  624. return PlsRG16F;
  625. else if (!strcmp(str, "rg16"))
  626. return PlsRG16;
  627. else if (!strcmp(str, "rgb10_a2"))
  628. return PlsRGB10A2;
  629. else if (!strcmp(str, "rgba8"))
  630. return PlsRGBA8;
  631. else if (!strcmp(str, "rgba8i"))
  632. return PlsRGBA8I;
  633. else if (!strcmp(str, "rgba8ui"))
  634. return PlsRGBA8UI;
  635. else if (!strcmp(str, "rg16i"))
  636. return PlsRG16I;
  637. else if (!strcmp(str, "rgb10_a2ui"))
  638. return PlsRGB10A2UI;
  639. else if (!strcmp(str, "rg16ui"))
  640. return PlsRG16UI;
  641. else if (!strcmp(str, "r32ui"))
  642. return PlsR32UI;
  643. else
  644. return PlsNone;
  645. }
  646. static ExecutionModel stage_to_execution_model(const std::string &stage)
  647. {
  648. if (stage == "vert")
  649. return ExecutionModelVertex;
  650. else if (stage == "frag")
  651. return ExecutionModelFragment;
  652. else if (stage == "comp")
  653. return ExecutionModelGLCompute;
  654. else if (stage == "tesc")
  655. return ExecutionModelTessellationControl;
  656. else if (stage == "tese")
  657. return ExecutionModelTessellationEvaluation;
  658. else if (stage == "geom")
  659. return ExecutionModelGeometry;
  660. else
  661. SPIRV_CROSS_THROW("Invalid stage.");
  662. }
  663. static HLSLBindingFlags hlsl_resource_type_to_flag(const std::string &arg)
  664. {
  665. if (arg == "push")
  666. return HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT;
  667. else if (arg == "cbv")
  668. return HLSL_BINDING_AUTO_CBV_BIT;
  669. else if (arg == "srv")
  670. return HLSL_BINDING_AUTO_SRV_BIT;
  671. else if (arg == "uav")
  672. return HLSL_BINDING_AUTO_UAV_BIT;
  673. else if (arg == "sampler")
  674. return HLSL_BINDING_AUTO_SAMPLER_BIT;
  675. else if (arg == "all")
  676. return HLSL_BINDING_AUTO_ALL;
  677. else
  678. {
  679. fprintf(stderr, "Invalid resource type for --hlsl-auto-binding: %s\n", arg.c_str());
  680. return 0;
  681. }
  682. }
  683. static string compile_iteration(const CLIArguments &args, std::vector<uint32_t> spirv_file)
  684. {
  685. Parser spirv_parser(move(spirv_file));
  686. spirv_parser.parse();
  687. unique_ptr<CompilerGLSL> compiler;
  688. bool combined_image_samplers = false;
  689. bool build_dummy_sampler = false;
  690. if (args.cpp)
  691. {
  692. compiler.reset(new CompilerCPP(move(spirv_parser.get_parsed_ir())));
  693. if (args.cpp_interface_name)
  694. static_cast<CompilerCPP *>(compiler.get())->set_interface_name(args.cpp_interface_name);
  695. }
  696. else if (args.msl)
  697. {
  698. compiler.reset(new CompilerMSL(move(spirv_parser.get_parsed_ir())));
  699. auto *msl_comp = static_cast<CompilerMSL *>(compiler.get());
  700. auto msl_opts = msl_comp->get_msl_options();
  701. if (args.set_msl_version)
  702. msl_opts.msl_version = args.msl_version;
  703. msl_opts.capture_output_to_buffer = args.msl_capture_output_to_buffer;
  704. msl_opts.swizzle_texture_samples = args.msl_swizzle_texture_samples;
  705. msl_opts.invariant_float_math = args.msl_invariant_float_math;
  706. if (args.msl_ios)
  707. {
  708. msl_opts.platform = CompilerMSL::Options::iOS;
  709. msl_opts.ios_use_framebuffer_fetch_subpasses = args.msl_framebuffer_fetch;
  710. msl_opts.emulate_cube_array = args.msl_emulate_cube_array;
  711. }
  712. msl_opts.pad_fragment_output_components = args.msl_pad_fragment_output;
  713. msl_opts.tess_domain_origin_lower_left = args.msl_domain_lower_left;
  714. msl_opts.argument_buffers = args.msl_argument_buffers;
  715. msl_opts.texture_buffer_native = args.msl_texture_buffer_native;
  716. msl_opts.multiview = args.msl_multiview;
  717. msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index;
  718. msl_opts.dispatch_base = args.msl_dispatch_base;
  719. msl_comp->set_msl_options(msl_opts);
  720. for (auto &v : args.msl_discrete_descriptor_sets)
  721. msl_comp->add_discrete_descriptor_set(v);
  722. for (auto &v : args.msl_device_argument_buffers)
  723. msl_comp->set_argument_buffer_device_address_space(v, true);
  724. uint32_t i = 0;
  725. for (auto &v : args.msl_dynamic_buffers)
  726. msl_comp->add_dynamic_buffer(v.first, v.second, i++);
  727. }
  728. else if (args.hlsl)
  729. compiler.reset(new CompilerHLSL(move(spirv_parser.get_parsed_ir())));
  730. else
  731. {
  732. combined_image_samplers = !args.vulkan_semantics;
  733. if (!args.vulkan_semantics || args.vulkan_glsl_disable_ext_samplerless_texture_functions)
  734. build_dummy_sampler = true;
  735. compiler.reset(new CompilerGLSL(move(spirv_parser.get_parsed_ir())));
  736. }
  737. if (!args.variable_type_remaps.empty())
  738. {
  739. auto remap_cb = [&](const SPIRType &, const string &name, string &out) -> void {
  740. for (const VariableTypeRemap &remap : args.variable_type_remaps)
  741. if (name == remap.variable_name)
  742. out = remap.new_variable_type;
  743. };
  744. compiler->set_variable_type_remap_callback(move(remap_cb));
  745. }
  746. for (auto &rename : args.entry_point_rename)
  747. compiler->rename_entry_point(rename.old_name, rename.new_name, rename.execution_model);
  748. auto entry_points = compiler->get_entry_points_and_stages();
  749. auto entry_point = args.entry;
  750. ExecutionModel model = ExecutionModelMax;
  751. if (!args.entry_stage.empty())
  752. {
  753. model = stage_to_execution_model(args.entry_stage);
  754. if (entry_point.empty())
  755. {
  756. // Just use the first entry point with this stage.
  757. for (auto &e : entry_points)
  758. {
  759. if (e.execution_model == model)
  760. {
  761. entry_point = e.name;
  762. break;
  763. }
  764. }
  765. if (entry_point.empty())
  766. {
  767. fprintf(stderr, "Could not find an entry point with stage: %s\n", args.entry_stage.c_str());
  768. exit(EXIT_FAILURE);
  769. }
  770. }
  771. else
  772. {
  773. // Make sure both stage and name exists.
  774. bool exists = false;
  775. for (auto &e : entry_points)
  776. {
  777. if (e.execution_model == model && e.name == entry_point)
  778. {
  779. exists = true;
  780. break;
  781. }
  782. }
  783. if (!exists)
  784. {
  785. fprintf(stderr, "Could not find an entry point %s with stage: %s\n", entry_point.c_str(),
  786. args.entry_stage.c_str());
  787. exit(EXIT_FAILURE);
  788. }
  789. }
  790. }
  791. else if (!entry_point.empty())
  792. {
  793. // Make sure there is just one entry point with this name, or the stage
  794. // is ambiguous.
  795. uint32_t stage_count = 0;
  796. for (auto &e : entry_points)
  797. {
  798. if (e.name == entry_point)
  799. {
  800. stage_count++;
  801. model = e.execution_model;
  802. }
  803. }
  804. if (stage_count == 0)
  805. {
  806. fprintf(stderr, "There is no entry point with name: %s\n", entry_point.c_str());
  807. exit(EXIT_FAILURE);
  808. }
  809. else if (stage_count > 1)
  810. {
  811. fprintf(stderr, "There is more than one entry point with name: %s. Use --stage.\n", entry_point.c_str());
  812. exit(EXIT_FAILURE);
  813. }
  814. }
  815. if (!entry_point.empty())
  816. compiler->set_entry_point(entry_point, model);
  817. if (!args.set_version && !compiler->get_common_options().version)
  818. {
  819. fprintf(stderr, "Didn't specify GLSL version and SPIR-V did not specify language.\n");
  820. print_help();
  821. exit(EXIT_FAILURE);
  822. }
  823. CompilerGLSL::Options opts = compiler->get_common_options();
  824. if (args.set_version)
  825. opts.version = args.version;
  826. if (args.set_es)
  827. opts.es = args.es;
  828. opts.force_temporary = args.force_temporary;
  829. opts.separate_shader_objects = args.sso;
  830. opts.flatten_multidimensional_arrays = args.flatten_multidimensional_arrays;
  831. opts.enable_420pack_extension = args.use_420pack_extension;
  832. opts.vulkan_semantics = args.vulkan_semantics;
  833. opts.vertex.fixup_clipspace = args.fixup;
  834. opts.vertex.flip_vert_y = args.yflip;
  835. opts.vertex.support_nonzero_base_instance = args.support_nonzero_baseinstance;
  836. opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo;
  837. opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms;
  838. opts.emit_line_directives = args.emit_line_directives;
  839. compiler->set_common_options(opts);
  840. // Set HLSL specific options.
  841. if (args.hlsl)
  842. {
  843. auto *hlsl = static_cast<CompilerHLSL *>(compiler.get());
  844. auto hlsl_opts = hlsl->get_hlsl_options();
  845. if (args.set_shader_model)
  846. {
  847. if (args.shader_model < 30)
  848. {
  849. fprintf(stderr, "Shader model earlier than 30 (3.0) not supported.\n");
  850. exit(EXIT_FAILURE);
  851. }
  852. hlsl_opts.shader_model = args.shader_model;
  853. }
  854. if (args.hlsl_compat)
  855. {
  856. // Enable all compat options.
  857. hlsl_opts.point_size_compat = true;
  858. hlsl_opts.point_coord_compat = true;
  859. }
  860. if (hlsl_opts.shader_model <= 30)
  861. {
  862. combined_image_samplers = true;
  863. build_dummy_sampler = true;
  864. }
  865. hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base;
  866. hlsl->set_hlsl_options(hlsl_opts);
  867. hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
  868. }
  869. if (build_dummy_sampler)
  870. {
  871. uint32_t sampler = compiler->build_dummy_sampler_for_combined_images();
  872. if (sampler != 0)
  873. {
  874. // Set some defaults to make validation happy.
  875. compiler->set_decoration(sampler, DecorationDescriptorSet, 0);
  876. compiler->set_decoration(sampler, DecorationBinding, 0);
  877. }
  878. }
  879. ShaderResources res;
  880. if (args.remove_unused)
  881. {
  882. auto active = compiler->get_active_interface_variables();
  883. res = compiler->get_shader_resources(active);
  884. compiler->set_enabled_interface_variables(move(active));
  885. }
  886. else
  887. res = compiler->get_shader_resources();
  888. if (args.flatten_ubo)
  889. {
  890. for (auto &ubo : res.uniform_buffers)
  891. compiler->flatten_buffer_block(ubo.id);
  892. for (auto &ubo : res.push_constant_buffers)
  893. compiler->flatten_buffer_block(ubo.id);
  894. }
  895. auto pls_inputs = remap_pls(args.pls_in, res.stage_inputs, &res.subpass_inputs);
  896. auto pls_outputs = remap_pls(args.pls_out, res.stage_outputs, nullptr);
  897. compiler->remap_pixel_local_storage(move(pls_inputs), move(pls_outputs));
  898. for (auto &ext : args.extensions)
  899. compiler->require_extension(ext);
  900. for (auto &remap : args.remaps)
  901. {
  902. if (remap_generic(*compiler, res.stage_inputs, remap))
  903. continue;
  904. if (remap_generic(*compiler, res.stage_outputs, remap))
  905. continue;
  906. if (remap_generic(*compiler, res.subpass_inputs, remap))
  907. continue;
  908. }
  909. for (auto &rename : args.interface_variable_renames)
  910. {
  911. if (rename.storageClass == StorageClassInput)
  912. spirv_cross_util::rename_interface_variable(*compiler, res.stage_inputs, rename.location,
  913. rename.variable_name);
  914. else if (rename.storageClass == StorageClassOutput)
  915. spirv_cross_util::rename_interface_variable(*compiler, res.stage_outputs, rename.location,
  916. rename.variable_name);
  917. else
  918. {
  919. fprintf(stderr, "error at --rename-interface-variable <in|out> ...\n");
  920. exit(EXIT_FAILURE);
  921. }
  922. }
  923. if (args.dump_resources)
  924. {
  925. print_resources(*compiler, res);
  926. print_push_constant_resources(*compiler, res.push_constant_buffers);
  927. print_spec_constants(*compiler);
  928. print_capabilities_and_extensions(*compiler);
  929. }
  930. if (combined_image_samplers)
  931. {
  932. compiler->build_combined_image_samplers();
  933. if (args.combined_samplers_inherit_bindings)
  934. spirv_cross_util::inherit_combined_sampler_bindings(*compiler);
  935. // Give the remapped combined samplers new names.
  936. for (auto &remap : compiler->get_combined_image_samplers())
  937. {
  938. compiler->set_name(remap.combined_id, join("SPIRV_Cross_Combined", compiler->get_name(remap.image_id),
  939. compiler->get_name(remap.sampler_id)));
  940. }
  941. }
  942. if (args.hlsl)
  943. {
  944. auto *hlsl_compiler = static_cast<CompilerHLSL *>(compiler.get());
  945. uint32_t new_builtin = hlsl_compiler->remap_num_workgroups_builtin();
  946. if (new_builtin)
  947. {
  948. hlsl_compiler->set_decoration(new_builtin, DecorationDescriptorSet, 0);
  949. hlsl_compiler->set_decoration(new_builtin, DecorationBinding, 0);
  950. }
  951. }
  952. if (args.hlsl)
  953. {
  954. for (auto &remap : args.hlsl_attr_remap)
  955. static_cast<CompilerHLSL *>(compiler.get())->add_vertex_attribute_remap(remap);
  956. }
  957. return compiler->compile();
  958. }
  959. static int main_inner(int argc, char *argv[])
  960. {
  961. CLIArguments args;
  962. CLICallbacks cbs;
  963. cbs.add("--help", [](CLIParser &parser) {
  964. print_help();
  965. parser.end();
  966. });
  967. cbs.add("--revision", [](CLIParser &parser) {
  968. print_version();
  969. parser.end();
  970. });
  971. cbs.add("--output", [&args](CLIParser &parser) { args.output = parser.next_string(); });
  972. cbs.add("--es", [&args](CLIParser &) {
  973. args.es = true;
  974. args.set_es = true;
  975. });
  976. cbs.add("--no-es", [&args](CLIParser &) {
  977. args.es = false;
  978. args.set_es = true;
  979. });
  980. cbs.add("--version", [&args](CLIParser &parser) {
  981. args.version = parser.next_uint();
  982. args.set_version = true;
  983. });
  984. cbs.add("--dump-resources", [&args](CLIParser &) { args.dump_resources = true; });
  985. cbs.add("--force-temporary", [&args](CLIParser &) { args.force_temporary = true; });
  986. cbs.add("--flatten-ubo", [&args](CLIParser &) { args.flatten_ubo = true; });
  987. cbs.add("--fixup-clipspace", [&args](CLIParser &) { args.fixup = true; });
  988. cbs.add("--flip-vert-y", [&args](CLIParser &) { args.yflip = true; });
  989. cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); });
  990. cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; });
  991. cbs.add("--reflect", [&args](CLIParser &parser) { args.reflect = parser.next_value_string("json"); });
  992. cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); });
  993. cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility
  994. cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; });
  995. cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; });
  996. cbs.add("--vulkan-glsl-disable-ext-samplerless-texture-functions",
  997. [&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = true; });
  998. cbs.add("--msl", [&args](CLIParser &) { args.msl = true; });
  999. cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; });
  1000. cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
  1001. cbs.add("--hlsl-support-nonzero-basevertex-baseinstance",
  1002. [&args](CLIParser &) { args.hlsl_support_nonzero_base = true; });
  1003. cbs.add("--hlsl-auto-binding", [&args](CLIParser &parser) {
  1004. args.hlsl_binding_flags |= hlsl_resource_type_to_flag(parser.next_string());
  1005. });
  1006. cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
  1007. cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
  1008. cbs.add("--no-420pack-extension", [&args](CLIParser &) { args.use_420pack_extension = false; });
  1009. cbs.add("--msl-capture-output", [&args](CLIParser &) { args.msl_capture_output_to_buffer = true; });
  1010. cbs.add("--msl-swizzle-texture-samples", [&args](CLIParser &) { args.msl_swizzle_texture_samples = true; });
  1011. cbs.add("--msl-ios", [&args](CLIParser &) { args.msl_ios = true; });
  1012. cbs.add("--msl-pad-fragment-output", [&args](CLIParser &) { args.msl_pad_fragment_output = true; });
  1013. cbs.add("--msl-domain-lower-left", [&args](CLIParser &) { args.msl_domain_lower_left = true; });
  1014. cbs.add("--msl-argument-buffers", [&args](CLIParser &) { args.msl_argument_buffers = true; });
  1015. cbs.add("--msl-discrete-descriptor-set",
  1016. [&args](CLIParser &parser) { args.msl_discrete_descriptor_sets.push_back(parser.next_uint()); });
  1017. cbs.add("--msl-device-argument-buffer",
  1018. [&args](CLIParser &parser) { args.msl_device_argument_buffers.push_back(parser.next_uint()); });
  1019. cbs.add("--msl-texture-buffer-native", [&args](CLIParser &) { args.msl_texture_buffer_native = true; });
  1020. cbs.add("--msl-framebuffer-fetch", [&args](CLIParser &) { args.msl_framebuffer_fetch = true; });
  1021. cbs.add("--msl-invariant-float-math", [&args](CLIParser &) { args.msl_invariant_float_math = true; });
  1022. cbs.add("--msl-emulate-cube-array", [&args](CLIParser &) { args.msl_emulate_cube_array = true; });
  1023. cbs.add("--msl-multiview", [&args](CLIParser &) { args.msl_multiview = true; });
  1024. cbs.add("--msl-view-index-from-device-index",
  1025. [&args](CLIParser &) { args.msl_view_index_from_device_index = true; });
  1026. cbs.add("--msl-dispatch-base", [&args](CLIParser &) { args.msl_dispatch_base = true; });
  1027. cbs.add("--msl-dynamic-buffer", [&args](CLIParser &parser) {
  1028. args.msl_argument_buffers = true;
  1029. // Make sure next_uint() is called in-order.
  1030. uint32_t desc_set = parser.next_uint();
  1031. uint32_t binding = parser.next_uint();
  1032. args.msl_dynamic_buffers.push_back(make_pair(desc_set, binding));
  1033. });
  1034. cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
  1035. cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
  1036. auto old_name = parser.next_string();
  1037. auto new_name = parser.next_string();
  1038. auto model = stage_to_execution_model(parser.next_string());
  1039. args.entry_point_rename.push_back({ old_name, new_name, move(model) });
  1040. });
  1041. cbs.add("--entry", [&args](CLIParser &parser) { args.entry = parser.next_string(); });
  1042. cbs.add("--stage", [&args](CLIParser &parser) { args.entry_stage = parser.next_string(); });
  1043. cbs.add("--separate-shader-objects", [&args](CLIParser &) { args.sso = true; });
  1044. cbs.add("--set-hlsl-vertex-input-semantic", [&args](CLIParser &parser) {
  1045. HLSLVertexAttributeRemap remap;
  1046. remap.location = parser.next_uint();
  1047. remap.semantic = parser.next_string();
  1048. args.hlsl_attr_remap.push_back(move(remap));
  1049. });
  1050. cbs.add("--remap", [&args](CLIParser &parser) {
  1051. string src = parser.next_string();
  1052. string dst = parser.next_string();
  1053. uint32_t components = parser.next_uint();
  1054. args.remaps.push_back({ move(src), move(dst), components });
  1055. });
  1056. cbs.add("--remap-variable-type", [&args](CLIParser &parser) {
  1057. string var_name = parser.next_string();
  1058. string new_type = parser.next_string();
  1059. args.variable_type_remaps.push_back({ move(var_name), move(new_type) });
  1060. });
  1061. cbs.add("--rename-interface-variable", [&args](CLIParser &parser) {
  1062. StorageClass cls = StorageClassMax;
  1063. string clsStr = parser.next_string();
  1064. if (clsStr == "in")
  1065. cls = StorageClassInput;
  1066. else if (clsStr == "out")
  1067. cls = StorageClassOutput;
  1068. uint32_t loc = parser.next_uint();
  1069. string var_name = parser.next_string();
  1070. args.interface_variable_renames.push_back({ cls, loc, move(var_name) });
  1071. });
  1072. cbs.add("--pls-in", [&args](CLIParser &parser) {
  1073. auto fmt = pls_format(parser.next_string());
  1074. auto name = parser.next_string();
  1075. args.pls_in.push_back({ move(fmt), move(name) });
  1076. });
  1077. cbs.add("--pls-out", [&args](CLIParser &parser) {
  1078. auto fmt = pls_format(parser.next_string());
  1079. auto name = parser.next_string();
  1080. args.pls_out.push_back({ move(fmt), move(name) });
  1081. });
  1082. cbs.add("--shader-model", [&args](CLIParser &parser) {
  1083. args.shader_model = parser.next_uint();
  1084. args.set_shader_model = true;
  1085. });
  1086. cbs.add("--msl-version", [&args](CLIParser &parser) {
  1087. args.msl_version = parser.next_uint();
  1088. args.set_msl_version = true;
  1089. });
  1090. cbs.add("--remove-unused-variables", [&args](CLIParser &) { args.remove_unused = true; });
  1091. cbs.add("--combined-samplers-inherit-bindings",
  1092. [&args](CLIParser &) { args.combined_samplers_inherit_bindings = true; });
  1093. cbs.add("--no-support-nonzero-baseinstance", [&](CLIParser &) { args.support_nonzero_baseinstance = false; });
  1094. cbs.add("--emit-line-directives", [&args](CLIParser &) { args.emit_line_directives = true; });
  1095. cbs.default_handler = [&args](const char *value) { args.input = value; };
  1096. cbs.error_handler = [] { print_help(); };
  1097. CLIParser parser{ move(cbs), argc - 1, argv + 1 };
  1098. if (!parser.parse())
  1099. return EXIT_FAILURE;
  1100. else if (parser.ended_state)
  1101. return EXIT_SUCCESS;
  1102. if (!args.input)
  1103. {
  1104. fprintf(stderr, "Didn't specify input file.\n");
  1105. print_help();
  1106. return EXIT_FAILURE;
  1107. }
  1108. auto spirv_file = read_spirv_file(args.input);
  1109. if (spirv_file.empty())
  1110. return EXIT_FAILURE;
  1111. // Special case reflection because it has little to do with the path followed by code-outputting compilers
  1112. if (!args.reflect.empty())
  1113. {
  1114. Parser spirv_parser(move(spirv_file));
  1115. spirv_parser.parse();
  1116. CompilerReflection compiler(move(spirv_parser.get_parsed_ir()));
  1117. compiler.set_format(args.reflect);
  1118. auto json = compiler.compile();
  1119. if (args.output)
  1120. write_string_to_file(args.output, json.c_str());
  1121. else
  1122. printf("%s", json.c_str());
  1123. return EXIT_SUCCESS;
  1124. }
  1125. string compiled_output;
  1126. if (args.iterations == 1)
  1127. compiled_output = compile_iteration(args, move(spirv_file));
  1128. else
  1129. {
  1130. for (unsigned i = 0; i < args.iterations; i++)
  1131. compiled_output = compile_iteration(args, spirv_file);
  1132. }
  1133. if (args.output)
  1134. write_string_to_file(args.output, compiled_output.c_str());
  1135. else
  1136. printf("%s", compiled_output.c_str());
  1137. return EXIT_SUCCESS;
  1138. }
  1139. int main(int argc, char *argv[])
  1140. {
  1141. #ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
  1142. return main_inner(argc, argv);
  1143. #else
  1144. // Make sure we catch the exception or it just disappears into the aether on Windows.
  1145. try
  1146. {
  1147. return main_inner(argc, argv);
  1148. }
  1149. catch (const std::exception &e)
  1150. {
  1151. fprintf(stderr, "SPIRV-Cross threw an exception: %s\n", e.what());
  1152. return EXIT_FAILURE;
  1153. }
  1154. #endif
  1155. }