blob: c322d972bdf52379d540c833176e71327c0a880d [file] [log] [blame]
Brad Davis709d3c62018-06-03 11:16:37 -07001/*
Brad Davis6c88b002018-06-18 09:30:16 -07002 * Copyright 2018 Bradley Austin Davis
Brad Davis709d3c62018-06-03 11:16:37 -07003 *
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 Davis6c88b002018-06-18 09:30:16 -070018#include "spirv_glsl.hpp"
Brad Davis8d84a542018-06-20 11:47:31 -070019#include <iomanip>
Brad Davis709d3c62018-06-03 11:16:37 -070020
21using namespace spv;
22using namespace spirv_cross;
23using namespace std;
24
Brad Davis6c88b002018-06-18 09:30:16 -070025namespace simple_json
Brad Davis709d3c62018-06-03 11:16:37 -070026{
Brad Davis6c88b002018-06-18 09:30:16 -070027enum class Type
28{
29 Object,
30 Array,
31};
Brad Davis709d3c62018-06-03 11:16:37 -070032
Brad Davis6c88b002018-06-18 09:30:16 -070033using State = std::pair<Type, bool>;
34using Stack = std::stack<State>;
35
36class Stream
Brad Davis709d3c62018-06-03 11:16:37 -070037{
Brad Davis6c88b002018-06-18 09:30:16 -070038 Stack stack;
39 std::ostringstream buffer;
40 uint32_t indent{ 0 };
41
42public:
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 Davis8d84a542018-06-20 11:47:31 -070049 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 Davis6c88b002018-06-18 09:30:16 -070051 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 Davis709d3c62018-06-03 11:16:37 -070060 {
Brad Davis6c88b002018-06-18 09:30:16 -070061 return buffer.str();
Brad Davis709d3c62018-06-03 11:16:37 -070062 }
Brad Davis709d3c62018-06-03 11:16:37 -070063
Brad Davis6c88b002018-06-18 09:30:16 -070064private:
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
101using 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
105void Stream::begin_json_array()
Brad Davis709d3c62018-06-03 11:16:37 -0700106{
Brad Davis6c88b002018-06-18 09:30:16 -0700107 if (!stack.empty() && stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700108 {
109 statement_inner(",\n");
110 }
111 statement("[");
112 ++indent;
Brad Davis6c88b002018-06-18 09:30:16 -0700113 stack.emplace(Type::Array, false);
Brad Davis709d3c62018-06-03 11:16:37 -0700114}
115
Brad Davis6c88b002018-06-18 09:30:16 -0700116void Stream::end_json_array()
Brad Davis709d3c62018-06-03 11:16:37 -0700117{
Brad Davis6c88b002018-06-18 09:30:16 -0700118 if (stack.empty() || stack.top().first != Type::Array)
Brad Davis709d3c62018-06-03 11:16:37 -0700119 SPIRV_CROSS_THROW("Invalid JSON state");
Brad Davis6c88b002018-06-18 09:30:16 -0700120 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700121 {
122 statement_inner("\n");
123 }
124 --indent;
125 statement_no_return("]");
Brad Davis6c88b002018-06-18 09:30:16 -0700126 stack.pop();
127 if (!stack.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700128 {
Brad Davis6c88b002018-06-18 09:30:16 -0700129 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700130 }
131}
132
Brad Davis6c88b002018-06-18 09:30:16 -0700133void Stream::emit_json_array_value(const std::string &value)
Brad Davis709d3c62018-06-03 11:16:37 -0700134{
Brad Davis6c88b002018-06-18 09:30:16 -0700135 if (stack.empty() || stack.top().first != Type::Array)
Brad Davis709d3c62018-06-03 11:16:37 -0700136 SPIRV_CROSS_THROW("Invalid JSON state");
137
Brad Davis6c88b002018-06-18 09:30:16 -0700138 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700139 statement_inner(",\n");
140
141 statement_no_return("\"", value, "\"");
Brad Davis6c88b002018-06-18 09:30:16 -0700142 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700143}
144
Brad Davis6c88b002018-06-18 09:30:16 -0700145void Stream::emit_json_array_value(uint32_t value)
Brad Davis709d3c62018-06-03 11:16:37 -0700146{
Brad Davis6c88b002018-06-18 09:30:16 -0700147 if (stack.empty() || stack.top().first != Type::Array)
Brad Davis709d3c62018-06-03 11:16:37 -0700148 SPIRV_CROSS_THROW("Invalid JSON state");
Brad Davis6c88b002018-06-18 09:30:16 -0700149 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700150 statement_inner(",\n");
151 statement_no_return(std::to_string(value));
Brad Davis6c88b002018-06-18 09:30:16 -0700152 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700153}
154
Brad Davis6c88b002018-06-18 09:30:16 -0700155void Stream::begin_json_object()
Brad Davis709d3c62018-06-03 11:16:37 -0700156{
Brad Davis6c88b002018-06-18 09:30:16 -0700157 if (!stack.empty() && stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700158 {
159 statement_inner(",\n");
160 }
Brad Davis6c88b002018-06-18 09:30:16 -0700161 statement("{");
162 ++indent;
163 stack.emplace(Type::Object, false);
Brad Davis709d3c62018-06-03 11:16:37 -0700164}
165
Brad Davis6c88b002018-06-18 09:30:16 -0700166void Stream::end_json_object()
Brad Davis709d3c62018-06-03 11:16:37 -0700167{
Brad Davis6c88b002018-06-18 09:30:16 -0700168 if (stack.empty() || stack.top().first != Type::Object)
Brad Davis709d3c62018-06-03 11:16:37 -0700169 SPIRV_CROSS_THROW("Invalid JSON state");
Brad Davis6c88b002018-06-18 09:30:16 -0700170 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700171 {
172 statement_inner("\n");
173 }
174 --indent;
175 statement_no_return("}");
Brad Davis6c88b002018-06-18 09:30:16 -0700176 stack.pop();
177 if (!stack.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700178 {
Brad Davis6c88b002018-06-18 09:30:16 -0700179 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700180 }
181}
182
Brad Davis6c88b002018-06-18 09:30:16 -0700183void Stream::emit_json_key(const std::string &key)
Brad Davis709d3c62018-06-03 11:16:37 -0700184{
Brad Davis6c88b002018-06-18 09:30:16 -0700185 if (stack.empty() || stack.top().first != Type::Object)
Brad Davis709d3c62018-06-03 11:16:37 -0700186 SPIRV_CROSS_THROW("Invalid JSON state");
187
Brad Davis6c88b002018-06-18 09:30:16 -0700188 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700189 statement_inner(",\n");
190 statement_no_return("\"", key, "\" : ");
Brad Davis6c88b002018-06-18 09:30:16 -0700191 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700192}
193
Brad Davis6c88b002018-06-18 09:30:16 -0700194void Stream::emit_json_key_value(const std::string &key, const std::string &value)
Brad Davis709d3c62018-06-03 11:16:37 -0700195{
196 emit_json_key(key);
197 statement_inner("\"", value, "\"");
198}
199
Brad Davis6c88b002018-06-18 09:30:16 -0700200void Stream::emit_json_key_value(const std::string &key, uint32_t value)
Brad Davis709d3c62018-06-03 11:16:37 -0700201{
202 emit_json_key(key);
203 statement_inner(value);
204}
205
Brad Davis8d84a542018-06-20 11:47:31 -0700206void Stream::emit_json_key_value(const std::string &key, int32_t value)
207{
208 emit_json_key(key);
209 statement_inner(value);
210}
211
212void Stream::emit_json_key_value(const std::string &key, float value)
213{
214 emit_json_key(key);
215 statement_inner(value);
216}
217
Brad Davis6c88b002018-06-18 09:30:16 -0700218void Stream::emit_json_key_value(const std::string &key, bool value)
Brad Davis709d3c62018-06-03 11:16:37 -0700219{
220 emit_json_key(key);
221 statement_inner(value ? "true" : "false");
222}
223
Brad Davis6c88b002018-06-18 09:30:16 -0700224void Stream::emit_json_key_object(const std::string &key)
Brad Davis709d3c62018-06-03 11:16:37 -0700225{
226 emit_json_key(key);
227 statement_inner("{\n");
228 ++indent;
Brad Davis6c88b002018-06-18 09:30:16 -0700229 stack.emplace(Type::Object, false);
Brad Davis709d3c62018-06-03 11:16:37 -0700230}
231
Brad Davis6c88b002018-06-18 09:30:16 -0700232void Stream::emit_json_key_array(const std::string &key)
Brad Davis709d3c62018-06-03 11:16:37 -0700233{
234 emit_json_key(key);
235 statement_inner("[\n");
236 ++indent;
Brad Davis6c88b002018-06-18 09:30:16 -0700237 stack.emplace(Type::Array, false);
238}
239
240void CompilerReflection::set_format(const std::string &format)
241{
242 if (format != "json")
243 {
244 SPIRV_CROSS_THROW("Unsupported format");
245 }
Brad Davis709d3c62018-06-03 11:16:37 -0700246}
247
248string CompilerReflection::compile()
249{
Brad Davis709d3c62018-06-03 11:16:37 -0700250 // 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 Davis76204002018-06-20 10:25:38 -0700254 json_stream = std::make_shared<simple_json::Stream>();
Brad Davis6c88b002018-06-18 09:30:16 -0700255 json_stream->begin_json_object();
Brad Davis76204002018-06-20 10:25:38 -0700256 emit_entry_points();
Brad Davis709d3c62018-06-03 11:16:37 -0700257 emit_types();
258 emit_resources();
Brad Davis8d84a542018-06-20 11:47:31 -0700259 emit_specialization_constants();
Brad Davis6c88b002018-06-18 09:30:16 -0700260 json_stream->end_json_object();
Brad Davis6c88b002018-06-18 09:30:16 -0700261 return json_stream->str();
Brad Davis709d3c62018-06-03 11:16:37 -0700262}
263
Brad Davis709d3c62018-06-03 11:16:37 -0700264void CompilerReflection::emit_types()
265{
266 bool emitted_open_tag = false;
267 for (auto &id : ids)
268 {
Brad Davis6c88b002018-06-18 09:30:16 -0700269 auto idType = id.get_type();
270 if (idType == TypeType)
Brad Davis709d3c62018-06-03 11:16:37 -0700271 {
272 auto &type = id.get<SPIRType>();
Brad Davis6c88b002018-06-18 09:30:16 -0700273 if (type.basetype == SPIRType::Struct && !type.pointer && type.array.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700274 {
275 emit_type(type, emitted_open_tag);
276 }
277 }
278 }
279
280 if (emitted_open_tag)
281 {
Brad Davis6c88b002018-06-18 09:30:16 -0700282 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700283 }
284}
285
286void CompilerReflection::emit_type(const SPIRType &type, bool &emitted_open_tag)
287{
Brad Davis76204002018-06-20 10:25:38 -0700288 auto name = type_to_glsl(type);
Brad Davis709d3c62018-06-03 11:16:37 -0700289
Brad Davis76204002018-06-20 10:25:38 -0700290 if (type.type_alias != 0)
Brad Davis709d3c62018-06-03 11:16:37 -0700291 return;
292
Brad Davis709d3c62018-06-03 11:16:37 -0700293 if (!emitted_open_tag)
294 {
Brad Davis6c88b002018-06-18 09:30:16 -0700295 json_stream->emit_json_key_object("types");
Brad Davis709d3c62018-06-03 11:16:37 -0700296 emitted_open_tag = true;
297 }
Brad Davis9ad43242018-06-21 09:24:22 -0700298 json_stream->emit_json_key_object("_" + std::to_string(type.self));
Brad Davis6c88b002018-06-18 09:30:16 -0700299 json_stream->emit_json_key_value("name", name);
Brad Davis6c88b002018-06-18 09:30:16 -0700300 json_stream->emit_json_key_array("members");
Brad Davis76204002018-06-20 10:25:38 -0700301 // 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 Davis709d3c62018-06-03 11:16:37 -0700312 auto size = type.member_types.size();
313 for (uint32_t i = 0; i < size; ++i)
314 {
315 emit_type_member(type, i);
316 }
Brad Davis6c88b002018-06-18 09:30:16 -0700317 json_stream->end_json_array();
318 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700319}
320
321void CompilerReflection::emit_type_member(const SPIRType &type, uint32_t index)
322{
323 auto &membertype = get<SPIRType>(type.member_types[index]);
Brad Davis6c88b002018-06-18 09:30:16 -0700324 json_stream->begin_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700325 auto name = to_member_name(type, index);
Brad Davis76204002018-06-20 10:25:38 -0700326 // 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 Davis6c88b002018-06-18 09:30:16 -0700328 json_stream->emit_json_key_value("name", name);
329 if (membertype.basetype == SPIRType::Struct)
330 {
Brad Davis9ad43242018-06-21 09:24:22 -0700331 json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.self));
Brad Davis6c88b002018-06-18 09:30:16 -0700332 }
333 else
334 {
Brad Davis76204002018-06-20 10:25:38 -0700335 json_stream->emit_json_key_value("type", type_to_glsl(membertype));
Brad Davis6c88b002018-06-18 09:30:16 -0700336 }
Brad Davis709d3c62018-06-03 11:16:37 -0700337 emit_type_member_qualifiers(type, index);
Brad Davis6c88b002018-06-18 09:30:16 -0700338 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700339}
340
341void CompilerReflection::emit_type_array(const SPIRType &type)
342{
343 if (!type.array.empty())
344 {
Brad Davis6c88b002018-06-18 09:30:16 -0700345 json_stream->emit_json_key_array("array");
Brad Davis76204002018-06-20 10:25:38 -0700346 // 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 Davis709d3c62018-06-03 11:16:37 -0700349 for (const auto &value : type.array)
Brad Davis6c88b002018-06-18 09:30:16 -0700350 json_stream->emit_json_array_value(value);
351 json_stream->end_json_array();
Brad Davis709d3c62018-06-03 11:16:37 -0700352 }
353}
354
355void 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 Davis6c88b002018-06-18 09:30:16 -0700359 json_stream->emit_json_key_value("row_major", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700360
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 Davis6c88b002018-06-18 09:30:16 -0700367 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 Davis709d3c62018-06-03 11:16:37 -0700371 }
372}
373
Brad Davis76204002018-06-20 10:25:38 -0700374string CompilerReflection::execution_model_to_str(spv::ExecutionModel model)
Brad Davis709d3c62018-06-03 11:16:37 -0700375{
376 switch (model)
377 {
378 case spv::ExecutionModelVertex:
Brad Davis76204002018-06-20 10:25:38 -0700379 return "vert";
Brad Davis709d3c62018-06-03 11:16:37 -0700380 case spv::ExecutionModelTessellationControl:
Brad Davis76204002018-06-20 10:25:38 -0700381 return "tesc";
Brad Davis709d3c62018-06-03 11:16:37 -0700382 case ExecutionModelTessellationEvaluation:
Brad Davis76204002018-06-20 10:25:38 -0700383 return "tese";
Brad Davis709d3c62018-06-03 11:16:37 -0700384 case ExecutionModelGeometry:
Brad Davis76204002018-06-20 10:25:38 -0700385 return "geom";
Brad Davis709d3c62018-06-03 11:16:37 -0700386 case ExecutionModelFragment:
Brad Davis76204002018-06-20 10:25:38 -0700387 return "frag";
Brad Davis709d3c62018-06-03 11:16:37 -0700388 case ExecutionModelGLCompute:
Brad Davis76204002018-06-20 10:25:38 -0700389 return "comp";
Brad Davis709d3c62018-06-03 11:16:37 -0700390 default:
391 return "???";
392 }
393}
394
Brad Davis6c88b002018-06-18 09:30:16 -0700395// FIXME include things like the local_size dimensions, geometry output vertex count, etc
Brad Davis709d3c62018-06-03 11:16:37 -0700396void CompilerReflection::emit_entry_points()
397{
Hans-Kristian Arntzen040204d2018-06-22 09:41:43 +0200398 auto entries = get_entry_points_and_stages();
399 if (!entries.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700400 {
Brad Davis6c88b002018-06-18 09:30:16 -0700401 json_stream->emit_json_key_array("entryPoints");
Hans-Kristian Arntzen040204d2018-06-22 09:41:43 +0200402 for (auto &e : entries)
Brad Davis709d3c62018-06-03 11:16:37 -0700403 {
Brad Davis6c88b002018-06-18 09:30:16 -0700404 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 Davis709d3c62018-06-03 11:16:37 -0700408 }
Brad Davis6c88b002018-06-18 09:30:16 -0700409 json_stream->end_json_array();
Brad Davis709d3c62018-06-03 11:16:37 -0700410 }
Brad Davis709d3c62018-06-03 11:16:37 -0700411}
412
413void 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 Davis8d84a542018-06-20 11:47:31 -0700425 emit_resources("push_constants", res.push_constant_buffers);
Brad Davis709d3c62018-06-03 11:16:37 -0700426 emit_resources("counters", res.atomic_counters);
427}
428
429void CompilerReflection::emit_resources(const char *tag, const vector<Resource> &resources)
430{
431 if (resources.empty())
432 {
433 return;
434 }
435
Brad Davis6c88b002018-06-18 09:30:16 -0700436 json_stream->emit_json_key_array(tag);
Brad Davis709d3c62018-06-03 11:16:37 -0700437 for (auto &res : resources)
438 {
Brad Davis709d3c62018-06-03 11:16:37 -0700439 auto &type = get_type(res.type_id);
440 auto typeflags = meta[type.self].decoration.decoration_flags;
Brad Davis709d3c62018-06-03 11:16:37 -0700441 auto &mask = get_decoration_bitset(res.id);
Brad Davis709d3c62018-06-03 11:16:37 -0700442
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 Davis6c88b002018-06-18 09:30:16 -0700449
Brad Davis709d3c62018-06-03 11:16:37 -0700450 uint32_t fallback_id = !is_push_constant && is_block ? res.base_type_id : res.id;
Brad Davis6c88b002018-06-18 09:30:16 -0700451
452 json_stream->begin_json_object();
453
454 if (type.basetype == SPIRType::Struct)
Brad Davis709d3c62018-06-03 11:16:37 -0700455 {
Brad Davis9ad43242018-06-21 09:24:22 -0700456 json_stream->emit_json_key_value("type", "_" + std::to_string(res.base_type_id));
Brad Davis6c88b002018-06-18 09:30:16 -0700457 }
458 else
459 {
Brad Davis76204002018-06-20 10:25:38 -0700460 json_stream->emit_json_key_value("type", type_to_glsl(type));
Brad Davis6c88b002018-06-18 09:30:16 -0700461 }
462
463 json_stream->emit_json_key_value("name", !res.name.empty() ? res.name : get_fallback_name(fallback_id));
464 {
Brad Davis709d3c62018-06-03 11:16:37 -0700465 bool ssbo_block = type.storage == StorageClassStorageBuffer ||
466 (type.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
Brad Davis709d3c62018-06-03 11:16:37 -0700467 if (ssbo_block)
468 {
Brad Davis6c88b002018-06-18 09:30:16 -0700469 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 Davis709d3c62018-06-03 11:16:37 -0700478 }
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 Davis709d3c62018-06-03 11:16:37 -0700486 if (is_sized_block)
Brad Davis6c88b002018-06-18 09:30:16 -0700487 {
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 Davis709d3c62018-06-03 11:16:37 -0700491 }
492
493 if (type.storage == StorageClassPushConstant)
Brad Davis6c88b002018-06-18 09:30:16 -0700494 json_stream->emit_json_key_value("push_constant", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700495 if (mask.get(DecorationLocation))
Brad Davis6c88b002018-06-18 09:30:16 -0700496 json_stream->emit_json_key_value("location", get_decoration(res.id, DecorationLocation));
Brad Davis709d3c62018-06-03 11:16:37 -0700497 if (mask.get(DecorationRowMajor))
Brad Davis6c88b002018-06-18 09:30:16 -0700498 json_stream->emit_json_key_value("row_major", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700499 if (mask.get(DecorationColMajor))
Brad Davis6c88b002018-06-18 09:30:16 -0700500 json_stream->emit_json_key_value("column_major", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700501 if (mask.get(DecorationIndex))
Brad Davis6c88b002018-06-18 09:30:16 -0700502 json_stream->emit_json_key_value("index", get_decoration(res.id, DecorationIndex));
Brad Davis709d3c62018-06-03 11:16:37 -0700503 if (type.storage != StorageClassPushConstant && mask.get(DecorationDescriptorSet))
Brad Davis6c88b002018-06-18 09:30:16 -0700504 json_stream->emit_json_key_value("set", get_decoration(res.id, DecorationDescriptorSet));
Brad Davis709d3c62018-06-03 11:16:37 -0700505 if (mask.get(DecorationBinding))
Brad Davis6c88b002018-06-18 09:30:16 -0700506 json_stream->emit_json_key_value("binding", get_decoration(res.id, DecorationBinding));
Brad Davis709d3c62018-06-03 11:16:37 -0700507 if (mask.get(DecorationInputAttachmentIndex))
Brad Davis6c88b002018-06-18 09:30:16 -0700508 json_stream->emit_json_key_value("input_attachment_index",
509 get_decoration(res.id, DecorationInputAttachmentIndex));
Brad Davis709d3c62018-06-03 11:16:37 -0700510 if (mask.get(DecorationOffset))
Brad Davis6c88b002018-06-18 09:30:16 -0700511 json_stream->emit_json_key_value("offset", get_decoration(res.id, DecorationOffset));
Brad Davis709d3c62018-06-03 11:16:37 -0700512
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 Davis76204002018-06-20 10:25:38 -0700517 const char *fmt = format_to_glsl(type.image.format);
Brad Davis709d3c62018-06-03 11:16:37 -0700518 if (fmt != nullptr)
Brad Davis6c88b002018-06-18 09:30:16 -0700519 json_stream->emit_json_key_value("format", std::string(fmt));
Brad Davis709d3c62018-06-03 11:16:37 -0700520 }
Brad Davis6c88b002018-06-18 09:30:16 -0700521 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700522 }
Brad Davis6c88b002018-06-18 09:30:16 -0700523 json_stream->end_json_array();
524}
525
Brad Davis8d84a542018-06-20 11:47:31 -0700526void 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 Arntzen040204d2018-06-22 09:41:43 +0200557
558 default:
559 break;
Brad Davis8d84a542018-06-20 11:47:31 -0700560 }
561 json_stream->end_json_object();
562 }
563 json_stream->end_json_array();
564}
565
Brad Davis6c88b002018-06-18 09:30:16 -0700566string 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 Davis709d3c62018-06-03 11:16:37 -0700573}