1 /* 2 * Copyright 2016-2019 The Brenwill Workshop Ltd. 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 #ifndef SPIRV_CROSS_MSL_HPP 18 #define SPIRV_CROSS_MSL_HPP 19 20 #include "spirv_glsl.hpp" 21 #include <map> 22 #include <set> 23 #include <stddef.h> 24 #include <unordered_map> 25 #include <unordered_set> 26 27 namespace SPIRV_CROSS_NAMESPACE 28 { 29 30 // Indicates the format of the vertex attribute. Currently limited to specifying 31 // if the attribute is an 8-bit unsigned integer, 16-bit unsigned integer, or 32 // some other format. 33 enum MSLVertexFormat 34 { 35 MSL_VERTEX_FORMAT_OTHER = 0, 36 MSL_VERTEX_FORMAT_UINT8 = 1, 37 MSL_VERTEX_FORMAT_UINT16 = 2, 38 MSL_VERTEX_FORMAT_INT_MAX = 0x7fffffff 39 }; 40 41 // Defines MSL characteristics of a vertex attribute at a particular location. 42 // After compilation, it is possible to query whether or not this location was used. 43 struct MSLVertexAttr 44 { 45 uint32_t location = 0; 46 uint32_t msl_buffer = 0; 47 uint32_t msl_offset = 0; 48 uint32_t msl_stride = 0; 49 bool per_instance = false; 50 MSLVertexFormat format = MSL_VERTEX_FORMAT_OTHER; 51 spv::BuiltIn builtin = spv::BuiltInMax; 52 }; 53 54 // Matches the binding index of a MSL resource for a binding within a descriptor set. 55 // Taken together, the stage, desc_set and binding combine to form a reference to a resource 56 // descriptor used in a particular shading stage. 57 // If using MSL 2.0 argument buffers, the descriptor set is not marked as a discrete descriptor set, 58 // and (for iOS only) the resource is not a storage image (sampled != 2), the binding reference we 59 // remap to will become an [[id(N)]] attribute within the "descriptor set" argument buffer structure. 60 // For resources which are bound in the "classic" MSL 1.0 way or discrete descriptors, the remap will become a 61 // [[buffer(N)]], [[texture(N)]] or [[sampler(N)]] depending on the resource types used. 62 struct MSLResourceBinding 63 { 64 spv::ExecutionModel stage = spv::ExecutionModelMax; 65 uint32_t desc_set = 0; 66 uint32_t binding = 0; 67 uint32_t msl_buffer = 0; 68 uint32_t msl_texture = 0; 69 uint32_t msl_sampler = 0; 70 }; 71 72 enum MSLSamplerCoord 73 { 74 MSL_SAMPLER_COORD_NORMALIZED = 0, 75 MSL_SAMPLER_COORD_PIXEL = 1, 76 MSL_SAMPLER_INT_MAX = 0x7fffffff 77 }; 78 79 enum MSLSamplerFilter 80 { 81 MSL_SAMPLER_FILTER_NEAREST = 0, 82 MSL_SAMPLER_FILTER_LINEAR = 1, 83 MSL_SAMPLER_FILTER_INT_MAX = 0x7fffffff 84 }; 85 86 enum MSLSamplerMipFilter 87 { 88 MSL_SAMPLER_MIP_FILTER_NONE = 0, 89 MSL_SAMPLER_MIP_FILTER_NEAREST = 1, 90 MSL_SAMPLER_MIP_FILTER_LINEAR = 2, 91 MSL_SAMPLER_MIP_FILTER_INT_MAX = 0x7fffffff 92 }; 93 94 enum MSLSamplerAddress 95 { 96 MSL_SAMPLER_ADDRESS_CLAMP_TO_ZERO = 0, 97 MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE = 1, 98 MSL_SAMPLER_ADDRESS_CLAMP_TO_BORDER = 2, 99 MSL_SAMPLER_ADDRESS_REPEAT = 3, 100 MSL_SAMPLER_ADDRESS_MIRRORED_REPEAT = 4, 101 MSL_SAMPLER_ADDRESS_INT_MAX = 0x7fffffff 102 }; 103 104 enum MSLSamplerCompareFunc 105 { 106 MSL_SAMPLER_COMPARE_FUNC_NEVER = 0, 107 MSL_SAMPLER_COMPARE_FUNC_LESS = 1, 108 MSL_SAMPLER_COMPARE_FUNC_LESS_EQUAL = 2, 109 MSL_SAMPLER_COMPARE_FUNC_GREATER = 3, 110 MSL_SAMPLER_COMPARE_FUNC_GREATER_EQUAL = 4, 111 MSL_SAMPLER_COMPARE_FUNC_EQUAL = 5, 112 MSL_SAMPLER_COMPARE_FUNC_NOT_EQUAL = 6, 113 MSL_SAMPLER_COMPARE_FUNC_ALWAYS = 7, 114 MSL_SAMPLER_COMPARE_FUNC_INT_MAX = 0x7fffffff 115 }; 116 117 enum MSLSamplerBorderColor 118 { 119 MSL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK = 0, 120 MSL_SAMPLER_BORDER_COLOR_OPAQUE_BLACK = 1, 121 MSL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE = 2, 122 MSL_SAMPLER_BORDER_COLOR_INT_MAX = 0x7fffffff 123 }; 124 125 enum MSLFormatResolution 126 { 127 MSL_FORMAT_RESOLUTION_444 = 0, 128 MSL_FORMAT_RESOLUTION_422, 129 MSL_FORMAT_RESOLUTION_420, 130 MSL_FORMAT_RESOLUTION_INT_MAX = 0x7fffffff 131 }; 132 133 enum MSLChromaLocation 134 { 135 MSL_CHROMA_LOCATION_COSITED_EVEN = 0, 136 MSL_CHROMA_LOCATION_MIDPOINT, 137 MSL_CHROMA_LOCATION_INT_MAX = 0x7fffffff 138 }; 139 140 enum MSLComponentSwizzle 141 { 142 MSL_COMPONENT_SWIZZLE_IDENTITY = 0, 143 MSL_COMPONENT_SWIZZLE_ZERO, 144 MSL_COMPONENT_SWIZZLE_ONE, 145 MSL_COMPONENT_SWIZZLE_R, 146 MSL_COMPONENT_SWIZZLE_G, 147 MSL_COMPONENT_SWIZZLE_B, 148 MSL_COMPONENT_SWIZZLE_A, 149 MSL_COMPONENT_SWIZZLE_INT_MAX = 0x7fffffff 150 }; 151 152 enum MSLSamplerYCbCrModelConversion 153 { 154 MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, 155 MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, 156 MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_709, 157 MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_601, 158 MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020, 159 MSL_SAMPLER_YCBCR_MODEL_CONVERSION_INT_MAX = 0x7fffffff 160 }; 161 162 enum MSLSamplerYCbCrRange 163 { 164 MSL_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, 165 MSL_SAMPLER_YCBCR_RANGE_ITU_NARROW, 166 MSL_SAMPLER_YCBCR_RANGE_INT_MAX = 0x7fffffff 167 }; 168 169 struct MSLConstexprSampler 170 { 171 MSLSamplerCoord coord = MSL_SAMPLER_COORD_NORMALIZED; 172 MSLSamplerFilter min_filter = MSL_SAMPLER_FILTER_NEAREST; 173 MSLSamplerFilter mag_filter = MSL_SAMPLER_FILTER_NEAREST; 174 MSLSamplerMipFilter mip_filter = MSL_SAMPLER_MIP_FILTER_NONE; 175 MSLSamplerAddress s_address = MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; 176 MSLSamplerAddress t_address = MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; 177 MSLSamplerAddress r_address = MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; 178 MSLSamplerCompareFunc compare_func = MSL_SAMPLER_COMPARE_FUNC_NEVER; 179 MSLSamplerBorderColor border_color = MSL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK; 180 float lod_clamp_min = 0.0f; 181 float lod_clamp_max = 1000.0f; 182 int max_anisotropy = 1; 183 184 // Sampler Y'CbCr conversion parameters 185 uint32_t planes = 0; 186 MSLFormatResolution resolution = MSL_FORMAT_RESOLUTION_444; 187 MSLSamplerFilter chroma_filter = MSL_SAMPLER_FILTER_NEAREST; 188 MSLChromaLocation x_chroma_offset = MSL_CHROMA_LOCATION_COSITED_EVEN; 189 MSLChromaLocation y_chroma_offset = MSL_CHROMA_LOCATION_COSITED_EVEN; 190 MSLComponentSwizzle swizzle[4]; // IDENTITY, IDENTITY, IDENTITY, IDENTITY 191 MSLSamplerYCbCrModelConversion ycbcr_model = MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; 192 MSLSamplerYCbCrRange ycbcr_range = MSL_SAMPLER_YCBCR_RANGE_ITU_FULL; 193 uint32_t bpc = 8; 194 195 bool compare_enable = false; 196 bool lod_clamp_enable = false; 197 bool anisotropy_enable = false; 198 bool ycbcr_conversion_enable = false; 199 MSLConstexprSamplerSPIRV_CROSS_NAMESPACE::MSLConstexprSampler200 MSLConstexprSampler() 201 { 202 for (uint32_t i = 0; i < 4; i++) 203 swizzle[i] = MSL_COMPONENT_SWIZZLE_IDENTITY; 204 } swizzle_is_identitySPIRV_CROSS_NAMESPACE::MSLConstexprSampler205 bool swizzle_is_identity() const 206 { 207 return (swizzle[0] == MSL_COMPONENT_SWIZZLE_IDENTITY && swizzle[1] == MSL_COMPONENT_SWIZZLE_IDENTITY && 208 swizzle[2] == MSL_COMPONENT_SWIZZLE_IDENTITY && swizzle[3] == MSL_COMPONENT_SWIZZLE_IDENTITY); 209 } swizzle_has_one_or_zeroSPIRV_CROSS_NAMESPACE::MSLConstexprSampler210 bool swizzle_has_one_or_zero() const 211 { 212 return (swizzle[0] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[0] == MSL_COMPONENT_SWIZZLE_ONE || 213 swizzle[1] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[1] == MSL_COMPONENT_SWIZZLE_ONE || 214 swizzle[2] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[2] == MSL_COMPONENT_SWIZZLE_ONE || 215 swizzle[3] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[3] == MSL_COMPONENT_SWIZZLE_ONE); 216 } 217 }; 218 219 // Special constant used in a MSLResourceBinding desc_set 220 // element to indicate the bindings for the push constants. 221 static const uint32_t kPushConstDescSet = ~(0u); 222 223 // Special constant used in a MSLResourceBinding binding 224 // element to indicate the bindings for the push constants. 225 static const uint32_t kPushConstBinding = 0; 226 227 // Special constant used in a MSLResourceBinding binding 228 // element to indicate the buffer binding for swizzle buffers. 229 static const uint32_t kSwizzleBufferBinding = ~(1u); 230 231 // Special constant used in a MSLResourceBinding binding 232 // element to indicate the buffer binding for buffer size buffers to support OpArrayLength. 233 static const uint32_t kBufferSizeBufferBinding = ~(2u); 234 235 // Special constant used in a MSLResourceBinding binding 236 // element to indicate the buffer binding used for the argument buffer itself. 237 // This buffer binding should be kept as small as possible as all automatic bindings for buffers 238 // will start at max(kArgumentBufferBinding) + 1. 239 static const uint32_t kArgumentBufferBinding = ~(3u); 240 241 static const uint32_t kMaxArgumentBuffers = 8; 242 243 // Decompiles SPIR-V to Metal Shading Language 244 class CompilerMSL : public CompilerGLSL 245 { 246 public: 247 // Options for compiling to Metal Shading Language 248 struct Options 249 { 250 typedef enum 251 { 252 iOS = 0, 253 macOS = 1 254 } Platform; 255 256 Platform platform = macOS; 257 uint32_t msl_version = make_msl_version(1, 2); 258 uint32_t texel_buffer_texture_width = 4096; // Width of 2D Metal textures used as 1D texel buffers 259 uint32_t swizzle_buffer_index = 30; 260 uint32_t indirect_params_buffer_index = 29; 261 uint32_t shader_output_buffer_index = 28; 262 uint32_t shader_patch_output_buffer_index = 27; 263 uint32_t shader_tess_factor_buffer_index = 26; 264 uint32_t buffer_size_buffer_index = 25; 265 uint32_t view_mask_buffer_index = 24; 266 uint32_t dynamic_offsets_buffer_index = 23; 267 uint32_t shader_input_wg_index = 0; 268 uint32_t device_index = 0; 269 bool enable_point_size_builtin = true; 270 bool disable_rasterization = false; 271 bool capture_output_to_buffer = false; 272 bool swizzle_texture_samples = false; 273 bool tess_domain_origin_lower_left = false; 274 bool multiview = false; 275 bool view_index_from_device_index = false; 276 bool dispatch_base = false; 277 bool texture_1D_as_2D = false; 278 279 // Enable use of MSL 2.0 indirect argument buffers. 280 // MSL 2.0 must also be enabled. 281 bool argument_buffers = false; 282 283 // Ensures vertex and instance indices start at zero. This reflects the behavior of HLSL with SV_VertexID and SV_InstanceID. 284 bool enable_base_index_zero = false; 285 286 // Fragment output in MSL must have at least as many components as the render pass. 287 // Add support to explicit pad out components. 288 bool pad_fragment_output_components = false; 289 290 // Specifies whether the iOS target version supports the [[base_vertex]] and [[base_instance]] attributes. 291 bool ios_support_base_vertex_instance = false; 292 293 // Use Metal's native frame-buffer fetch API for subpass inputs. 294 bool ios_use_framebuffer_fetch_subpasses = false; 295 296 // Enables use of "fma" intrinsic for invariant float math 297 bool invariant_float_math = false; 298 299 // Emulate texturecube_array with texture2d_array for iOS where this type is not available 300 bool emulate_cube_array = false; 301 302 // Allow user to enable decoration binding 303 bool enable_decoration_binding = false; 304 305 // Requires MSL 2.1, use the native support for texel buffers. 306 bool texture_buffer_native = false; 307 is_iosSPIRV_CROSS_NAMESPACE::CompilerMSL::Options308 bool is_ios() 309 { 310 return platform == iOS; 311 } 312 is_macosSPIRV_CROSS_NAMESPACE::CompilerMSL::Options313 bool is_macos() 314 { 315 return platform == macOS; 316 } 317 set_msl_versionSPIRV_CROSS_NAMESPACE::CompilerMSL::Options318 void set_msl_version(uint32_t major, uint32_t minor = 0, uint32_t patch = 0) 319 { 320 msl_version = make_msl_version(major, minor, patch); 321 } 322 supports_msl_versionSPIRV_CROSS_NAMESPACE::CompilerMSL::Options323 bool supports_msl_version(uint32_t major, uint32_t minor = 0, uint32_t patch = 0) const 324 { 325 return msl_version >= make_msl_version(major, minor, patch); 326 } 327 make_msl_versionSPIRV_CROSS_NAMESPACE::CompilerMSL::Options328 static uint32_t make_msl_version(uint32_t major, uint32_t minor = 0, uint32_t patch = 0) 329 { 330 return (major * 10000) + (minor * 100) + patch; 331 } 332 }; 333 get_msl_options() const334 const Options &get_msl_options() const 335 { 336 return msl_options; 337 } 338 set_msl_options(const Options & opts)339 void set_msl_options(const Options &opts) 340 { 341 msl_options = opts; 342 } 343 344 // Provide feedback to calling API to allow runtime to disable pipeline 345 // rasterization if vertex shader requires rasterization to be disabled. get_is_rasterization_disabled() const346 bool get_is_rasterization_disabled() const 347 { 348 return is_rasterization_disabled && (get_entry_point().model == spv::ExecutionModelVertex || 349 get_entry_point().model == spv::ExecutionModelTessellationControl || 350 get_entry_point().model == spv::ExecutionModelTessellationEvaluation); 351 } 352 353 // Provide feedback to calling API to allow it to pass an auxiliary 354 // swizzle buffer if the shader needs it. needs_swizzle_buffer() const355 bool needs_swizzle_buffer() const 356 { 357 return used_swizzle_buffer; 358 } 359 360 // Provide feedback to calling API to allow it to pass a buffer 361 // containing STORAGE_BUFFER buffer sizes to support OpArrayLength. needs_buffer_size_buffer() const362 bool needs_buffer_size_buffer() const 363 { 364 return !buffers_requiring_array_length.empty(); 365 } 366 367 // Provide feedback to calling API to allow it to pass a buffer 368 // containing the view mask for the current multiview subpass. needs_view_mask_buffer() const369 bool needs_view_mask_buffer() const 370 { 371 return msl_options.multiview && !msl_options.view_index_from_device_index; 372 } 373 374 // Provide feedback to calling API to allow it to pass a buffer 375 // containing the dispatch base workgroup ID. needs_dispatch_base_buffer() const376 bool needs_dispatch_base_buffer() const 377 { 378 return msl_options.dispatch_base && !msl_options.supports_msl_version(1, 2); 379 } 380 381 // Provide feedback to calling API to allow it to pass an output 382 // buffer if the shader needs it. needs_output_buffer() const383 bool needs_output_buffer() const 384 { 385 return capture_output_to_buffer && stage_out_var_id != ID(0); 386 } 387 388 // Provide feedback to calling API to allow it to pass a patch output 389 // buffer if the shader needs it. needs_patch_output_buffer() const390 bool needs_patch_output_buffer() const 391 { 392 return capture_output_to_buffer && patch_stage_out_var_id != ID(0); 393 } 394 395 // Provide feedback to calling API to allow it to pass an input threadgroup 396 // buffer if the shader needs it. needs_input_threadgroup_mem() const397 bool needs_input_threadgroup_mem() const 398 { 399 return capture_output_to_buffer && stage_in_var_id != ID(0); 400 } 401 402 explicit CompilerMSL(std::vector<uint32_t> spirv); 403 CompilerMSL(const uint32_t *ir, size_t word_count); 404 explicit CompilerMSL(const ParsedIR &ir); 405 explicit CompilerMSL(ParsedIR &&ir); 406 407 // attr is a vertex attribute binding used to match 408 // vertex content locations to MSL attributes. If vertex attributes are provided, 409 // is_msl_vertex_attribute_used() will return true after calling ::compile() if 410 // the location was used by the MSL code. 411 void add_msl_vertex_attribute(const MSLVertexAttr &attr); 412 413 // resource is a resource binding to indicate the MSL buffer, 414 // texture or sampler index to use for a particular SPIR-V description set 415 // and binding. If resource bindings are provided, 416 // is_msl_resource_binding_used() will return true after calling ::compile() if 417 // the set/binding combination was used by the MSL code. 418 void add_msl_resource_binding(const MSLResourceBinding &resource); 419 420 // desc_set and binding are the SPIR-V descriptor set and binding of a buffer resource 421 // in this shader. index is the index within the dynamic offset buffer to use. This 422 // function marks that resource as using a dynamic offset (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC 423 // or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC). This function only has any effect if argument buffers 424 // are enabled. If so, the buffer will have its address adjusted at the beginning of the shader with 425 // an offset taken from the dynamic offset buffer. 426 void add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32_t index); 427 428 // When using MSL argument buffers, we can force "classic" MSL 1.0 binding schemes for certain descriptor sets. 429 // This corresponds to VK_KHR_push_descriptor in Vulkan. 430 void add_discrete_descriptor_set(uint32_t desc_set); 431 432 // If an argument buffer is large enough, it may need to be in the device storage space rather than 433 // constant. Opt-in to this behavior here on a per set basis. 434 void set_argument_buffer_device_address_space(uint32_t desc_set, bool device_storage); 435 436 // Query after compilation is done. This allows you to check if a location or set/binding combination was used by the shader. 437 bool is_msl_vertex_attribute_used(uint32_t location); 438 439 // NOTE: Only resources which are remapped using add_msl_resource_binding will be reported here. 440 // Constexpr samplers are always assumed to be emitted. 441 // No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped 442 // by remap_constexpr_sampler(_by_binding). 443 bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding); 444 445 // This must only be called after a successful call to CompilerMSL::compile(). 446 // For a variable resource ID obtained through reflection API, report the automatically assigned resource index. 447 // If the descriptor set was part of an argument buffer, report the [[id(N)]], 448 // or [[buffer/texture/sampler]] binding for other resources. 449 // If the resource was a combined image sampler, report the image binding here, 450 // use the _secondary version of this call to query the sampler half of the resource. 451 // If no binding exists, uint32_t(-1) is returned. 452 uint32_t get_automatic_msl_resource_binding(uint32_t id) const; 453 454 // Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers, in which case the 455 // sampler's binding is returned instead. For any other resource type, -1 is returned. 456 uint32_t get_automatic_msl_resource_binding_secondary(uint32_t id) const; 457 458 // Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers for multiplanar images, 459 // in which case the second plane's binding is returned instead. For any other resource type, -1 is returned. 460 uint32_t get_automatic_msl_resource_binding_tertiary(uint32_t id) const; 461 462 // Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers for triplanar images, 463 // in which case the third plane's binding is returned instead. For any other resource type, -1 is returned. 464 uint32_t get_automatic_msl_resource_binding_quaternary(uint32_t id) const; 465 466 // Compiles the SPIR-V code into Metal Shading Language. 467 std::string compile() override; 468 469 // Remap a sampler with ID to a constexpr sampler. 470 // Older iOS targets must use constexpr samplers in certain cases (PCF), 471 // so a static sampler must be used. 472 // The sampler will not consume a binding, but be declared in the entry point as a constexpr sampler. 473 // This can be used on both combined image/samplers (sampler2D) or standalone samplers. 474 // The remapped sampler must not be an array of samplers. 475 // Prefer remap_constexpr_sampler_by_binding unless you're also doing reflection anyways. 476 void remap_constexpr_sampler(VariableID id, const MSLConstexprSampler &sampler); 477 478 // Same as remap_constexpr_sampler, except you provide set/binding, rather than variable ID. 479 // Remaps based on ID take priority over set/binding remaps. 480 void remap_constexpr_sampler_by_binding(uint32_t desc_set, uint32_t binding, const MSLConstexprSampler &sampler); 481 482 // If using CompilerMSL::Options::pad_fragment_output_components, override the number of components we expect 483 // to use for a particular location. The default is 4 if number of components is not overridden. 484 void set_fragment_output_components(uint32_t location, uint32_t components); 485 486 protected: 487 // An enum of SPIR-V functions that are implemented in additional 488 // source code that is added to the shader if necessary. 489 enum SPVFuncImpl 490 { 491 SPVFuncImplNone, 492 SPVFuncImplMod, 493 SPVFuncImplRadians, 494 SPVFuncImplDegrees, 495 SPVFuncImplFindILsb, 496 SPVFuncImplFindSMsb, 497 SPVFuncImplFindUMsb, 498 SPVFuncImplSSign, 499 SPVFuncImplArrayCopyMultidimBase, 500 // Unfortunately, we cannot use recursive templates in the MSL compiler properly, 501 // so stamp out variants up to some arbitrary maximum. 502 SPVFuncImplArrayCopy = SPVFuncImplArrayCopyMultidimBase + 1, 503 SPVFuncImplArrayOfArrayCopy2Dim = SPVFuncImplArrayCopyMultidimBase + 2, 504 SPVFuncImplArrayOfArrayCopy3Dim = SPVFuncImplArrayCopyMultidimBase + 3, 505 SPVFuncImplArrayOfArrayCopy4Dim = SPVFuncImplArrayCopyMultidimBase + 4, 506 SPVFuncImplArrayOfArrayCopy5Dim = SPVFuncImplArrayCopyMultidimBase + 5, 507 SPVFuncImplArrayOfArrayCopy6Dim = SPVFuncImplArrayCopyMultidimBase + 6, 508 SPVFuncImplTexelBufferCoords, 509 SPVFuncImplImage2DAtomicCoords, // Emulate texture2D atomic operations 510 SPVFuncImplFMul, 511 SPVFuncImplFAdd, 512 SPVFuncImplCubemapTo2DArrayFace, 513 SPVFuncImplUnsafeArray, // Allow Metal to use the array<T> template to make arrays a value type 514 SPVFuncImplInverse4x4, 515 SPVFuncImplInverse3x3, 516 SPVFuncImplInverse2x2, 517 // It is very important that this come before *Swizzle and ChromaReconstruct*, to ensure it's 518 // emitted before them. 519 SPVFuncImplForwardArgs, 520 // Likewise, this must come before *Swizzle. 521 SPVFuncImplGetSwizzle, 522 SPVFuncImplTextureSwizzle, 523 SPVFuncImplGatherSwizzle, 524 SPVFuncImplGatherCompareSwizzle, 525 SPVFuncImplSubgroupBallot, 526 SPVFuncImplSubgroupBallotBitExtract, 527 SPVFuncImplSubgroupBallotFindLSB, 528 SPVFuncImplSubgroupBallotFindMSB, 529 SPVFuncImplSubgroupBallotBitCount, 530 SPVFuncImplSubgroupAllEqual, 531 SPVFuncImplReflectScalar, 532 SPVFuncImplRefractScalar, 533 SPVFuncImplFaceForwardScalar, 534 SPVFuncImplChromaReconstructNearest2Plane, 535 SPVFuncImplChromaReconstructNearest3Plane, 536 SPVFuncImplChromaReconstructLinear422CositedEven2Plane, 537 SPVFuncImplChromaReconstructLinear422CositedEven3Plane, 538 SPVFuncImplChromaReconstructLinear422Midpoint2Plane, 539 SPVFuncImplChromaReconstructLinear422Midpoint3Plane, 540 SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven2Plane, 541 SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven3Plane, 542 SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven2Plane, 543 SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven3Plane, 544 SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint2Plane, 545 SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint3Plane, 546 SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint2Plane, 547 SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint3Plane, 548 SPVFuncImplExpandITUFullRange, 549 SPVFuncImplExpandITUNarrowRange, 550 SPVFuncImplConvertYCbCrBT709, 551 SPVFuncImplConvertYCbCrBT601, 552 SPVFuncImplConvertYCbCrBT2020, 553 SPVFuncImplDynamicImageSampler, 554 555 SPVFuncImplArrayCopyMultidimMax = 6 556 }; 557 558 // If the underlying resource has been used for comparison then duplicate loads of that resource must be too 559 // Use Metal's native frame-buffer fetch API for subpass inputs. 560 void emit_texture_op(const Instruction &i) override; 561 void emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); 562 void emit_instruction(const Instruction &instr) override; 563 void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, 564 uint32_t count) override; 565 void emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t result_id, uint32_t op, 566 const uint32_t *args, uint32_t count) override; 567 void emit_header() override; 568 void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override; 569 void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override; 570 void emit_subgroup_op(const Instruction &i) override; 571 std::string to_texture_op(const Instruction &i, bool *forward, 572 SmallVector<uint32_t> &inherited_expressions) override; 573 void emit_fixup() override; 574 std::string to_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, 575 const std::string &qualifier = ""); 576 void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, 577 const std::string &qualifier = "", uint32_t base_offset = 0) override; 578 void emit_struct_padding_target(const SPIRType &type) override; 579 std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; 580 581 // Allow Metal to use the array<T> template to make arrays a value type 582 std::string type_to_array_glsl(const SPIRType &type) override; 583 584 // Threadgroup arrays can't have a wrapper type 585 std::string variable_decl(const SPIRVariable &variable) override; 586 587 // GCC workaround of lambdas calling protected functions (for older GCC versions) 588 std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0) override; 589 590 std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override; 591 std::string sampler_type(const SPIRType &type); 592 std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override; 593 std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override; 594 std::string to_name(uint32_t id, bool allow_alias = true) const override; 595 std::string to_function_name(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, 596 bool has_array_offsets, bool has_offset, bool has_grad, bool has_dref, uint32_t lod, 597 uint32_t minlod) override; 598 std::string to_function_args(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, 599 uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x, 600 uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, 601 uint32_t comp, uint32_t sample, uint32_t minlod, bool *p_forward) override; 602 std::string to_initializer_expression(const SPIRVariable &var) override; 603 604 std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t physical_type_id, 605 bool is_packed, bool row_major) override; 606 607 // Returns true for BuiltInSampleMask because gl_SampleMask[] is an array in SPIR-V, but [[sample_mask]] is a scalar in Metal. 608 bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override; 609 610 std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override; 611 bool skip_argument(uint32_t id) const override; 612 std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain) override; 613 std::string to_qualifiers_glsl(uint32_t id) override; 614 void replace_illegal_names() override; 615 void declare_undefined_values() override; 616 void declare_constant_arrays(); 617 618 // Constant arrays of non-primitive types (i.e. matrices) won't link properly into Metal libraries 619 void declare_complex_constant_arrays(); 620 621 bool is_patch_block(const SPIRType &type); 622 bool is_non_native_row_major_matrix(uint32_t id) override; 623 bool member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index) override; 624 std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type, uint32_t physical_type_id, 625 bool is_packed) override; 626 627 void preprocess_op_codes(); 628 void localize_global_variables(); 629 void extract_global_variables_from_functions(); 630 void mark_packable_structs(); 631 void mark_as_packable(SPIRType &type); 632 633 std::unordered_map<uint32_t, std::set<uint32_t>> function_global_vars; 634 void extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids, 635 std::unordered_set<uint32_t> &global_var_ids, 636 std::unordered_set<uint32_t> &processed_func_ids); 637 uint32_t add_interface_block(spv::StorageClass storage, bool patch = false); 638 uint32_t add_interface_block_pointer(uint32_t ib_var_id, spv::StorageClass storage); 639 640 void add_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type, 641 SPIRVariable &var, bool strip_array); 642 void add_composite_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, 643 SPIRType &ib_type, SPIRVariable &var, bool strip_array); 644 void add_plain_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, 645 SPIRType &ib_type, SPIRVariable &var, bool strip_array); 646 void add_plain_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, 647 SPIRType &ib_type, SPIRVariable &var, uint32_t index, 648 bool strip_array); 649 void add_composite_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, 650 SPIRType &ib_type, SPIRVariable &var, uint32_t index, 651 bool strip_array); 652 uint32_t get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array); 653 void add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var); 654 655 void fix_up_interface_member_indices(spv::StorageClass storage, uint32_t ib_type_id); 656 657 void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage); 658 uint32_t ensure_correct_builtin_type(uint32_t type_id, spv::BuiltIn builtin); 659 uint32_t ensure_correct_attribute_type(uint32_t type_id, uint32_t location); 660 661 void emit_custom_templates(); 662 void emit_custom_functions(); 663 void emit_resources(); 664 void emit_specialization_constants_and_structs(); 665 void emit_interface_block(uint32_t ib_var_id); 666 bool maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs); 667 668 void fix_up_shader_inputs_outputs(); 669 670 std::string func_type_decl(SPIRType &type); 671 std::string entry_point_args_classic(bool append_comma); 672 std::string entry_point_args_argument_buffer(bool append_comma); 673 std::string entry_point_arg_stage_in(); 674 void entry_point_args_builtin(std::string &args); 675 void entry_point_args_discrete_descriptors(std::string &args); 676 std::string to_qualified_member_name(const SPIRType &type, uint32_t index); 677 std::string ensure_valid_name(std::string name, std::string pfx); 678 std::string to_sampler_expression(uint32_t id); 679 std::string to_swizzle_expression(uint32_t id); 680 std::string to_buffer_size_expression(uint32_t id); 681 std::string builtin_qualifier(spv::BuiltIn builtin); 682 std::string builtin_type_decl(spv::BuiltIn builtin, uint32_t id = 0); 683 std::string built_in_func_arg(spv::BuiltIn builtin, bool prefix_comma); 684 std::string member_attribute_qualifier(const SPIRType &type, uint32_t index); 685 std::string argument_decl(const SPIRFunction::Parameter &arg); 686 std::string round_fp_tex_coords(std::string tex_coords, bool coord_is_fp); 687 uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype, uint32_t plane = 0); 688 uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index, uint32_t *comp = nullptr); 689 690 // MSL packing rules. These compute the effective packing rules as observed by the MSL compiler in the MSL output. 691 // These values can change depending on various extended decorations which control packing rules. 692 // We need to make these rules match up with SPIR-V declared rules. 693 uint32_t get_declared_type_size_msl(const SPIRType &type, bool packed, bool row_major) const; 694 uint32_t get_declared_type_array_stride_msl(const SPIRType &type, bool packed, bool row_major) const; 695 uint32_t get_declared_type_matrix_stride_msl(const SPIRType &type, bool packed, bool row_major) const; 696 uint32_t get_declared_type_alignment_msl(const SPIRType &type, bool packed, bool row_major) const; 697 698 uint32_t get_declared_struct_member_size_msl(const SPIRType &struct_type, uint32_t index) const; 699 uint32_t get_declared_struct_member_array_stride_msl(const SPIRType &struct_type, uint32_t index) const; 700 uint32_t get_declared_struct_member_matrix_stride_msl(const SPIRType &struct_type, uint32_t index) const; 701 uint32_t get_declared_struct_member_alignment_msl(const SPIRType &struct_type, uint32_t index) const; 702 703 const SPIRType &get_physical_member_type(const SPIRType &struct_type, uint32_t index) const; 704 705 uint32_t get_declared_struct_size_msl(const SPIRType &struct_type, bool ignore_alignment = false, 706 bool ignore_padding = false) const; 707 708 std::string to_component_argument(uint32_t id); 709 void align_struct(SPIRType &ib_type, std::unordered_set<uint32_t> &aligned_structs); 710 void mark_scalar_layout_structs(const SPIRType &ib_type); 711 void mark_struct_members_packed(const SPIRType &type); 712 void ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t index); 713 bool validate_member_packing_rules_msl(const SPIRType &type, uint32_t index) const; 714 std::string get_argument_address_space(const SPIRVariable &argument); 715 std::string get_type_address_space(const SPIRType &type, uint32_t id, bool argument = false); 716 const char *to_restrict(uint32_t id, bool space = true); 717 SPIRType &get_stage_in_struct_type(); 718 SPIRType &get_stage_out_struct_type(); 719 SPIRType &get_patch_stage_in_struct_type(); 720 SPIRType &get_patch_stage_out_struct_type(); 721 std::string get_tess_factor_struct_name(); 722 void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, uint32_t mem_order_1, 723 uint32_t mem_order_2, bool has_mem_order_2, uint32_t op0, uint32_t op1 = 0, 724 bool op1_is_pointer = false, bool op1_is_literal = false, uint32_t op2 = 0); 725 const char *get_memory_order(uint32_t spv_mem_sem); 726 void add_pragma_line(const std::string &line); 727 void add_typedef_line(const std::string &line); 728 void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem); 729 void emit_array_copy(const std::string &lhs, uint32_t rhs_id, spv::StorageClass lhs_storage, 730 spv::StorageClass rhs_storage) override; 731 void build_implicit_builtins(); 732 uint32_t build_constant_uint_array_pointer(); 733 void emit_entry_point_declarations() override; 734 uint32_t builtin_frag_coord_id = 0; 735 uint32_t builtin_sample_id_id = 0; 736 uint32_t builtin_vertex_idx_id = 0; 737 uint32_t builtin_base_vertex_id = 0; 738 uint32_t builtin_instance_idx_id = 0; 739 uint32_t builtin_base_instance_id = 0; 740 uint32_t builtin_view_idx_id = 0; 741 uint32_t builtin_layer_id = 0; 742 uint32_t builtin_invocation_id_id = 0; 743 uint32_t builtin_primitive_id_id = 0; 744 uint32_t builtin_subgroup_invocation_id_id = 0; 745 uint32_t builtin_subgroup_size_id = 0; 746 uint32_t builtin_dispatch_base_id = 0; 747 uint32_t swizzle_buffer_id = 0; 748 uint32_t buffer_size_buffer_id = 0; 749 uint32_t view_mask_buffer_id = 0; 750 uint32_t dynamic_offsets_buffer_id = 0; 751 752 void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override; 753 void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override; 754 void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression) override; 755 756 void analyze_sampled_image_usage(); 757 758 bool emit_tessellation_access_chain(const uint32_t *ops, uint32_t length); 759 bool emit_tessellation_io_load(uint32_t result_type, uint32_t id, uint32_t ptr); 760 bool is_out_of_bounds_tessellation_level(uint32_t id_lhs); 761 762 void ensure_builtin(spv::StorageClass storage, spv::BuiltIn builtin); 763 764 void mark_implicit_builtin(spv::StorageClass storage, spv::BuiltIn builtin, uint32_t id); 765 766 std::string convert_to_f32(const std::string &expr, uint32_t components); 767 768 Options msl_options; 769 std::set<SPVFuncImpl> spv_function_implementations; 770 std::unordered_map<uint32_t, MSLVertexAttr> vtx_attrs_by_location; 771 std::unordered_map<uint32_t, MSLVertexAttr> vtx_attrs_by_builtin; 772 std::unordered_set<uint32_t> vtx_attrs_in_use; 773 std::unordered_map<uint32_t, uint32_t> fragment_output_components; 774 std::set<std::string> pragma_lines; 775 std::set<std::string> typedef_lines; 776 SmallVector<uint32_t> vars_needing_early_declaration; 777 778 struct SetBindingPair 779 { 780 uint32_t desc_set; 781 uint32_t binding; 782 bool operator==(const SetBindingPair &other) const; 783 bool operator<(const SetBindingPair &other) const; 784 }; 785 786 struct StageSetBinding 787 { 788 spv::ExecutionModel model; 789 uint32_t desc_set; 790 uint32_t binding; 791 bool operator==(const StageSetBinding &other) const; 792 }; 793 794 struct InternalHasher 795 { 796 size_t operator()(const SetBindingPair &value) const; 797 size_t operator()(const StageSetBinding &value) const; 798 }; 799 800 std::unordered_map<StageSetBinding, std::pair<MSLResourceBinding, bool>, InternalHasher> resource_bindings; 801 802 uint32_t next_metal_resource_index_buffer = 0; 803 uint32_t next_metal_resource_index_texture = 0; 804 uint32_t next_metal_resource_index_sampler = 0; 805 // Intentionally uninitialized, works around MSVC 2013 bug. 806 uint32_t next_metal_resource_ids[kMaxArgumentBuffers]; 807 808 VariableID stage_in_var_id = 0; 809 VariableID stage_out_var_id = 0; 810 VariableID patch_stage_in_var_id = 0; 811 VariableID patch_stage_out_var_id = 0; 812 VariableID stage_in_ptr_var_id = 0; 813 VariableID stage_out_ptr_var_id = 0; 814 815 // Handle HLSL-style 0-based vertex/instance index. 816 enum class TriState 817 { 818 Neutral, 819 No, 820 Yes 821 }; 822 TriState needs_base_vertex_arg = TriState::Neutral; 823 TriState needs_base_instance_arg = TriState::Neutral; 824 825 bool has_sampled_images = false; 826 bool builtin_declaration = false; // Handle HLSL-style 0-based vertex/instance index. 827 bool use_builtin_array = false; // Force the use of C style array declaration. 828 bool is_rasterization_disabled = false; 829 bool capture_output_to_buffer = false; 830 bool needs_swizzle_buffer_def = false; 831 bool used_swizzle_buffer = false; 832 bool added_builtin_tess_level = false; 833 bool needs_subgroup_invocation_id = false; 834 std::string qual_pos_var_name; 835 std::string stage_in_var_name = "in"; 836 std::string stage_out_var_name = "out"; 837 std::string patch_stage_in_var_name = "patchIn"; 838 std::string patch_stage_out_var_name = "patchOut"; 839 std::string sampler_name_suffix = "Smplr"; 840 std::string swizzle_name_suffix = "Swzl"; 841 std::string buffer_size_name_suffix = "BufferSize"; 842 std::string plane_name_suffix = "Plane"; 843 std::string input_wg_var_name = "gl_in"; 844 std::string output_buffer_var_name = "spvOut"; 845 std::string patch_output_buffer_var_name = "spvPatchOut"; 846 std::string tess_factor_buffer_var_name = "spvTessLevel"; 847 spv::Op previous_instruction_opcode = spv::OpNop; 848 849 // Must be ordered since declaration is in a specific order. 850 std::map<uint32_t, MSLConstexprSampler> constexpr_samplers_by_id; 851 std::unordered_map<SetBindingPair, MSLConstexprSampler, InternalHasher> constexpr_samplers_by_binding; 852 const MSLConstexprSampler *find_constexpr_sampler(uint32_t id) const; 853 854 std::unordered_set<uint32_t> buffers_requiring_array_length; 855 SmallVector<uint32_t> buffer_arrays; 856 std::unordered_set<uint32_t> atomic_image_vars; // Emulate texture2D atomic operations 857 858 // Must be ordered since array is in a specific order. 859 std::map<SetBindingPair, std::pair<uint32_t, uint32_t>> buffers_requiring_dynamic_offset; 860 861 uint32_t argument_buffer_ids[kMaxArgumentBuffers]; 862 uint32_t argument_buffer_discrete_mask = 0; 863 uint32_t argument_buffer_device_storage_mask = 0; 864 865 void analyze_argument_buffers(); 866 bool descriptor_set_is_argument_buffer(uint32_t desc_set) const; 867 868 uint32_t get_target_components_for_fragment_location(uint32_t location) const; 869 uint32_t build_extended_vector_type(uint32_t type_id, uint32_t components); 870 871 bool suppress_missing_prototypes = false; 872 873 void add_spv_func_and_recompile(SPVFuncImpl spv_func); 874 875 // OpcodeHandler that handles several MSL preprocessing operations. 876 struct OpCodePreprocessor : OpcodeHandler 877 { OpCodePreprocessorSPIRV_CROSS_NAMESPACE::CompilerMSL::OpCodePreprocessor878 OpCodePreprocessor(CompilerMSL &compiler_) 879 : compiler(compiler_) 880 { 881 } 882 883 bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override; 884 CompilerMSL::SPVFuncImpl get_spv_func_impl(spv::Op opcode, const uint32_t *args); 885 void check_resource_write(uint32_t var_id); 886 887 CompilerMSL &compiler; 888 std::unordered_map<uint32_t, uint32_t> result_types; 889 std::unordered_map<uint32_t, uint32_t> image_pointers; // Emulate texture2D atomic operations 890 bool suppress_missing_prototypes = false; 891 bool uses_atomics = false; 892 bool uses_resource_write = false; 893 bool needs_subgroup_invocation_id = false; 894 }; 895 896 // OpcodeHandler that scans for uses of sampled images 897 struct SampledImageScanner : OpcodeHandler 898 { SampledImageScannerSPIRV_CROSS_NAMESPACE::CompilerMSL::SampledImageScanner899 SampledImageScanner(CompilerMSL &compiler_) 900 : compiler(compiler_) 901 { 902 } 903 904 bool handle(spv::Op opcode, const uint32_t *args, uint32_t) override; 905 906 CompilerMSL &compiler; 907 }; 908 909 // Sorts the members of a SPIRType and associated Meta info based on a settable sorting 910 // aspect, which defines which aspect of the struct members will be used to sort them. 911 // Regardless of the sorting aspect, built-in members always appear at the end of the struct. 912 struct MemberSorter 913 { 914 enum SortAspect 915 { 916 Location, 917 LocationReverse, 918 Offset, 919 OffsetThenLocationReverse, 920 Alphabetical 921 }; 922 923 void sort(); 924 bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2); 925 MemberSorter(SPIRType &t, Meta &m, SortAspect sa); 926 927 SPIRType &type; 928 Meta &meta; 929 SortAspect sort_aspect; 930 }; 931 }; 932 } // namespace SPIRV_CROSS_NAMESPACE 933 934 #endif 935