spirv_cross.hpp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091
  1. /*
  2. * Copyright 2015-2021 Arm Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * At your option, you may choose to accept this material under either:
  18. * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
  19. * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
  20. * SPDX-License-Identifier: Apache-2.0 OR MIT.
  21. */
  22. #ifndef SPIRV_CROSS_HPP
  23. #define SPIRV_CROSS_HPP
  24. #include "Khronos/spirv/spirv.hpp"
  25. #include "spirv_cfg.hpp"
  26. #include "spirv_cross_parsed_ir.hpp"
  27. namespace SPIRV_CROSS_NAMESPACE
  28. {
  29. struct Resource
  30. {
  31. // Resources are identified with their SPIR-V ID.
  32. // This is the ID of the OpVariable.
  33. ID id;
  34. // The type ID of the variable which includes arrays and all type modifications.
  35. // This type ID is not suitable for parsing OpMemberDecoration of a struct and other decorations in general
  36. // since these modifications typically happen on the base_type_id.
  37. TypeID type_id;
  38. // The base type of the declared resource.
  39. // This type is the base type which ignores pointers and arrays of the type_id.
  40. // This is mostly useful to parse decorations of the underlying type.
  41. // base_type_id can also be obtained with get_type(get_type(type_id).self).
  42. TypeID base_type_id;
  43. // The declared name (OpName) of the resource.
  44. // For Buffer blocks, the name actually reflects the externally
  45. // visible Block name.
  46. //
  47. // This name can be retrieved again by using either
  48. // get_name(id) or get_name(base_type_id) depending if it's a buffer block or not.
  49. //
  50. // This name can be an empty string in which case get_fallback_name(id) can be
  51. // used which obtains a suitable fallback identifier for an ID.
  52. std::string name;
  53. };
  54. struct ShaderResources
  55. {
  56. SmallVector<Resource> uniform_buffers;
  57. SmallVector<Resource> storage_buffers;
  58. SmallVector<Resource> stage_inputs;
  59. SmallVector<Resource> stage_outputs;
  60. SmallVector<Resource> subpass_inputs;
  61. SmallVector<Resource> storage_images;
  62. SmallVector<Resource> sampled_images;
  63. SmallVector<Resource> atomic_counters;
  64. SmallVector<Resource> acceleration_structures;
  65. // There can only be one push constant block,
  66. // but keep the vector in case this restriction is lifted in the future.
  67. SmallVector<Resource> push_constant_buffers;
  68. // For Vulkan GLSL and HLSL source,
  69. // these correspond to separate texture2D and samplers respectively.
  70. SmallVector<Resource> separate_images;
  71. SmallVector<Resource> separate_samplers;
  72. };
  73. struct CombinedImageSampler
  74. {
  75. // The ID of the sampler2D variable.
  76. VariableID combined_id;
  77. // The ID of the texture2D variable.
  78. VariableID image_id;
  79. // The ID of the sampler variable.
  80. VariableID sampler_id;
  81. };
  82. struct SpecializationConstant
  83. {
  84. // The ID of the specialization constant.
  85. ConstantID id;
  86. // The constant ID of the constant, used in Vulkan during pipeline creation.
  87. uint32_t constant_id;
  88. };
  89. struct BufferRange
  90. {
  91. unsigned index;
  92. size_t offset;
  93. size_t range;
  94. };
  95. enum BufferPackingStandard
  96. {
  97. BufferPackingStd140,
  98. BufferPackingStd430,
  99. BufferPackingStd140EnhancedLayout,
  100. BufferPackingStd430EnhancedLayout,
  101. BufferPackingHLSLCbuffer,
  102. BufferPackingHLSLCbufferPackOffset,
  103. BufferPackingScalar,
  104. BufferPackingScalarEnhancedLayout
  105. };
  106. struct EntryPoint
  107. {
  108. std::string name;
  109. spv::ExecutionModel execution_model;
  110. };
  111. class Compiler
  112. {
  113. public:
  114. friend class CFG;
  115. friend class DominatorBuilder;
  116. // The constructor takes a buffer of SPIR-V words and parses it.
  117. // It will create its own parser, parse the SPIR-V and move the parsed IR
  118. // as if you had called the constructors taking ParsedIR directly.
  119. explicit Compiler(std::vector<uint32_t> ir);
  120. Compiler(const uint32_t *ir, size_t word_count);
  121. // This is more modular. We can also consume a ParsedIR structure directly, either as a move, or copy.
  122. // With copy, we can reuse the same parsed IR for multiple Compiler instances.
  123. explicit Compiler(const ParsedIR &ir);
  124. explicit Compiler(ParsedIR &&ir);
  125. virtual ~Compiler() = default;
  126. // After parsing, API users can modify the SPIR-V via reflection and call this
  127. // to disassemble the SPIR-V into the desired langauage.
  128. // Sub-classes actually implement this.
  129. virtual std::string compile();
  130. // Gets the identifier (OpName) of an ID. If not defined, an empty string will be returned.
  131. const std::string &get_name(ID id) const;
  132. // Applies a decoration to an ID. Effectively injects OpDecorate.
  133. void set_decoration(ID id, spv::Decoration decoration, uint32_t argument = 0);
  134. void set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument);
  135. // Overrides the identifier OpName of an ID.
  136. // Identifiers beginning with underscores or identifiers which contain double underscores
  137. // are reserved by the implementation.
  138. void set_name(ID id, const std::string &name);
  139. // Gets a bitmask for the decorations which are applied to ID.
  140. // I.e. (1ull << spv::DecorationFoo) | (1ull << spv::DecorationBar)
  141. const Bitset &get_decoration_bitset(ID id) const;
  142. // Returns whether the decoration has been applied to the ID.
  143. bool has_decoration(ID id, spv::Decoration decoration) const;
  144. // Gets the value for decorations which take arguments.
  145. // If the decoration is a boolean (i.e. spv::DecorationNonWritable),
  146. // 1 will be returned.
  147. // If decoration doesn't exist or decoration is not recognized,
  148. // 0 will be returned.
  149. uint32_t get_decoration(ID id, spv::Decoration decoration) const;
  150. const std::string &get_decoration_string(ID id, spv::Decoration decoration) const;
  151. // Removes the decoration for an ID.
  152. void unset_decoration(ID id, spv::Decoration decoration);
  153. // Gets the SPIR-V type associated with ID.
  154. // Mostly used with Resource::type_id and Resource::base_type_id to parse the underlying type of a resource.
  155. const SPIRType &get_type(TypeID id) const;
  156. // Gets the SPIR-V type of a variable.
  157. const SPIRType &get_type_from_variable(VariableID id) const;
  158. // Gets the underlying storage class for an OpVariable.
  159. spv::StorageClass get_storage_class(VariableID id) const;
  160. // If get_name() is an empty string, get the fallback name which will be used
  161. // instead in the disassembled source.
  162. virtual const std::string get_fallback_name(ID id) const;
  163. // If get_name() of a Block struct is an empty string, get the fallback name.
  164. // This needs to be per-variable as multiple variables can use the same block type.
  165. virtual const std::string get_block_fallback_name(VariableID id) const;
  166. // Given an OpTypeStruct in ID, obtain the identifier for member number "index".
  167. // This may be an empty string.
  168. const std::string &get_member_name(TypeID id, uint32_t index) const;
  169. // Given an OpTypeStruct in ID, obtain the OpMemberDecoration for member number "index".
  170. uint32_t get_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
  171. const std::string &get_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration) const;
  172. // Sets the member identifier for OpTypeStruct ID, member number "index".
  173. void set_member_name(TypeID id, uint32_t index, const std::string &name);
  174. // Returns the qualified member identifier for OpTypeStruct ID, member number "index",
  175. // or an empty string if no qualified alias exists
  176. const std::string &get_member_qualified_name(TypeID type_id, uint32_t index) const;
  177. // Gets the decoration mask for a member of a struct, similar to get_decoration_mask.
  178. const Bitset &get_member_decoration_bitset(TypeID id, uint32_t index) const;
  179. // Returns whether the decoration has been applied to a member of a struct.
  180. bool has_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
  181. // Similar to set_decoration, but for struct members.
  182. void set_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0);
  183. void set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration,
  184. const std::string &argument);
  185. // Unsets a member decoration, similar to unset_decoration.
  186. void unset_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration);
  187. // Gets the fallback name for a member, similar to get_fallback_name.
  188. virtual const std::string get_fallback_member_name(uint32_t index) const
  189. {
  190. return join("_", index);
  191. }
  192. // Returns a vector of which members of a struct are potentially in use by a
  193. // SPIR-V shader. The granularity of this analysis is per-member of a struct.
  194. // This can be used for Buffer (UBO), BufferBlock/StorageBuffer (SSBO) and PushConstant blocks.
  195. // ID is the Resource::id obtained from get_shader_resources().
  196. SmallVector<BufferRange> get_active_buffer_ranges(VariableID id) const;
  197. // Returns the effective size of a buffer block.
  198. size_t get_declared_struct_size(const SPIRType &struct_type) const;
  199. // Returns the effective size of a buffer block, with a given array size
  200. // for a runtime array.
  201. // SSBOs are typically declared as runtime arrays. get_declared_struct_size() will return 0 for the size.
  202. // This is not very helpful for applications which might need to know the array stride of its last member.
  203. // This can be done through the API, but it is not very intuitive how to accomplish this, so here we provide a helper function
  204. // to query the size of the buffer, assuming that the last member has a certain size.
  205. // If the buffer does not contain a runtime array, array_size is ignored, and the function will behave as
  206. // get_declared_struct_size().
  207. // To get the array stride of the last member, something like:
  208. // get_declared_struct_size_runtime_array(type, 1) - get_declared_struct_size_runtime_array(type, 0) will work.
  209. size_t get_declared_struct_size_runtime_array(const SPIRType &struct_type, size_t array_size) const;
  210. // Returns the effective size of a buffer block struct member.
  211. size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const;
  212. // Returns a set of all global variables which are statically accessed
  213. // by the control flow graph from the current entry point.
  214. // Only variables which change the interface for a shader are returned, that is,
  215. // variables with storage class of Input, Output, Uniform, UniformConstant, PushConstant and AtomicCounter
  216. // storage classes are returned.
  217. //
  218. // To use the returned set as the filter for which variables are used during compilation,
  219. // this set can be moved to set_enabled_interface_variables().
  220. std::unordered_set<VariableID> get_active_interface_variables() const;
  221. // Sets the interface variables which are used during compilation.
  222. // By default, all variables are used.
  223. // Once set, compile() will only consider the set in active_variables.
  224. void set_enabled_interface_variables(std::unordered_set<VariableID> active_variables);
  225. // Query shader resources, use ids with reflection interface to modify or query binding points, etc.
  226. ShaderResources get_shader_resources() const;
  227. // Query shader resources, but only return the variables which are part of active_variables.
  228. // E.g.: get_shader_resources(get_active_variables()) to only return the variables which are statically
  229. // accessed.
  230. ShaderResources get_shader_resources(const std::unordered_set<VariableID> &active_variables) const;
  231. // Remapped variables are considered built-in variables and a backend will
  232. // not emit a declaration for this variable.
  233. // This is mostly useful for making use of builtins which are dependent on extensions.
  234. void set_remapped_variable_state(VariableID id, bool remap_enable);
  235. bool get_remapped_variable_state(VariableID id) const;
  236. // For subpassInput variables which are remapped to plain variables,
  237. // the number of components in the remapped
  238. // variable must be specified as the backing type of subpass inputs are opaque.
  239. void set_subpass_input_remapped_components(VariableID id, uint32_t components);
  240. uint32_t get_subpass_input_remapped_components(VariableID id) const;
  241. // All operations work on the current entry point.
  242. // Entry points can be swapped out with set_entry_point().
  243. // Entry points should be set right after the constructor completes as some reflection functions traverse the graph from the entry point.
  244. // Resource reflection also depends on the entry point.
  245. // By default, the current entry point is set to the first OpEntryPoint which appears in the SPIR-V module.
  246. // Some shader languages restrict the names that can be given to entry points, and the
  247. // corresponding backend will automatically rename an entry point name, during the call
  248. // to compile() if it is illegal. For example, the common entry point name main() is
  249. // illegal in MSL, and is renamed to an alternate name by the MSL backend.
  250. // Given the original entry point name contained in the SPIR-V, this function returns
  251. // the name, as updated by the backend during the call to compile(). If the name is not
  252. // illegal, and has not been renamed, or if this function is called before compile(),
  253. // this function will simply return the same name.
  254. // New variants of entry point query and reflection.
  255. // Names for entry points in the SPIR-V module may alias if they belong to different execution models.
  256. // To disambiguate, we must pass along with the entry point names the execution model.
  257. SmallVector<EntryPoint> get_entry_points_and_stages() const;
  258. void set_entry_point(const std::string &entry, spv::ExecutionModel execution_model);
  259. // Renames an entry point from old_name to new_name.
  260. // If old_name is currently selected as the current entry point, it will continue to be the current entry point,
  261. // albeit with a new name.
  262. // get_entry_points() is essentially invalidated at this point.
  263. void rename_entry_point(const std::string &old_name, const std::string &new_name,
  264. spv::ExecutionModel execution_model);
  265. const SPIREntryPoint &get_entry_point(const std::string &name, spv::ExecutionModel execution_model) const;
  266. SPIREntryPoint &get_entry_point(const std::string &name, spv::ExecutionModel execution_model);
  267. const std::string &get_cleansed_entry_point_name(const std::string &name,
  268. spv::ExecutionModel execution_model) const;
  269. // Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader.
  270. void update_active_builtins();
  271. bool has_active_builtin(spv::BuiltIn builtin, spv::StorageClass storage);
  272. // Query and modify OpExecutionMode.
  273. const Bitset &get_execution_mode_bitset() const;
  274. void unset_execution_mode(spv::ExecutionMode mode);
  275. void set_execution_mode(spv::ExecutionMode mode, uint32_t arg0 = 0, uint32_t arg1 = 0, uint32_t arg2 = 0);
  276. // Gets argument for an execution mode (LocalSize, Invocations, OutputVertices).
  277. // For LocalSize, the index argument is used to select the dimension (X = 0, Y = 1, Z = 2).
  278. // For execution modes which do not have arguments, 0 is returned.
  279. uint32_t get_execution_mode_argument(spv::ExecutionMode mode, uint32_t index = 0) const;
  280. spv::ExecutionModel get_execution_model() const;
  281. bool is_tessellation_shader() const;
  282. // In SPIR-V, the compute work group size can be represented by a constant vector, in which case
  283. // the LocalSize execution mode is ignored.
  284. //
  285. // This constant vector can be a constant vector, specialization constant vector, or partly specialized constant vector.
  286. // To modify and query work group dimensions which are specialization constants, SPIRConstant values must be modified
  287. // directly via get_constant() rather than using LocalSize directly. This function will return which constants should be modified.
  288. //
  289. // To modify dimensions which are *not* specialization constants, set_execution_mode should be used directly.
  290. // Arguments to set_execution_mode which are specialization constants are effectively ignored during compilation.
  291. // NOTE: This is somewhat different from how SPIR-V works. In SPIR-V, the constant vector will completely replace LocalSize,
  292. // while in this interface, LocalSize is only ignored for specialization constants.
  293. //
  294. // The specialization constant will be written to x, y and z arguments.
  295. // If the component is not a specialization constant, a zeroed out struct will be written.
  296. // The return value is the constant ID of the builtin WorkGroupSize, but this is not expected to be useful
  297. // for most use cases.
  298. uint32_t get_work_group_size_specialization_constants(SpecializationConstant &x, SpecializationConstant &y,
  299. SpecializationConstant &z) const;
  300. // Analyzes all OpImageFetch (texelFetch) opcodes and checks if there are instances where
  301. // said instruction is used without a combined image sampler.
  302. // GLSL targets do not support the use of texelFetch without a sampler.
  303. // To workaround this, we must inject a dummy sampler which can be used to form a sampler2D at the call-site of
  304. // texelFetch as necessary.
  305. //
  306. // This must be called before build_combined_image_samplers().
  307. // build_combined_image_samplers() may refer to the ID returned by this method if the returned ID is non-zero.
  308. // The return value will be the ID of a sampler object if a dummy sampler is necessary, or 0 if no sampler object
  309. // is required.
  310. //
  311. // If the returned ID is non-zero, it can be decorated with set/bindings as desired before calling compile().
  312. // Calling this function also invalidates get_active_interface_variables(), so this should be called
  313. // before that function.
  314. VariableID build_dummy_sampler_for_combined_images();
  315. // Analyzes all separate image and samplers used from the currently selected entry point,
  316. // and re-routes them all to a combined image sampler instead.
  317. // This is required to "support" separate image samplers in targets which do not natively support
  318. // this feature, like GLSL/ESSL.
  319. //
  320. // This must be called before compile() if such remapping is desired.
  321. // This call will add new sampled images to the SPIR-V,
  322. // so it will appear in reflection if get_shader_resources() is called after build_combined_image_samplers.
  323. //
  324. // If any image/sampler remapping was found, no separate image/samplers will appear in the decompiled output,
  325. // but will still appear in reflection.
  326. //
  327. // The resulting samplers will be void of any decorations like name, descriptor sets and binding points,
  328. // so this can be added before compile() if desired.
  329. //
  330. // Combined image samplers originating from this set are always considered active variables.
  331. // Arrays of separate samplers are not supported, but arrays of separate images are supported.
  332. // Array of images + sampler -> Array of combined image samplers.
  333. void build_combined_image_samplers();
  334. // Gets a remapping for the combined image samplers.
  335. const SmallVector<CombinedImageSampler> &get_combined_image_samplers() const
  336. {
  337. return combined_image_samplers;
  338. }
  339. // Set a new variable type remap callback.
  340. // The type remapping is designed to allow global interface variable to assume more special types.
  341. // A typical example here is to remap sampler2D into samplerExternalOES, which currently isn't supported
  342. // directly by SPIR-V.
  343. //
  344. // In compile() while emitting code,
  345. // for every variable that is declared, including function parameters, the callback will be called
  346. // and the API user has a chance to change the textual representation of the type used to declare the variable.
  347. // The API user can detect special patterns in names to guide the remapping.
  348. void set_variable_type_remap_callback(VariableTypeRemapCallback cb)
  349. {
  350. variable_remap_callback = std::move(cb);
  351. }
  352. // API for querying which specialization constants exist.
  353. // To modify a specialization constant before compile(), use get_constant(constant.id),
  354. // then update constants directly in the SPIRConstant data structure.
  355. // For composite types, the subconstants can be iterated over and modified.
  356. // constant_type is the SPIRType for the specialization constant,
  357. // which can be queried to determine which fields in the unions should be poked at.
  358. SmallVector<SpecializationConstant> get_specialization_constants() const;
  359. SPIRConstant &get_constant(ConstantID id);
  360. const SPIRConstant &get_constant(ConstantID id) const;
  361. uint32_t get_current_id_bound() const
  362. {
  363. return uint32_t(ir.ids.size());
  364. }
  365. // API for querying buffer objects.
  366. // The type passed in here should be the base type of a resource, i.e.
  367. // get_type(resource.base_type_id)
  368. // as decorations are set in the basic Block type.
  369. // The type passed in here must have these decorations set, or an exception is raised.
  370. // Only UBOs and SSBOs or sub-structs which are part of these buffer types will have these decorations set.
  371. uint32_t type_struct_member_offset(const SPIRType &type, uint32_t index) const;
  372. uint32_t type_struct_member_array_stride(const SPIRType &type, uint32_t index) const;
  373. uint32_t type_struct_member_matrix_stride(const SPIRType &type, uint32_t index) const;
  374. // Gets the offset in SPIR-V words (uint32_t) for a decoration which was originally declared in the SPIR-V binary.
  375. // The offset will point to one or more uint32_t literals which can be modified in-place before using the SPIR-V binary.
  376. // Note that adding or removing decorations using the reflection API will not change the behavior of this function.
  377. // If the decoration was declared, sets the word_offset to an offset into the provided SPIR-V binary buffer and returns true,
  378. // otherwise, returns false.
  379. // If the decoration does not have any value attached to it (e.g. DecorationRelaxedPrecision), this function will also return false.
  380. bool get_binary_offset_for_decoration(VariableID id, spv::Decoration decoration, uint32_t &word_offset) const;
  381. // HLSL counter buffer reflection interface.
  382. // Append/Consume/Increment/Decrement in HLSL is implemented as two "neighbor" buffer objects where
  383. // one buffer implements the storage, and a single buffer containing just a lone "int" implements the counter.
  384. // To SPIR-V these will be exposed as two separate buffers, but glslang HLSL frontend emits a special indentifier
  385. // which lets us link the two buffers together.
  386. // Queries if a variable ID is a counter buffer which "belongs" to a regular buffer object.
  387. // If SPV_GOOGLE_hlsl_functionality1 is used, this can be used even with a stripped SPIR-V module.
  388. // Otherwise, this query is purely based on OpName identifiers as found in the SPIR-V module, and will
  389. // only return true if OpSource was reported HLSL.
  390. // To rely on this functionality, ensure that the SPIR-V module is not stripped.
  391. bool buffer_is_hlsl_counter_buffer(VariableID id) const;
  392. // Queries if a buffer object has a neighbor "counter" buffer.
  393. // If so, the ID of that counter buffer will be returned in counter_id.
  394. // If SPV_GOOGLE_hlsl_functionality1 is used, this can be used even with a stripped SPIR-V module.
  395. // Otherwise, this query is purely based on OpName identifiers as found in the SPIR-V module, and will
  396. // only return true if OpSource was reported HLSL.
  397. // To rely on this functionality, ensure that the SPIR-V module is not stripped.
  398. bool buffer_get_hlsl_counter_buffer(VariableID id, uint32_t &counter_id) const;
  399. // Gets the list of all SPIR-V Capabilities which were declared in the SPIR-V module.
  400. const SmallVector<spv::Capability> &get_declared_capabilities() const;
  401. // Gets the list of all SPIR-V extensions which were declared in the SPIR-V module.
  402. const SmallVector<std::string> &get_declared_extensions() const;
  403. // When declaring buffer blocks in GLSL, the name declared in the GLSL source
  404. // might not be the same as the name declared in the SPIR-V module due to naming conflicts.
  405. // In this case, SPIRV-Cross needs to find a fallback-name, and it might only
  406. // be possible to know this name after compiling to GLSL.
  407. // This is particularly important for HLSL input and UAVs which tends to reuse the same block type
  408. // for multiple distinct blocks. For these cases it is not possible to modify the name of the type itself
  409. // because it might be unique. Instead, you can use this interface to check after compilation which
  410. // name was actually used if your input SPIR-V tends to have this problem.
  411. // For other names like remapped names for variables, etc, it's generally enough to query the name of the variables
  412. // after compiling, block names are an exception to this rule.
  413. // ID is the name of a variable as returned by Resource::id, and must be a variable with a Block-like type.
  414. //
  415. // This also applies to HLSL cbuffers.
  416. std::string get_remapped_declared_block_name(VariableID id) const;
  417. // For buffer block variables, get the decorations for that variable.
  418. // Sometimes, decorations for buffer blocks are found in member decorations instead
  419. // of direct decorations on the variable itself.
  420. // The most common use here is to check if a buffer is readonly or writeonly.
  421. Bitset get_buffer_block_flags(VariableID id) const;
  422. // Returns whether the position output is invariant
  423. bool is_position_invariant() const
  424. {
  425. return position_invariant;
  426. }
  427. protected:
  428. const uint32_t *stream(const Instruction &instr) const
  429. {
  430. // If we're not going to use any arguments, just return nullptr.
  431. // We want to avoid case where we return an out of range pointer
  432. // that trips debug assertions on some platforms.
  433. if (!instr.length)
  434. return nullptr;
  435. if (instr.offset + instr.length > ir.spirv.size())
  436. SPIRV_CROSS_THROW("Compiler::stream() out of range.");
  437. return &ir.spirv[instr.offset];
  438. }
  439. ParsedIR ir;
  440. // Marks variables which have global scope and variables which can alias with other variables
  441. // (SSBO, image load store, etc)
  442. SmallVector<uint32_t> global_variables;
  443. SmallVector<uint32_t> aliased_variables;
  444. SPIRFunction *current_function = nullptr;
  445. SPIRBlock *current_block = nullptr;
  446. uint32_t current_loop_level = 0;
  447. std::unordered_set<VariableID> active_interface_variables;
  448. bool check_active_interface_variables = false;
  449. void add_loop_level();
  450. void set_initializers(SPIRExpression &e)
  451. {
  452. e.emitted_loop_level = current_loop_level;
  453. }
  454. template <typename T>
  455. void set_initializers(const T &)
  456. {
  457. }
  458. // If our IDs are out of range here as part of opcodes, throw instead of
  459. // undefined behavior.
  460. template <typename T, typename... P>
  461. T &set(uint32_t id, P &&... args)
  462. {
  463. ir.add_typed_id(static_cast<Types>(T::type), id);
  464. auto &var = variant_set<T>(ir.ids[id], std::forward<P>(args)...);
  465. var.self = id;
  466. set_initializers(var);
  467. return var;
  468. }
  469. template <typename T>
  470. T &get(uint32_t id)
  471. {
  472. return variant_get<T>(ir.ids[id]);
  473. }
  474. template <typename T>
  475. T *maybe_get(uint32_t id)
  476. {
  477. if (id >= ir.ids.size())
  478. return nullptr;
  479. else if (ir.ids[id].get_type() == static_cast<Types>(T::type))
  480. return &get<T>(id);
  481. else
  482. return nullptr;
  483. }
  484. template <typename T>
  485. const T &get(uint32_t id) const
  486. {
  487. return variant_get<T>(ir.ids[id]);
  488. }
  489. template <typename T>
  490. const T *maybe_get(uint32_t id) const
  491. {
  492. if (id >= ir.ids.size())
  493. return nullptr;
  494. else if (ir.ids[id].get_type() == static_cast<Types>(T::type))
  495. return &get<T>(id);
  496. else
  497. return nullptr;
  498. }
  499. // Gets the id of SPIR-V type underlying the given type_id, which might be a pointer.
  500. uint32_t get_pointee_type_id(uint32_t type_id) const;
  501. // Gets the SPIR-V type underlying the given type, which might be a pointer.
  502. const SPIRType &get_pointee_type(const SPIRType &type) const;
  503. // Gets the SPIR-V type underlying the given type_id, which might be a pointer.
  504. const SPIRType &get_pointee_type(uint32_t type_id) const;
  505. // Gets the ID of the SPIR-V type underlying a variable.
  506. uint32_t get_variable_data_type_id(const SPIRVariable &var) const;
  507. // Gets the SPIR-V type underlying a variable.
  508. SPIRType &get_variable_data_type(const SPIRVariable &var);
  509. // Gets the SPIR-V type underlying a variable.
  510. const SPIRType &get_variable_data_type(const SPIRVariable &var) const;
  511. // Gets the SPIR-V element type underlying an array variable.
  512. SPIRType &get_variable_element_type(const SPIRVariable &var);
  513. // Gets the SPIR-V element type underlying an array variable.
  514. const SPIRType &get_variable_element_type(const SPIRVariable &var) const;
  515. // Sets the qualified member identifier for OpTypeStruct ID, member number "index".
  516. void set_member_qualified_name(uint32_t type_id, uint32_t index, const std::string &name);
  517. void set_qualified_name(uint32_t id, const std::string &name);
  518. // Returns if the given type refers to a sampled image.
  519. bool is_sampled_image_type(const SPIRType &type);
  520. const SPIREntryPoint &get_entry_point() const;
  521. SPIREntryPoint &get_entry_point();
  522. static bool is_tessellation_shader(spv::ExecutionModel model);
  523. virtual std::string to_name(uint32_t id, bool allow_alias = true) const;
  524. bool is_builtin_variable(const SPIRVariable &var) const;
  525. bool is_builtin_type(const SPIRType &type) const;
  526. bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
  527. bool is_immutable(uint32_t id) const;
  528. bool is_member_builtin(const SPIRType &type, uint32_t index, spv::BuiltIn *builtin) const;
  529. bool is_scalar(const SPIRType &type) const;
  530. bool is_vector(const SPIRType &type) const;
  531. bool is_matrix(const SPIRType &type) const;
  532. bool is_array(const SPIRType &type) const;
  533. uint32_t expression_type_id(uint32_t id) const;
  534. const SPIRType &expression_type(uint32_t id) const;
  535. bool expression_is_lvalue(uint32_t id) const;
  536. bool variable_storage_is_aliased(const SPIRVariable &var);
  537. SPIRVariable *maybe_get_backing_variable(uint32_t chain);
  538. spv::StorageClass get_expression_effective_storage_class(uint32_t ptr);
  539. void register_read(uint32_t expr, uint32_t chain, bool forwarded);
  540. void register_write(uint32_t chain);
  541. inline bool is_continue(uint32_t next) const
  542. {
  543. return (ir.block_meta[next] & ParsedIR::BLOCK_META_CONTINUE_BIT) != 0;
  544. }
  545. inline bool is_single_block_loop(uint32_t next) const
  546. {
  547. auto &block = get<SPIRBlock>(next);
  548. return block.merge == SPIRBlock::MergeLoop && block.continue_block == ID(next);
  549. }
  550. inline bool is_break(uint32_t next) const
  551. {
  552. return (ir.block_meta[next] &
  553. (ParsedIR::BLOCK_META_LOOP_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT)) != 0;
  554. }
  555. inline bool is_loop_break(uint32_t next) const
  556. {
  557. return (ir.block_meta[next] & ParsedIR::BLOCK_META_LOOP_MERGE_BIT) != 0;
  558. }
  559. inline bool is_conditional(uint32_t next) const
  560. {
  561. return (ir.block_meta[next] &
  562. (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT)) != 0;
  563. }
  564. // Dependency tracking for temporaries read from variables.
  565. void flush_dependees(SPIRVariable &var);
  566. void flush_all_active_variables();
  567. void flush_control_dependent_expressions(uint32_t block);
  568. void flush_all_atomic_capable_variables();
  569. void flush_all_aliased_variables();
  570. void register_global_read_dependencies(const SPIRBlock &func, uint32_t id);
  571. void register_global_read_dependencies(const SPIRFunction &func, uint32_t id);
  572. std::unordered_set<uint32_t> invalid_expressions;
  573. void update_name_cache(std::unordered_set<std::string> &cache, std::string &name);
  574. // A variant which takes two sets of names. The secondary is only used to verify there are no collisions,
  575. // but the set is not updated when we have found a new name.
  576. // Used primarily when adding block interface names.
  577. void update_name_cache(std::unordered_set<std::string> &cache_primary,
  578. const std::unordered_set<std::string> &cache_secondary, std::string &name);
  579. bool function_is_pure(const SPIRFunction &func);
  580. bool block_is_pure(const SPIRBlock &block);
  581. bool execution_is_branchless(const SPIRBlock &from, const SPIRBlock &to) const;
  582. bool execution_is_direct_branch(const SPIRBlock &from, const SPIRBlock &to) const;
  583. bool execution_is_noop(const SPIRBlock &from, const SPIRBlock &to) const;
  584. SPIRBlock::ContinueBlockType continue_block_type(const SPIRBlock &continue_block) const;
  585. void force_recompile();
  586. void clear_force_recompile();
  587. bool is_forcing_recompilation() const;
  588. bool is_force_recompile = false;
  589. bool block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method method) const;
  590. bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const;
  591. void inherit_expression_dependencies(uint32_t dst, uint32_t source);
  592. void add_implied_read_expression(SPIRExpression &e, uint32_t source);
  593. void add_implied_read_expression(SPIRAccessChain &e, uint32_t source);
  594. // For proper multiple entry point support, allow querying if an Input or Output
  595. // variable is part of that entry points interface.
  596. bool interface_variable_exists_in_entry_point(uint32_t id) const;
  597. SmallVector<CombinedImageSampler> combined_image_samplers;
  598. void remap_variable_type_name(const SPIRType &type, const std::string &var_name, std::string &type_name) const
  599. {
  600. if (variable_remap_callback)
  601. variable_remap_callback(type, var_name, type_name);
  602. }
  603. void set_ir(const ParsedIR &parsed);
  604. void set_ir(ParsedIR &&parsed);
  605. void parse_fixup();
  606. // Used internally to implement various traversals for queries.
  607. struct OpcodeHandler
  608. {
  609. virtual ~OpcodeHandler() = default;
  610. // Return true if traversal should continue.
  611. // If false, traversal will end immediately.
  612. virtual bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) = 0;
  613. virtual bool follow_function_call(const SPIRFunction &)
  614. {
  615. return true;
  616. }
  617. virtual void set_current_block(const SPIRBlock &)
  618. {
  619. }
  620. // Called after returning from a function or when entering a block,
  621. // can be called multiple times per block,
  622. // while set_current_block is only called on block entry.
  623. virtual void rearm_current_block(const SPIRBlock &)
  624. {
  625. }
  626. virtual bool begin_function_scope(const uint32_t *, uint32_t)
  627. {
  628. return true;
  629. }
  630. virtual bool end_function_scope(const uint32_t *, uint32_t)
  631. {
  632. return true;
  633. }
  634. };
  635. struct BufferAccessHandler : OpcodeHandler
  636. {
  637. BufferAccessHandler(const Compiler &compiler_, SmallVector<BufferRange> &ranges_, uint32_t id_)
  638. : compiler(compiler_)
  639. , ranges(ranges_)
  640. , id(id_)
  641. {
  642. }
  643. bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
  644. const Compiler &compiler;
  645. SmallVector<BufferRange> &ranges;
  646. uint32_t id;
  647. std::unordered_set<uint32_t> seen;
  648. };
  649. struct InterfaceVariableAccessHandler : OpcodeHandler
  650. {
  651. InterfaceVariableAccessHandler(const Compiler &compiler_, std::unordered_set<VariableID> &variables_)
  652. : compiler(compiler_)
  653. , variables(variables_)
  654. {
  655. }
  656. bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
  657. const Compiler &compiler;
  658. std::unordered_set<VariableID> &variables;
  659. };
  660. struct CombinedImageSamplerHandler : OpcodeHandler
  661. {
  662. CombinedImageSamplerHandler(Compiler &compiler_)
  663. : compiler(compiler_)
  664. {
  665. }
  666. bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
  667. bool begin_function_scope(const uint32_t *args, uint32_t length) override;
  668. bool end_function_scope(const uint32_t *args, uint32_t length) override;
  669. Compiler &compiler;
  670. // Each function in the call stack needs its own remapping for parameters so we can deduce which global variable each texture/sampler the parameter is statically bound to.
  671. std::stack<std::unordered_map<uint32_t, uint32_t>> parameter_remapping;
  672. std::stack<SPIRFunction *> functions;
  673. uint32_t remap_parameter(uint32_t id);
  674. void push_remap_parameters(const SPIRFunction &func, const uint32_t *args, uint32_t length);
  675. void pop_remap_parameters();
  676. void register_combined_image_sampler(SPIRFunction &caller, VariableID combined_id, VariableID texture_id,
  677. VariableID sampler_id, bool depth);
  678. };
  679. struct DummySamplerForCombinedImageHandler : OpcodeHandler
  680. {
  681. DummySamplerForCombinedImageHandler(Compiler &compiler_)
  682. : compiler(compiler_)
  683. {
  684. }
  685. bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
  686. Compiler &compiler;
  687. bool need_dummy_sampler = false;
  688. };
  689. struct ActiveBuiltinHandler : OpcodeHandler
  690. {
  691. ActiveBuiltinHandler(Compiler &compiler_)
  692. : compiler(compiler_)
  693. {
  694. }
  695. bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
  696. Compiler &compiler;
  697. void handle_builtin(const SPIRType &type, spv::BuiltIn builtin, const Bitset &decoration_flags);
  698. void add_if_builtin(uint32_t id);
  699. void add_if_builtin_or_block(uint32_t id);
  700. void add_if_builtin(uint32_t id, bool allow_blocks);
  701. };
  702. bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
  703. bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
  704. // This must be an ordered data structure so we always pick the same type aliases.
  705. SmallVector<uint32_t> global_struct_cache;
  706. ShaderResources get_shader_resources(const std::unordered_set<VariableID> *active_variables) const;
  707. VariableTypeRemapCallback variable_remap_callback;
  708. bool get_common_basic_type(const SPIRType &type, SPIRType::BaseType &base_type);
  709. std::unordered_set<uint32_t> forced_temporaries;
  710. std::unordered_set<uint32_t> forwarded_temporaries;
  711. std::unordered_set<uint32_t> suppressed_usage_tracking;
  712. std::unordered_set<uint32_t> hoisted_temporaries;
  713. std::unordered_set<uint32_t> forced_invariant_temporaries;
  714. Bitset active_input_builtins;
  715. Bitset active_output_builtins;
  716. uint32_t clip_distance_count = 0;
  717. uint32_t cull_distance_count = 0;
  718. bool position_invariant = false;
  719. void analyze_parameter_preservation(
  720. SPIRFunction &entry, const CFG &cfg,
  721. const std::unordered_map<uint32_t, std::unordered_set<uint32_t>> &variable_to_blocks,
  722. const std::unordered_map<uint32_t, std::unordered_set<uint32_t>> &complete_write_blocks);
  723. // If a variable ID or parameter ID is found in this set, a sampler is actually a shadow/comparison sampler.
  724. // SPIR-V does not support this distinction, so we must keep track of this information outside the type system.
  725. // There might be unrelated IDs found in this set which do not correspond to actual variables.
  726. // This set should only be queried for the existence of samplers which are already known to be variables or parameter IDs.
  727. // Similar is implemented for images, as well as if subpass inputs are needed.
  728. std::unordered_set<uint32_t> comparison_ids;
  729. bool need_subpass_input = false;
  730. // In certain backends, we will need to use a dummy sampler to be able to emit code.
  731. // GLSL does not support texelFetch on texture2D objects, but SPIR-V does,
  732. // so we need to workaround by having the application inject a dummy sampler.
  733. uint32_t dummy_sampler_id = 0;
  734. void analyze_image_and_sampler_usage();
  735. struct CombinedImageSamplerDrefHandler : OpcodeHandler
  736. {
  737. CombinedImageSamplerDrefHandler(Compiler &compiler_)
  738. : compiler(compiler_)
  739. {
  740. }
  741. bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
  742. Compiler &compiler;
  743. std::unordered_set<uint32_t> dref_combined_samplers;
  744. };
  745. struct CombinedImageSamplerUsageHandler : OpcodeHandler
  746. {
  747. CombinedImageSamplerUsageHandler(Compiler &compiler_,
  748. const std::unordered_set<uint32_t> &dref_combined_samplers_)
  749. : compiler(compiler_)
  750. , dref_combined_samplers(dref_combined_samplers_)
  751. {
  752. }
  753. bool begin_function_scope(const uint32_t *args, uint32_t length) override;
  754. bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
  755. Compiler &compiler;
  756. const std::unordered_set<uint32_t> &dref_combined_samplers;
  757. std::unordered_map<uint32_t, std::unordered_set<uint32_t>> dependency_hierarchy;
  758. std::unordered_set<uint32_t> comparison_ids;
  759. void add_hierarchy_to_comparison_ids(uint32_t ids);
  760. bool need_subpass_input = false;
  761. void add_dependency(uint32_t dst, uint32_t src);
  762. };
  763. void build_function_control_flow_graphs_and_analyze();
  764. std::unordered_map<uint32_t, std::unique_ptr<CFG>> function_cfgs;
  765. const CFG &get_cfg_for_current_function() const;
  766. const CFG &get_cfg_for_function(uint32_t id) const;
  767. struct CFGBuilder : OpcodeHandler
  768. {
  769. explicit CFGBuilder(Compiler &compiler_);
  770. bool follow_function_call(const SPIRFunction &func) override;
  771. bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
  772. Compiler &compiler;
  773. std::unordered_map<uint32_t, std::unique_ptr<CFG>> function_cfgs;
  774. };
  775. struct AnalyzeVariableScopeAccessHandler : OpcodeHandler
  776. {
  777. AnalyzeVariableScopeAccessHandler(Compiler &compiler_, SPIRFunction &entry_);
  778. bool follow_function_call(const SPIRFunction &) override;
  779. void set_current_block(const SPIRBlock &block) override;
  780. void notify_variable_access(uint32_t id, uint32_t block);
  781. bool id_is_phi_variable(uint32_t id) const;
  782. bool id_is_potential_temporary(uint32_t id) const;
  783. bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
  784. Compiler &compiler;
  785. SPIRFunction &entry;
  786. std::unordered_map<uint32_t, std::unordered_set<uint32_t>> accessed_variables_to_block;
  787. std::unordered_map<uint32_t, std::unordered_set<uint32_t>> accessed_temporaries_to_block;
  788. std::unordered_map<uint32_t, uint32_t> result_id_to_type;
  789. std::unordered_map<uint32_t, std::unordered_set<uint32_t>> complete_write_variables_to_block;
  790. std::unordered_map<uint32_t, std::unordered_set<uint32_t>> partial_write_variables_to_block;
  791. std::unordered_set<uint32_t> access_chain_expressions;
  792. // Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers.
  793. std::unordered_map<uint32_t, std::unordered_set<uint32_t>> access_chain_children;
  794. const SPIRBlock *current_block = nullptr;
  795. };
  796. struct StaticExpressionAccessHandler : OpcodeHandler
  797. {
  798. StaticExpressionAccessHandler(Compiler &compiler_, uint32_t variable_id_);
  799. bool follow_function_call(const SPIRFunction &) override;
  800. bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
  801. Compiler &compiler;
  802. uint32_t variable_id;
  803. uint32_t static_expression = 0;
  804. uint32_t write_count = 0;
  805. };
  806. struct PhysicalStorageBufferPointerHandler : OpcodeHandler
  807. {
  808. explicit PhysicalStorageBufferPointerHandler(Compiler &compiler_);
  809. bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
  810. Compiler &compiler;
  811. std::unordered_set<uint32_t> types;
  812. };
  813. void analyze_non_block_pointer_types();
  814. SmallVector<uint32_t> physical_storage_non_block_pointer_types;
  815. void analyze_variable_scope(SPIRFunction &function, AnalyzeVariableScopeAccessHandler &handler);
  816. void find_function_local_luts(SPIRFunction &function, const AnalyzeVariableScopeAccessHandler &handler,
  817. bool single_function);
  818. bool may_read_undefined_variable_in_block(const SPIRBlock &block, uint32_t var);
  819. // Finds all resources that are written to from inside the critical section, if present.
  820. // The critical section is delimited by OpBeginInvocationInterlockEXT and
  821. // OpEndInvocationInterlockEXT instructions. In MSL and HLSL, any resources written
  822. // while inside the critical section must be placed in a raster order group.
  823. struct InterlockedResourceAccessHandler : OpcodeHandler
  824. {
  825. InterlockedResourceAccessHandler(Compiler &compiler_, uint32_t entry_point_id)
  826. : compiler(compiler_)
  827. {
  828. call_stack.push_back(entry_point_id);
  829. }
  830. bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
  831. bool begin_function_scope(const uint32_t *args, uint32_t length) override;
  832. bool end_function_scope(const uint32_t *args, uint32_t length) override;
  833. Compiler &compiler;
  834. bool in_crit_sec = false;
  835. uint32_t interlock_function_id = 0;
  836. bool split_function_case = false;
  837. bool control_flow_interlock = false;
  838. bool use_critical_section = false;
  839. bool call_stack_is_interlocked = false;
  840. SmallVector<uint32_t> call_stack;
  841. void access_potential_resource(uint32_t id);
  842. };
  843. struct InterlockedResourceAccessPrepassHandler : OpcodeHandler
  844. {
  845. InterlockedResourceAccessPrepassHandler(Compiler &compiler_, uint32_t entry_point_id)
  846. : compiler(compiler_)
  847. {
  848. call_stack.push_back(entry_point_id);
  849. }
  850. void rearm_current_block(const SPIRBlock &block) override;
  851. bool handle(spv::Op op, const uint32_t *args, uint32_t length) override;
  852. bool begin_function_scope(const uint32_t *args, uint32_t length) override;
  853. bool end_function_scope(const uint32_t *args, uint32_t length) override;
  854. Compiler &compiler;
  855. uint32_t interlock_function_id = 0;
  856. uint32_t current_block_id = 0;
  857. bool split_function_case = false;
  858. bool control_flow_interlock = false;
  859. SmallVector<uint32_t> call_stack;
  860. };
  861. void analyze_interlocked_resource_usage();
  862. // The set of all resources written while inside the critical section, if present.
  863. std::unordered_set<uint32_t> interlocked_resources;
  864. bool interlocked_is_complex = false;
  865. void make_constant_null(uint32_t id, uint32_t type);
  866. std::unordered_map<uint32_t, std::string> declared_block_names;
  867. bool instruction_to_result_type(uint32_t &result_type, uint32_t &result_id, spv::Op op, const uint32_t *args,
  868. uint32_t length);
  869. Bitset combined_decoration_for_member(const SPIRType &type, uint32_t index) const;
  870. static bool is_desktop_only_format(spv::ImageFormat format);
  871. bool image_is_comparison(const SPIRType &type, uint32_t id) const;
  872. void set_extended_decoration(uint32_t id, ExtendedDecorations decoration, uint32_t value = 0);
  873. uint32_t get_extended_decoration(uint32_t id, ExtendedDecorations decoration) const;
  874. bool has_extended_decoration(uint32_t id, ExtendedDecorations decoration) const;
  875. void unset_extended_decoration(uint32_t id, ExtendedDecorations decoration);
  876. void set_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration,
  877. uint32_t value = 0);
  878. uint32_t get_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration) const;
  879. bool has_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration) const;
  880. void unset_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration);
  881. bool type_is_array_of_pointers(const SPIRType &type) const;
  882. bool type_is_top_level_physical_pointer(const SPIRType &type) const;
  883. bool type_is_block_like(const SPIRType &type) const;
  884. bool type_is_opaque_value(const SPIRType &type) const;
  885. bool reflection_ssbo_instance_name_is_significant() const;
  886. std::string get_remapped_declared_block_name(uint32_t id, bool fallback_prefer_instance_name) const;
  887. bool flush_phi_required(BlockID from, BlockID to) const;
  888. uint32_t evaluate_spec_constant_u32(const SPIRConstantOp &spec) const;
  889. uint32_t evaluate_constant_u32(uint32_t id) const;
  890. bool is_vertex_like_shader() const;
  891. private:
  892. // Used only to implement the old deprecated get_entry_point() interface.
  893. const SPIREntryPoint &get_first_entry_point(const std::string &name) const;
  894. SPIREntryPoint &get_first_entry_point(const std::string &name);
  895. };
  896. } // namespace SPIRV_CROSS_NAMESPACE
  897. #endif