| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028 |
- /*
- * Copyright 2015-2021 Arm Limited
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- * At your option, you may choose to accept this material under either:
- * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
- * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
- */
- #include "spirv_cpp.hpp"
- #include "spirv_cross_util.hpp"
- #include "spirv_glsl.hpp"
- #include "spirv_hlsl.hpp"
- #include "spirv_msl.hpp"
- #include "spirv_parser.hpp"
- #include "spirv_reflect.hpp"
- #include <algorithm>
- #include <cstdio>
- #include <cstring>
- #include <functional>
- #include <limits>
- #include <memory>
- #include <stdexcept>
- #include <unordered_map>
- #include <unordered_set>
- #ifdef _WIN32
- #include <io.h>
- #include <fcntl.h>
- #endif
- #ifdef HAVE_SPIRV_CROSS_GIT_VERSION
- #include "gitversion.h"
- #endif
- using namespace SPIRV_CROSS_SPV_HEADER_NAMESPACE;
- using namespace SPIRV_CROSS_NAMESPACE;
- using namespace std;
- #ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- static inline void THROW(const char *str)
- {
- fprintf(stderr, "SPIRV-Cross will abort: %s\n", str);
- fflush(stderr);
- abort();
- }
- #else
- #define THROW(x) throw runtime_error(x)
- #endif
- struct CLIParser;
- struct CLICallbacks
- {
- void add(const char *cli, const function<void(CLIParser &)> &func)
- {
- callbacks[cli] = func;
- }
- unordered_map<string, function<void(CLIParser &)>> callbacks;
- function<void()> error_handler;
- function<void(const char *)> default_handler;
- };
- struct CLIParser
- {
- CLIParser(CLICallbacks cbs_, int argc_, char *argv_[])
- : cbs(std::move(cbs_))
- , argc(argc_)
- , argv(argv_)
- {
- }
- bool parse()
- {
- #ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- try
- #endif
- {
- while (argc && !ended_state)
- {
- const char *next = *argv++;
- argc--;
- if (*next != '-' && cbs.default_handler)
- {
- cbs.default_handler(next);
- }
- else
- {
- auto itr = cbs.callbacks.find(next);
- if (itr == ::end(cbs.callbacks))
- {
- THROW("Invalid argument");
- }
- itr->second(*this);
- }
- }
- return true;
- }
- #ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- catch (...)
- {
- if (cbs.error_handler)
- {
- cbs.error_handler();
- }
- return false;
- }
- #endif
- }
- void end()
- {
- ended_state = true;
- }
- uint32_t next_uint()
- {
- if (!argc)
- {
- THROW("Tried to parse uint, but nothing left in arguments");
- }
- uint64_t val = stoul(*argv);
- if (val > numeric_limits<uint32_t>::max())
- {
- THROW("next_uint() out of range");
- }
- argc--;
- argv++;
- return uint32_t(val);
- }
- uint32_t next_hex_uint()
- {
- if (!argc)
- {
- THROW("Tried to parse uint, but nothing left in arguments");
- }
- uint64_t val = stoul(*argv, nullptr, 16);
- if (val > numeric_limits<uint32_t>::max())
- {
- THROW("next_uint() out of range");
- }
- argc--;
- argv++;
- return uint32_t(val);
- }
- double next_double()
- {
- if (!argc)
- {
- THROW("Tried to parse double, but nothing left in arguments");
- }
- double val = stod(*argv);
- argc--;
- argv++;
- return val;
- }
- // Return a string only if it's not prefixed with `--`, otherwise return the default value
- const char *next_value_string(const char *default_value)
- {
- if (!argc)
- {
- return default_value;
- }
- if (0 == strncmp("--", *argv, 2))
- {
- return default_value;
- }
- return next_string();
- }
- const char *next_string()
- {
- if (!argc)
- {
- THROW("Tried to parse string, but nothing left in arguments");
- }
- const char *ret = *argv;
- argc--;
- argv++;
- return ret;
- }
- CLICallbacks cbs;
- int argc;
- char **argv;
- bool ended_state = false;
- };
- #if defined(__clang__) || defined(__GNUC__)
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #elif defined(_MSC_VER)
- #pragma warning(push)
- #pragma warning(disable : 4996)
- #endif
- static vector<uint32_t> read_spirv_file_stdin()
- {
- #ifdef _WIN32
- setmode(fileno(stdin), O_BINARY);
- #endif
- vector<uint32_t> buffer;
- uint32_t tmp[256];
- size_t ret;
- while ((ret = fread(tmp, sizeof(uint32_t), 256, stdin)))
- buffer.insert(buffer.end(), tmp, tmp + ret);
- return buffer;
- }
- static vector<uint32_t> read_spirv_file(const char *path)
- {
- if (path[0] == '-' && path[1] == '\0')
- return read_spirv_file_stdin();
- FILE *file = fopen(path, "rb");
- if (!file)
- {
- fprintf(stderr, "Failed to open SPIR-V file: %s\n", path);
- return {};
- }
- fseek(file, 0, SEEK_END);
- long len = ftell(file) / sizeof(uint32_t);
- rewind(file);
- vector<uint32_t> spirv(len);
- if (fread(spirv.data(), sizeof(uint32_t), len, file) != size_t(len))
- spirv.clear();
- fclose(file);
- return spirv;
- }
- static bool write_string_to_file(const char *path, const char *string)
- {
- FILE *file = fopen(path, "w");
- if (!file)
- {
- fprintf(stderr, "Failed to write file: %s\n", path);
- return false;
- }
- fprintf(file, "%s", string);
- fclose(file);
- return true;
- }
- #if defined(__clang__) || defined(__GNUC__)
- #pragma GCC diagnostic pop
- #elif defined(_MSC_VER)
- #pragma warning(pop)
- #endif
- static void print_resources(const Compiler &compiler, StorageClass storage,
- const SmallVector<BuiltInResource> &resources)
- {
- fprintf(stderr, "%s\n", storage == StorageClassInput ? "builtin inputs" : "builtin outputs");
- fprintf(stderr, "=============\n\n");
- for (auto &res : resources)
- {
- bool active = compiler.has_active_builtin(res.builtin, storage);
- const char *basetype = "?";
- auto &type = compiler.get_type(res.value_type_id);
- switch (type.basetype)
- {
- case SPIRType::Float: basetype = "float"; break;
- case SPIRType::Int: basetype = "int"; break;
- case SPIRType::UInt: basetype = "uint"; break;
- default: break;
- }
- uint32_t array_size = 0;
- bool array_size_literal = false;
- if (!type.array.empty())
- {
- array_size = type.array.front();
- array_size_literal = type.array_size_literal.front();
- }
- string type_str = basetype;
- if (type.vecsize > 1)
- type_str += std::to_string(type.vecsize);
- if (array_size)
- {
- if (array_size_literal)
- type_str += join("[", array_size, "]");
- else
- type_str += join("[", array_size, " (spec constant ID)]");
- }
- string builtin_str;
- switch (res.builtin)
- {
- case BuiltInPosition: builtin_str = "Position"; break;
- case BuiltInPointSize: builtin_str = "PointSize"; break;
- case BuiltInCullDistance: builtin_str = "CullDistance"; break;
- case BuiltInClipDistance: builtin_str = "ClipDistance"; break;
- case BuiltInTessLevelInner: builtin_str = "TessLevelInner"; break;
- case BuiltInTessLevelOuter: builtin_str = "TessLevelOuter"; break;
- default: builtin_str = string("builtin #") + to_string(res.builtin);
- }
- fprintf(stderr, "Builtin %s (%s) (active: %s).\n", builtin_str.c_str(), type_str.c_str(), active ? "yes" : "no");
- }
- fprintf(stderr, "=============\n\n");
- }
- static void print_resources(const Compiler &compiler, const char *tag, const SmallVector<Resource> &resources)
- {
- fprintf(stderr, "%s\n", tag);
- fprintf(stderr, "=============\n\n");
- bool print_ssbo = !strcmp(tag, "ssbos");
- for (auto &res : resources)
- {
- auto &type = compiler.get_type(res.type_id);
- if (print_ssbo && compiler.buffer_is_hlsl_counter_buffer(res.id))
- continue;
- // If we don't have a name, use the fallback for the type instead of the variable
- // for SSBOs and UBOs since those are the only meaningful names to use externally.
- // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks.
- bool is_push_constant = compiler.get_storage_class(res.id) == StorageClassPushConstant;
- bool is_block = compiler.get_decoration_bitset(type.self).get(DecorationBlock) ||
- compiler.get_decoration_bitset(type.self).get(DecorationBufferBlock);
- bool is_sized_block = is_block && (compiler.get_storage_class(res.id) == StorageClassUniform ||
- compiler.get_storage_class(res.id) == StorageClassUniformConstant);
- ID fallback_id = !is_push_constant && is_block ? ID(res.base_type_id) : ID(res.id);
- uint32_t block_size = 0;
- uint32_t runtime_array_stride = 0;
- if (is_sized_block)
- {
- auto &base_type = compiler.get_type(res.base_type_id);
- block_size = uint32_t(compiler.get_declared_struct_size(base_type));
- runtime_array_stride = uint32_t(compiler.get_declared_struct_size_runtime_array(base_type, 1) -
- compiler.get_declared_struct_size_runtime_array(base_type, 0));
- }
- Bitset mask;
- if (print_ssbo)
- mask = compiler.get_buffer_block_flags(res.id);
- else
- mask = compiler.get_decoration_bitset(res.id);
- string array;
- for (auto arr : type.array)
- array = join("[", arr ? convert_to_string(arr) : "", "]") + array;
- fprintf(stderr, " ID %03u : %s%s", uint32_t(res.id),
- !res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str(), array.c_str());
- if (mask.get(DecorationLocation))
- fprintf(stderr, " (Location : %u)", compiler.get_decoration(res.id, DecorationLocation));
- if (mask.get(DecorationDescriptorSet))
- fprintf(stderr, " (Set : %u)", compiler.get_decoration(res.id, DecorationDescriptorSet));
- if (mask.get(DecorationBinding))
- fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding));
- if (static_cast<const CompilerGLSL &>(compiler).variable_is_depth_or_compare(res.id))
- fprintf(stderr, " (comparison)");
- if (mask.get(DecorationInputAttachmentIndex))
- fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex));
- if (mask.get(DecorationNonReadable))
- fprintf(stderr, " writeonly");
- if (mask.get(DecorationNonWritable))
- fprintf(stderr, " readonly");
- if (mask.get(DecorationRestrict))
- fprintf(stderr, " restrict");
- if (mask.get(DecorationCoherent))
- fprintf(stderr, " coherent");
- if (mask.get(DecorationVolatile))
- fprintf(stderr, " volatile");
- if (is_sized_block)
- {
- fprintf(stderr, " (BlockSize : %u bytes)", block_size);
- if (runtime_array_stride)
- fprintf(stderr, " (Unsized array stride: %u bytes)", runtime_array_stride);
- }
- uint32_t counter_id = 0;
- if (print_ssbo && compiler.buffer_get_hlsl_counter_buffer(res.id, counter_id))
- fprintf(stderr, " (HLSL counter buffer ID: %u)", counter_id);
- fprintf(stderr, "\n");
- }
- fprintf(stderr, "=============\n\n");
- }
- static const char *execution_model_to_str(ExecutionModel model)
- {
- switch (model)
- {
- case ExecutionModelVertex:
- return "vertex";
- case ExecutionModelTessellationControl:
- return "tessellation control";
- case ExecutionModelTessellationEvaluation:
- return "tessellation evaluation";
- case ExecutionModelGeometry:
- return "geometry";
- case ExecutionModelFragment:
- return "fragment";
- case ExecutionModelGLCompute:
- return "compute";
- case ExecutionModelRayGenerationNV:
- return "raygenNV";
- case ExecutionModelIntersectionNV:
- return "intersectionNV";
- case ExecutionModelCallableNV:
- return "callableNV";
- case ExecutionModelAnyHitNV:
- return "anyhitNV";
- case ExecutionModelClosestHitNV:
- return "closesthitNV";
- case ExecutionModelMissNV:
- return "missNV";
- default:
- return "???";
- }
- }
- static void print_resources(const Compiler &compiler, const ShaderResources &res)
- {
- auto &modes = compiler.get_execution_mode_bitset();
- fprintf(stderr, "Entry points:\n");
- auto entry_points = compiler.get_entry_points_and_stages();
- for (auto &e : entry_points)
- fprintf(stderr, " %s (%s)\n", e.name.c_str(), execution_model_to_str(e.execution_model));
- fprintf(stderr, "\n");
- fprintf(stderr, "Execution modes:\n");
- modes.for_each_bit([&](uint32_t i) {
- auto mode = static_cast<ExecutionMode>(i);
- uint32_t arg0 = compiler.get_execution_mode_argument(mode, 0);
- uint32_t arg1 = compiler.get_execution_mode_argument(mode, 1);
- uint32_t arg2 = compiler.get_execution_mode_argument(mode, 2);
- switch (static_cast<ExecutionMode>(i))
- {
- case ExecutionModeInvocations:
- fprintf(stderr, " Invocations: %u\n", arg0);
- break;
- case ExecutionModeLocalSize:
- fprintf(stderr, " LocalSize: (%u, %u, %u)\n", arg0, arg1, arg2);
- break;
- case ExecutionModeOutputVertices:
- fprintf(stderr, " OutputVertices: %u\n", arg0);
- break;
- #define CHECK_MODE(m) \
- case ExecutionMode##m: \
- fprintf(stderr, " %s\n", #m); \
- break
- CHECK_MODE(SpacingEqual);
- CHECK_MODE(SpacingFractionalEven);
- CHECK_MODE(SpacingFractionalOdd);
- CHECK_MODE(VertexOrderCw);
- CHECK_MODE(VertexOrderCcw);
- CHECK_MODE(PixelCenterInteger);
- CHECK_MODE(OriginUpperLeft);
- CHECK_MODE(OriginLowerLeft);
- CHECK_MODE(EarlyFragmentTests);
- CHECK_MODE(PointMode);
- CHECK_MODE(Xfb);
- CHECK_MODE(DepthReplacing);
- CHECK_MODE(DepthGreater);
- CHECK_MODE(DepthLess);
- CHECK_MODE(DepthUnchanged);
- CHECK_MODE(LocalSizeHint);
- CHECK_MODE(InputPoints);
- CHECK_MODE(InputLines);
- CHECK_MODE(InputLinesAdjacency);
- CHECK_MODE(Triangles);
- CHECK_MODE(InputTrianglesAdjacency);
- CHECK_MODE(Quads);
- CHECK_MODE(Isolines);
- CHECK_MODE(OutputPoints);
- CHECK_MODE(OutputLineStrip);
- CHECK_MODE(OutputTriangleStrip);
- CHECK_MODE(VecTypeHint);
- CHECK_MODE(ContractionOff);
- default:
- break;
- }
- });
- fprintf(stderr, "\n");
- print_resources(compiler, "subpass inputs", res.subpass_inputs);
- print_resources(compiler, "inputs", res.stage_inputs);
- print_resources(compiler, "outputs", res.stage_outputs);
- print_resources(compiler, "textures", res.sampled_images);
- print_resources(compiler, "separate images", res.separate_images);
- print_resources(compiler, "separate samplers", res.separate_samplers);
- print_resources(compiler, "images", res.storage_images);
- print_resources(compiler, "ssbos", res.storage_buffers);
- print_resources(compiler, "ubos", res.uniform_buffers);
- print_resources(compiler, "push", res.push_constant_buffers);
- print_resources(compiler, "counters", res.atomic_counters);
- print_resources(compiler, "acceleration structures", res.acceleration_structures);
- print_resources(compiler, "tensors", res.tensors);
- print_resources(compiler, "record buffers", res.shader_record_buffers);
- print_resources(compiler, StorageClassInput, res.builtin_inputs);
- print_resources(compiler, StorageClassOutput, res.builtin_outputs);
- }
- static void print_push_constant_resources(const Compiler &compiler, const SmallVector<Resource> &res)
- {
- for (auto &block : res)
- {
- auto ranges = compiler.get_active_buffer_ranges(block.id);
- fprintf(stderr, "Active members in buffer: %s\n",
- !block.name.empty() ? block.name.c_str() : compiler.get_fallback_name(block.id).c_str());
- fprintf(stderr, "==================\n\n");
- for (auto &range : ranges)
- {
- const auto &name = compiler.get_member_name(block.base_type_id, range.index);
- fprintf(stderr, "Member #%3u (%s): Offset: %4u, Range: %4u\n", range.index,
- !name.empty() ? name.c_str() : compiler.get_fallback_member_name(range.index).c_str(),
- unsigned(range.offset), unsigned(range.range));
- }
- fprintf(stderr, "==================\n\n");
- }
- }
- static void print_spec_constants(const Compiler &compiler)
- {
- auto spec_constants = compiler.get_specialization_constants();
- fprintf(stderr, "Specialization constants\n");
- fprintf(stderr, "==================\n\n");
- for (auto &c : spec_constants)
- fprintf(stderr, "ID: %u, Spec ID: %u\n", uint32_t(c.id), c.constant_id);
- fprintf(stderr, "==================\n\n");
- }
- static void print_capabilities_and_extensions(const Compiler &compiler)
- {
- fprintf(stderr, "Capabilities\n");
- fprintf(stderr, "============\n");
- for (auto &capability : compiler.get_declared_capabilities())
- fprintf(stderr, "Capability: %u\n", static_cast<unsigned>(capability));
- fprintf(stderr, "============\n\n");
- fprintf(stderr, "Extensions\n");
- fprintf(stderr, "============\n");
- for (auto &ext : compiler.get_declared_extensions())
- fprintf(stderr, "Extension: %s\n", ext.c_str());
- fprintf(stderr, "============\n\n");
- }
- struct PLSArg
- {
- PlsFormat format;
- string name;
- };
- struct Remap
- {
- string src_name;
- string dst_name;
- unsigned components;
- };
- struct VariableTypeRemap
- {
- string variable_name;
- string new_variable_type;
- };
- struct InterfaceVariableRename
- {
- StorageClass storageClass;
- uint32_t location;
- string variable_name;
- };
- struct HLSLVertexAttributeRemapNamed
- {
- std::string name;
- std::string semantic;
- };
- struct CLIArguments
- {
- const char *input = nullptr;
- const char *output = nullptr;
- const char *cpp_interface_name = nullptr;
- uint32_t version = 0;
- uint32_t shader_model = 0;
- uint32_t msl_version = 0;
- bool es = false;
- bool set_version = false;
- bool set_shader_model = false;
- bool set_msl_version = false;
- bool set_es = false;
- bool dump_resources = false;
- bool force_temporary = false;
- bool flatten_ubo = false;
- bool fixup = false;
- bool yflip = false;
- bool sso = false;
- bool support_nonzero_baseinstance = true;
- bool msl_capture_output_to_buffer = false;
- bool msl_swizzle_texture_samples = false;
- bool msl_ios = false;
- bool msl_pad_fragment_output = false;
- bool msl_domain_lower_left = false;
- bool msl_argument_buffers = false;
- uint32_t msl_argument_buffers_tier = 0; // Tier 1
- bool msl_texture_buffer_native = false;
- bool msl_framebuffer_fetch = false;
- bool msl_invariant_float_math = false;
- bool msl_emulate_cube_array = false;
- bool msl_multiview = false;
- bool msl_multiview_layered_rendering = true;
- bool msl_view_index_from_device_index = false;
- bool msl_dispatch_base = false;
- bool msl_decoration_binding = false;
- bool msl_force_active_argument_buffer_resources = false;
- bool msl_force_native_arrays = false;
- bool msl_enable_frag_depth_builtin = true;
- bool msl_enable_frag_stencil_ref_builtin = true;
- uint32_t msl_enable_frag_output_mask = 0xffffffff;
- bool msl_enable_clip_distance_user_varying = true;
- bool msl_raw_buffer_tese_input = false;
- bool msl_multi_patch_workgroup = false;
- bool msl_vertex_for_tessellation = false;
- uint32_t msl_additional_fixed_sample_mask = 0xffffffff;
- bool msl_arrayed_subpass_input = false;
- uint32_t msl_r32ui_linear_texture_alignment = 4;
- uint32_t msl_r32ui_alignment_constant_id = 65535;
- bool msl_texture_1d_as_2d = false;
- bool msl_ios_use_simdgroup_functions = false;
- bool msl_emulate_subgroups = false;
- uint32_t msl_fixed_subgroup_size = 0;
- bool msl_force_sample_rate_shading = false;
- bool msl_manual_helper_invocation_updates = true;
- bool msl_check_discarded_frag_stores = false;
- bool msl_force_fragment_with_side_effects_execution = false;
- bool msl_sample_dref_lod_array_as_grad = false;
- bool msl_runtime_array_rich_descriptor = false;
- bool msl_replace_recursive_inputs = false;
- bool msl_readwrite_texture_fences = true;
- bool msl_agx_manual_cube_grad_fixup = false;
- bool msl_input_attachment_is_ds_attachment = false;
- bool msl_disable_rasterization = false;
- bool msl_auto_disable_rasterization = false;
- bool msl_enable_point_size_default = false;
- float msl_default_point_size = 1.0f;
- const char *msl_combined_sampler_suffix = nullptr;
- bool glsl_emit_push_constant_as_ubo = false;
- bool glsl_emit_ubo_as_plain_uniforms = false;
- bool glsl_force_flattened_io_blocks = false;
- uint32_t glsl_ovr_multiview_view_count = 0;
- SmallVector<pair<uint32_t, uint32_t>> glsl_ext_framebuffer_fetch;
- bool glsl_ext_framebuffer_fetch_noncoherent = false;
- bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
- bool emit_line_directives = false;
- bool enable_storage_image_qualifier_deduction = true;
- bool force_zero_initialized_variables = false;
- bool relax_nan_checks = false;
- uint32_t force_recompile_max_debug_iterations = 3;
- SmallVector<uint32_t> msl_discrete_descriptor_sets;
- SmallVector<uint32_t> msl_device_argument_buffers;
- SmallVector<pair<uint32_t, uint32_t>> msl_dynamic_buffers;
- SmallVector<pair<uint32_t, uint32_t>> msl_inline_uniform_blocks;
- SmallVector<MSLShaderInterfaceVariable> msl_shader_inputs;
- SmallVector<MSLShaderInterfaceVariable> msl_shader_outputs;
- SmallVector<PLSArg> pls_in;
- SmallVector<PLSArg> pls_out;
- SmallVector<Remap> remaps;
- SmallVector<string> extensions;
- SmallVector<VariableTypeRemap> variable_type_remaps;
- SmallVector<InterfaceVariableRename> interface_variable_renames;
- SmallVector<HLSLVertexAttributeRemap> hlsl_attr_remap;
- SmallVector<HLSLVertexAttributeRemapNamed> hlsl_attr_remap_named;
- SmallVector<std::pair<uint32_t, uint32_t>> masked_stage_outputs;
- SmallVector<BuiltIn> masked_stage_builtins;
- string entry;
- string entry_stage;
- struct Rename
- {
- string old_name;
- string new_name;
- ExecutionModel execution_model;
- };
- SmallVector<Rename> entry_point_rename;
- uint32_t iterations = 1;
- bool cpp = false;
- string reflect;
- bool msl = false;
- bool hlsl = false;
- bool hlsl_compat = false;
- bool hlsl_support_nonzero_base = false;
- bool hlsl_base_vertex_index_explicit_binding = false;
- uint32_t hlsl_base_vertex_index_register_index = 0;
- uint32_t hlsl_base_vertex_index_register_space = 0;
- bool hlsl_force_storage_buffer_as_uav = false;
- bool hlsl_nonwritable_uav_texture_as_srv = false;
- bool hlsl_enable_16bit_types = false;
- bool hlsl_flatten_matrix_vertex_input_semantics = false;
- bool hlsl_preserve_structured_buffers = false;
- HLSLBindingFlags hlsl_binding_flags = 0;
- bool vulkan_semantics = false;
- bool flatten_multidimensional_arrays = false;
- bool use_420pack_extension = true;
- bool remove_unused = false;
- bool combined_samplers_inherit_bindings = false;
- };
- static void print_version()
- {
- #ifdef HAVE_SPIRV_CROSS_GIT_VERSION
- fprintf(stderr, "%s\n", SPIRV_CROSS_GIT_REVISION);
- #else
- fprintf(stderr, "Git revision unknown. Build with CMake to create timestamp and revision info.\n");
- #endif
- }
- static void print_help_backend()
- {
- // clang-format off
- fprintf(stderr, "\nSelect backend:\n"
- "\tBy default, OpenGL-style GLSL is the target, with #version and GLSL/ESSL information inherited from the SPIR-V module if present.\n"
- "\t[--vulkan-semantics] or [-V]:\n\t\tEmit Vulkan GLSL instead of plain GLSL. Makes use of Vulkan-only features to match SPIR-V.\n"
- "\t[--msl]:\n\t\tEmit Metal Shading Language (MSL).\n"
- "\t[--hlsl]:\n\t\tEmit HLSL.\n"
- "\t[--reflect]:\n\t\tEmit JSON reflection.\n"
- "\t[--cpp]:\n\t\tDEPRECATED. Emits C++ code.\n"
- );
- // clang-format on
- }
- static void print_help_glsl()
- {
- // clang-format off
- fprintf(stderr, "\nGLSL options:\n"
- "\t[--es]:\n\t\tForce ESSL.\n"
- "\t[--no-es]:\n\t\tForce desktop GLSL.\n"
- "\t[--version <GLSL version>]:\n\t\tE.g. --version 450 will emit '#version 450' in shader.\n"
- "\t\tCode generation will depend on the version used.\n"
- "\t[--flatten-ubo]:\n\t\tEmit UBOs as plain uniform arrays which are suitable for use with glUniform4*v().\n"
- "\t\tThis can be an optimization on GL implementations where this is faster or works around buggy driver implementations.\n"
- "\t\tE.g.: uniform MyUBO { vec4 a; float b, c, d, e; }; will be emitted as uniform vec4 MyUBO[2];\n"
- "\t\tCaveat: You cannot mix and match floating-point and integer in the same UBO with this option.\n"
- "\t\tLegacy GLSL/ESSL (where this flattening makes sense) does not support bit-casting, which would have been the obvious workaround.\n"
- "\t[--extension ext]:\n\t\tAdd #extension string of your choosing to GLSL output.\n"
- "\t\tUseful if you use variable name remapping to something that requires an extension unknown to SPIRV-Cross.\n"
- "\t[--remove-unused-variables]:\n\t\tDo not emit interface variables which are not statically accessed by the shader.\n"
- "\t[--separate-shader-objects]:\n\t\tRedeclare gl_PerVertex blocks to be suitable for desktop GL separate shader objects.\n"
- "\t[--glsl-emit-push-constant-as-ubo]:\n\t\tInstead of a plain uniform of struct for push constants, emit a UBO block instead.\n"
- "\t[--glsl-emit-ubo-as-plain-uniforms]:\n\t\tInstead of emitting UBOs, emit them as plain uniform structs.\n"
- "\t[--glsl-remap-ext-framebuffer-fetch input-attachment color-location]:\n\t\tRemaps an input attachment to use GL_EXT_shader_framebuffer_fetch.\n"
- "\t\tgl_LastFragData[location] is read from. The attachment to read from must be declared as an output in the shader.\n"
- "\t[--glsl-ext-framebuffer-fetch-noncoherent]:\n\t\tUses noncoherent qualifier for framebuffer fetch.\n"
- "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]:\n\t\tDo not allow use of GL_EXT_samperless_texture_functions, even in Vulkan GLSL.\n"
- "\t\tUse of texelFetch and similar might have to create dummy samplers to work around it.\n"
- "\t[--combined-samplers-inherit-bindings]:\n\t\tInherit binding information from the textures when building combined image samplers from separate textures and samplers.\n"
- "\t[--no-support-nonzero-baseinstance]:\n\t\tWhen using gl_InstanceIndex with desktop GL,\n"
- "\t\tassume that base instance is always 0, and do not attempt to fix up gl_InstanceID to match Vulkan semantics.\n"
- "\t[--pls-in format input-name]:\n\t\tRemaps a subpass input with name into a GL_EXT_pixel_local_storage input.\n"
- "\t\tEntry in PLS block is ordered where first --pls-in marks the first entry. Can be called multiple times.\n"
- "\t\tFormats allowed: r11f_g11f_b10f, r32f, rg16f, rg16, rgb10_a2, rgba8, rgba8i, rgba8ui, rg16i, rgb10_a2ui, rg16ui, r32ui.\n"
- "\t\tRequires ESSL.\n"
- "\t[--pls-out format output-name]:\n\t\tRemaps a color output with name into a GL_EXT_pixel_local_storage output.\n"
- "\t\tEntry in PLS block is ordered where first --pls-output marks the first entry. Can be called multiple times.\n"
- "\t\tFormats allowed: r11f_g11f_b10f, r32f, rg16f, rg16, rgb10_a2, rgba8, rgba8i, rgba8ui, rg16i, rgb10_a2ui, rg16ui, r32ui.\n"
- "\t\tRequires ESSL.\n"
- "\t[--remap source_name target_name components]:\n\t\tRemaps a variable to a different name with N components.\n"
- "\t\tMain use case is to remap a subpass input to gl_LastFragDepthARM.\n"
- "\t\tE.g.:\n"
- "\t\tuniform subpassInput uDepth;\n"
- "\t\t--remap uDepth gl_LastFragDepthARM 1 --extension GL_ARM_shader_framebuffer_fetch_depth_stencil\n"
- "\t[--no-420pack-extension]:\n\t\tDo not make use of GL_ARB_shading_language_420pack in older GL targets to support layout(binding).\n"
- "\t[--remap-variable-type <variable_name> <new_variable_type>]:\n\t\tRemaps a variable type based on name.\n"
- "\t\tPrimary use case is supporting external samplers in ESSL for video rendering on Android where you could remap a texture to a YUV one.\n"
- "\t[--glsl-force-flattened-io-blocks]:\n\t\tAlways flatten I/O blocks and structs.\n"
- "\t[--glsl-ovr-multiview-view-count count]:\n\t\tIn GL_OVR_multiview2, specify layout(num_views).\n"
- );
- // clang-format on
- }
- static void print_help_hlsl()
- {
- // clang-format off
- fprintf(stderr, "\nHLSL options:\n"
- "\t[--shader-model]:\n\t\tEnables a specific shader model, e.g. --shader-model 50 for SM 5.0.\n"
- "\t[--flatten-ubo]:\n\t\tEmit UBOs as plain uniform arrays.\n"
- "\t\tE.g.: uniform MyUBO { vec4 a; float b, c, d, e; }; will be emitted as uniform float4 MyUBO[2];\n"
- "\t\tCaveat: You cannot mix and match floating-point and integer in the same UBO with this option.\n"
- "\t[--hlsl-enable-compat]:\n\t\tAllow point size and point coord to be used, even if they won't work as expected.\n"
- "\t\tPointSize is ignored, and PointCoord returns (0.5, 0.5).\n"
- "\t[--hlsl-support-nonzero-basevertex-baseinstance]:\n\t\tSupport base vertex and base instance by emitting a special cbuffer declared as:\n"
- "\t\tcbuffer SPIRV_Cross_VertexInfo { int SPIRV_Cross_BaseVertex; int SPIRV_Cross_BaseInstance; };\n"
- "\t[--hlsl-basevertex-baseinstance-binding <register index> <register space>]:\n\t\tAssign a fixed binding to SPIRV_Cross_VertexInfo.\n"
- "\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n"
- "\t\tDo not emit any : register(#) bindings for specific resource types, and rely on HLSL compiler to assign something.\n"
- "\t[--hlsl-force-storage-buffer-as-uav]:\n\t\tAlways emit SSBOs as UAVs, even when marked as read-only.\n"
- "\t\tNormally, SSBOs marked with NonWritable will be emitted as SRVs.\n"
- "\t[--hlsl-nonwritable-uav-texture-as-srv]:\n\t\tEmit NonWritable storage images as SRV textures instead of UAV.\n"
- "\t\tUsing this option messes with the type system. SPIRV-Cross cannot guarantee that this will work.\n"
- "\t\tOne major problem area with this feature is function arguments, where we won't know if we're seeing a UAV or SRV.\n"
- "\t\tShader must ensure that read/write state is consistent at all call sites.\n"
- "\t[--set-hlsl-vertex-input-semantic <location> <semantic>]:\n\t\tEmits a specific vertex input semantic for a given location.\n"
- "\t\tOtherwise, TEXCOORD# is used as semantics, where # is location.\n"
- "\t[--set-hlsl-named-vertex-input-semantic <name> <semantic>]:\n\t\tEmits a specific vertex input semantic for a given name.\n"
- "\t\tOpName reflection information must be intact.\n"
- "\t[--hlsl-enable-16bit-types]:\n\t\tEnables native use of half/int16_t/uint16_t and ByteAddressBuffer interaction with these types. Requires SM 6.2.\n"
- "\t[--hlsl-flatten-matrix-vertex-input-semantics]:\n\t\tEmits matrix vertex inputs with input semantics as if they were independent vectors, e.g. TEXCOORD{2,3,4} rather than matrix form TEXCOORD2_{0,1,2}.\n"
- "\t[--hlsl-preserve-structured-buffers]:\n\t\tEmit SturucturedBuffer<T> rather than ByteAddressBuffer. Requires UserTypeGOOGLE to be emitted. Intended for DXC roundtrips.\n"
- );
- // clang-format on
- }
- static void print_help_msl()
- {
- // clang-format off
- fprintf(stderr, "\nMSL options:\n"
- "\t[--msl-version <MMmmpp>]:\n\t\tUses a specific MSL version, e.g. --msl-version 20100 for MSL 2.1.\n"
- "\t[--msl-capture-output]:\n\t\tWrites geometry varyings to a buffer instead of as stage-outputs.\n"
- "\t[--msl-swizzle-texture-samples]:\n\t\tWorks around lack of support for VkImageView component swizzles.\n"
- "\t\tThis has a massive impact on performance and bloat. Do not use this unless you are absolutely forced to.\n"
- "\t\tTo use this feature, the API side must pass down swizzle buffers.\n"
- "\t\tShould only be used by translation layers as a last resort.\n"
- "\t\tRecent Metal versions do not require this workaround.\n"
- "\t[--msl-ios]:\n\t\tTarget iOS Metal instead of macOS Metal.\n"
- "\t[--msl-pad-fragment-output]:\n\t\tAlways emit color outputs as 4-component variables.\n"
- "\t\tIn Metal, the fragment shader must emit at least as many components as the render target format.\n"
- "\t[--msl-domain-lower-left]:\n\t\tUse a lower-left tessellation domain.\n"
- "\t[--msl-argument-buffers]:\n\t\tEmit Metal argument buffers instead of discrete resource bindings.\n"
- "\t\tRequires MSL 2.0 to be enabled.\n"
- "\t[--msl-argument-buffer-tier]:\n\t\tWhen using Metal argument buffers, indicate the Metal argument buffer tier level supported by the Metal platform.\n"
- "\t\tUses same values as Metal MTLArgumentBuffersTier enumeration (0 = Tier1, 1 = Tier2).\n"
- "\t\tNOTE: Setting this value no longer enables msl-argument-buffers implicitly.\n"
- "\t[--msl-runtime-array-rich-descriptor]:\n\t\tWhen declaring a runtime array of SSBOs, declare an array of {ptr, len} pairs to support OpArrayLength.\n"
- "\t[--msl-replace-recursive-inputs]:\n\t\tWorks around a Metal 3.1 regression bug, which causes an infinite recursion crash during Metal's analysis of an entry point input structure that itself contains internal recursion.\n"
- "\t[--msl-texture-buffer-native]:\n\t\tEnable native support for texel buffers. Otherwise, it is emulated as a normal texture.\n"
- "\t[--msl-input-attachment-is-ds-attachment]:\n\t\tAdds a simple depth passthrough in fragment shaders when they do not modify the depth value.\n"
- "\t\tRequired to force Metal to write to the depth/stencil attachment post fragment execution.\n"
- "\t\tOtherwise, Metal may optimize the write to pre fragment execution which goes against the Vulkan spec.\n"
- "\t\tOnly required if an input attachment and depth/stencil attachment reference the same resource.\n"
- "\t[--msl-framebuffer-fetch]:\n\t\tImplement subpass inputs with frame buffer fetch.\n"
- "\t\tEmits [[color(N)]] inputs in fragment stage.\n"
- "\t\tRequires an Apple GPU.\n"
- "\t[--msl-emulate-cube-array]:\n\t\tEmulate cube arrays with 2D array and manual math.\n"
- "\t[--msl-discrete-descriptor-set <index>]:\n\t\tWhen using argument buffers, forces a specific descriptor set to be implemented without argument buffers.\n"
- "\t\tUseful for implementing push descriptors in emulation layers.\n"
- "\t\tCan be used multiple times for each descriptor set in question.\n"
- "\t[--msl-device-argument-buffer <descriptor set index>]:\n\t\tUse device address space to hold indirect argument buffers instead of constant.\n"
- "\t\tComes up when trying to support argument buffers which are larger than 64 KiB.\n"
- "\t[--msl-multiview]:\n\t\tEnable SPV_KHR_multiview emulation.\n"
- "\t[--msl-multiview-no-layered-rendering]:\n\t\tDon't set [[render_target_array_index]] in multiview shaders.\n"
- "\t\tUseful for devices which don't support layered rendering. Only effective when --msl-multiview is enabled.\n"
- "\t[--msl-view-index-from-device-index]:\n\t\tTreat the view index as the device index instead.\n"
- "\t\tFor multi-GPU rendering.\n"
- "\t[--msl-dispatch-base]:\n\t\tAdd support for vkCmdDispatchBase() or similar APIs.\n"
- "\t\tOffsets the workgroup ID based on a buffer.\n"
- "\t[--msl-dynamic-buffer <set index> <binding>]:\n\t\tMarks a buffer as having dynamic offset.\n"
- "\t\tThe offset is applied in the shader with pointer arithmetic.\n"
- "\t\tUseful for argument buffers where it is non-trivial to apply dynamic offset otherwise.\n"
- "\t[--msl-inline-uniform-block <set index> <binding>]:\n\t\tIn argument buffers, mark an UBO as being an inline uniform block which is embedded into the argument buffer itself.\n"
- "\t[--msl-decoration-binding]:\n\t\tUse SPIR-V bindings directly as MSL bindings.\n"
- "\t\tThis does not work in the general case as there is no descriptor set support, and combined image samplers are split up.\n"
- "\t\tHowever, if the shader author knows of binding limitations, this option will avoid the need for reflection on Metal side.\n"
- "\t[--msl-force-active-argument-buffer-resources]:\n\t\tAlways emit resources which are part of argument buffers.\n"
- "\t\tThis makes sure that similar shaders with same resource declarations can share the argument buffer as declaring an argument buffer implies an ABI.\n"
- "\t[--msl-force-native-arrays]:\n\t\tRather than implementing array types as a templated value type ala std::array<T>, use plain, native arrays.\n"
- "\t\tThis will lead to worse code-gen, but can work around driver bugs on certain driver revisions of certain Intel-based Macbooks where template arrays break.\n"
- "\t[--msl-disable-frag-depth-builtin]:\n\t\tDisables FragDepth output. Useful if pipeline does not enable depth, as pipeline creation might otherwise fail.\n"
- "\t[--msl-disable-frag-stencil-ref-builtin]:\n\t\tDisable FragStencilRef output. Useful if pipeline does not enable stencil output, as pipeline creation might otherwise fail.\n"
- "\t[--msl-enable-frag-output-mask <mask>]:\n\t\tOnly selectively enable fragment outputs. Useful if pipeline does not enable fragment output for certain locations, as pipeline creation might otherwise fail.\n"
- "\t[--msl-no-clip-distance-user-varying]:\n\t\tDo not emit user varyings to emulate gl_ClipDistance in fragment shaders.\n"
- "\t[--msl-add-shader-input <index> <format> <size> <rate>]:\n\t\tSpecify the format of the shader input at <index>.\n"
- "\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
- "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader. <rate> can be 'vertex', "
- "'primitive', or 'patch' to indicate a per-vertex, per-primitive, or per-patch variable.\n"
- "\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\n"
- "\t[--msl-add-shader-output <index> <format> <size> <rate>]:\n\t\tSpecify the format of the shader output at <index>.\n"
- "\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
- "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader. <rate> can be 'vertex', "
- "'primitive', or 'patch' to indicate a per-vertex, per-primitive, or per-patch variable.\n"
- "\t\tUseful if shader stage interfaces don't match up, as pipeline creation might otherwise fail.\n"
- "\t[--msl-shader-input <index> <format> <size>]:\n\t\tSpecify the format of the shader input at <index>.\n"
- "\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
- "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader."
- "\t\tEquivalent to --msl-add-shader-input with a rate of 'vertex'.\n"
- "\t[--msl-shader-output <index> <format> <size>]:\n\t\tSpecify the format of the shader output at <index>.\n"
- "\t\t<format> can be 'any32', 'any16', 'u16', 'u8', or 'other', to indicate a 32-bit opaque value, 16-bit opaque value, 16-bit unsigned integer, 8-bit unsigned integer, "
- "or other-typed variable. <size> is the vector length of the variable, which must be greater than or equal to that declared in the shader."
- "\t\tEquivalent to --msl-add-shader-output with a rate of 'vertex'.\n"
- "\t[--msl-raw-buffer-tese-input]:\n\t\tUse raw buffers for tessellation evaluation input.\n"
- "\t\tThis allows the use of nested structures and arrays.\n"
- "\t\tIn a future version of SPIRV-Cross, this will become the default.\n"
- "\t[--msl-multi-patch-workgroup]:\n\t\tUse the new style of tessellation control processing, where multiple patches are processed per workgroup.\n"
- "\t\tThis should increase throughput by ensuring all the GPU's SIMD lanes are occupied, but it is not compatible with the old style.\n"
- "\t\tIn addition, this style also passes input variables in buffers directly instead of using vertex attribute processing.\n"
- "\t\tIn a future version of SPIRV-Cross, this will become the default.\n"
- "\t[--msl-vertex-for-tessellation]:\n\t\tWhen handling a vertex shader, marks it as one that will be used with a new-style tessellation control shader.\n"
- "\t\tThe vertex shader is output to MSL as a compute kernel which outputs vertices to the buffer in the order they are received, rather than in index order as with --msl-capture-output normally.\n"
- "\t[--msl-additional-fixed-sample-mask <mask>]:\n"
- "\t\tSet an additional fixed sample mask. If the shader outputs a sample mask, then the final sample mask will be a bitwise AND of the two.\n"
- "\t[--msl-arrayed-subpass-input]:\n\t\tAssume that images of dimension SubpassData have multiple layers. Layered input attachments are accessed relative to BuiltInLayer.\n"
- "\t\tThis option has no effect if multiview is also enabled.\n"
- "\t[--msl-r32ui-linear-texture-align <alignment>]:\n\t\tThe required alignment of linear textures of format MTLPixelFormatR32Uint.\n"
- "\t\tThis is used to align the row stride for atomic accesses to such images.\n"
- "\t[--msl-r32ui-linear-texture-align-constant-id <id>]:\n\t\tThe function constant ID to use for the linear texture alignment.\n"
- "\t\tOn MSL 1.2 or later, you can override the alignment by setting this function constant.\n"
- "\t[--msl-texture-1d-as-2d]:\n\t\tEmit Image variables of dimension Dim1D as texture2d.\n"
- "\t\tIn Metal, 1D textures do not support all features that 2D textures do. Use this option if your code relies on these features.\n"
- "\t[--msl-ios-use-simdgroup-functions]:\n\t\tUse simd_*() functions for subgroup ops instead of quad_*().\n"
- "\t\tRecent Apple GPUs support SIMD-groups larger than a quad. Use this option to take advantage of this support.\n"
- "\t[--msl-emulate-subgroups]:\n\t\tAssume subgroups of size 1.\n"
- "\t\tIntended for Vulkan Portability implementations where Metal support for SIMD-groups is insufficient for true subgroups.\n"
- "\t[--msl-fixed-subgroup-size <size>]:\n\t\tAssign a constant <size> to the SubgroupSize builtin.\n"
- "\t\tIntended for Vulkan Portability implementations where VK_EXT_subgroup_size_control is not supported or disabled.\n"
- "\t\tIf 0, assume variable subgroup size as actually exposed by Metal.\n"
- "\t[--msl-force-sample-rate-shading]:\n\t\tForce fragment shaders to run per sample.\n"
- "\t\tThis adds a [[sample_id]] parameter if none is already present.\n"
- "\t[--msl-no-manual-helper-invocation-updates]:\n\t\tDo not manually update the HelperInvocation builtin when a fragment is discarded.\n"
- "\t\tSome Metal devices have a bug where simd_is_helper_thread() does not return true\n"
- "\t\tafter the fragment is discarded. This behavior is required by Vulkan and SPIR-V, however.\n"
- "\t[--msl-check-discarded-frag-stores]:\n\t\tAdd additional checks to resource stores in a fragment shader.\n"
- "\t\tSome Metal devices have a bug where stores to resources from a fragment shader\n"
- "\t\tcontinue to execute, even when the fragment is discarded. These checks\n"
- "\t\tprevent these stores from executing.\n"
- "\t[--msl-force-frag-execution]:\n\t\tEnforces fragment execution to avoid early discard by Metal\n"
- "\t\tMetal will prematurely discard fragments before execution when side effects are present.\n"
- "\t\tThis condition is triggered under the following conditions (side effect operations happen before discard):\n"
- "\t\t\t1. Pre fragment depth test fails.\n"
- "\t\t\t2. Modify depth value in fragment shader to constant value known at compile time.\n"
- "\t\t\t3. Constant value will not pass post fragment depth test.\n"
- "\t\t\t4. Fragment is always discarded in fragment execution.\n"
- "\t\tHowever, Vulkan expects fragment shader to be executed since it cannot be discarded until the discard\n"
- "\t\tpresent in the fragment execution, which would also execute the operations with side effects.\n"
- "\t[--msl-sample-dref-lod-array-as-grad]:\n\t\tUse a gradient instead of a level argument.\n"
- "\t\tSome Metal devices have a bug where the level() argument to\n"
- "\t\tdepth2d_array<T>::sample_compare() in a fragment shader is biased by some\n"
- "\t\tunknown amount. This prevents the bias from being added.\n"
- "\t[--msl-no-readwrite-texture-fences]:\n\t\tDo not insert fences before each read of a\n"
- "\t\tread_write texture. MSL does not guarantee coherence between writes and later reads\n"
- "\t\tof read_write textures. If you don't rely on this, you can disable this for a\n"
- "\t\tpossible performance improvement.\n"
- "\t[--msl-agx-manual-cube-grad-fixup]:\n\t\tManually transform cube texture gradients.\n"
- "\t\tAll released Apple Silicon GPUs to date ignore one of the three partial derivatives\n"
- "\t\tbased on the selected major axis, and expect the remaining derivatives to be\n"
- "\t\tpartially transformed. This fixup gives correct results on Apple Silicon.\n"
- "\t[--msl-combined-sampler-suffix <suffix>]:\n\t\tUses a custom suffix for combined samplers.\n"
- "\t[--msl-disable-rasterization]:\n\t\tDisables rasterization and returns void from vertex-like entry points.\n"
- "\t[--msl-auto-disable-rasterization]:\n\t\tDisables rasterization if BuiltInPosition is not written.\n"
- "\t[--msl-default-point-size <size>]:\n\t\tApplies a default value if BuiltInPointSize is not written.\n");
- // clang-format on
- }
- static void print_help_common()
- {
- // clang-format off
- fprintf(stderr, "\nCommon options:\n"
- "\t[--entry name]:\n\t\tUse a specific entry point. By default, the first entry point in the module is used.\n"
- "\t[--stage <stage (vert, frag, geom, tesc, tese, comp)>]:\n\t\tForces use of a certain shader stage.\n"
- "\t\tCan disambiguate the entry point if more than one entry point exists with same name, but different stage.\n"
- "\t[--emit-line-directives]:\n\t\tIf SPIR-V has OpLine directives, aim to emit those accurately in output code as well.\n"
- "\t[--rename-entry-point <old> <new> <stage>]:\n\t\tRenames an entry point from what is declared in SPIR-V to code output.\n"
- "\t\tMostly relevant for HLSL or MSL.\n"
- "\t[--rename-interface-variable <in|out> <location> <new_variable_name>]:\n\t\tRename an interface variable based on location decoration.\n"
- "\t[--force-zero-initialized-variables]:\n\t\tForces temporary variables to be initialized to zero.\n"
- "\t\tCan be useful in environments where compilers do not allow potentially uninitialized variables.\n"
- "\t\tThis usually comes up with Phi temporaries.\n"
- "\t[--fixup-clipspace]:\n\t\tFixup Z clip-space at the end of a vertex shader. The behavior is backend-dependent.\n"
- "\t\tGLSL: Rewrites [0, w] Z range (D3D/Metal/Vulkan) to GL-style [-w, w].\n"
- "\t\tHLSL/MSL: Rewrites [-w, w] Z range (GL) to D3D/Metal/Vulkan-style [0, w].\n"
- "\t[--flip-vert-y]:\n\t\tInverts gl_Position.y (or equivalent) at the end of a vertex shader. This is equivalent to using negative viewport height.\n"
- "\t[--mask-stage-output-location <location> <component>]:\n"
- "\t\tIf a stage output variable with matching location and component is active, optimize away the variable if applicable.\n"
- "\t[--mask-stage-output-builtin <Position|PointSize|ClipDistance|CullDistance>]:\n"
- "\t\tIf a stage output variable with matching builtin is active, "
- "optimize away the variable if it can affect cross-stage linking correctness.\n"
- "\t[--relax-nan-checks]:\n\t\tRelax NaN checks for N{Clamp,Min,Max} and ordered vs. unordered compare instructions.\n"
- );
- // clang-format on
- }
- static void print_help_obscure()
- {
- // clang-format off
- fprintf(stderr, "\nObscure options:\n"
- "\tThese options are not meant to be used on a regular basis. They have some occasional uses in the test suite.\n"
- "\t[--force-temporary]:\n\t\tAggressively emit temporary expressions instead of forwarding expressions. Very rarely used and under-tested.\n"
- "\t[--revision]:\n\t\tPrints build timestamp and Git commit information (updated when cmake is configured).\n"
- "\t[--iterations iter]:\n\t\tRecompiles the same shader over and over, benchmarking related.\n"
- "\t[--disable-storage-image-qualifier-deduction]:\n\t\tIf storage images are received without any nonwritable or nonreadable information,\n"""
- "\t\tdo not attempt to analyze usage, and always emit read/write state.\n"
- "\t[--flatten-multidimensional-arrays]:\n\t\tDo not support multi-dimensional arrays and flatten them to one dimension.\n"
- "\t[--cpp-interface-name <name>]:\n\t\tEmit a specific class name in C++ codegen.\n"
- "\t[--force-recompile-max-debug-iterations <count>]:\n\t\tAllow compilation loop to run for N loops.\n"
- "\t\tCan be used to triage workarounds, but should not be used as a crutch, since it masks an implementation bug.\n"
- );
- // clang-format on
- }
- static void print_help()
- {
- print_version();
- // clang-format off
- fprintf(stderr, "Usage: spirv-cross <...>\n"
- "\nBasic:\n"
- "\t[SPIR-V file] (- is stdin)\n"
- "\t[--output <output path>]: If not provided, prints output to stdout.\n"
- "\t[--dump-resources]:\n\t\tPrints a basic reflection of the SPIR-V module along with other output.\n"
- "\t[--help]:\n\t\tPrints this help message.\n"
- );
- // clang-format on
- print_help_backend();
- print_help_common();
- print_help_glsl();
- print_help_msl();
- print_help_hlsl();
- print_help_obscure();
- }
- static bool remap_generic(Compiler &compiler, const SmallVector<Resource> &resources, const Remap &remap)
- {
- auto itr =
- find_if(begin(resources), end(resources), [&remap](const Resource &res) { return res.name == remap.src_name; });
- if (itr != end(resources))
- {
- compiler.set_remapped_variable_state(itr->id, true);
- compiler.set_name(itr->id, remap.dst_name);
- compiler.set_subpass_input_remapped_components(itr->id, remap.components);
- return true;
- }
- else
- return false;
- }
- static vector<PlsRemap> remap_pls(const SmallVector<PLSArg> &pls_variables, const SmallVector<Resource> &resources,
- const SmallVector<Resource> *secondary_resources)
- {
- vector<PlsRemap> ret;
- for (auto &pls : pls_variables)
- {
- bool found = false;
- for (auto &res : resources)
- {
- if (res.name == pls.name)
- {
- ret.push_back({ res.id, pls.format });
- found = true;
- break;
- }
- }
- if (!found && secondary_resources)
- {
- for (auto &res : *secondary_resources)
- {
- if (res.name == pls.name)
- {
- ret.push_back({ res.id, pls.format });
- found = true;
- break;
- }
- }
- }
- if (!found)
- fprintf(stderr, "Did not find stage input/output/target with name \"%s\".\n", pls.name.c_str());
- }
- return ret;
- }
- static PlsFormat pls_format(const char *str)
- {
- if (!strcmp(str, "r11f_g11f_b10f"))
- return PlsR11FG11FB10F;
- else if (!strcmp(str, "r32f"))
- return PlsR32F;
- else if (!strcmp(str, "rg16f"))
- return PlsRG16F;
- else if (!strcmp(str, "rg16"))
- return PlsRG16;
- else if (!strcmp(str, "rgb10_a2"))
- return PlsRGB10A2;
- else if (!strcmp(str, "rgba8"))
- return PlsRGBA8;
- else if (!strcmp(str, "rgba8i"))
- return PlsRGBA8I;
- else if (!strcmp(str, "rgba8ui"))
- return PlsRGBA8UI;
- else if (!strcmp(str, "rg16i"))
- return PlsRG16I;
- else if (!strcmp(str, "rgb10_a2ui"))
- return PlsRGB10A2UI;
- else if (!strcmp(str, "rg16ui"))
- return PlsRG16UI;
- else if (!strcmp(str, "r32ui"))
- return PlsR32UI;
- else
- return PlsNone;
- }
- static ExecutionModel stage_to_execution_model(const std::string &stage)
- {
- if (stage == "vert")
- return ExecutionModelVertex;
- else if (stage == "frag")
- return ExecutionModelFragment;
- else if (stage == "comp")
- return ExecutionModelGLCompute;
- else if (stage == "tesc")
- return ExecutionModelTessellationControl;
- else if (stage == "tese")
- return ExecutionModelTessellationEvaluation;
- else if (stage == "geom")
- return ExecutionModelGeometry;
- else if (stage == "rgen")
- return ExecutionModelRayGenerationKHR;
- else if (stage == "rint")
- return ExecutionModelIntersectionKHR;
- else if (stage == "rahit")
- return ExecutionModelAnyHitKHR;
- else if (stage == "rchit")
- return ExecutionModelClosestHitKHR;
- else if (stage == "rmiss")
- return ExecutionModelMissKHR;
- else if (stage == "rcall")
- return ExecutionModelCallableKHR;
- else if (stage == "mesh")
- return ExecutionModelMeshEXT;
- else if (stage == "task")
- return ExecutionModelTaskEXT;
- else
- SPIRV_CROSS_THROW("Invalid stage.");
- }
- static HLSLBindingFlags hlsl_resource_type_to_flag(const std::string &arg)
- {
- if (arg == "push")
- return HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT;
- else if (arg == "cbv")
- return HLSL_BINDING_AUTO_CBV_BIT;
- else if (arg == "srv")
- return HLSL_BINDING_AUTO_SRV_BIT;
- else if (arg == "uav")
- return HLSL_BINDING_AUTO_UAV_BIT;
- else if (arg == "sampler")
- return HLSL_BINDING_AUTO_SAMPLER_BIT;
- else if (arg == "all")
- return HLSL_BINDING_AUTO_ALL;
- else
- {
- fprintf(stderr, "Invalid resource type for --hlsl-auto-binding: %s\n", arg.c_str());
- return 0;
- }
- }
- static string compile_iteration(const CLIArguments &args, std::vector<uint32_t> spirv_file)
- {
- Parser spirv_parser(std::move(spirv_file));
- spirv_parser.parse();
- unique_ptr<CompilerGLSL> compiler;
- bool combined_image_samplers = false;
- bool build_dummy_sampler = false;
- if (args.cpp)
- {
- compiler.reset(new CompilerCPP(std::move(spirv_parser.get_parsed_ir())));
- if (args.cpp_interface_name)
- static_cast<CompilerCPP *>(compiler.get())->set_interface_name(args.cpp_interface_name);
- }
- else if (args.msl)
- {
- compiler.reset(new CompilerMSL(std::move(spirv_parser.get_parsed_ir())));
- auto *msl_comp = static_cast<CompilerMSL *>(compiler.get());
- auto msl_opts = msl_comp->get_msl_options();
- if (args.set_msl_version)
- msl_opts.msl_version = args.msl_version;
- msl_opts.capture_output_to_buffer = args.msl_capture_output_to_buffer;
- msl_opts.swizzle_texture_samples = args.msl_swizzle_texture_samples;
- msl_opts.invariant_float_math = args.msl_invariant_float_math;
- if (args.msl_ios)
- {
- msl_opts.platform = CompilerMSL::Options::iOS;
- msl_opts.emulate_cube_array = args.msl_emulate_cube_array;
- }
- msl_opts.use_framebuffer_fetch_subpasses = args.msl_framebuffer_fetch;
- msl_opts.pad_fragment_output_components = args.msl_pad_fragment_output;
- msl_opts.tess_domain_origin_lower_left = args.msl_domain_lower_left;
- msl_opts.argument_buffers = args.msl_argument_buffers;
- msl_opts.argument_buffers_tier = static_cast<CompilerMSL::Options::ArgumentBuffersTier>(args.msl_argument_buffers_tier);
- msl_opts.texture_buffer_native = args.msl_texture_buffer_native;
- msl_opts.multiview = args.msl_multiview;
- msl_opts.multiview_layered_rendering = args.msl_multiview_layered_rendering;
- msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index;
- msl_opts.dispatch_base = args.msl_dispatch_base;
- msl_opts.enable_decoration_binding = args.msl_decoration_binding;
- msl_opts.force_active_argument_buffer_resources = args.msl_force_active_argument_buffer_resources;
- msl_opts.force_native_arrays = args.msl_force_native_arrays;
- msl_opts.enable_frag_depth_builtin = args.msl_enable_frag_depth_builtin;
- msl_opts.enable_frag_stencil_ref_builtin = args.msl_enable_frag_stencil_ref_builtin;
- msl_opts.enable_frag_output_mask = args.msl_enable_frag_output_mask;
- msl_opts.enable_clip_distance_user_varying = args.msl_enable_clip_distance_user_varying;
- msl_opts.raw_buffer_tese_input = args.msl_raw_buffer_tese_input;
- msl_opts.multi_patch_workgroup = args.msl_multi_patch_workgroup;
- msl_opts.vertex_for_tessellation = args.msl_vertex_for_tessellation;
- msl_opts.additional_fixed_sample_mask = args.msl_additional_fixed_sample_mask;
- msl_opts.arrayed_subpass_input = args.msl_arrayed_subpass_input;
- msl_opts.r32ui_linear_texture_alignment = args.msl_r32ui_linear_texture_alignment;
- msl_opts.r32ui_alignment_constant_id = args.msl_r32ui_alignment_constant_id;
- msl_opts.texture_1D_as_2D = args.msl_texture_1d_as_2d;
- msl_opts.ios_use_simdgroup_functions = args.msl_ios_use_simdgroup_functions;
- msl_opts.emulate_subgroups = args.msl_emulate_subgroups;
- msl_opts.fixed_subgroup_size = args.msl_fixed_subgroup_size;
- msl_opts.force_sample_rate_shading = args.msl_force_sample_rate_shading;
- msl_opts.manual_helper_invocation_updates = args.msl_manual_helper_invocation_updates;
- msl_opts.check_discarded_frag_stores = args.msl_check_discarded_frag_stores;
- msl_opts.force_fragment_with_side_effects_execution = args.msl_force_fragment_with_side_effects_execution;
- msl_opts.sample_dref_lod_array_as_grad = args.msl_sample_dref_lod_array_as_grad;
- msl_opts.ios_support_base_vertex_instance = true;
- msl_opts.runtime_array_rich_descriptor = args.msl_runtime_array_rich_descriptor;
- msl_opts.replace_recursive_inputs = args.msl_replace_recursive_inputs;
- msl_opts.input_attachment_is_ds_attachment = args.msl_input_attachment_is_ds_attachment;
- msl_opts.readwrite_texture_fences = args.msl_readwrite_texture_fences;
- msl_opts.agx_manual_cube_grad_fixup = args.msl_agx_manual_cube_grad_fixup;
- msl_opts.disable_rasterization = args.msl_disable_rasterization;
- msl_opts.auto_disable_rasterization = args.msl_auto_disable_rasterization;
- msl_opts.enable_point_size_default = args.msl_enable_point_size_default;
- msl_opts.default_point_size = args.msl_default_point_size;
- msl_comp->set_msl_options(msl_opts);
- for (auto &v : args.msl_discrete_descriptor_sets)
- msl_comp->add_discrete_descriptor_set(v);
- for (auto &v : args.msl_device_argument_buffers)
- msl_comp->set_argument_buffer_device_address_space(v, true);
- uint32_t i = 0;
- for (auto &v : args.msl_dynamic_buffers)
- msl_comp->add_dynamic_buffer(v.first, v.second, i++);
- for (auto &v : args.msl_inline_uniform_blocks)
- msl_comp->add_inline_uniform_block(v.first, v.second);
- for (auto &v : args.msl_shader_inputs)
- msl_comp->add_msl_shader_input(v);
- for (auto &v : args.msl_shader_outputs)
- msl_comp->add_msl_shader_output(v);
- if (args.msl_combined_sampler_suffix)
- msl_comp->set_combined_sampler_suffix(args.msl_combined_sampler_suffix);
- }
- else if (args.hlsl)
- compiler.reset(new CompilerHLSL(std::move(spirv_parser.get_parsed_ir())));
- else
- {
- combined_image_samplers = !args.vulkan_semantics;
- if (!args.vulkan_semantics || args.vulkan_glsl_disable_ext_samplerless_texture_functions)
- build_dummy_sampler = true;
- compiler.reset(new CompilerGLSL(std::move(spirv_parser.get_parsed_ir())));
- }
- if (!args.variable_type_remaps.empty())
- {
- auto remap_cb = [&](const SPIRType &, const string &name, string &out) -> void {
- for (const VariableTypeRemap &remap : args.variable_type_remaps)
- if (name == remap.variable_name)
- out = remap.new_variable_type;
- };
- compiler->set_variable_type_remap_callback(std::move(remap_cb));
- }
- for (auto &masked : args.masked_stage_outputs)
- compiler->mask_stage_output_by_location(masked.first, masked.second);
- for (auto &masked : args.masked_stage_builtins)
- compiler->mask_stage_output_by_builtin(masked);
- for (auto &rename : args.entry_point_rename)
- compiler->rename_entry_point(rename.old_name, rename.new_name, rename.execution_model);
- auto entry_points = compiler->get_entry_points_and_stages();
- auto entry_point = args.entry;
- ExecutionModel model = ExecutionModelMax;
- if (!args.entry_stage.empty())
- {
- model = stage_to_execution_model(args.entry_stage);
- if (entry_point.empty())
- {
- // Just use the first entry point with this stage.
- for (auto &e : entry_points)
- {
- if (e.execution_model == model)
- {
- entry_point = e.name;
- break;
- }
- }
- if (entry_point.empty())
- {
- fprintf(stderr, "Could not find an entry point with stage: %s\n", args.entry_stage.c_str());
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- // Make sure both stage and name exists.
- bool exists = false;
- for (auto &e : entry_points)
- {
- if (e.execution_model == model && e.name == entry_point)
- {
- exists = true;
- break;
- }
- }
- if (!exists)
- {
- fprintf(stderr, "Could not find an entry point %s with stage: %s\n", entry_point.c_str(),
- args.entry_stage.c_str());
- exit(EXIT_FAILURE);
- }
- }
- }
- else if (!entry_point.empty())
- {
- // Make sure there is just one entry point with this name, or the stage
- // is ambiguous.
- uint32_t stage_count = 0;
- for (auto &e : entry_points)
- {
- if (e.name == entry_point)
- {
- stage_count++;
- model = e.execution_model;
- }
- }
- if (stage_count == 0)
- {
- fprintf(stderr, "There is no entry point with name: %s\n", entry_point.c_str());
- exit(EXIT_FAILURE);
- }
- else if (stage_count > 1)
- {
- fprintf(stderr, "There is more than one entry point with name: %s. Use --stage.\n", entry_point.c_str());
- exit(EXIT_FAILURE);
- }
- }
- if (!entry_point.empty())
- compiler->set_entry_point(entry_point, model);
- if (!args.set_version && !compiler->get_common_options().version)
- {
- fprintf(stderr, "Didn't specify GLSL version and SPIR-V did not specify language.\n");
- print_help();
- exit(EXIT_FAILURE);
- }
- CompilerGLSL::Options opts = compiler->get_common_options();
- if (args.set_version)
- opts.version = args.version;
- if (args.set_es)
- opts.es = args.es;
- opts.force_temporary = args.force_temporary;
- opts.separate_shader_objects = args.sso;
- opts.flatten_multidimensional_arrays = args.flatten_multidimensional_arrays;
- opts.enable_420pack_extension = args.use_420pack_extension;
- opts.vulkan_semantics = args.vulkan_semantics;
- opts.vertex.fixup_clipspace = args.fixup;
- opts.vertex.flip_vert_y = args.yflip;
- opts.vertex.support_nonzero_base_instance = args.support_nonzero_baseinstance;
- opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo;
- opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms;
- opts.force_flattened_io_blocks = args.glsl_force_flattened_io_blocks;
- opts.ovr_multiview_view_count = args.glsl_ovr_multiview_view_count;
- opts.emit_line_directives = args.emit_line_directives;
- opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction;
- opts.force_zero_initialized_variables = args.force_zero_initialized_variables;
- opts.relax_nan_checks = args.relax_nan_checks;
- opts.force_recompile_max_debug_iterations = args.force_recompile_max_debug_iterations;
- compiler->set_common_options(opts);
- for (auto &fetch : args.glsl_ext_framebuffer_fetch)
- compiler->remap_ext_framebuffer_fetch(fetch.first, fetch.second, !args.glsl_ext_framebuffer_fetch_noncoherent);
- // Set HLSL specific options.
- if (args.hlsl)
- {
- auto *hlsl = static_cast<CompilerHLSL *>(compiler.get());
- auto hlsl_opts = hlsl->get_hlsl_options();
- if (args.set_shader_model)
- {
- if (args.shader_model < 30)
- {
- fprintf(stderr, "Shader model earlier than 30 (3.0) not supported.\n");
- exit(EXIT_FAILURE);
- }
- hlsl_opts.shader_model = args.shader_model;
- }
- if (args.hlsl_compat)
- {
- // Enable all compat options.
- hlsl_opts.point_size_compat = true;
- hlsl_opts.point_coord_compat = true;
- }
- if (hlsl_opts.shader_model <= 30)
- {
- combined_image_samplers = true;
- build_dummy_sampler = true;
- }
- // If we're explicitly renaming, we probably want that name to be output.
- if (!args.entry_point_rename.empty())
- hlsl_opts.use_entry_point_name = true;
- hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base;
- hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav;
- hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv;
- hlsl_opts.enable_16bit_types = args.hlsl_enable_16bit_types;
- hlsl_opts.flatten_matrix_vertex_input_semantics = args.hlsl_flatten_matrix_vertex_input_semantics;
- hlsl_opts.preserve_structured_buffers = args.hlsl_preserve_structured_buffers;
- hlsl->set_hlsl_options(hlsl_opts);
- hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
- if (args.hlsl_base_vertex_index_explicit_binding)
- {
- hlsl->set_hlsl_aux_buffer_binding(HLSL_AUX_BINDING_BASE_VERTEX_INSTANCE,
- args.hlsl_base_vertex_index_register_index,
- args.hlsl_base_vertex_index_register_space);
- }
- }
- if (build_dummy_sampler)
- {
- uint32_t sampler = compiler->build_dummy_sampler_for_combined_images();
- if (sampler != 0)
- {
- // Set some defaults to make validation happy.
- compiler->set_decoration(sampler, DecorationDescriptorSet, 0);
- compiler->set_decoration(sampler, DecorationBinding, 0);
- }
- }
- ShaderResources res;
- if (args.remove_unused)
- {
- auto active = compiler->get_active_interface_variables();
- res = compiler->get_shader_resources(active);
- compiler->set_enabled_interface_variables(std::move(active));
- }
- else
- res = compiler->get_shader_resources();
- if (args.flatten_ubo)
- {
- for (auto &ubo : res.uniform_buffers)
- compiler->flatten_buffer_block(ubo.id);
- for (auto &ubo : res.push_constant_buffers)
- compiler->flatten_buffer_block(ubo.id);
- }
- auto pls_inputs = remap_pls(args.pls_in, res.stage_inputs, &res.subpass_inputs);
- auto pls_outputs = remap_pls(args.pls_out, res.stage_outputs, nullptr);
- compiler->remap_pixel_local_storage(std::move(pls_inputs), std::move(pls_outputs));
- for (auto &ext : args.extensions)
- compiler->require_extension(ext);
- for (auto &remap : args.remaps)
- {
- if (remap_generic(*compiler, res.stage_inputs, remap))
- continue;
- if (remap_generic(*compiler, res.stage_outputs, remap))
- continue;
- if (remap_generic(*compiler, res.subpass_inputs, remap))
- continue;
- }
- for (auto &rename : args.interface_variable_renames)
- {
- if (rename.storageClass == StorageClassInput)
- spirv_cross_util::rename_interface_variable(*compiler, res.stage_inputs, rename.location,
- rename.variable_name);
- else if (rename.storageClass == StorageClassOutput)
- spirv_cross_util::rename_interface_variable(*compiler, res.stage_outputs, rename.location,
- rename.variable_name);
- else
- {
- fprintf(stderr, "error at --rename-interface-variable <in|out> ...\n");
- exit(EXIT_FAILURE);
- }
- }
- if (combined_image_samplers)
- {
- compiler->build_combined_image_samplers();
- if (args.combined_samplers_inherit_bindings)
- spirv_cross_util::inherit_combined_sampler_bindings(*compiler);
- // Give the remapped combined samplers new names.
- for (auto &remap : compiler->get_combined_image_samplers())
- {
- compiler->set_name(remap.combined_id, join("SPIRV_Cross_Combined", compiler->get_name(remap.image_id),
- compiler->get_name(remap.sampler_id)));
- }
- }
- if (args.hlsl)
- {
- auto *hlsl_compiler = static_cast<CompilerHLSL *>(compiler.get());
- hlsl_compiler->remap_num_workgroups_builtin();
- }
- if (args.hlsl)
- {
- for (auto &remap : args.hlsl_attr_remap)
- static_cast<CompilerHLSL *>(compiler.get())->add_vertex_attribute_remap(remap);
- for (auto &named_remap : args.hlsl_attr_remap_named)
- {
- auto itr = std::find_if(res.stage_inputs.begin(), res.stage_inputs.end(), [&](const Resource &input_res) {
- return input_res.name == named_remap.name;
- });
- if (itr != res.stage_inputs.end())
- {
- HLSLVertexAttributeRemap remap = {
- compiler->get_decoration(itr->id, DecorationLocation),
- named_remap.semantic,
- };
- static_cast<CompilerHLSL *>(compiler.get())->add_vertex_attribute_remap(remap);
- }
- }
- }
- auto ret = compiler->compile();
- if (args.dump_resources)
- {
- compiler->update_active_builtins();
- print_resources(*compiler, res);
- print_push_constant_resources(*compiler, res.push_constant_buffers);
- print_spec_constants(*compiler);
- print_capabilities_and_extensions(*compiler);
- }
- return ret;
- }
- static int main_inner(int argc, char *argv[])
- {
- CLIArguments args;
- CLICallbacks cbs;
- cbs.add("--help", [](CLIParser &parser) {
- print_help();
- parser.end();
- });
- cbs.add("--revision", [](CLIParser &parser) {
- print_version();
- parser.end();
- });
- cbs.add("--output", [&args](CLIParser &parser) { args.output = parser.next_string(); });
- cbs.add("--es", [&args](CLIParser &) {
- args.es = true;
- args.set_es = true;
- });
- cbs.add("--no-es", [&args](CLIParser &) {
- args.es = false;
- args.set_es = true;
- });
- cbs.add("--version", [&args](CLIParser &parser) {
- args.version = parser.next_uint();
- args.set_version = true;
- });
- cbs.add("--dump-resources", [&args](CLIParser &) { args.dump_resources = true; });
- cbs.add("--force-temporary", [&args](CLIParser &) { args.force_temporary = true; });
- cbs.add("--flatten-ubo", [&args](CLIParser &) { args.flatten_ubo = true; });
- cbs.add("--fixup-clipspace", [&args](CLIParser &) { args.fixup = true; });
- cbs.add("--flip-vert-y", [&args](CLIParser &) { args.yflip = true; });
- cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); });
- cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; });
- cbs.add("--reflect", [&args](CLIParser &parser) { args.reflect = parser.next_value_string("json"); });
- cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); });
- cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility
- cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; });
- cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; });
- cbs.add("--glsl-force-flattened-io-blocks", [&args](CLIParser &) { args.glsl_force_flattened_io_blocks = true; });
- cbs.add("--glsl-ovr-multiview-view-count", [&args](CLIParser &parser) { args.glsl_ovr_multiview_view_count = parser.next_uint(); });
- cbs.add("--glsl-remap-ext-framebuffer-fetch", [&args](CLIParser &parser) {
- uint32_t input_index = parser.next_uint();
- uint32_t color_attachment = parser.next_uint();
- args.glsl_ext_framebuffer_fetch.push_back({ input_index, color_attachment });
- });
- cbs.add("--glsl-ext-framebuffer-fetch-noncoherent", [&args](CLIParser &) {
- args.glsl_ext_framebuffer_fetch_noncoherent = true;
- });
- cbs.add("--vulkan-glsl-disable-ext-samplerless-texture-functions",
- [&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = true; });
- cbs.add("--disable-storage-image-qualifier-deduction",
- [&args](CLIParser &) { args.enable_storage_image_qualifier_deduction = false; });
- cbs.add("--force-zero-initialized-variables",
- [&args](CLIParser &) { args.force_zero_initialized_variables = true; });
- cbs.add("--msl", [&args](CLIParser &) { args.msl = true; });
- cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; });
- cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
- cbs.add("--hlsl-support-nonzero-basevertex-baseinstance",
- [&args](CLIParser &) { args.hlsl_support_nonzero_base = true; });
- cbs.add("--hlsl-basevertex-baseinstance-binding", [&args](CLIParser &parser) {
- args.hlsl_base_vertex_index_explicit_binding = true;
- args.hlsl_base_vertex_index_register_index = parser.next_uint();
- args.hlsl_base_vertex_index_register_space = parser.next_uint();
- });
- cbs.add("--hlsl-auto-binding", [&args](CLIParser &parser) {
- args.hlsl_binding_flags |= hlsl_resource_type_to_flag(parser.next_string());
- });
- cbs.add("--hlsl-force-storage-buffer-as-uav",
- [&args](CLIParser &) { args.hlsl_force_storage_buffer_as_uav = true; });
- cbs.add("--hlsl-nonwritable-uav-texture-as-srv",
- [&args](CLIParser &) { args.hlsl_nonwritable_uav_texture_as_srv = true; });
- cbs.add("--hlsl-enable-16bit-types", [&args](CLIParser &) { args.hlsl_enable_16bit_types = true; });
- cbs.add("--hlsl-flatten-matrix-vertex-input-semantics",
- [&args](CLIParser &) { args.hlsl_flatten_matrix_vertex_input_semantics = true; });
- cbs.add("--hlsl-preserve-structured-buffers", [&args](CLIParser &) { args.hlsl_preserve_structured_buffers = true; });
- cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
- cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; });
- cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
- cbs.add("--no-420pack-extension", [&args](CLIParser &) { args.use_420pack_extension = false; });
- cbs.add("--msl-capture-output", [&args](CLIParser &) { args.msl_capture_output_to_buffer = true; });
- cbs.add("--msl-swizzle-texture-samples", [&args](CLIParser &) { args.msl_swizzle_texture_samples = true; });
- cbs.add("--msl-ios", [&args](CLIParser &) { args.msl_ios = true; });
- cbs.add("--msl-pad-fragment-output", [&args](CLIParser &) { args.msl_pad_fragment_output = true; });
- cbs.add("--msl-domain-lower-left", [&args](CLIParser &) { args.msl_domain_lower_left = true; });
- cbs.add("--msl-argument-buffers", [&args](CLIParser &) { args.msl_argument_buffers = true; });
- cbs.add("--msl-argument-buffer-tier",
- [&args](CLIParser &parser) { args.msl_argument_buffers_tier = parser.next_uint(); });
- cbs.add("--msl-discrete-descriptor-set",
- [&args](CLIParser &parser) { args.msl_discrete_descriptor_sets.push_back(parser.next_uint()); });
- cbs.add("--msl-device-argument-buffer",
- [&args](CLIParser &parser) { args.msl_device_argument_buffers.push_back(parser.next_uint()); });
- cbs.add("--msl-texture-buffer-native", [&args](CLIParser &) { args.msl_texture_buffer_native = true; });
- cbs.add("--msl-framebuffer-fetch", [&args](CLIParser &) { args.msl_framebuffer_fetch = true; });
- cbs.add("--msl-invariant-float-math", [&args](CLIParser &) { args.msl_invariant_float_math = true; });
- cbs.add("--msl-emulate-cube-array", [&args](CLIParser &) { args.msl_emulate_cube_array = true; });
- cbs.add("--msl-multiview", [&args](CLIParser &) { args.msl_multiview = true; });
- cbs.add("--msl-multiview-no-layered-rendering",
- [&args](CLIParser &) { args.msl_multiview_layered_rendering = false; });
- cbs.add("--msl-view-index-from-device-index",
- [&args](CLIParser &) { args.msl_view_index_from_device_index = true; });
- cbs.add("--msl-dispatch-base", [&args](CLIParser &) { args.msl_dispatch_base = true; });
- cbs.add("--msl-dynamic-buffer", [&args](CLIParser &parser) {
- args.msl_argument_buffers = true;
- // Make sure next_uint() is called in-order.
- uint32_t desc_set = parser.next_uint();
- uint32_t binding = parser.next_uint();
- args.msl_dynamic_buffers.push_back(make_pair(desc_set, binding));
- });
- cbs.add("--msl-decoration-binding", [&args](CLIParser &) { args.msl_decoration_binding = true; });
- cbs.add("--msl-force-active-argument-buffer-resources",
- [&args](CLIParser &) { args.msl_force_active_argument_buffer_resources = true; });
- cbs.add("--msl-inline-uniform-block", [&args](CLIParser &parser) {
- args.msl_argument_buffers = true;
- // Make sure next_uint() is called in-order.
- uint32_t desc_set = parser.next_uint();
- uint32_t binding = parser.next_uint();
- args.msl_inline_uniform_blocks.push_back(make_pair(desc_set, binding));
- });
- cbs.add("--msl-force-native-arrays", [&args](CLIParser &) { args.msl_force_native_arrays = true; });
- cbs.add("--msl-disable-frag-depth-builtin", [&args](CLIParser &) { args.msl_enable_frag_depth_builtin = false; });
- cbs.add("--msl-disable-frag-stencil-ref-builtin",
- [&args](CLIParser &) { args.msl_enable_frag_stencil_ref_builtin = false; });
- cbs.add("--msl-enable-frag-output-mask",
- [&args](CLIParser &parser) { args.msl_enable_frag_output_mask = parser.next_hex_uint(); });
- cbs.add("--msl-no-clip-distance-user-varying",
- [&args](CLIParser &) { args.msl_enable_clip_distance_user_varying = false; });
- cbs.add("--msl-add-shader-input", [&args](CLIParser &parser) {
- MSLShaderInterfaceVariable input;
- // Make sure next_uint() is called in-order.
- input.location = parser.next_uint();
- const char *format = parser.next_value_string("other");
- if (strcmp(format, "any32") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_ANY32;
- else if (strcmp(format, "any16") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_ANY16;
- else if (strcmp(format, "u16") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_UINT16;
- else if (strcmp(format, "u8") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_UINT8;
- else
- input.format = MSL_SHADER_VARIABLE_FORMAT_OTHER;
- input.vecsize = parser.next_uint();
- const char *rate = parser.next_value_string("vertex");
- if (strcmp(rate, "primitive") == 0)
- input.rate = MSL_SHADER_VARIABLE_RATE_PER_PRIMITIVE;
- else if (strcmp(rate, "patch") == 0)
- input.rate = MSL_SHADER_VARIABLE_RATE_PER_PATCH;
- else
- input.rate = MSL_SHADER_VARIABLE_RATE_PER_VERTEX;
- args.msl_shader_inputs.push_back(input);
- });
- cbs.add("--msl-add-shader-output", [&args](CLIParser &parser) {
- MSLShaderInterfaceVariable output;
- // Make sure next_uint() is called in-order.
- output.location = parser.next_uint();
- const char *format = parser.next_value_string("other");
- if (strcmp(format, "any32") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_ANY32;
- else if (strcmp(format, "any16") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_ANY16;
- else if (strcmp(format, "u16") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_UINT16;
- else if (strcmp(format, "u8") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_UINT8;
- else
- output.format = MSL_SHADER_VARIABLE_FORMAT_OTHER;
- output.vecsize = parser.next_uint();
- const char *rate = parser.next_value_string("vertex");
- if (strcmp(rate, "primitive") == 0)
- output.rate = MSL_SHADER_VARIABLE_RATE_PER_PRIMITIVE;
- else if (strcmp(rate, "patch") == 0)
- output.rate = MSL_SHADER_VARIABLE_RATE_PER_PATCH;
- else
- output.rate = MSL_SHADER_VARIABLE_RATE_PER_VERTEX;
- args.msl_shader_outputs.push_back(output);
- });
- cbs.add("--msl-shader-input", [&args](CLIParser &parser) {
- MSLShaderInterfaceVariable input;
- // Make sure next_uint() is called in-order.
- input.location = parser.next_uint();
- const char *format = parser.next_value_string("other");
- if (strcmp(format, "any32") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_ANY32;
- else if (strcmp(format, "any16") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_ANY16;
- else if (strcmp(format, "u16") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_UINT16;
- else if (strcmp(format, "u8") == 0)
- input.format = MSL_SHADER_VARIABLE_FORMAT_UINT8;
- else
- input.format = MSL_SHADER_VARIABLE_FORMAT_OTHER;
- input.vecsize = parser.next_uint();
- args.msl_shader_inputs.push_back(input);
- });
- cbs.add("--msl-shader-output", [&args](CLIParser &parser) {
- MSLShaderInterfaceVariable output;
- // Make sure next_uint() is called in-order.
- output.location = parser.next_uint();
- const char *format = parser.next_value_string("other");
- if (strcmp(format, "any32") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_ANY32;
- else if (strcmp(format, "any16") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_ANY16;
- else if (strcmp(format, "u16") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_UINT16;
- else if (strcmp(format, "u8") == 0)
- output.format = MSL_SHADER_VARIABLE_FORMAT_UINT8;
- else
- output.format = MSL_SHADER_VARIABLE_FORMAT_OTHER;
- output.vecsize = parser.next_uint();
- args.msl_shader_outputs.push_back(output);
- });
- cbs.add("--msl-raw-buffer-tese-input", [&args](CLIParser &) { args.msl_raw_buffer_tese_input = true; });
- cbs.add("--msl-multi-patch-workgroup", [&args](CLIParser &) { args.msl_multi_patch_workgroup = true; });
- cbs.add("--msl-vertex-for-tessellation", [&args](CLIParser &) { args.msl_vertex_for_tessellation = true; });
- cbs.add("--msl-additional-fixed-sample-mask",
- [&args](CLIParser &parser) { args.msl_additional_fixed_sample_mask = parser.next_hex_uint(); });
- cbs.add("--msl-arrayed-subpass-input", [&args](CLIParser &) { args.msl_arrayed_subpass_input = true; });
- cbs.add("--msl-r32ui-linear-texture-align",
- [&args](CLIParser &parser) { args.msl_r32ui_linear_texture_alignment = parser.next_uint(); });
- cbs.add("--msl-r32ui-linear-texture-align-constant-id",
- [&args](CLIParser &parser) { args.msl_r32ui_alignment_constant_id = parser.next_uint(); });
- cbs.add("--msl-texture-1d-as-2d", [&args](CLIParser &) { args.msl_texture_1d_as_2d = true; });
- cbs.add("--msl-ios-use-simdgroup-functions", [&args](CLIParser &) { args.msl_ios_use_simdgroup_functions = true; });
- cbs.add("--msl-emulate-subgroups", [&args](CLIParser &) { args.msl_emulate_subgroups = true; });
- cbs.add("--msl-fixed-subgroup-size",
- [&args](CLIParser &parser) { args.msl_fixed_subgroup_size = parser.next_uint(); });
- cbs.add("--msl-force-sample-rate-shading", [&args](CLIParser &) { args.msl_force_sample_rate_shading = true; });
- cbs.add("--msl-no-manual-helper-invocation-updates",
- [&args](CLIParser &) { args.msl_manual_helper_invocation_updates = false; });
- cbs.add("--msl-check-discarded-frag-stores", [&args](CLIParser &) { args.msl_check_discarded_frag_stores = true; });
- cbs.add("--msl-force-frag-with-side-effects-execution", [&args](CLIParser &) { args.msl_force_fragment_with_side_effects_execution = true; });
- cbs.add("--msl-sample-dref-lod-array-as-grad",
- [&args](CLIParser &) { args.msl_sample_dref_lod_array_as_grad = true; });
- cbs.add("--msl-no-readwrite-texture-fences", [&args](CLIParser &) { args.msl_readwrite_texture_fences = false; });
- cbs.add("--msl-agx-manual-cube-grad-fixup", [&args](CLIParser &) { args.msl_agx_manual_cube_grad_fixup = true; });
- cbs.add("--msl-combined-sampler-suffix", [&args](CLIParser &parser) {
- args.msl_combined_sampler_suffix = parser.next_string();
- });
- cbs.add("--msl-runtime-array-rich-descriptor",
- [&args](CLIParser &) { args.msl_runtime_array_rich_descriptor = true; });
- cbs.add("--msl-replace-recursive-inputs",
- [&args](CLIParser &) { args.msl_replace_recursive_inputs = true; });
- cbs.add("--msl-input-attachment-is-ds-attachment", [&args](CLIParser &) { args.msl_input_attachment_is_ds_attachment = true; });
- cbs.add("--msl-disable-rasterization", [&args](CLIParser &) { args.msl_disable_rasterization = true; });
- cbs.add("--msl-auto-disable-rasterization", [&args](CLIParser &) { args.msl_auto_disable_rasterization = true; });
- cbs.add("--msl-default-point-size", [&args](CLIParser &parser) {
- args.msl_enable_point_size_default = true;
- args.msl_default_point_size = static_cast<float>(parser.next_double());
- });
- cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
- cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
- auto old_name = parser.next_string();
- auto new_name = parser.next_string();
- auto model = stage_to_execution_model(parser.next_string());
- args.entry_point_rename.push_back({ old_name, new_name, std::move(model) });
- });
- cbs.add("--entry", [&args](CLIParser &parser) { args.entry = parser.next_string(); });
- cbs.add("--stage", [&args](CLIParser &parser) { args.entry_stage = parser.next_string(); });
- cbs.add("--separate-shader-objects", [&args](CLIParser &) { args.sso = true; });
- cbs.add("--set-hlsl-vertex-input-semantic", [&args](CLIParser &parser) {
- HLSLVertexAttributeRemap remap;
- remap.location = parser.next_uint();
- remap.semantic = parser.next_string();
- args.hlsl_attr_remap.push_back(std::move(remap));
- });
- cbs.add("--set-hlsl-named-vertex-input-semantic", [&args](CLIParser &parser) {
- HLSLVertexAttributeRemapNamed remap;
- remap.name = parser.next_string();
- remap.semantic = parser.next_string();
- args.hlsl_attr_remap_named.push_back(std::move(remap));
- });
- cbs.add("--remap", [&args](CLIParser &parser) {
- string src = parser.next_string();
- string dst = parser.next_string();
- uint32_t components = parser.next_uint();
- args.remaps.push_back({ std::move(src), std::move(dst), components });
- });
- cbs.add("--remap-variable-type", [&args](CLIParser &parser) {
- string var_name = parser.next_string();
- string new_type = parser.next_string();
- args.variable_type_remaps.push_back({ std::move(var_name), std::move(new_type) });
- });
- cbs.add("--rename-interface-variable", [&args](CLIParser &parser) {
- StorageClass cls = StorageClassMax;
- string clsStr = parser.next_string();
- if (clsStr == "in")
- cls = StorageClassInput;
- else if (clsStr == "out")
- cls = StorageClassOutput;
- uint32_t loc = parser.next_uint();
- string var_name = parser.next_string();
- args.interface_variable_renames.push_back({ cls, loc, std::move(var_name) });
- });
- cbs.add("--pls-in", [&args](CLIParser &parser) {
- auto fmt = pls_format(parser.next_string());
- auto name = parser.next_string();
- args.pls_in.push_back({ std::move(fmt), std::move(name) });
- });
- cbs.add("--pls-out", [&args](CLIParser &parser) {
- auto fmt = pls_format(parser.next_string());
- auto name = parser.next_string();
- args.pls_out.push_back({ std::move(fmt), std::move(name) });
- });
- cbs.add("--shader-model", [&args](CLIParser &parser) {
- args.shader_model = parser.next_uint();
- args.set_shader_model = true;
- });
- cbs.add("--msl-version", [&args](CLIParser &parser) {
- args.msl_version = parser.next_uint();
- args.set_msl_version = true;
- });
- cbs.add("--remove-unused-variables", [&args](CLIParser &) { args.remove_unused = true; });
- cbs.add("--combined-samplers-inherit-bindings",
- [&args](CLIParser &) { args.combined_samplers_inherit_bindings = true; });
- cbs.add("--no-support-nonzero-baseinstance", [&](CLIParser &) { args.support_nonzero_baseinstance = false; });
- cbs.add("--emit-line-directives", [&args](CLIParser &) { args.emit_line_directives = true; });
- cbs.add("--mask-stage-output-location", [&](CLIParser &parser) {
- uint32_t location = parser.next_uint();
- uint32_t component = parser.next_uint();
- args.masked_stage_outputs.push_back({ location, component });
- });
- cbs.add("--mask-stage-output-builtin", [&](CLIParser &parser) {
- BuiltIn masked_builtin = BuiltInMax;
- std::string builtin = parser.next_string();
- if (builtin == "Position")
- masked_builtin = BuiltInPosition;
- else if (builtin == "PointSize")
- masked_builtin = BuiltInPointSize;
- else if (builtin == "CullDistance")
- masked_builtin = BuiltInCullDistance;
- else if (builtin == "ClipDistance")
- masked_builtin = BuiltInClipDistance;
- else
- {
- print_help();
- exit(EXIT_FAILURE);
- }
- args.masked_stage_builtins.push_back(masked_builtin);
- });
- cbs.add("--force-recompile-max-debug-iterations", [&](CLIParser &parser) {
- args.force_recompile_max_debug_iterations = parser.next_uint();
- });
- cbs.add("--relax-nan-checks", [&](CLIParser &) { args.relax_nan_checks = true; });
- cbs.default_handler = [&args](const char *value) { args.input = value; };
- cbs.add("-", [&args](CLIParser &) { args.input = "-"; });
- cbs.error_handler = [] { print_help(); };
- CLIParser parser{ std::move(cbs), argc - 1, argv + 1 };
- if (!parser.parse())
- return EXIT_FAILURE;
- else if (parser.ended_state)
- return EXIT_SUCCESS;
- if (!args.input)
- {
- fprintf(stderr, "Didn't specify input file.\n");
- print_help();
- return EXIT_FAILURE;
- }
- auto spirv_file = read_spirv_file(args.input);
- if (spirv_file.empty())
- return EXIT_FAILURE;
- // Special case reflection because it has little to do with the path followed by code-outputting compilers
- if (!args.reflect.empty())
- {
- Parser spirv_parser(std::move(spirv_file));
- spirv_parser.parse();
- CompilerReflection compiler(std::move(spirv_parser.get_parsed_ir()));
- compiler.set_format(args.reflect);
- auto json = compiler.compile();
- if (args.output)
- write_string_to_file(args.output, json.c_str());
- else
- printf("%s", json.c_str());
- return EXIT_SUCCESS;
- }
- string compiled_output;
- if (args.iterations == 1)
- compiled_output = compile_iteration(args, std::move(spirv_file));
- else
- {
- for (unsigned i = 0; i < args.iterations; i++)
- compiled_output = compile_iteration(args, spirv_file);
- }
- if (args.output)
- write_string_to_file(args.output, compiled_output.c_str());
- else
- printf("%s", compiled_output.c_str());
- return EXIT_SUCCESS;
- }
- int main(int argc, char *argv[])
- {
- #ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- return main_inner(argc, argv);
- #else
- // Make sure we catch the exception or it just disappears into the aether on Windows.
- try
- {
- return main_inner(argc, argv);
- }
- catch (const std::exception &e)
- {
- fprintf(stderr, "SPIRV-Cross threw an exception: %s\n", e.what());
- return EXIT_FAILURE;
- }
- #endif
- }
|