Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 1 | /* |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 2 | * Copyright 2018 Bradley Austin Davis |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 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 | |
| 17 | #include "spirv_reflect.hpp" |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 18 | #include "spirv_glsl.hpp" |
Brad Davis | 8d84a54 | 2018-06-20 11:47:31 -0700 | [diff] [blame] | 19 | #include <iomanip> |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 20 | |
| 21 | using namespace spv; |
| 22 | using namespace spirv_cross; |
| 23 | using namespace std; |
| 24 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 25 | namespace simple_json |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 26 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 27 | enum class Type |
| 28 | { |
| 29 | Object, |
| 30 | Array, |
| 31 | }; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 32 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 33 | using State = std::pair<Type, bool>; |
| 34 | using Stack = std::stack<State>; |
| 35 | |
| 36 | class Stream |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 37 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 38 | Stack stack; |
| 39 | std::ostringstream buffer; |
| 40 | uint32_t indent{ 0 }; |
| 41 | |
| 42 | public: |
| 43 | void begin_json_object(); |
| 44 | void end_json_object(); |
| 45 | void emit_json_key(const std::string &key); |
| 46 | void emit_json_key_value(const std::string &key, const std::string &value); |
| 47 | void emit_json_key_value(const std::string &key, bool value); |
| 48 | void emit_json_key_value(const std::string &key, uint32_t value); |
Brad Davis | 8d84a54 | 2018-06-20 11:47:31 -0700 | [diff] [blame] | 49 | void emit_json_key_value(const std::string &key, int32_t value); |
| 50 | void emit_json_key_value(const std::string &key, float value); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 51 | void emit_json_key_object(const std::string &key); |
| 52 | void emit_json_key_array(const std::string &key); |
| 53 | |
| 54 | void begin_json_array(); |
| 55 | void end_json_array(); |
| 56 | void emit_json_array_value(const std::string &value); |
| 57 | void emit_json_array_value(uint32_t value); |
| 58 | |
| 59 | std::string str() const |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 60 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 61 | return buffer.str(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 62 | } |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 63 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 64 | private: |
| 65 | inline void statement_indent() |
| 66 | { |
| 67 | for (uint32_t i = 0; i < indent; i++) |
| 68 | buffer << " "; |
| 69 | } |
| 70 | |
| 71 | template <typename T> |
| 72 | inline void statement_inner(T &&t) |
| 73 | { |
| 74 | buffer << std::forward<T>(t); |
| 75 | } |
| 76 | |
| 77 | template <typename T, typename... Ts> |
| 78 | inline void statement_inner(T &&t, Ts &&... ts) |
| 79 | { |
| 80 | buffer << std::forward<T>(t); |
| 81 | statement_inner(std::forward<Ts>(ts)...); |
| 82 | } |
| 83 | |
| 84 | template <typename... Ts> |
| 85 | inline void statement(Ts &&... ts) |
| 86 | { |
| 87 | statement_indent(); |
| 88 | statement_inner(std::forward<Ts>(ts)...); |
| 89 | buffer << '\n'; |
| 90 | } |
| 91 | |
| 92 | template <typename... Ts> |
| 93 | void statement_no_return(Ts &&... ts) |
| 94 | { |
| 95 | statement_indent(); |
| 96 | statement_inner(std::forward<Ts>(ts)...); |
| 97 | } |
| 98 | }; |
| 99 | } // namespace simple_json |
| 100 | |
| 101 | using namespace simple_json; |
| 102 | |
| 103 | // Hackery to emit JSON without using nlohmann/json C++ library (which requires a |
| 104 | // higher level of compiler compliance than is required by SPIRV-Cross |
| 105 | void Stream::begin_json_array() |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 106 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 107 | if (!stack.empty() && stack.top().second) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 108 | { |
| 109 | statement_inner(",\n"); |
| 110 | } |
| 111 | statement("["); |
| 112 | ++indent; |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 113 | stack.emplace(Type::Array, false); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 114 | } |
| 115 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 116 | void Stream::end_json_array() |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 117 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 118 | if (stack.empty() || stack.top().first != Type::Array) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 119 | SPIRV_CROSS_THROW("Invalid JSON state"); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 120 | if (stack.top().second) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 121 | { |
| 122 | statement_inner("\n"); |
| 123 | } |
| 124 | --indent; |
| 125 | statement_no_return("]"); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 126 | stack.pop(); |
| 127 | if (!stack.empty()) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 128 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 129 | stack.top().second = true; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 130 | } |
| 131 | } |
| 132 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 133 | void Stream::emit_json_array_value(const std::string &value) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 134 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 135 | if (stack.empty() || stack.top().first != Type::Array) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 136 | SPIRV_CROSS_THROW("Invalid JSON state"); |
| 137 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 138 | if (stack.top().second) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 139 | statement_inner(",\n"); |
| 140 | |
| 141 | statement_no_return("\"", value, "\""); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 142 | stack.top().second = true; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 145 | void Stream::emit_json_array_value(uint32_t value) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 146 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 147 | if (stack.empty() || stack.top().first != Type::Array) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 148 | SPIRV_CROSS_THROW("Invalid JSON state"); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 149 | if (stack.top().second) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 150 | statement_inner(",\n"); |
| 151 | statement_no_return(std::to_string(value)); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 152 | stack.top().second = true; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 153 | } |
| 154 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 155 | void Stream::begin_json_object() |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 156 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 157 | if (!stack.empty() && stack.top().second) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 158 | { |
| 159 | statement_inner(",\n"); |
| 160 | } |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 161 | statement("{"); |
| 162 | ++indent; |
| 163 | stack.emplace(Type::Object, false); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 164 | } |
| 165 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 166 | void Stream::end_json_object() |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 167 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 168 | if (stack.empty() || stack.top().first != Type::Object) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 169 | SPIRV_CROSS_THROW("Invalid JSON state"); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 170 | if (stack.top().second) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 171 | { |
| 172 | statement_inner("\n"); |
| 173 | } |
| 174 | --indent; |
| 175 | statement_no_return("}"); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 176 | stack.pop(); |
| 177 | if (!stack.empty()) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 178 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 179 | stack.top().second = true; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 180 | } |
| 181 | } |
| 182 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 183 | void Stream::emit_json_key(const std::string &key) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 184 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 185 | if (stack.empty() || stack.top().first != Type::Object) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 186 | SPIRV_CROSS_THROW("Invalid JSON state"); |
| 187 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 188 | if (stack.top().second) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 189 | statement_inner(",\n"); |
| 190 | statement_no_return("\"", key, "\" : "); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 191 | stack.top().second = true; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 192 | } |
| 193 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 194 | void Stream::emit_json_key_value(const std::string &key, const std::string &value) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 195 | { |
| 196 | emit_json_key(key); |
| 197 | statement_inner("\"", value, "\""); |
| 198 | } |
| 199 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 200 | void Stream::emit_json_key_value(const std::string &key, uint32_t value) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 201 | { |
| 202 | emit_json_key(key); |
| 203 | statement_inner(value); |
| 204 | } |
| 205 | |
Brad Davis | 8d84a54 | 2018-06-20 11:47:31 -0700 | [diff] [blame] | 206 | void Stream::emit_json_key_value(const std::string &key, int32_t value) |
| 207 | { |
| 208 | emit_json_key(key); |
| 209 | statement_inner(value); |
| 210 | } |
| 211 | |
| 212 | void Stream::emit_json_key_value(const std::string &key, float value) |
| 213 | { |
| 214 | emit_json_key(key); |
| 215 | statement_inner(value); |
| 216 | } |
| 217 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 218 | void Stream::emit_json_key_value(const std::string &key, bool value) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 219 | { |
| 220 | emit_json_key(key); |
| 221 | statement_inner(value ? "true" : "false"); |
| 222 | } |
| 223 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 224 | void Stream::emit_json_key_object(const std::string &key) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 225 | { |
| 226 | emit_json_key(key); |
| 227 | statement_inner("{\n"); |
| 228 | ++indent; |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 229 | stack.emplace(Type::Object, false); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 230 | } |
| 231 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 232 | void Stream::emit_json_key_array(const std::string &key) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 233 | { |
| 234 | emit_json_key(key); |
| 235 | statement_inner("[\n"); |
| 236 | ++indent; |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 237 | stack.emplace(Type::Array, false); |
| 238 | } |
| 239 | |
| 240 | void CompilerReflection::set_format(const std::string &format) |
| 241 | { |
| 242 | if (format != "json") |
| 243 | { |
| 244 | SPIRV_CROSS_THROW("Unsupported format"); |
| 245 | } |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | string CompilerReflection::compile() |
| 249 | { |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 250 | // Force a classic "C" locale, reverts when function returns |
| 251 | ClassicLocale classic_locale; |
| 252 | |
| 253 | // Move constructor for this type is broken on GCC 4.9 ... |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 254 | json_stream = std::make_shared<simple_json::Stream>(); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 255 | json_stream->begin_json_object(); |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 256 | emit_entry_points(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 257 | emit_types(); |
| 258 | emit_resources(); |
Brad Davis | 8d84a54 | 2018-06-20 11:47:31 -0700 | [diff] [blame] | 259 | emit_specialization_constants(); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 260 | json_stream->end_json_object(); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 261 | return json_stream->str(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 262 | } |
| 263 | |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 264 | void CompilerReflection::emit_types() |
| 265 | { |
| 266 | bool emitted_open_tag = false; |
| 267 | for (auto &id : ids) |
| 268 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 269 | auto idType = id.get_type(); |
| 270 | if (idType == TypeType) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 271 | { |
| 272 | auto &type = id.get<SPIRType>(); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 273 | if (type.basetype == SPIRType::Struct && !type.pointer && type.array.empty()) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 274 | { |
| 275 | emit_type(type, emitted_open_tag); |
| 276 | } |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | if (emitted_open_tag) |
| 281 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 282 | json_stream->end_json_object(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 283 | } |
| 284 | } |
| 285 | |
| 286 | void CompilerReflection::emit_type(const SPIRType &type, bool &emitted_open_tag) |
| 287 | { |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 288 | auto name = type_to_glsl(type); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 289 | |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 290 | if (type.type_alias != 0) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 291 | return; |
| 292 | |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 293 | if (!emitted_open_tag) |
| 294 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 295 | json_stream->emit_json_key_object("types"); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 296 | emitted_open_tag = true; |
| 297 | } |
Brad Davis | 9ad4324 | 2018-06-21 09:24:22 -0700 | [diff] [blame] | 298 | json_stream->emit_json_key_object("_" + std::to_string(type.self)); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 299 | json_stream->emit_json_key_value("name", name); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 300 | json_stream->emit_json_key_array("members"); |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 301 | // FIXME ideally we'd like to emit the size of a structure as a |
| 302 | // convenience to people parsing the reflected JSON. The problem |
| 303 | // is that there's no implicit size for a type. It's final size |
| 304 | // will be determined by the top level declaration in which it's |
| 305 | // included. So there might be one size for the struct if it's |
| 306 | // included in a std140 uniform block and another if it's included |
| 307 | // in a std430 uniform block. |
| 308 | // The solution is to include *all* potential sizes as a map of |
| 309 | // layout type name to integer, but that will probably require |
| 310 | // some additional logic being written in this class, or in the |
| 311 | // parent CompilerGLSL class. |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 312 | auto size = type.member_types.size(); |
| 313 | for (uint32_t i = 0; i < size; ++i) |
| 314 | { |
| 315 | emit_type_member(type, i); |
| 316 | } |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 317 | json_stream->end_json_array(); |
| 318 | json_stream->end_json_object(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 319 | } |
| 320 | |
| 321 | void CompilerReflection::emit_type_member(const SPIRType &type, uint32_t index) |
| 322 | { |
| 323 | auto &membertype = get<SPIRType>(type.member_types[index]); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 324 | json_stream->begin_json_object(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 325 | auto name = to_member_name(type, index); |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 326 | // FIXME we'd like to emit the offset of each member, but such offsets are |
| 327 | // context dependent. See the comment above regarding structure sizes |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 328 | json_stream->emit_json_key_value("name", name); |
| 329 | if (membertype.basetype == SPIRType::Struct) |
| 330 | { |
Brad Davis | 9ad4324 | 2018-06-21 09:24:22 -0700 | [diff] [blame] | 331 | json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.self)); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 332 | } |
| 333 | else |
| 334 | { |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 335 | json_stream->emit_json_key_value("type", type_to_glsl(membertype)); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 336 | } |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 337 | emit_type_member_qualifiers(type, index); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 338 | json_stream->end_json_object(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 339 | } |
| 340 | |
| 341 | void CompilerReflection::emit_type_array(const SPIRType &type) |
| 342 | { |
| 343 | if (!type.array.empty()) |
| 344 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 345 | json_stream->emit_json_key_array("array"); |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 346 | // Note that we emit the zeros here as a means of identifying |
| 347 | // unbounded arrays. This is necessary as otherwise there would |
| 348 | // be no way of differentiating between float[4] and float[4][] |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 349 | for (const auto &value : type.array) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 350 | json_stream->emit_json_array_value(value); |
| 351 | json_stream->end_json_array(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 352 | } |
| 353 | } |
| 354 | |
| 355 | void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint32_t index) |
| 356 | { |
| 357 | auto flags = combined_decoration_for_member(type, index); |
| 358 | if (flags.get(DecorationRowMajor)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 359 | json_stream->emit_json_key_value("row_major", true); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 360 | |
| 361 | auto &membertype = get<SPIRType>(type.member_types[index]); |
| 362 | emit_type_array(membertype); |
| 363 | auto &memb = meta[type.self].members; |
| 364 | if (index < memb.size()) |
| 365 | { |
| 366 | auto &dec = memb[index]; |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 367 | if (dec.decoration_flags.get(DecorationLocation)) |
| 368 | json_stream->emit_json_key_value("location", dec.location); |
| 369 | if (dec.decoration_flags.get(DecorationOffset)) |
| 370 | json_stream->emit_json_key_value("offset", dec.offset); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 371 | } |
| 372 | } |
| 373 | |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 374 | string CompilerReflection::execution_model_to_str(spv::ExecutionModel model) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 375 | { |
| 376 | switch (model) |
| 377 | { |
| 378 | case spv::ExecutionModelVertex: |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 379 | return "vert"; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 380 | case spv::ExecutionModelTessellationControl: |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 381 | return "tesc"; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 382 | case ExecutionModelTessellationEvaluation: |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 383 | return "tese"; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 384 | case ExecutionModelGeometry: |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 385 | return "geom"; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 386 | case ExecutionModelFragment: |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 387 | return "frag"; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 388 | case ExecutionModelGLCompute: |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 389 | return "comp"; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 390 | default: |
| 391 | return "???"; |
| 392 | } |
| 393 | } |
| 394 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 395 | // FIXME include things like the local_size dimensions, geometry output vertex count, etc |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 396 | void CompilerReflection::emit_entry_points() |
| 397 | { |
Hans-Kristian Arntzen | 040204d | 2018-06-22 09:41:43 +0200 | [diff] [blame] | 398 | auto entries = get_entry_points_and_stages(); |
| 399 | if (!entries.empty()) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 400 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 401 | json_stream->emit_json_key_array("entryPoints"); |
Hans-Kristian Arntzen | 040204d | 2018-06-22 09:41:43 +0200 | [diff] [blame] | 402 | for (auto &e : entries) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 403 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 404 | json_stream->begin_json_object(); |
| 405 | json_stream->emit_json_key_value("name", e.name); |
| 406 | json_stream->emit_json_key_value("mode", execution_model_to_str(e.execution_model)); |
| 407 | json_stream->end_json_object(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 408 | } |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 409 | json_stream->end_json_array(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 410 | } |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 411 | } |
| 412 | |
| 413 | void CompilerReflection::emit_resources() |
| 414 | { |
| 415 | auto res = get_shader_resources(); |
| 416 | emit_resources("subpass_inputs", res.subpass_inputs); |
| 417 | emit_resources("inputs", res.stage_inputs); |
| 418 | emit_resources("outputs", res.stage_outputs); |
| 419 | emit_resources("textures", res.sampled_images); |
| 420 | emit_resources("separate_images", res.separate_images); |
| 421 | emit_resources("separate_samplers", res.separate_samplers); |
| 422 | emit_resources("images", res.storage_images); |
| 423 | emit_resources("ssbos", res.storage_buffers); |
| 424 | emit_resources("ubos", res.uniform_buffers); |
Brad Davis | 8d84a54 | 2018-06-20 11:47:31 -0700 | [diff] [blame] | 425 | emit_resources("push_constants", res.push_constant_buffers); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 426 | emit_resources("counters", res.atomic_counters); |
| 427 | } |
| 428 | |
| 429 | void CompilerReflection::emit_resources(const char *tag, const vector<Resource> &resources) |
| 430 | { |
| 431 | if (resources.empty()) |
| 432 | { |
| 433 | return; |
| 434 | } |
| 435 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 436 | json_stream->emit_json_key_array(tag); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 437 | for (auto &res : resources) |
| 438 | { |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 439 | auto &type = get_type(res.type_id); |
| 440 | auto typeflags = meta[type.self].decoration.decoration_flags; |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 441 | auto &mask = get_decoration_bitset(res.id); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 442 | |
| 443 | // If we don't have a name, use the fallback for the type instead of the variable |
| 444 | // for SSBOs and UBOs since those are the only meaningful names to use externally. |
| 445 | // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks. |
| 446 | bool is_push_constant = get_storage_class(res.id) == StorageClassPushConstant; |
| 447 | bool is_block = get_decoration_bitset(type.self).get(DecorationBlock) || |
| 448 | get_decoration_bitset(type.self).get(DecorationBufferBlock); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 449 | |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 450 | uint32_t fallback_id = !is_push_constant && is_block ? res.base_type_id : res.id; |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 451 | |
| 452 | json_stream->begin_json_object(); |
| 453 | |
| 454 | if (type.basetype == SPIRType::Struct) |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 455 | { |
Brad Davis | 9ad4324 | 2018-06-21 09:24:22 -0700 | [diff] [blame] | 456 | json_stream->emit_json_key_value("type", "_" + std::to_string(res.base_type_id)); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 457 | } |
| 458 | else |
| 459 | { |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 460 | json_stream->emit_json_key_value("type", type_to_glsl(type)); |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 461 | } |
| 462 | |
| 463 | json_stream->emit_json_key_value("name", !res.name.empty() ? res.name : get_fallback_name(fallback_id)); |
| 464 | { |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 465 | bool ssbo_block = type.storage == StorageClassStorageBuffer || |
| 466 | (type.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 467 | if (ssbo_block) |
| 468 | { |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 469 | auto buffer_flags = get_buffer_block_flags(res.id); |
| 470 | if (buffer_flags.get(DecorationNonReadable)) |
| 471 | json_stream->emit_json_key_value("writeonly", true); |
| 472 | if (buffer_flags.get(DecorationNonWritable)) |
| 473 | json_stream->emit_json_key_value("readonly", true); |
| 474 | if (buffer_flags.get(DecorationRestrict)) |
| 475 | json_stream->emit_json_key_value("restrict", true); |
| 476 | if (buffer_flags.get(DecorationCoherent)) |
| 477 | json_stream->emit_json_key_value("coherent", true); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 478 | } |
| 479 | } |
| 480 | |
| 481 | emit_type_array(type); |
| 482 | |
| 483 | { |
| 484 | bool is_sized_block = is_block && (get_storage_class(res.id) == StorageClassUniform || |
| 485 | get_storage_class(res.id) == StorageClassUniformConstant); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 486 | if (is_sized_block) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 487 | { |
| 488 | uint32_t block_size = uint32_t(get_declared_struct_size(get_type(res.base_type_id))); |
| 489 | json_stream->emit_json_key_value("block_size", block_size); |
| 490 | } |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 491 | } |
| 492 | |
| 493 | if (type.storage == StorageClassPushConstant) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 494 | json_stream->emit_json_key_value("push_constant", true); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 495 | if (mask.get(DecorationLocation)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 496 | json_stream->emit_json_key_value("location", get_decoration(res.id, DecorationLocation)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 497 | if (mask.get(DecorationRowMajor)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 498 | json_stream->emit_json_key_value("row_major", true); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 499 | if (mask.get(DecorationColMajor)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 500 | json_stream->emit_json_key_value("column_major", true); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 501 | if (mask.get(DecorationIndex)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 502 | json_stream->emit_json_key_value("index", get_decoration(res.id, DecorationIndex)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 503 | if (type.storage != StorageClassPushConstant && mask.get(DecorationDescriptorSet)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 504 | json_stream->emit_json_key_value("set", get_decoration(res.id, DecorationDescriptorSet)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 505 | if (mask.get(DecorationBinding)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 506 | json_stream->emit_json_key_value("binding", get_decoration(res.id, DecorationBinding)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 507 | if (mask.get(DecorationInputAttachmentIndex)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 508 | json_stream->emit_json_key_value("input_attachment_index", |
| 509 | get_decoration(res.id, DecorationInputAttachmentIndex)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 510 | if (mask.get(DecorationOffset)) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 511 | json_stream->emit_json_key_value("offset", get_decoration(res.id, DecorationOffset)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 512 | |
| 513 | // For images, the type itself adds a layout qualifer. |
| 514 | // Only emit the format for storage images. |
| 515 | if (type.basetype == SPIRType::Image && type.image.sampled == 2) |
| 516 | { |
Brad Davis | 7620400 | 2018-06-20 10:25:38 -0700 | [diff] [blame] | 517 | const char *fmt = format_to_glsl(type.image.format); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 518 | if (fmt != nullptr) |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 519 | json_stream->emit_json_key_value("format", std::string(fmt)); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 520 | } |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 521 | json_stream->end_json_object(); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 522 | } |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 523 | json_stream->end_json_array(); |
| 524 | } |
| 525 | |
Brad Davis | 8d84a54 | 2018-06-20 11:47:31 -0700 | [diff] [blame] | 526 | void CompilerReflection::emit_specialization_constants() |
| 527 | { |
| 528 | auto specialization_constants = get_specialization_constants(); |
| 529 | if (specialization_constants.empty()) |
| 530 | return; |
| 531 | |
| 532 | json_stream->emit_json_key_array("specialization_constants"); |
| 533 | for (const auto spec_const : specialization_constants) |
| 534 | { |
| 535 | auto &c = get<SPIRConstant>(spec_const.id); |
| 536 | auto type = get<SPIRType>(c.constant_type); |
| 537 | json_stream->begin_json_object(); |
| 538 | json_stream->emit_json_key_value("id", spec_const.constant_id); |
| 539 | json_stream->emit_json_key_value("type", type_to_glsl(type)); |
| 540 | switch (type.basetype) |
| 541 | { |
| 542 | case SPIRType::UInt: |
| 543 | json_stream->emit_json_key_value("default_value", c.scalar()); |
| 544 | break; |
| 545 | |
| 546 | case SPIRType::Int: |
| 547 | json_stream->emit_json_key_value("default_value", c.scalar_i32()); |
| 548 | break; |
| 549 | |
| 550 | case SPIRType::Float: |
| 551 | json_stream->emit_json_key_value("default_value", c.scalar_f32()); |
| 552 | break; |
| 553 | |
| 554 | case SPIRType::Boolean: |
| 555 | json_stream->emit_json_key_value("default_value", c.scalar() != 0); |
| 556 | break; |
Hans-Kristian Arntzen | 040204d | 2018-06-22 09:41:43 +0200 | [diff] [blame] | 557 | |
| 558 | default: |
| 559 | break; |
Brad Davis | 8d84a54 | 2018-06-20 11:47:31 -0700 | [diff] [blame] | 560 | } |
| 561 | json_stream->end_json_object(); |
| 562 | } |
| 563 | json_stream->end_json_array(); |
| 564 | } |
| 565 | |
Brad Davis | 6c88b00 | 2018-06-18 09:30:16 -0700 | [diff] [blame] | 566 | string CompilerReflection::to_member_name(const SPIRType &type, uint32_t index) const |
| 567 | { |
| 568 | auto &memb = meta[type.self].members; |
| 569 | if (index < memb.size() && !memb[index].alias.empty()) |
| 570 | return memb[index].alias; |
| 571 | else |
| 572 | return join("_m", index); |
Brad Davis | 709d3c6 | 2018-06-03 11:16:37 -0700 | [diff] [blame] | 573 | } |