blob: ee2fe930dcccb88c73fceb28bc5c8beeff8f9b18 [file] [log] [blame]
Brad Davis709d3c62018-06-03 11:16:37 -07001/*
Hans-Kristian Arntzen47044822021-01-14 16:07:49 +01002 * Copyright 2018-2021 Bradley Austin Davis
Jon Leechf2a65542021-05-08 01:47:48 -07003 * SPDX-License-Identifier: Apache-2.0 OR MIT
Brad Davis709d3c62018-06-03 11:16:37 -07004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010018/*
19 * At your option, you may choose to accept this material under either:
20 * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
21 * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010022 */
23
Brad Davis709d3c62018-06-03 11:16:37 -070024#include "spirv_reflect.hpp"
Brad Davis6c88b002018-06-18 09:30:16 -070025#include "spirv_glsl.hpp"
Brad Davis8d84a542018-06-20 11:47:31 -070026#include <iomanip>
Brad Davis709d3c62018-06-03 11:16:37 -070027
28using namespace spv;
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010029using namespace SPIRV_CROSS_NAMESPACE;
Brad Davis709d3c62018-06-03 11:16:37 -070030using namespace std;
31
Brad Davis6c88b002018-06-18 09:30:16 -070032namespace simple_json
Brad Davis709d3c62018-06-03 11:16:37 -070033{
Brad Davis6c88b002018-06-18 09:30:16 -070034enum class Type
35{
36 Object,
37 Array,
38};
Brad Davis709d3c62018-06-03 11:16:37 -070039
Brad Davis6c88b002018-06-18 09:30:16 -070040using State = std::pair<Type, bool>;
41using Stack = std::stack<State>;
42
43class Stream
Brad Davis709d3c62018-06-03 11:16:37 -070044{
Brad Davis6c88b002018-06-18 09:30:16 -070045 Stack stack;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020046 StringStream<> buffer;
Brad Davis6c88b002018-06-18 09:30:16 -070047 uint32_t indent{ 0 };
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020048 char current_locale_radix_character = '.';
Brad Davis6c88b002018-06-18 09:30:16 -070049
50public:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020051 void set_current_locale_radix_character(char c)
52 {
53 current_locale_radix_character = c;
54 }
55
Brad Davis6c88b002018-06-18 09:30:16 -070056 void begin_json_object();
57 void end_json_object();
58 void emit_json_key(const std::string &key);
59 void emit_json_key_value(const std::string &key, const std::string &value);
60 void emit_json_key_value(const std::string &key, bool value);
61 void emit_json_key_value(const std::string &key, uint32_t value);
Brad Davis8d84a542018-06-20 11:47:31 -070062 void emit_json_key_value(const std::string &key, int32_t value);
63 void emit_json_key_value(const std::string &key, float value);
Brad Davis6c88b002018-06-18 09:30:16 -070064 void emit_json_key_object(const std::string &key);
65 void emit_json_key_array(const std::string &key);
66
67 void begin_json_array();
68 void end_json_array();
69 void emit_json_array_value(const std::string &value);
70 void emit_json_array_value(uint32_t value);
Hans-Kristian Arntzen43e89bd2019-10-04 10:37:47 +020071 void emit_json_array_value(bool value);
Brad Davis6c88b002018-06-18 09:30:16 -070072
73 std::string str() const
Brad Davis709d3c62018-06-03 11:16:37 -070074 {
Brad Davis6c88b002018-06-18 09:30:16 -070075 return buffer.str();
Brad Davis709d3c62018-06-03 11:16:37 -070076 }
Brad Davis709d3c62018-06-03 11:16:37 -070077
Brad Davis6c88b002018-06-18 09:30:16 -070078private:
79 inline void statement_indent()
80 {
81 for (uint32_t i = 0; i < indent; i++)
82 buffer << " ";
83 }
84
85 template <typename T>
86 inline void statement_inner(T &&t)
87 {
88 buffer << std::forward<T>(t);
89 }
90
91 template <typename T, typename... Ts>
92 inline void statement_inner(T &&t, Ts &&... ts)
93 {
94 buffer << std::forward<T>(t);
95 statement_inner(std::forward<Ts>(ts)...);
96 }
97
98 template <typename... Ts>
99 inline void statement(Ts &&... ts)
100 {
101 statement_indent();
102 statement_inner(std::forward<Ts>(ts)...);
103 buffer << '\n';
104 }
105
106 template <typename... Ts>
107 void statement_no_return(Ts &&... ts)
108 {
109 statement_indent();
110 statement_inner(std::forward<Ts>(ts)...);
111 }
112};
113} // namespace simple_json
114
115using namespace simple_json;
116
117// Hackery to emit JSON without using nlohmann/json C++ library (which requires a
118// higher level of compiler compliance than is required by SPIRV-Cross
119void Stream::begin_json_array()
Brad Davis709d3c62018-06-03 11:16:37 -0700120{
Brad Davis6c88b002018-06-18 09:30:16 -0700121 if (!stack.empty() && stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700122 {
123 statement_inner(",\n");
124 }
125 statement("[");
126 ++indent;
Brad Davis6c88b002018-06-18 09:30:16 -0700127 stack.emplace(Type::Array, false);
Brad Davis709d3c62018-06-03 11:16:37 -0700128}
129
Brad Davis6c88b002018-06-18 09:30:16 -0700130void Stream::end_json_array()
Brad Davis709d3c62018-06-03 11:16:37 -0700131{
Brad Davis6c88b002018-06-18 09:30:16 -0700132 if (stack.empty() || stack.top().first != Type::Array)
Brad Davis709d3c62018-06-03 11:16:37 -0700133 SPIRV_CROSS_THROW("Invalid JSON state");
Brad Davis6c88b002018-06-18 09:30:16 -0700134 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700135 {
136 statement_inner("\n");
137 }
138 --indent;
139 statement_no_return("]");
Brad Davis6c88b002018-06-18 09:30:16 -0700140 stack.pop();
141 if (!stack.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700142 {
Brad Davis6c88b002018-06-18 09:30:16 -0700143 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700144 }
145}
146
Brad Davis6c88b002018-06-18 09:30:16 -0700147void Stream::emit_json_array_value(const std::string &value)
Brad Davis709d3c62018-06-03 11:16:37 -0700148{
Brad Davis6c88b002018-06-18 09:30:16 -0700149 if (stack.empty() || stack.top().first != Type::Array)
Brad Davis709d3c62018-06-03 11:16:37 -0700150 SPIRV_CROSS_THROW("Invalid JSON state");
151
Brad Davis6c88b002018-06-18 09:30:16 -0700152 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700153 statement_inner(",\n");
154
155 statement_no_return("\"", value, "\"");
Brad Davis6c88b002018-06-18 09:30:16 -0700156 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700157}
158
Brad Davis6c88b002018-06-18 09:30:16 -0700159void Stream::emit_json_array_value(uint32_t value)
Brad Davis709d3c62018-06-03 11:16:37 -0700160{
Brad Davis6c88b002018-06-18 09:30:16 -0700161 if (stack.empty() || stack.top().first != Type::Array)
Brad Davis709d3c62018-06-03 11:16:37 -0700162 SPIRV_CROSS_THROW("Invalid JSON state");
Brad Davis6c88b002018-06-18 09:30:16 -0700163 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700164 statement_inner(",\n");
165 statement_no_return(std::to_string(value));
Brad Davis6c88b002018-06-18 09:30:16 -0700166 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700167}
168
Hans-Kristian Arntzen43e89bd2019-10-04 10:37:47 +0200169void Stream::emit_json_array_value(bool value)
170{
171 if (stack.empty() || stack.top().first != Type::Array)
172 SPIRV_CROSS_THROW("Invalid JSON state");
173 if (stack.top().second)
174 statement_inner(",\n");
175 statement_no_return(value ? "true" : "false");
176 stack.top().second = true;
177}
178
Brad Davis6c88b002018-06-18 09:30:16 -0700179void Stream::begin_json_object()
Brad Davis709d3c62018-06-03 11:16:37 -0700180{
Brad Davis6c88b002018-06-18 09:30:16 -0700181 if (!stack.empty() && stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700182 {
183 statement_inner(",\n");
184 }
Brad Davis6c88b002018-06-18 09:30:16 -0700185 statement("{");
186 ++indent;
187 stack.emplace(Type::Object, false);
Brad Davis709d3c62018-06-03 11:16:37 -0700188}
189
Brad Davis6c88b002018-06-18 09:30:16 -0700190void Stream::end_json_object()
Brad Davis709d3c62018-06-03 11:16:37 -0700191{
Brad Davis6c88b002018-06-18 09:30:16 -0700192 if (stack.empty() || stack.top().first != Type::Object)
Brad Davis709d3c62018-06-03 11:16:37 -0700193 SPIRV_CROSS_THROW("Invalid JSON state");
Brad Davis6c88b002018-06-18 09:30:16 -0700194 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700195 {
196 statement_inner("\n");
197 }
198 --indent;
199 statement_no_return("}");
Brad Davis6c88b002018-06-18 09:30:16 -0700200 stack.pop();
201 if (!stack.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700202 {
Brad Davis6c88b002018-06-18 09:30:16 -0700203 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700204 }
205}
206
Brad Davis6c88b002018-06-18 09:30:16 -0700207void Stream::emit_json_key(const std::string &key)
Brad Davis709d3c62018-06-03 11:16:37 -0700208{
Brad Davis6c88b002018-06-18 09:30:16 -0700209 if (stack.empty() || stack.top().first != Type::Object)
Brad Davis709d3c62018-06-03 11:16:37 -0700210 SPIRV_CROSS_THROW("Invalid JSON state");
211
Brad Davis6c88b002018-06-18 09:30:16 -0700212 if (stack.top().second)
Brad Davis709d3c62018-06-03 11:16:37 -0700213 statement_inner(",\n");
214 statement_no_return("\"", key, "\" : ");
Brad Davis6c88b002018-06-18 09:30:16 -0700215 stack.top().second = true;
Brad Davis709d3c62018-06-03 11:16:37 -0700216}
217
Brad Davis6c88b002018-06-18 09:30:16 -0700218void Stream::emit_json_key_value(const std::string &key, const std::string &value)
Brad Davis709d3c62018-06-03 11:16:37 -0700219{
220 emit_json_key(key);
221 statement_inner("\"", value, "\"");
222}
223
Brad Davis6c88b002018-06-18 09:30:16 -0700224void Stream::emit_json_key_value(const std::string &key, uint32_t value)
Brad Davis709d3c62018-06-03 11:16:37 -0700225{
226 emit_json_key(key);
227 statement_inner(value);
228}
229
Brad Davis8d84a542018-06-20 11:47:31 -0700230void Stream::emit_json_key_value(const std::string &key, int32_t value)
231{
232 emit_json_key(key);
233 statement_inner(value);
234}
235
236void Stream::emit_json_key_value(const std::string &key, float value)
237{
238 emit_json_key(key);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200239 statement_inner(convert_to_string(value, current_locale_radix_character));
Brad Davis8d84a542018-06-20 11:47:31 -0700240}
241
Brad Davis6c88b002018-06-18 09:30:16 -0700242void Stream::emit_json_key_value(const std::string &key, bool value)
Brad Davis709d3c62018-06-03 11:16:37 -0700243{
244 emit_json_key(key);
245 statement_inner(value ? "true" : "false");
246}
247
Brad Davis6c88b002018-06-18 09:30:16 -0700248void Stream::emit_json_key_object(const std::string &key)
Brad Davis709d3c62018-06-03 11:16:37 -0700249{
250 emit_json_key(key);
251 statement_inner("{\n");
252 ++indent;
Brad Davis6c88b002018-06-18 09:30:16 -0700253 stack.emplace(Type::Object, false);
Brad Davis709d3c62018-06-03 11:16:37 -0700254}
255
Brad Davis6c88b002018-06-18 09:30:16 -0700256void Stream::emit_json_key_array(const std::string &key)
Brad Davis709d3c62018-06-03 11:16:37 -0700257{
258 emit_json_key(key);
259 statement_inner("[\n");
260 ++indent;
Brad Davis6c88b002018-06-18 09:30:16 -0700261 stack.emplace(Type::Array, false);
262}
263
264void CompilerReflection::set_format(const std::string &format)
265{
266 if (format != "json")
267 {
268 SPIRV_CROSS_THROW("Unsupported format");
269 }
Brad Davis709d3c62018-06-03 11:16:37 -0700270}
271
272string CompilerReflection::compile()
273{
Brad Davis76204002018-06-20 10:25:38 -0700274 json_stream = std::make_shared<simple_json::Stream>();
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200275 json_stream->set_current_locale_radix_character(current_locale_radix_character);
Brad Davis6c88b002018-06-18 09:30:16 -0700276 json_stream->begin_json_object();
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +0200277 reorder_type_alias();
Brad Davis76204002018-06-20 10:25:38 -0700278 emit_entry_points();
Brad Davis709d3c62018-06-03 11:16:37 -0700279 emit_types();
280 emit_resources();
Brad Davis8d84a542018-06-20 11:47:31 -0700281 emit_specialization_constants();
Brad Davis6c88b002018-06-18 09:30:16 -0700282 json_stream->end_json_object();
Brad Davis6c88b002018-06-18 09:30:16 -0700283 return json_stream->str();
Brad Davis709d3c62018-06-03 11:16:37 -0700284}
285
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200286static bool naturally_emit_type(const SPIRType &type)
287{
288 return type.basetype == SPIRType::Struct && !type.pointer && type.array.empty();
289}
290
291bool CompilerReflection::type_is_reference(const SPIRType &type) const
292{
293 // Physical pointers and arrays of physical pointers need to refer to the pointee's type.
294 return type_is_top_level_physical_pointer(type) ||
295 (!type.array.empty() && type_is_top_level_physical_pointer(get<SPIRType>(type.parent_type)));
296}
297
Brad Davis709d3c62018-06-03 11:16:37 -0700298void CompilerReflection::emit_types()
299{
300 bool emitted_open_tag = false;
Hans-Kristian Arntzenb82cede2019-01-10 14:42:17 +0100301
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200302 SmallVector<uint32_t> physical_pointee_types;
303
304 // If we have physical pointers or arrays of physical pointers, it's also helpful to emit the pointee type
305 // and chain the type hierarchy. For POD, arrays can emit the entire type in-place.
306 ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
307 if (naturally_emit_type(type))
308 {
309 emit_type(self, emitted_open_tag);
310 }
311 else if (type_is_reference(type))
312 {
313 if (!naturally_emit_type(this->get<SPIRType>(type.parent_type)) &&
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +0200314 find(physical_pointee_types.begin(), physical_pointee_types.end(), type.parent_type) ==
315 physical_pointee_types.end())
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200316 {
317 physical_pointee_types.push_back(type.parent_type);
318 }
319 }
Hans-Kristian Arntzenb82cede2019-01-10 14:42:17 +0100320 });
Brad Davis709d3c62018-06-03 11:16:37 -0700321
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200322 for (uint32_t pointee_type : physical_pointee_types)
323 emit_type(pointee_type, emitted_open_tag);
324
Brad Davis709d3c62018-06-03 11:16:37 -0700325 if (emitted_open_tag)
326 {
Brad Davis6c88b002018-06-18 09:30:16 -0700327 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700328 }
329}
330
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200331void CompilerReflection::emit_type(uint32_t type_id, bool &emitted_open_tag)
Brad Davis709d3c62018-06-03 11:16:37 -0700332{
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200333 auto &type = get<SPIRType>(type_id);
Brad Davis76204002018-06-20 10:25:38 -0700334 auto name = type_to_glsl(type);
Brad Davis709d3c62018-06-03 11:16:37 -0700335
Brad Davis709d3c62018-06-03 11:16:37 -0700336 if (!emitted_open_tag)
337 {
Brad Davis6c88b002018-06-18 09:30:16 -0700338 json_stream->emit_json_key_object("types");
Brad Davis709d3c62018-06-03 11:16:37 -0700339 emitted_open_tag = true;
340 }
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200341 json_stream->emit_json_key_object("_" + std::to_string(type_id));
Brad Davis6c88b002018-06-18 09:30:16 -0700342 json_stream->emit_json_key_value("name", name);
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200343
344 if (type_is_top_level_physical_pointer(type))
Brad Davis709d3c62018-06-03 11:16:37 -0700345 {
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200346 json_stream->emit_json_key_value("type", "_" + std::to_string(type.parent_type));
347 json_stream->emit_json_key_value("physical_pointer", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700348 }
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200349 else if (!type.array.empty())
350 {
351 emit_type_array(type);
352 json_stream->emit_json_key_value("type", "_" + std::to_string(type.parent_type));
353 json_stream->emit_json_key_value("array_stride", get_decoration(type_id, DecorationArrayStride));
354 }
355 else
356 {
357 json_stream->emit_json_key_array("members");
358 // FIXME ideally we'd like to emit the size of a structure as a
359 // convenience to people parsing the reflected JSON. The problem
360 // is that there's no implicit size for a type. It's final size
361 // will be determined by the top level declaration in which it's
362 // included. So there might be one size for the struct if it's
363 // included in a std140 uniform block and another if it's included
364 // in a std430 uniform block.
365 // The solution is to include *all* potential sizes as a map of
366 // layout type name to integer, but that will probably require
367 // some additional logic being written in this class, or in the
368 // parent CompilerGLSL class.
369 auto size = type.member_types.size();
370 for (uint32_t i = 0; i < size; ++i)
371 {
372 emit_type_member(type, i);
373 }
374 json_stream->end_json_array();
375 }
376
Brad Davis6c88b002018-06-18 09:30:16 -0700377 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700378}
379
380void CompilerReflection::emit_type_member(const SPIRType &type, uint32_t index)
381{
382 auto &membertype = get<SPIRType>(type.member_types[index]);
Brad Davis6c88b002018-06-18 09:30:16 -0700383 json_stream->begin_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700384 auto name = to_member_name(type, index);
Brad Davis76204002018-06-20 10:25:38 -0700385 // FIXME we'd like to emit the offset of each member, but such offsets are
386 // context dependent. See the comment above regarding structure sizes
Brad Davis6c88b002018-06-18 09:30:16 -0700387 json_stream->emit_json_key_value("name", name);
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200388
389 if (type_is_reference(membertype))
390 {
391 json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.parent_type));
392 }
393 else if (membertype.basetype == SPIRType::Struct)
Brad Davis6c88b002018-06-18 09:30:16 -0700394 {
Brad Davis9ad43242018-06-21 09:24:22 -0700395 json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.self));
Brad Davis6c88b002018-06-18 09:30:16 -0700396 }
397 else
398 {
Brad Davis76204002018-06-20 10:25:38 -0700399 json_stream->emit_json_key_value("type", type_to_glsl(membertype));
Brad Davis6c88b002018-06-18 09:30:16 -0700400 }
Brad Davis709d3c62018-06-03 11:16:37 -0700401 emit_type_member_qualifiers(type, index);
Brad Davis6c88b002018-06-18 09:30:16 -0700402 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700403}
404
405void CompilerReflection::emit_type_array(const SPIRType &type)
406{
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200407 if (!type_is_top_level_physical_pointer(type) && !type.array.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700408 {
Brad Davis6c88b002018-06-18 09:30:16 -0700409 json_stream->emit_json_key_array("array");
Brad Davis76204002018-06-20 10:25:38 -0700410 // Note that we emit the zeros here as a means of identifying
411 // unbounded arrays. This is necessary as otherwise there would
412 // be no way of differentiating between float[4] and float[4][]
Brad Davis709d3c62018-06-03 11:16:37 -0700413 for (const auto &value : type.array)
Brad Davis6c88b002018-06-18 09:30:16 -0700414 json_stream->emit_json_array_value(value);
415 json_stream->end_json_array();
Hans-Kristian Arntzen18e24c32020-01-15 16:46:38 +0100416
417 json_stream->emit_json_key_array("array_size_is_literal");
418 for (const auto &value : type.array_size_literal)
419 json_stream->emit_json_array_value(value);
420 json_stream->end_json_array();
Brad Davis709d3c62018-06-03 11:16:37 -0700421 }
422}
423
424void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint32_t index)
425{
Brad Davis709d3c62018-06-03 11:16:37 -0700426 auto &membertype = get<SPIRType>(type.member_types[index]);
427 emit_type_array(membertype);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200428 auto &memb = ir.meta[type.self].members;
Brad Davis709d3c62018-06-03 11:16:37 -0700429 if (index < memb.size())
430 {
431 auto &dec = memb[index];
Brad Davis6c88b002018-06-18 09:30:16 -0700432 if (dec.decoration_flags.get(DecorationLocation))
433 json_stream->emit_json_key_value("location", dec.location);
434 if (dec.decoration_flags.get(DecorationOffset))
435 json_stream->emit_json_key_value("offset", dec.offset);
Hans-Kristian Arntzen762c87a2020-01-15 17:01:35 +0100436
437 // Array stride is a property of the array type, not the struct.
438 if (has_decoration(type.member_types[index], DecorationArrayStride))
Hans-Kristian Arntzen7a411252020-01-16 15:20:59 +0100439 json_stream->emit_json_key_value("array_stride",
440 get_decoration(type.member_types[index], DecorationArrayStride));
Hans-Kristian Arntzen762c87a2020-01-15 17:01:35 +0100441
442 if (dec.decoration_flags.get(DecorationMatrixStride))
443 json_stream->emit_json_key_value("matrix_stride", dec.matrix_stride);
444 if (dec.decoration_flags.get(DecorationRowMajor))
445 json_stream->emit_json_key_value("row_major", true);
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200446
447 if (type_is_top_level_physical_pointer(membertype))
448 json_stream->emit_json_key_value("physical_pointer", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700449 }
450}
451
Brad Davis76204002018-06-20 10:25:38 -0700452string CompilerReflection::execution_model_to_str(spv::ExecutionModel model)
Brad Davis709d3c62018-06-03 11:16:37 -0700453{
454 switch (model)
455 {
Patrick Mours524bd432019-03-26 14:46:51 +0100456 case ExecutionModelVertex:
Brad Davis76204002018-06-20 10:25:38 -0700457 return "vert";
Patrick Mours524bd432019-03-26 14:46:51 +0100458 case ExecutionModelTessellationControl:
Brad Davis76204002018-06-20 10:25:38 -0700459 return "tesc";
Brad Davis709d3c62018-06-03 11:16:37 -0700460 case ExecutionModelTessellationEvaluation:
Brad Davis76204002018-06-20 10:25:38 -0700461 return "tese";
Brad Davis709d3c62018-06-03 11:16:37 -0700462 case ExecutionModelGeometry:
Brad Davis76204002018-06-20 10:25:38 -0700463 return "geom";
Brad Davis709d3c62018-06-03 11:16:37 -0700464 case ExecutionModelFragment:
Brad Davis76204002018-06-20 10:25:38 -0700465 return "frag";
Brad Davis709d3c62018-06-03 11:16:37 -0700466 case ExecutionModelGLCompute:
Brad Davis76204002018-06-20 10:25:38 -0700467 return "comp";
Patrick Mours524bd432019-03-26 14:46:51 +0100468 case ExecutionModelRayGenerationNV:
469 return "rgen";
470 case ExecutionModelIntersectionNV:
471 return "rint";
472 case ExecutionModelAnyHitNV:
473 return "rahit";
474 case ExecutionModelClosestHitNV:
475 return "rchit";
476 case ExecutionModelMissNV:
477 return "rmiss";
478 case ExecutionModelCallableNV:
479 return "rcall";
Brad Davis709d3c62018-06-03 11:16:37 -0700480 default:
481 return "???";
482 }
483}
484
Brad Davis6c88b002018-06-18 09:30:16 -0700485// FIXME include things like the local_size dimensions, geometry output vertex count, etc
Brad Davis709d3c62018-06-03 11:16:37 -0700486void CompilerReflection::emit_entry_points()
487{
Hans-Kristian Arntzen040204d2018-06-22 09:41:43 +0200488 auto entries = get_entry_points_and_stages();
489 if (!entries.empty())
Brad Davis709d3c62018-06-03 11:16:37 -0700490 {
Hans-Kristian Arntzend2cc43e2019-02-19 17:00:49 +0100491 // Needed to make output deterministic.
492 sort(begin(entries), end(entries), [](const EntryPoint &a, const EntryPoint &b) -> bool {
493 if (a.execution_model < b.execution_model)
494 return true;
495 else if (a.execution_model > b.execution_model)
496 return false;
497 else
498 return a.name < b.name;
499 });
500
Brad Davis6c88b002018-06-18 09:30:16 -0700501 json_stream->emit_json_key_array("entryPoints");
Hans-Kristian Arntzen040204d2018-06-22 09:41:43 +0200502 for (auto &e : entries)
Brad Davis709d3c62018-06-03 11:16:37 -0700503 {
Brad Davis6c88b002018-06-18 09:30:16 -0700504 json_stream->begin_json_object();
505 json_stream->emit_json_key_value("name", e.name);
506 json_stream->emit_json_key_value("mode", execution_model_to_str(e.execution_model));
Hans-Kristian Arntzen43e89bd2019-10-04 10:37:47 +0200507 if (e.execution_model == ExecutionModelGLCompute)
Frank Richter227a0042019-10-03 16:36:17 +0200508 {
509 const auto &spv_entry = get_entry_point(e.name, e.execution_model);
Hans-Kristian Arntzen43e89bd2019-10-04 10:37:47 +0200510
511 SpecializationConstant spec_x, spec_y, spec_z;
512 get_work_group_size_specialization_constants(spec_x, spec_y, spec_z);
513
Frank Richter227a0042019-10-03 16:36:17 +0200514 json_stream->emit_json_key_array("workgroup_size");
Hans-Kristian Arntzen2d20b1a2019-10-07 10:29:04 +0200515 json_stream->emit_json_array_value(spec_x.id != ID(0) ? spec_x.constant_id :
516 spv_entry.workgroup_size.x);
517 json_stream->emit_json_array_value(spec_y.id != ID(0) ? spec_y.constant_id :
518 spv_entry.workgroup_size.y);
519 json_stream->emit_json_array_value(spec_z.id != ID(0) ? spec_z.constant_id :
520 spv_entry.workgroup_size.z);
Hans-Kristian Arntzen43e89bd2019-10-04 10:37:47 +0200521 json_stream->end_json_array();
522
523 json_stream->emit_json_key_array("workgroup_size_is_spec_constant_id");
524 json_stream->emit_json_array_value(spec_x.id != ID(0));
525 json_stream->emit_json_array_value(spec_y.id != ID(0));
526 json_stream->emit_json_array_value(spec_z.id != ID(0));
Frank Richter227a0042019-10-03 16:36:17 +0200527 json_stream->end_json_array();
528 }
Brad Davis6c88b002018-06-18 09:30:16 -0700529 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700530 }
Brad Davis6c88b002018-06-18 09:30:16 -0700531 json_stream->end_json_array();
Brad Davis709d3c62018-06-03 11:16:37 -0700532 }
Brad Davis709d3c62018-06-03 11:16:37 -0700533}
534
535void CompilerReflection::emit_resources()
536{
537 auto res = get_shader_resources();
538 emit_resources("subpass_inputs", res.subpass_inputs);
539 emit_resources("inputs", res.stage_inputs);
540 emit_resources("outputs", res.stage_outputs);
541 emit_resources("textures", res.sampled_images);
542 emit_resources("separate_images", res.separate_images);
543 emit_resources("separate_samplers", res.separate_samplers);
544 emit_resources("images", res.storage_images);
545 emit_resources("ssbos", res.storage_buffers);
546 emit_resources("ubos", res.uniform_buffers);
Brad Davis8d84a542018-06-20 11:47:31 -0700547 emit_resources("push_constants", res.push_constant_buffers);
Brad Davis709d3c62018-06-03 11:16:37 -0700548 emit_resources("counters", res.atomic_counters);
Patrick Moursb2a66752019-03-26 15:02:00 +0100549 emit_resources("acceleration_structures", res.acceleration_structures);
Brad Davis709d3c62018-06-03 11:16:37 -0700550}
551
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200552void CompilerReflection::emit_resources(const char *tag, const SmallVector<Resource> &resources)
Brad Davis709d3c62018-06-03 11:16:37 -0700553{
554 if (resources.empty())
555 {
556 return;
557 }
558
Brad Davis6c88b002018-06-18 09:30:16 -0700559 json_stream->emit_json_key_array(tag);
Brad Davis709d3c62018-06-03 11:16:37 -0700560 for (auto &res : resources)
561 {
Brad Davis709d3c62018-06-03 11:16:37 -0700562 auto &type = get_type(res.type_id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200563 auto typeflags = ir.meta[type.self].decoration.decoration_flags;
Brad Davis709d3c62018-06-03 11:16:37 -0700564 auto &mask = get_decoration_bitset(res.id);
Brad Davis709d3c62018-06-03 11:16:37 -0700565
566 // If we don't have a name, use the fallback for the type instead of the variable
567 // for SSBOs and UBOs since those are the only meaningful names to use externally.
568 // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks.
569 bool is_push_constant = get_storage_class(res.id) == StorageClassPushConstant;
570 bool is_block = get_decoration_bitset(type.self).get(DecorationBlock) ||
571 get_decoration_bitset(type.self).get(DecorationBufferBlock);
Brad Davis6c88b002018-06-18 09:30:16 -0700572
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200573 ID fallback_id = !is_push_constant && is_block ? ID(res.base_type_id) : ID(res.id);
Brad Davis6c88b002018-06-18 09:30:16 -0700574
575 json_stream->begin_json_object();
576
577 if (type.basetype == SPIRType::Struct)
Brad Davis709d3c62018-06-03 11:16:37 -0700578 {
Brad Davis9ad43242018-06-21 09:24:22 -0700579 json_stream->emit_json_key_value("type", "_" + std::to_string(res.base_type_id));
Brad Davis6c88b002018-06-18 09:30:16 -0700580 }
581 else
582 {
Brad Davis76204002018-06-20 10:25:38 -0700583 json_stream->emit_json_key_value("type", type_to_glsl(type));
Brad Davis6c88b002018-06-18 09:30:16 -0700584 }
585
586 json_stream->emit_json_key_value("name", !res.name.empty() ? res.name : get_fallback_name(fallback_id));
587 {
Brad Davis709d3c62018-06-03 11:16:37 -0700588 bool ssbo_block = type.storage == StorageClassStorageBuffer ||
589 (type.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
Brad Davis709d3c62018-06-03 11:16:37 -0700590 if (ssbo_block)
591 {
Brad Davis6c88b002018-06-18 09:30:16 -0700592 auto buffer_flags = get_buffer_block_flags(res.id);
593 if (buffer_flags.get(DecorationNonReadable))
594 json_stream->emit_json_key_value("writeonly", true);
595 if (buffer_flags.get(DecorationNonWritable))
596 json_stream->emit_json_key_value("readonly", true);
597 if (buffer_flags.get(DecorationRestrict))
598 json_stream->emit_json_key_value("restrict", true);
599 if (buffer_flags.get(DecorationCoherent))
600 json_stream->emit_json_key_value("coherent", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700601 }
602 }
603
604 emit_type_array(type);
605
606 {
607 bool is_sized_block = is_block && (get_storage_class(res.id) == StorageClassUniform ||
Hans-Kristian Arntzen4e7777c2019-01-30 13:31:17 +0100608 get_storage_class(res.id) == StorageClassUniformConstant ||
609 get_storage_class(res.id) == StorageClassStorageBuffer);
Brad Davis709d3c62018-06-03 11:16:37 -0700610 if (is_sized_block)
Brad Davis6c88b002018-06-18 09:30:16 -0700611 {
612 uint32_t block_size = uint32_t(get_declared_struct_size(get_type(res.base_type_id)));
613 json_stream->emit_json_key_value("block_size", block_size);
614 }
Brad Davis709d3c62018-06-03 11:16:37 -0700615 }
616
617 if (type.storage == StorageClassPushConstant)
Brad Davis6c88b002018-06-18 09:30:16 -0700618 json_stream->emit_json_key_value("push_constant", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700619 if (mask.get(DecorationLocation))
Brad Davis6c88b002018-06-18 09:30:16 -0700620 json_stream->emit_json_key_value("location", get_decoration(res.id, DecorationLocation));
Brad Davis709d3c62018-06-03 11:16:37 -0700621 if (mask.get(DecorationRowMajor))
Brad Davis6c88b002018-06-18 09:30:16 -0700622 json_stream->emit_json_key_value("row_major", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700623 if (mask.get(DecorationColMajor))
Brad Davis6c88b002018-06-18 09:30:16 -0700624 json_stream->emit_json_key_value("column_major", true);
Brad Davis709d3c62018-06-03 11:16:37 -0700625 if (mask.get(DecorationIndex))
Brad Davis6c88b002018-06-18 09:30:16 -0700626 json_stream->emit_json_key_value("index", get_decoration(res.id, DecorationIndex));
Brad Davis709d3c62018-06-03 11:16:37 -0700627 if (type.storage != StorageClassPushConstant && mask.get(DecorationDescriptorSet))
Brad Davis6c88b002018-06-18 09:30:16 -0700628 json_stream->emit_json_key_value("set", get_decoration(res.id, DecorationDescriptorSet));
Brad Davis709d3c62018-06-03 11:16:37 -0700629 if (mask.get(DecorationBinding))
Brad Davis6c88b002018-06-18 09:30:16 -0700630 json_stream->emit_json_key_value("binding", get_decoration(res.id, DecorationBinding));
Brad Davis709d3c62018-06-03 11:16:37 -0700631 if (mask.get(DecorationInputAttachmentIndex))
Brad Davis6c88b002018-06-18 09:30:16 -0700632 json_stream->emit_json_key_value("input_attachment_index",
633 get_decoration(res.id, DecorationInputAttachmentIndex));
Brad Davis709d3c62018-06-03 11:16:37 -0700634 if (mask.get(DecorationOffset))
Brad Davis6c88b002018-06-18 09:30:16 -0700635 json_stream->emit_json_key_value("offset", get_decoration(res.id, DecorationOffset));
Brad Davis709d3c62018-06-03 11:16:37 -0700636
637 // For images, the type itself adds a layout qualifer.
638 // Only emit the format for storage images.
639 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
640 {
Brad Davis76204002018-06-20 10:25:38 -0700641 const char *fmt = format_to_glsl(type.image.format);
Brad Davis709d3c62018-06-03 11:16:37 -0700642 if (fmt != nullptr)
Brad Davis6c88b002018-06-18 09:30:16 -0700643 json_stream->emit_json_key_value("format", std::string(fmt));
Brad Davis709d3c62018-06-03 11:16:37 -0700644 }
Brad Davis6c88b002018-06-18 09:30:16 -0700645 json_stream->end_json_object();
Brad Davis709d3c62018-06-03 11:16:37 -0700646 }
Brad Davis6c88b002018-06-18 09:30:16 -0700647 json_stream->end_json_array();
648}
649
Brad Davis8d84a542018-06-20 11:47:31 -0700650void CompilerReflection::emit_specialization_constants()
651{
652 auto specialization_constants = get_specialization_constants();
653 if (specialization_constants.empty())
654 return;
655
656 json_stream->emit_json_key_array("specialization_constants");
Corentin Wallezbcd71532020-09-04 10:04:25 +0200657 for (const auto &spec_const : specialization_constants)
Brad Davis8d84a542018-06-20 11:47:31 -0700658 {
659 auto &c = get<SPIRConstant>(spec_const.id);
660 auto type = get<SPIRType>(c.constant_type);
661 json_stream->begin_json_object();
Panagiotis Christopoulos Charitosb3109b82020-04-18 22:00:36 +0200662 json_stream->emit_json_key_value("name", get_name(spec_const.id));
Brad Davis8d84a542018-06-20 11:47:31 -0700663 json_stream->emit_json_key_value("id", spec_const.constant_id);
664 json_stream->emit_json_key_value("type", type_to_glsl(type));
Hans-Kristian Arntzen18e24c32020-01-15 16:46:38 +0100665 json_stream->emit_json_key_value("variable_id", spec_const.id);
Brad Davis8d84a542018-06-20 11:47:31 -0700666 switch (type.basetype)
667 {
668 case SPIRType::UInt:
669 json_stream->emit_json_key_value("default_value", c.scalar());
670 break;
671
672 case SPIRType::Int:
673 json_stream->emit_json_key_value("default_value", c.scalar_i32());
674 break;
675
676 case SPIRType::Float:
677 json_stream->emit_json_key_value("default_value", c.scalar_f32());
678 break;
679
680 case SPIRType::Boolean:
681 json_stream->emit_json_key_value("default_value", c.scalar() != 0);
682 break;
Hans-Kristian Arntzen040204d2018-06-22 09:41:43 +0200683
684 default:
685 break;
Brad Davis8d84a542018-06-20 11:47:31 -0700686 }
687 json_stream->end_json_object();
688 }
689 json_stream->end_json_array();
690}
691
Brad Davis6c88b002018-06-18 09:30:16 -0700692string CompilerReflection::to_member_name(const SPIRType &type, uint32_t index) const
693{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100694 auto *type_meta = ir.find_meta(type.self);
695
696 if (type_meta)
697 {
698 auto &memb = type_meta->members;
699 if (index < memb.size() && !memb[index].alias.empty())
700 return memb[index].alias;
701 else
702 return join("_m", index);
703 }
Brad Davis6c88b002018-06-18 09:30:16 -0700704 else
705 return join("_m", index);
Brad Davis709d3c62018-06-03 11:16:37 -0700706}