| 1 | /* | 
| 2 |  * Copyright 2016-2021 Robert Konrad | 
| 3 |  * SPDX-License-Identifier: Apache-2.0 OR MIT | 
| 4 |  * | 
| 5 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
| 6 |  * you may not use this file except in compliance with the License. | 
| 7 |  * You may obtain a copy of the License at | 
| 8 |  * | 
| 9 |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
| 10 |  * | 
| 11 |  * Unless required by applicable law or agreed to in writing, software | 
| 12 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 13 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 14 |  * See the License for the specific language governing permissions and | 
| 15 |  * limitations under the License. | 
| 16 |  */ | 
| 17 |  | 
| 18 | /* | 
| 19 |  * At your option, you may choose to accept this material under either: | 
| 20 |  *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or | 
| 21 |  *  2. The MIT License, found at <http://opensource.org/licenses/MIT>. | 
| 22 |  */ | 
| 23 |  | 
| 24 | #ifndef SPIRV_HLSL_HPP | 
| 25 | #define SPIRV_HLSL_HPP | 
| 26 |  | 
| 27 | #include "spirv_glsl.hpp" | 
| 28 | #include <utility> | 
| 29 |  | 
| 30 | namespace SPIRV_CROSS_NAMESPACE | 
| 31 | { | 
| 32 | // Interface which remaps vertex inputs to a fixed semantic name to make linking easier. | 
| 33 | struct HLSLVertexAttributeRemap | 
| 34 | { | 
| 35 | 	uint32_t location; | 
| 36 | 	std::string semantic; | 
| 37 | }; | 
| 38 | // Specifying a root constant (d3d12) or push constant range (vulkan). | 
| 39 | // | 
| 40 | // `start` and `end` denotes the range of the root constant in bytes. | 
| 41 | // Both values need to be multiple of 4. | 
| 42 | struct RootConstants | 
| 43 | { | 
| 44 | 	uint32_t start; | 
| 45 | 	uint32_t end; | 
| 46 |  | 
| 47 | 	uint32_t binding; | 
| 48 | 	uint32_t space; | 
| 49 | }; | 
| 50 |  | 
| 51 | // For finer control, decorations may be removed from specific resources instead with unset_decoration(). | 
| 52 | enum HLSLBindingFlagBits | 
| 53 | { | 
| 54 | 	HLSL_BINDING_AUTO_NONE_BIT = 0, | 
| 55 |  | 
| 56 | 	// Push constant (root constant) resources will be declared as CBVs (b-space) without a register() declaration. | 
| 57 | 	// A register will be automatically assigned by the D3D compiler, but must therefore be reflected in D3D-land. | 
| 58 | 	// Push constants do not normally have a DecorationBinding set, but if they do, this can be used to ignore it. | 
| 59 | 	HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT = 1 << 0, | 
| 60 |  | 
| 61 | 	// cbuffer resources will be declared as CBVs (b-space) without a register() declaration. | 
| 62 | 	// A register will be automatically assigned, but must be reflected in D3D-land. | 
| 63 | 	HLSL_BINDING_AUTO_CBV_BIT = 1 << 1, | 
| 64 |  | 
| 65 | 	// All SRVs (t-space) will be declared without a register() declaration. | 
| 66 | 	HLSL_BINDING_AUTO_SRV_BIT = 1 << 2, | 
| 67 |  | 
| 68 | 	// All UAVs (u-space) will be declared without a register() declaration. | 
| 69 | 	HLSL_BINDING_AUTO_UAV_BIT = 1 << 3, | 
| 70 |  | 
| 71 | 	// All samplers (s-space) will be declared without a register() declaration. | 
| 72 | 	HLSL_BINDING_AUTO_SAMPLER_BIT = 1 << 4, | 
| 73 |  | 
| 74 | 	// No resources will be declared with register(). | 
| 75 | 	HLSL_BINDING_AUTO_ALL = 0x7fffffff | 
| 76 | }; | 
| 77 | using HLSLBindingFlags = uint32_t; | 
| 78 |  | 
| 79 | // By matching stage, desc_set and binding for a SPIR-V resource, | 
| 80 | // register bindings are set based on whether the HLSL resource is a | 
| 81 | // CBV, UAV, SRV or Sampler. A single binding in SPIR-V might contain multiple | 
| 82 | // resource types, e.g. COMBINED_IMAGE_SAMPLER, and SRV/Sampler bindings will be used respectively. | 
| 83 | // On SM 5.0 and lower, register_space is ignored. | 
| 84 | // | 
| 85 | // To remap a push constant block which does not have any desc_set/binding associated with it, | 
| 86 | // use ResourceBindingPushConstant{DescriptorSet,Binding} as values for desc_set/binding. | 
| 87 | // For deeper control of push constants, set_root_constant_layouts() can be used instead. | 
| 88 | struct HLSLResourceBinding | 
| 89 | { | 
| 90 | 	spv::ExecutionModel stage = spv::ExecutionModelMax; | 
| 91 | 	uint32_t desc_set = 0; | 
| 92 | 	uint32_t binding = 0; | 
| 93 |  | 
| 94 | 	struct Binding | 
| 95 | 	{ | 
| 96 | 		uint32_t register_space = 0; | 
| 97 | 		uint32_t register_binding = 0; | 
| 98 | 	} cbv, uav, srv, sampler; | 
| 99 | }; | 
| 100 |  | 
| 101 | enum HLSLAuxBinding | 
| 102 | { | 
| 103 | 	HLSL_AUX_BINDING_BASE_VERTEX_INSTANCE = 0 | 
| 104 | }; | 
| 105 |  | 
| 106 | class CompilerHLSL : public CompilerGLSL | 
| 107 | { | 
| 108 | public: | 
| 109 | 	struct Options | 
| 110 | 	{ | 
| 111 | 		uint32_t shader_model = 30; // TODO: map ps_4_0_level_9_0,... somehow | 
| 112 |  | 
| 113 | 		// Allows the PointSize builtin in SM 4.0+, and ignores it, as PointSize is not supported in SM 4+. | 
| 114 | 		bool point_size_compat = false; | 
| 115 |  | 
| 116 | 		// Allows the PointCoord builtin, returns float2(0.5, 0.5), as PointCoord is not supported in HLSL. | 
| 117 | 		bool point_coord_compat = false; | 
| 118 |  | 
| 119 | 		// If true, the backend will assume that VertexIndex and InstanceIndex will need to apply | 
| 120 | 		// a base offset, and you will need to fill in a cbuffer with offsets. | 
| 121 | 		// Set to false if you know you will never use base instance or base vertex | 
| 122 | 		// functionality as it might remove an internal cbuffer. | 
| 123 | 		bool support_nonzero_base_vertex_base_instance = false; | 
| 124 |  | 
| 125 | 		// Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used. | 
| 126 | 		// By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead. | 
| 127 | 		// Alternatively, use set_hlsl_force_storage_buffer_as_uav to specify individually. | 
| 128 | 		bool force_storage_buffer_as_uav = false; | 
| 129 | 	 | 
| 130 | 		// Forces any storage image type marked as NonWritable to be considered an SRV instead. | 
| 131 | 		// For this to work with function call parameters, NonWritable must be considered to be part of the type system | 
| 132 | 		// so that NonWritable image arguments are also translated to Texture rather than RWTexture. | 
| 133 | 		bool nonwritable_uav_texture_as_srv = false; | 
| 134 |  | 
| 135 | 		// Enables native 16-bit types. Needs SM 6.2. | 
| 136 | 		// Uses half/int16_t/uint16_t instead of min16* types. | 
| 137 | 		// Also adds support for 16-bit load-store from (RW)ByteAddressBuffer. | 
| 138 | 		bool enable_16bit_types = false; | 
| 139 |  | 
| 140 | 		// If matrices are used as IO variables, flatten the attribute declaration to use | 
| 141 | 		// TEXCOORD{N,N+1,N+2,...} rather than TEXCOORDN_{0,1,2,3}. | 
| 142 | 		// If add_vertex_attribute_remap is used and this feature is used, | 
| 143 | 		// the semantic name will be queried once per active location. | 
| 144 | 		bool flatten_matrix_vertex_input_semantics = false; | 
| 145 |  | 
| 146 | 		// Rather than emitting main() for the entry point, use the name in SPIR-V. | 
| 147 | 		bool use_entry_point_name = false; | 
| 148 |  | 
| 149 | 		// Preserve (RW)StructuredBuffer types if the input source was HLSL. | 
| 150 | 		// This relies on UserTypeGOOGLE to encode the buffer type either as "structuredbuffer" or "rwstructuredbuffer" | 
| 151 | 		// whereas the type can be extended with an optional subtype, e.g. "structuredbuffer:int". | 
| 152 | 		bool preserve_structured_buffers = false; | 
| 153 | 	}; | 
| 154 |  | 
| 155 | 	explicit CompilerHLSL(std::vector<uint32_t> spirv_) | 
| 156 | 	    : CompilerGLSL(std::move(spirv_)) | 
| 157 | 	{ | 
| 158 | 	} | 
| 159 |  | 
| 160 | 	CompilerHLSL(const uint32_t *ir_, size_t size) | 
| 161 | 	    : CompilerGLSL(ir_, size) | 
| 162 | 	{ | 
| 163 | 	} | 
| 164 |  | 
| 165 | 	explicit CompilerHLSL(const ParsedIR &ir_) | 
| 166 | 	    : CompilerGLSL(ir_) | 
| 167 | 	{ | 
| 168 | 	} | 
| 169 |  | 
| 170 | 	explicit CompilerHLSL(ParsedIR &&ir_) | 
| 171 | 	    : CompilerGLSL(std::move(ir_)) | 
| 172 | 	{ | 
| 173 | 	} | 
| 174 |  | 
| 175 | 	const Options &get_hlsl_options() const | 
| 176 | 	{ | 
| 177 | 		return hlsl_options; | 
| 178 | 	} | 
| 179 |  | 
| 180 | 	void set_hlsl_options(const Options &opts) | 
| 181 | 	{ | 
| 182 | 		hlsl_options = opts; | 
| 183 | 	} | 
| 184 |  | 
| 185 | 	// Optionally specify a custom root constant layout. | 
| 186 | 	// | 
| 187 | 	// Push constants ranges will be split up according to the | 
| 188 | 	// layout specified. | 
| 189 | 	void set_root_constant_layouts(std::vector<RootConstants> layout); | 
| 190 |  | 
| 191 | 	// Compiles and remaps vertex attributes at specific locations to a fixed semantic. | 
| 192 | 	// The default is TEXCOORD# where # denotes location. | 
| 193 | 	// Matrices are unrolled to vectors with notation ${SEMANTIC}_#, where # denotes row. | 
| 194 | 	// $SEMANTIC is either TEXCOORD# or a semantic name specified here. | 
| 195 | 	void add_vertex_attribute_remap(const HLSLVertexAttributeRemap &vertex_attributes); | 
| 196 | 	std::string compile() override; | 
| 197 |  | 
| 198 | 	// This is a special HLSL workaround for the NumWorkGroups builtin. | 
| 199 | 	// This does not exist in HLSL, so the calling application must create a dummy cbuffer in | 
| 200 | 	// which the application will store this builtin. | 
| 201 | 	// The cbuffer layout will be: | 
| 202 | 	// cbuffer SPIRV_Cross_NumWorkgroups : register(b#, space#) { uint3 SPIRV_Cross_NumWorkgroups_count; }; | 
| 203 | 	// This must be called before compile(). | 
| 204 | 	// The function returns 0 if NumWorkGroups builtin is not statically used in the shader from the current entry point. | 
| 205 | 	// If non-zero, this returns the variable ID of a cbuffer which corresponds to | 
| 206 | 	// the cbuffer declared above. By default, no binding or descriptor set decoration is set, | 
| 207 | 	// so the calling application should declare explicit bindings on this ID before calling compile(). | 
| 208 | 	VariableID remap_num_workgroups_builtin(); | 
| 209 |  | 
| 210 | 	// Controls how resource bindings are declared in the output HLSL. | 
| 211 | 	void set_resource_binding_flags(HLSLBindingFlags flags); | 
| 212 |  | 
| 213 | 	// resource is a resource binding to indicate the HLSL CBV, SRV, UAV or sampler binding | 
| 214 | 	// to use for a particular SPIR-V description set | 
| 215 | 	// and binding. If resource bindings are provided, | 
| 216 | 	// is_hlsl_resource_binding_used() will return true after calling ::compile() if | 
| 217 | 	// the set/binding combination was used by the HLSL code. | 
| 218 | 	void add_hlsl_resource_binding(const HLSLResourceBinding &resource); | 
| 219 | 	bool is_hlsl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const; | 
| 220 |  | 
| 221 | 	// Controls which storage buffer bindings will be forced to be declared as UAVs. | 
| 222 | 	void set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint32_t binding); | 
| 223 |  | 
| 224 | 	// By default, these magic buffers are not assigned a specific binding. | 
| 225 | 	void set_hlsl_aux_buffer_binding(HLSLAuxBinding binding, uint32_t register_index, uint32_t register_space); | 
| 226 | 	void unset_hlsl_aux_buffer_binding(HLSLAuxBinding binding); | 
| 227 | 	bool is_hlsl_aux_buffer_binding_used(HLSLAuxBinding binding) const; | 
| 228 |  | 
| 229 | private: | 
| 230 | 	std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; | 
| 231 | 	std::string image_type_hlsl(const SPIRType &type, uint32_t id); | 
| 232 | 	std::string image_type_hlsl_modern(const SPIRType &type, uint32_t id); | 
| 233 | 	std::string image_type_hlsl_legacy(const SPIRType &type, uint32_t id); | 
| 234 | 	void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override; | 
| 235 | 	void emit_hlsl_entry_point(); | 
| 236 | 	void () override; | 
| 237 | 	void emit_resources(); | 
| 238 | 	void emit_interface_block_globally(const SPIRVariable &type); | 
| 239 | 	void emit_interface_block_in_struct(const SPIRVariable &var, std::unordered_set<uint32_t> &active_locations); | 
| 240 | 	void emit_interface_block_member_in_struct(const SPIRVariable &var, uint32_t member_index, uint32_t location, | 
| 241 | 	                                           std::unordered_set<uint32_t> &active_locations); | 
| 242 | 	void emit_builtin_inputs_in_struct(); | 
| 243 | 	void emit_builtin_outputs_in_struct(); | 
| 244 | 	void emit_builtin_primitive_outputs_in_struct(); | 
| 245 | 	void emit_texture_op(const Instruction &i, bool sparse) override; | 
| 246 | 	void emit_instruction(const Instruction &instruction) override; | 
| 247 | 	void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, | 
| 248 | 	                  uint32_t count) override; | 
| 249 | 	void emit_buffer_block(const SPIRVariable &type) override; | 
| 250 | 	void emit_push_constant_block(const SPIRVariable &var) override; | 
| 251 | 	void emit_uniform(const SPIRVariable &var) override; | 
| 252 | 	void emit_modern_uniform(const SPIRVariable &var); | 
| 253 | 	void emit_legacy_uniform(const SPIRVariable &var); | 
| 254 | 	void emit_specialization_constants_and_structs(); | 
| 255 | 	void emit_composite_constants(); | 
| 256 | 	void emit_fixup() override; | 
| 257 | 	std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override; | 
| 258 | 	std::string layout_for_member(const SPIRType &type, uint32_t index) override; | 
| 259 | 	std::string to_interpolation_qualifiers(const Bitset &flags) override; | 
| 260 | 	std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override; | 
| 261 | 	bool emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0) override; | 
| 262 | 	std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override; | 
| 263 | 	std::string to_sampler_expression(uint32_t id); | 
| 264 | 	std::string to_resource_binding(const SPIRVariable &var); | 
| 265 | 	std::string to_resource_binding_sampler(const SPIRVariable &var); | 
| 266 | 	std::string to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t set); | 
| 267 | 	std::string to_initializer_expression(const SPIRVariable &var) override; | 
| 268 | 	void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override; | 
| 269 | 	void emit_access_chain(const Instruction &instruction); | 
| 270 | 	void emit_load(const Instruction &instruction); | 
| 271 | 	void read_access_chain(std::string *expr, const std::string &lhs, const SPIRAccessChain &chain); | 
| 272 | 	void read_access_chain_struct(const std::string &lhs, const SPIRAccessChain &chain); | 
| 273 | 	void read_access_chain_array(const std::string &lhs, const SPIRAccessChain &chain); | 
| 274 | 	void write_access_chain(const SPIRAccessChain &chain, uint32_t value, const SmallVector<uint32_t> &composite_chain); | 
| 275 | 	void write_access_chain_struct(const SPIRAccessChain &chain, uint32_t value, | 
| 276 | 	                               const SmallVector<uint32_t> &composite_chain); | 
| 277 | 	void write_access_chain_array(const SPIRAccessChain &chain, uint32_t value, | 
| 278 | 	                              const SmallVector<uint32_t> &composite_chain); | 
| 279 | 	std::string write_access_chain_value(uint32_t value, const SmallVector<uint32_t> &composite_chain, bool enclose); | 
| 280 | 	void emit_store(const Instruction &instruction); | 
| 281 | 	void emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op); | 
| 282 | 	void emit_subgroup_op(const Instruction &i) override; | 
| 283 | 	void emit_block_hints(const SPIRBlock &block) override; | 
| 284 |  | 
| 285 | 	void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier, | 
| 286 | 	                        uint32_t base_offset = 0) override; | 
| 287 | 	void emit_rayquery_function(const char *commited, const char *candidate, const uint32_t *ops); | 
| 288 | 	void emit_mesh_tasks(SPIRBlock &block) override; | 
| 289 |  | 
| 290 | 	const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override; | 
| 291 | 	void replace_illegal_names() override; | 
| 292 |  | 
| 293 | 	SPIRType::BaseType get_builtin_basetype(spv::BuiltIn builtin, SPIRType::BaseType default_type) override; | 
| 294 |  | 
| 295 | 	bool is_hlsl_force_storage_buffer_as_uav(ID id) const; | 
| 296 |  | 
| 297 | 	Options hlsl_options; | 
| 298 |  | 
| 299 | 	// TODO: Refactor this to be more similar to MSL, maybe have some common system in place? | 
| 300 | 	bool requires_op_fmod = false; | 
| 301 | 	bool requires_fp16_packing = false; | 
| 302 | 	bool requires_uint2_packing = false; | 
| 303 | 	bool requires_explicit_fp16_packing = false; | 
| 304 | 	bool requires_unorm8_packing = false; | 
| 305 | 	bool requires_snorm8_packing = false; | 
| 306 | 	bool requires_unorm16_packing = false; | 
| 307 | 	bool requires_snorm16_packing = false; | 
| 308 | 	bool requires_bitfield_insert = false; | 
| 309 | 	bool  = false; | 
| 310 | 	bool requires_inverse_2x2 = false; | 
| 311 | 	bool requires_inverse_3x3 = false; | 
| 312 | 	bool requires_inverse_4x4 = false; | 
| 313 | 	bool requires_scalar_reflect = false; | 
| 314 | 	bool requires_scalar_refract = false; | 
| 315 | 	bool requires_scalar_faceforward = false; | 
| 316 |  | 
| 317 | 	struct TextureSizeVariants | 
| 318 | 	{ | 
| 319 | 		// MSVC 2013 workaround. | 
| 320 | 		TextureSizeVariants() | 
| 321 | 		{ | 
| 322 | 			srv = 0; | 
| 323 | 			for (auto &unorm : uav) | 
| 324 | 				for (auto &u : unorm) | 
| 325 | 					u = 0; | 
| 326 | 		} | 
| 327 | 		uint64_t srv; | 
| 328 | 		uint64_t uav[3][4]; | 
| 329 | 	} required_texture_size_variants; | 
| 330 |  | 
| 331 | 	void require_texture_query_variant(uint32_t var_id); | 
| 332 | 	void emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav, | 
| 333 | 	                                const char *type_qualifier); | 
| 334 |  | 
| 335 | 	enum TextureQueryVariantDim | 
| 336 | 	{ | 
| 337 | 		Query1D = 0, | 
| 338 | 		Query1DArray, | 
| 339 | 		Query2D, | 
| 340 | 		Query2DArray, | 
| 341 | 		Query3D, | 
| 342 | 		QueryBuffer, | 
| 343 | 		QueryCube, | 
| 344 | 		QueryCubeArray, | 
| 345 | 		Query2DMS, | 
| 346 | 		Query2DMSArray, | 
| 347 | 		QueryDimCount | 
| 348 | 	}; | 
| 349 |  | 
| 350 | 	enum TextureQueryVariantType | 
| 351 | 	{ | 
| 352 | 		QueryTypeFloat = 0, | 
| 353 | 		QueryTypeInt = 16, | 
| 354 | 		QueryTypeUInt = 32, | 
| 355 | 		QueryTypeCount = 3 | 
| 356 | 	}; | 
| 357 |  | 
| 358 | 	enum BitcastType | 
| 359 | 	{ | 
| 360 | 		TypeNormal, | 
| 361 | 		TypePackUint2x32, | 
| 362 | 		TypeUnpackUint64 | 
| 363 | 	}; | 
| 364 |  | 
| 365 | 	void analyze_meshlet_writes(); | 
| 366 | 	void analyze_meshlet_writes(uint32_t func_id, uint32_t id_per_vertex, uint32_t id_per_primitive, | 
| 367 | 	                            std::unordered_set<uint32_t> &processed_func_ids); | 
| 368 |  | 
| 369 | 	BitcastType get_bitcast_type(uint32_t result_type, uint32_t op0); | 
| 370 |  | 
| 371 | 	void emit_builtin_variables(); | 
| 372 | 	bool require_output = false; | 
| 373 | 	bool require_input = false; | 
| 374 | 	SmallVector<HLSLVertexAttributeRemap> remap_vertex_attributes; | 
| 375 |  | 
| 376 | 	uint32_t type_to_consumed_locations(const SPIRType &type) const; | 
| 377 |  | 
| 378 | 	std::string to_semantic(uint32_t location, spv::ExecutionModel em, spv::StorageClass sc); | 
| 379 |  | 
| 380 | 	uint32_t num_workgroups_builtin = 0; | 
| 381 | 	HLSLBindingFlags resource_binding_flags = 0; | 
| 382 |  | 
| 383 | 	// Custom root constant layout, which should be emitted | 
| 384 | 	// when translating push constant ranges. | 
| 385 | 	std::vector<RootConstants> root_constants_layout; | 
| 386 |  | 
| 387 | 	void validate_shader_model(); | 
| 388 |  | 
| 389 | 	std::string get_unique_identifier(); | 
| 390 | 	uint32_t unique_identifier_count = 0; | 
| 391 |  | 
| 392 | 	std::unordered_map<StageSetBinding, std::pair<HLSLResourceBinding, bool>, InternalHasher> resource_bindings; | 
| 393 | 	void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding); | 
| 394 |  | 
| 395 | 	std::unordered_set<SetBindingPair, InternalHasher> force_uav_buffer_bindings; | 
| 396 |  | 
| 397 | 	struct | 
| 398 | 	{ | 
| 399 | 		uint32_t register_index = 0; | 
| 400 | 		uint32_t register_space = 0; | 
| 401 | 		bool explicit_binding = false; | 
| 402 | 		bool used = false; | 
| 403 | 	} base_vertex_info; | 
| 404 |  | 
| 405 | 	// Returns true if the specified ID has a UserTypeGOOGLE decoration for StructuredBuffer or RWStructuredBuffer resources. | 
| 406 | 	bool is_user_type_structured(uint32_t id) const override; | 
| 407 |  | 
| 408 | 	std::vector<TypeID> composite_selection_workaround_types; | 
| 409 |  | 
| 410 | 	std::string get_inner_entry_point_name() const; | 
| 411 | }; | 
| 412 | } // namespace SPIRV_CROSS_NAMESPACE | 
| 413 |  | 
| 414 | #endif | 
| 415 |  |