Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015-2016 ARM Limited |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Hans-Kristian Arntzen | 147e53a | 2016-04-04 09:36:04 +0200 | [diff] [blame] | 17 | #include "spirv_cpp.hpp" |
Bill Hollings | 5f2d666 | 2016-04-11 11:31:03 -0400 | [diff] [blame] | 18 | #include "spirv_msl.hpp" |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 19 | #include <algorithm> |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 20 | #include <cstdio> |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 21 | #include <cstring> |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 22 | #include <functional> |
| 23 | #include <limits> |
| 24 | #include <memory> |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 25 | #include <stdexcept> |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 26 | #include <unordered_map> |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 27 | #include <unordered_set> |
| 28 | |
| 29 | using namespace spv; |
Hans-Kristian Arntzen | 147e53a | 2016-04-04 09:36:04 +0200 | [diff] [blame] | 30 | using namespace spirv_cross; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 31 | using namespace std; |
| 32 | |
| 33 | struct CLIParser; |
| 34 | struct CLICallbacks |
| 35 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 36 | void add(const char *cli, const function<void(CLIParser &)> &func) |
| 37 | { |
| 38 | callbacks[cli] = func; |
| 39 | } |
| 40 | unordered_map<string, function<void(CLIParser &)>> callbacks; |
| 41 | function<void()> error_handler; |
| 42 | function<void(const char *)> default_handler; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 43 | }; |
| 44 | |
| 45 | struct CLIParser |
| 46 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 47 | CLIParser(CLICallbacks cbs_, int argc_, char *argv_[]) |
| 48 | : cbs(move(cbs_)) |
| 49 | , argc(argc_) |
| 50 | , argv(argv_) |
| 51 | { |
| 52 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 53 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 54 | bool parse() |
| 55 | { |
| 56 | try |
| 57 | { |
| 58 | while (argc && !ended_state) |
| 59 | { |
| 60 | const char *next = *argv++; |
| 61 | argc--; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 62 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 63 | if (*next != '-' && cbs.default_handler) |
| 64 | { |
| 65 | cbs.default_handler(next); |
| 66 | } |
| 67 | else |
| 68 | { |
| 69 | auto itr = cbs.callbacks.find(next); |
| 70 | if (itr == ::end(cbs.callbacks)) |
| 71 | { |
| 72 | throw logic_error("Invalid argument.\n"); |
| 73 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 74 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 75 | itr->second(*this); |
| 76 | } |
| 77 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 78 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 79 | return true; |
| 80 | } |
| 81 | catch (...) |
| 82 | { |
| 83 | if (cbs.error_handler) |
| 84 | { |
| 85 | cbs.error_handler(); |
| 86 | } |
| 87 | return false; |
| 88 | } |
| 89 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 90 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 91 | void end() |
| 92 | { |
| 93 | ended_state = true; |
| 94 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 95 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 96 | uint32_t next_uint() |
| 97 | { |
| 98 | if (!argc) |
| 99 | { |
| 100 | throw logic_error("Tried to parse uint, but nothing left in arguments.\n"); |
| 101 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 102 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 103 | uint32_t val = stoul(*argv); |
| 104 | if (val > numeric_limits<uint32_t>::max()) |
| 105 | { |
| 106 | throw out_of_range("next_uint() out of range.\n"); |
| 107 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 108 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 109 | argc--; |
| 110 | argv++; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 111 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 112 | return val; |
| 113 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 114 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 115 | double next_double() |
| 116 | { |
| 117 | if (!argc) |
| 118 | { |
| 119 | throw logic_error("Tried to parse double, but nothing left in arguments.\n"); |
| 120 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 121 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 122 | double val = stod(*argv); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 123 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 124 | argc--; |
| 125 | argv++; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 126 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 127 | return val; |
| 128 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 129 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 130 | const char *next_string() |
| 131 | { |
| 132 | if (!argc) |
| 133 | { |
| 134 | throw logic_error("Tried to parse string, but nothing left in arguments.\n"); |
| 135 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 136 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 137 | const char *ret = *argv; |
| 138 | argc--; |
| 139 | argv++; |
| 140 | return ret; |
| 141 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 142 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 143 | CLICallbacks cbs; |
| 144 | int argc; |
| 145 | char **argv; |
| 146 | bool ended_state = false; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 147 | }; |
| 148 | |
| 149 | static vector<uint32_t> read_spirv_file(const char *path) |
| 150 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 151 | FILE *file = fopen(path, "rb"); |
| 152 | if (!file) |
| 153 | { |
| 154 | fprintf(stderr, "Failed to open SPIRV file: %s\n", path); |
| 155 | return {}; |
| 156 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 157 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 158 | fseek(file, 0, SEEK_END); |
| 159 | long len = ftell(file) / sizeof(uint32_t); |
| 160 | rewind(file); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 161 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 162 | vector<uint32_t> spirv(len); |
| 163 | if (fread(spirv.data(), sizeof(uint32_t), len, file) != size_t(len)) |
| 164 | spirv.clear(); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 165 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 166 | fclose(file); |
| 167 | return spirv; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | static bool write_string_to_file(const char *path, const char *string) |
| 171 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 172 | FILE *file = fopen(path, "w"); |
| 173 | if (!file) |
| 174 | { |
| 175 | fprintf(file, "Failed to write file: %s\n", path); |
| 176 | return false; |
| 177 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 178 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 179 | fprintf(file, "%s", string); |
| 180 | fclose(file); |
| 181 | return true; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | static void print_resources(const Compiler &compiler, const char *tag, const vector<Resource> &resources) |
| 185 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 186 | fprintf(stderr, "%s\n", tag); |
| 187 | fprintf(stderr, "=============\n\n"); |
| 188 | for (auto &res : resources) |
| 189 | { |
| 190 | auto &type = compiler.get_type(res.type_id); |
| 191 | auto mask = compiler.get_decoration_mask(res.id); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 192 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 193 | // If we don't have a name, use the fallback for the type instead of the variable |
| 194 | // for SSBOs and UBOs since those are the only meaningful names to use externally. |
| 195 | // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks. |
| 196 | bool is_push_constant = compiler.get_storage_class(res.id) == StorageClassPushConstant; |
| 197 | bool is_block = (compiler.get_decoration_mask(type.self) & |
| 198 | ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0; |
Hans-Kristian Arntzen | 5c24d99 | 2016-07-12 21:20:18 +0200 | [diff] [blame] | 199 | uint32_t fallback_id = !is_push_constant && is_block ? res.base_type_id : res.id; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 200 | |
Hans-Kristian Arntzen | 5c24d99 | 2016-07-12 21:20:18 +0200 | [diff] [blame] | 201 | string array; |
| 202 | for (auto arr : type.array) |
| 203 | array = join("[", arr ? convert_to_string(arr) : "", "]") + array; |
| 204 | |
| 205 | fprintf(stderr, " ID %03u : %s%s", res.id, |
| 206 | !res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str(), array.c_str()); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 207 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 208 | if (mask & (1ull << DecorationLocation)) |
| 209 | fprintf(stderr, " (Location : %u)", compiler.get_decoration(res.id, DecorationLocation)); |
| 210 | if (mask & (1ull << DecorationDescriptorSet)) |
| 211 | fprintf(stderr, " (Set : %u)", compiler.get_decoration(res.id, DecorationDescriptorSet)); |
| 212 | if (mask & (1ull << DecorationBinding)) |
| 213 | fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding)); |
| 214 | if (mask & (1ull << DecorationInputAttachmentIndex)) |
| 215 | fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex)); |
| 216 | fprintf(stderr, "\n"); |
| 217 | } |
| 218 | fprintf(stderr, "=============\n\n"); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | static void print_resources(const Compiler &compiler, const ShaderResources &res) |
| 222 | { |
Hans-Kristian Arntzen | 3c285a1 | 2016-07-04 13:30:05 +0200 | [diff] [blame] | 223 | uint64_t modes = compiler.get_execution_mode_mask(); |
| 224 | |
| 225 | fprintf(stderr, "Execution modes:\n"); |
| 226 | for (unsigned i = 0; i < 64; i++) |
| 227 | { |
| 228 | if (!(modes & (1ull << i))) |
| 229 | continue; |
| 230 | |
| 231 | auto mode = static_cast<ExecutionMode>(i); |
| 232 | uint32_t arg0 = compiler.get_execution_mode_argument(mode, 0); |
| 233 | uint32_t arg1 = compiler.get_execution_mode_argument(mode, 1); |
| 234 | uint32_t arg2 = compiler.get_execution_mode_argument(mode, 2); |
| 235 | |
| 236 | switch (static_cast<ExecutionMode>(i)) |
| 237 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 238 | case ExecutionModeInvocations: |
| 239 | fprintf(stderr, " Invocations: %u\n", arg0); |
| 240 | break; |
Hans-Kristian Arntzen | 3c285a1 | 2016-07-04 13:30:05 +0200 | [diff] [blame] | 241 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 242 | case ExecutionModeLocalSize: |
| 243 | fprintf(stderr, " LocalSize: (%u, %u, %u)\n", arg0, arg1, arg2); |
| 244 | break; |
Hans-Kristian Arntzen | 3c285a1 | 2016-07-04 13:30:05 +0200 | [diff] [blame] | 245 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 246 | case ExecutionModeOutputVertices: |
| 247 | fprintf(stderr, " OutputVertices: %u\n", arg0); |
| 248 | break; |
Hans-Kristian Arntzen | 3c285a1 | 2016-07-04 13:30:05 +0200 | [diff] [blame] | 249 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 250 | #define CHECK_MODE(m) \ |
| 251 | case ExecutionMode##m: \ |
| 252 | fprintf(stderr, " %s\n", #m); \ |
| 253 | break |
| 254 | CHECK_MODE(SpacingEqual); |
| 255 | CHECK_MODE(SpacingFractionalEven); |
| 256 | CHECK_MODE(SpacingFractionalOdd); |
| 257 | CHECK_MODE(VertexOrderCw); |
| 258 | CHECK_MODE(VertexOrderCcw); |
| 259 | CHECK_MODE(PixelCenterInteger); |
| 260 | CHECK_MODE(OriginUpperLeft); |
| 261 | CHECK_MODE(OriginLowerLeft); |
| 262 | CHECK_MODE(EarlyFragmentTests); |
| 263 | CHECK_MODE(PointMode); |
| 264 | CHECK_MODE(Xfb); |
| 265 | CHECK_MODE(DepthReplacing); |
| 266 | CHECK_MODE(DepthGreater); |
| 267 | CHECK_MODE(DepthLess); |
| 268 | CHECK_MODE(DepthUnchanged); |
| 269 | CHECK_MODE(LocalSizeHint); |
| 270 | CHECK_MODE(InputPoints); |
| 271 | CHECK_MODE(InputLines); |
| 272 | CHECK_MODE(InputLinesAdjacency); |
| 273 | CHECK_MODE(Triangles); |
| 274 | CHECK_MODE(InputTrianglesAdjacency); |
| 275 | CHECK_MODE(Quads); |
| 276 | CHECK_MODE(Isolines); |
| 277 | CHECK_MODE(OutputPoints); |
| 278 | CHECK_MODE(OutputLineStrip); |
| 279 | CHECK_MODE(OutputTriangleStrip); |
| 280 | CHECK_MODE(VecTypeHint); |
| 281 | CHECK_MODE(ContractionOff); |
Hans-Kristian Arntzen | 3c285a1 | 2016-07-04 13:30:05 +0200 | [diff] [blame] | 282 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 283 | default: |
| 284 | break; |
Hans-Kristian Arntzen | 3c285a1 | 2016-07-04 13:30:05 +0200 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | fprintf(stderr, "\n"); |
| 288 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 289 | print_resources(compiler, "subpass inputs", res.subpass_inputs); |
| 290 | print_resources(compiler, "inputs", res.stage_inputs); |
| 291 | print_resources(compiler, "outputs", res.stage_outputs); |
| 292 | print_resources(compiler, "textures", res.sampled_images); |
| 293 | print_resources(compiler, "images", res.storage_images); |
| 294 | print_resources(compiler, "ssbos", res.storage_buffers); |
| 295 | print_resources(compiler, "ubos", res.uniform_buffers); |
| 296 | print_resources(compiler, "push", res.push_constant_buffers); |
| 297 | print_resources(compiler, "counters", res.atomic_counters); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 298 | } |
| 299 | |
| 300 | static void print_push_constant_resources(const Compiler &compiler, const vector<Resource> &res) |
| 301 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 302 | for (auto &block : res) |
| 303 | { |
| 304 | auto ranges = compiler.get_active_buffer_ranges(block.id); |
| 305 | fprintf(stderr, "Active members in buffer: %s\n", |
| 306 | !block.name.empty() ? block.name.c_str() : compiler.get_fallback_name(block.id).c_str()); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 307 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 308 | fprintf(stderr, "==================\n\n"); |
| 309 | for (auto &range : ranges) |
| 310 | { |
Hans-Kristian Arntzen | 5c24d99 | 2016-07-12 21:20:18 +0200 | [diff] [blame] | 311 | const auto &name = compiler.get_member_name(block.base_type_id, range.index); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 312 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 313 | fprintf(stderr, "Member #%3u (%s): Offset: %4u, Range: %4u\n", range.index, |
| 314 | !name.empty() ? name.c_str() : compiler.get_fallback_member_name(range.index).c_str(), |
| 315 | unsigned(range.offset), unsigned(range.range)); |
| 316 | } |
| 317 | fprintf(stderr, "==================\n\n"); |
| 318 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 319 | } |
| 320 | |
| 321 | struct PLSArg |
| 322 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 323 | PlsFormat format; |
| 324 | string name; |
| 325 | }; |
| 326 | |
| 327 | struct Remap |
| 328 | { |
| 329 | string src_name; |
| 330 | string dst_name; |
| 331 | unsigned components; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 332 | }; |
| 333 | |
| 334 | struct CLIArguments |
| 335 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 336 | const char *input = nullptr; |
| 337 | const char *output = nullptr; |
| 338 | const char *cpp_interface_name = nullptr; |
| 339 | uint32_t version = 0; |
| 340 | bool es = false; |
| 341 | bool set_version = false; |
| 342 | bool set_es = false; |
| 343 | bool dump_resources = false; |
| 344 | bool force_temporary = false; |
| 345 | bool flatten_ubo = false; |
| 346 | bool fixup = false; |
| 347 | vector<PLSArg> pls_in; |
| 348 | vector<PLSArg> pls_out; |
| 349 | vector<Remap> remaps; |
| 350 | vector<string> extensions; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 351 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 352 | uint32_t iterations = 1; |
| 353 | bool cpp = false; |
| 354 | bool metal = false; |
| 355 | bool vulkan_semantics = false; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 356 | }; |
| 357 | |
| 358 | static void print_help() |
| 359 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 360 | fprintf(stderr, "Usage: spirv-cross [--output <output path>] [SPIR-V file] [--es] [--no-es] [--version <GLSL " |
| 361 | "version>] [--dump-resources] [--help] [--force-temporary] [--cpp] [--cpp-interface-name <name>] " |
| 362 | "[--metal] [--vulkan-semantics] [--flatten-ubo] [--fixup-clipspace] [--iterations iter] [--pls-in " |
| 363 | "format input-name] [--pls-out format output-name] [--remap source_name target_name components] " |
| 364 | "[--extension ext]\n"); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 365 | } |
| 366 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 367 | static bool remap_generic(Compiler &compiler, const vector<Resource> &resources, const Remap &remap) |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 368 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 369 | auto itr = |
| 370 | find_if(begin(resources), end(resources), [&remap](const Resource &res) { return res.name == remap.src_name; }); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 371 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 372 | if (itr != end(resources)) |
| 373 | { |
| 374 | compiler.set_remapped_variable_state(itr->id, true); |
| 375 | compiler.set_name(itr->id, remap.dst_name); |
| 376 | compiler.set_subpass_input_remapped_components(itr->id, remap.components); |
| 377 | return true; |
| 378 | } |
| 379 | else |
| 380 | return false; |
| 381 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 382 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 383 | static vector<PlsRemap> remap_pls(const vector<PLSArg> &pls_variables, const vector<Resource> &resources, |
| 384 | const vector<Resource> *secondary_resources) |
| 385 | { |
| 386 | vector<PlsRemap> ret; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 387 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 388 | for (auto &pls : pls_variables) |
| 389 | { |
| 390 | bool found = false; |
| 391 | for (auto &res : resources) |
| 392 | { |
| 393 | if (res.name == pls.name) |
| 394 | { |
| 395 | ret.push_back({ res.id, pls.format }); |
| 396 | found = true; |
| 397 | break; |
| 398 | } |
| 399 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 400 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 401 | if (!found && secondary_resources) |
| 402 | { |
| 403 | for (auto &res : *secondary_resources) |
| 404 | { |
| 405 | if (res.name == pls.name) |
| 406 | { |
| 407 | ret.push_back({ res.id, pls.format }); |
| 408 | found = true; |
| 409 | break; |
| 410 | } |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | if (!found) |
| 415 | fprintf(stderr, "Did not find stage input/output/target with name \"%s\".\n", pls.name.c_str()); |
| 416 | } |
| 417 | |
| 418 | return ret; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 419 | } |
| 420 | |
| 421 | static PlsFormat pls_format(const char *str) |
| 422 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 423 | if (!strcmp(str, "r11f_g11f_b10f")) |
| 424 | return PlsR11FG11FB10F; |
| 425 | else if (!strcmp(str, "r32f")) |
| 426 | return PlsR32F; |
| 427 | else if (!strcmp(str, "rg16f")) |
| 428 | return PlsRG16F; |
| 429 | else if (!strcmp(str, "rg16")) |
| 430 | return PlsRG16; |
| 431 | else if (!strcmp(str, "rgb10_a2")) |
| 432 | return PlsRGB10A2; |
| 433 | else if (!strcmp(str, "rgba8")) |
| 434 | return PlsRGBA8; |
| 435 | else if (!strcmp(str, "rgba8i")) |
| 436 | return PlsRGBA8I; |
| 437 | else if (!strcmp(str, "rgba8ui")) |
| 438 | return PlsRGBA8UI; |
| 439 | else if (!strcmp(str, "rg16i")) |
| 440 | return PlsRG16I; |
| 441 | else if (!strcmp(str, "rgb10_a2ui")) |
| 442 | return PlsRGB10A2UI; |
| 443 | else if (!strcmp(str, "rg16ui")) |
| 444 | return PlsRG16UI; |
| 445 | else if (!strcmp(str, "r32ui")) |
| 446 | return PlsR32UI; |
| 447 | else |
| 448 | return PlsNone; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 449 | } |
| 450 | |
| 451 | int main(int argc, char *argv[]) |
| 452 | { |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 453 | CLIArguments args; |
| 454 | CLICallbacks cbs; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 455 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 456 | cbs.add("--help", [](CLIParser &parser) { |
| 457 | print_help(); |
| 458 | parser.end(); |
| 459 | }); |
| 460 | cbs.add("--output", [&args](CLIParser &parser) { args.output = parser.next_string(); }); |
| 461 | cbs.add("--es", [&args](CLIParser &) { |
| 462 | args.es = true; |
| 463 | args.set_es = true; |
| 464 | }); |
| 465 | cbs.add("--no-es", [&args](CLIParser &) { |
| 466 | args.es = false; |
| 467 | args.set_es = true; |
| 468 | }); |
| 469 | cbs.add("--version", [&args](CLIParser &parser) { |
| 470 | args.version = parser.next_uint(); |
| 471 | args.set_version = true; |
| 472 | }); |
| 473 | cbs.add("--dump-resources", [&args](CLIParser &) { args.dump_resources = true; }); |
| 474 | cbs.add("--force-temporary", [&args](CLIParser &) { args.force_temporary = true; }); |
| 475 | cbs.add("--flatten-ubo", [&args](CLIParser &) { args.flatten_ubo = true; }); |
| 476 | cbs.add("--fixup-clipspace", [&args](CLIParser &) { args.fixup = true; }); |
| 477 | cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); }); |
| 478 | cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; }); |
| 479 | cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); }); |
| 480 | cbs.add("--metal", [&args](CLIParser &) { args.metal = true; }); |
| 481 | cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; }); |
| 482 | cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); }); |
| 483 | cbs.add("--remap", [&args](CLIParser &parser) { |
| 484 | string src = parser.next_string(); |
| 485 | string dst = parser.next_string(); |
| 486 | uint32_t components = parser.next_uint(); |
| 487 | args.remaps.push_back({ move(src), move(dst), components }); |
| 488 | }); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 489 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 490 | cbs.add("--pls-in", [&args](CLIParser &parser) { |
| 491 | auto fmt = pls_format(parser.next_string()); |
| 492 | auto name = parser.next_string(); |
| 493 | args.pls_in.push_back({ move(fmt), move(name) }); |
| 494 | }); |
| 495 | cbs.add("--pls-out", [&args](CLIParser &parser) { |
| 496 | auto fmt = pls_format(parser.next_string()); |
| 497 | auto name = parser.next_string(); |
| 498 | args.pls_out.push_back({ move(fmt), move(name) }); |
| 499 | }); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 500 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 501 | cbs.default_handler = [&args](const char *value) { args.input = value; }; |
| 502 | cbs.error_handler = [] { print_help(); }; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 503 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 504 | CLIParser parser{ move(cbs), argc - 1, argv + 1 }; |
| 505 | if (!parser.parse()) |
| 506 | { |
| 507 | return EXIT_FAILURE; |
| 508 | } |
| 509 | else if (parser.ended_state) |
| 510 | { |
| 511 | return EXIT_SUCCESS; |
| 512 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 513 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 514 | if (!args.input) |
| 515 | { |
| 516 | fprintf(stderr, "Didn't specify input file.\n"); |
| 517 | print_help(); |
| 518 | return EXIT_FAILURE; |
| 519 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 520 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 521 | unique_ptr<CompilerGLSL> compiler; |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 522 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 523 | if (args.cpp) |
| 524 | { |
| 525 | compiler = unique_ptr<CompilerGLSL>(new CompilerCPP(read_spirv_file(args.input))); |
| 526 | if (args.cpp_interface_name) |
| 527 | static_cast<CompilerCPP *>(compiler.get())->set_interface_name(args.cpp_interface_name); |
| 528 | } |
| 529 | else if (args.metal) |
| 530 | compiler = unique_ptr<CompilerMSL>(new CompilerMSL(read_spirv_file(args.input))); |
| 531 | else |
| 532 | compiler = unique_ptr<CompilerGLSL>(new CompilerGLSL(read_spirv_file(args.input))); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 533 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 534 | if (!args.set_version && !compiler->get_options().version) |
| 535 | { |
| 536 | fprintf(stderr, "Didn't specify GLSL version and SPIR-V did not specify language.\n"); |
| 537 | print_help(); |
| 538 | return EXIT_FAILURE; |
| 539 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 540 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 541 | CompilerGLSL::Options opts = compiler->get_options(); |
| 542 | if (args.set_version) |
| 543 | opts.version = args.version; |
| 544 | if (args.set_es) |
| 545 | opts.es = args.es; |
| 546 | opts.force_temporary = args.force_temporary; |
| 547 | opts.vulkan_semantics = args.vulkan_semantics; |
| 548 | opts.vertex.fixup_clipspace = args.fixup; |
| 549 | compiler->set_options(opts); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 550 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 551 | auto res = compiler->get_shader_resources(); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 552 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 553 | if (args.flatten_ubo) |
| 554 | for (auto &ubo : res.uniform_buffers) |
| 555 | compiler->flatten_interface_block(ubo.id); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 556 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 557 | auto pls_inputs = remap_pls(args.pls_in, res.stage_inputs, &res.subpass_inputs); |
| 558 | auto pls_outputs = remap_pls(args.pls_out, res.stage_outputs, nullptr); |
| 559 | compiler->remap_pixel_local_storage(move(pls_inputs), move(pls_outputs)); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 560 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 561 | for (auto &ext : args.extensions) |
| 562 | compiler->require_extension(ext); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 563 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 564 | for (auto &remap : args.remaps) |
| 565 | { |
| 566 | if (remap_generic(*compiler, res.stage_inputs, remap)) |
| 567 | continue; |
| 568 | if (remap_generic(*compiler, res.stage_outputs, remap)) |
| 569 | continue; |
| 570 | if (remap_generic(*compiler, res.subpass_inputs, remap)) |
| 571 | continue; |
| 572 | } |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 573 | |
Hans-Kristian Arntzen | 078eec5 | 2016-07-06 11:04:06 +0200 | [diff] [blame] | 574 | if (args.dump_resources) |
| 575 | { |
| 576 | print_resources(*compiler, res); |
| 577 | print_push_constant_resources(*compiler, res.push_constant_buffers); |
| 578 | } |
| 579 | |
| 580 | string glsl; |
| 581 | for (uint32_t i = 0; i < args.iterations; i++) |
| 582 | glsl = compiler->compile(); |
| 583 | |
| 584 | if (args.output) |
| 585 | write_string_to_file(args.output, glsl.c_str()); |
| 586 | else |
| 587 | printf("%s", glsl.c_str()); |
Hans-Kristian Arntzen | 75471fb | 2016-03-02 18:09:16 +0100 | [diff] [blame] | 588 | } |