| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286 |
- /*
- * Copyright 2015-2019 Arm Limited
- *
- * 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.
- */
- #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 HAVE_SPIRV_CROSS_GIT_VERSION
- #include "gitversion.h"
- #endif
- #ifdef _MSC_VER
- #pragma warning(disable : 4996)
- #endif
- using namespace spv;
- 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(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);
- }
- 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;
- };
- static vector<uint32_t> read_spirv_file(const char *path)
- {
- 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;
- }
- 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 (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 (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(spv::ExecutionModel model)
- {
- switch (model)
- {
- case spv::ExecutionModelVertex:
- return "vertex";
- case spv::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);
- }
- 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 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;
- 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_view_index_from_device_index = false;
- bool msl_dispatch_base = false;
- bool glsl_emit_push_constant_as_ubo = false;
- bool glsl_emit_ubo_as_plain_uniforms = false;
- bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
- bool emit_line_directives = false;
- SmallVector<uint32_t> msl_discrete_descriptor_sets;
- SmallVector<uint32_t> msl_device_argument_buffers;
- SmallVector<pair<uint32_t, uint32_t>> msl_dynamic_buffers;
- 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;
- 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;
- 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()
- {
- print_version();
- fprintf(stderr, "Usage: spirv-cross\n"
- "\t[--output <output path>]\n"
- "\t[SPIR-V file]\n"
- "\t[--es]\n"
- "\t[--no-es]\n"
- "\t[--version <GLSL version>]\n"
- "\t[--dump-resources]\n"
- "\t[--help]\n"
- "\t[--revision]\n"
- "\t[--force-temporary]\n"
- "\t[--vulkan-semantics]\n"
- "\t[--flatten-ubo]\n"
- "\t[--fixup-clipspace]\n"
- "\t[--flip-vert-y]\n"
- "\t[--iterations iter]\n"
- "\t[--cpp]\n"
- "\t[--cpp-interface-name <name>]\n"
- "\t[--glsl-emit-push-constant-as-ubo]\n"
- "\t[--glsl-emit-ubo-as-plain-uniforms]\n"
- "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]\n"
- "\t[--msl]\n"
- "\t[--msl-version <MMmmpp>]\n"
- "\t[--msl-capture-output]\n"
- "\t[--msl-swizzle-texture-samples]\n"
- "\t[--msl-ios]\n"
- "\t[--msl-pad-fragment-output]\n"
- "\t[--msl-domain-lower-left]\n"
- "\t[--msl-argument-buffers]\n"
- "\t[--msl-texture-buffer-native]\n"
- "\t[--msl-framebuffer-fetch]\n"
- "\t[--msl-emulate-cube-array]\n"
- "\t[--msl-discrete-descriptor-set <index>]\n"
- "\t[--msl-device-argument-buffer <index>]\n"
- "\t[--msl-multiview]\n"
- "\t[--msl-view-index-from-device-index]\n"
- "\t[--msl-dispatch-base]\n"
- "\t[--msl-dynamic-buffer <set index> <binding>]\n"
- "\t[--hlsl]\n"
- "\t[--reflect]\n"
- "\t[--shader-model]\n"
- "\t[--hlsl-enable-compat]\n"
- "\t[--hlsl-support-nonzero-basevertex-baseinstance]\n"
- "\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n"
- "\t[--separate-shader-objects]\n"
- "\t[--pls-in format input-name]\n"
- "\t[--pls-out format output-name]\n"
- "\t[--remap source_name target_name components]\n"
- "\t[--extension ext]\n"
- "\t[--entry name]\n"
- "\t[--stage <stage (vert, frag, geom, tesc, tese comp)>]\n"
- "\t[--remove-unused-variables]\n"
- "\t[--flatten-multidimensional-arrays]\n"
- "\t[--no-420pack-extension]\n"
- "\t[--remap-variable-type <variable_name> <new_variable_type>]\n"
- "\t[--rename-interface-variable <in|out> <location> <new_variable_name>]\n"
- "\t[--set-hlsl-vertex-input-semantic <location> <semantic>]\n"
- "\t[--rename-entry-point <old> <new> <stage>]\n"
- "\t[--combined-samplers-inherit-bindings]\n"
- "\t[--no-support-nonzero-baseinstance]\n"
- "\t[--emit-line-directives]\n"
- "\n");
- }
- 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
- 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(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(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(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.ios_use_framebuffer_fetch_subpasses = args.msl_framebuffer_fetch;
- msl_opts.emulate_cube_array = args.msl_emulate_cube_array;
- }
- 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.texture_buffer_native = args.msl_texture_buffer_native;
- msl_opts.multiview = args.msl_multiview;
- msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index;
- msl_opts.dispatch_base = args.msl_dispatch_base;
- 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++);
- }
- else if (args.hlsl)
- compiler.reset(new CompilerHLSL(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(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(move(remap_cb));
- }
- 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.emit_line_directives = args.emit_line_directives;
- compiler->set_common_options(opts);
- // 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;
- }
- hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base;
- hlsl->set_hlsl_options(hlsl_opts);
- hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
- }
- 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(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(move(pls_inputs), 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 (args.dump_resources)
- {
- print_resources(*compiler, res);
- print_push_constant_resources(*compiler, res.push_constant_buffers);
- print_spec_constants(*compiler);
- print_capabilities_and_extensions(*compiler);
- }
- 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());
- uint32_t new_builtin = hlsl_compiler->remap_num_workgroups_builtin();
- if (new_builtin)
- {
- hlsl_compiler->set_decoration(new_builtin, DecorationDescriptorSet, 0);
- hlsl_compiler->set_decoration(new_builtin, DecorationBinding, 0);
- }
- }
- if (args.hlsl)
- {
- for (auto &remap : args.hlsl_attr_remap)
- static_cast<CompilerHLSL *>(compiler.get())->add_vertex_attribute_remap(remap);
- }
- return compiler->compile();
- }
- 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("--vulkan-glsl-disable-ext-samplerless-texture-functions",
- [&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = 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-auto-binding", [&args](CLIParser &parser) {
- args.hlsl_binding_flags |= hlsl_resource_type_to_flag(parser.next_string());
- });
- cbs.add("--vulkan-semantics", [&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-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-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("--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, 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(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({ move(src), 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({ move(var_name), 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, 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({ move(fmt), 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({ move(fmt), 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.default_handler = [&args](const char *value) { args.input = value; };
- cbs.error_handler = [] { print_help(); };
- CLIParser parser{ 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(move(spirv_file));
- spirv_parser.parse();
- CompilerReflection compiler(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, 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
- }
|