spirv_reflect.cpp 22 KB

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