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