| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032 |
- /*
- * 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;
- bool hlsl_user_semantic = 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"
- "\t[--hlsl-user-semantic]:\n\t\tUses UserSemantic decoration to generate vertex input and output semantics.\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_opts.user_semantic = args.hlsl_user_semantic;
- 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("--hlsl-user-semantic", [&args](CLIParser &) { args.hlsl_user_semantic = 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
- }
|