1#!/usr/bin/python3 -i 2# 3# Copyright (c) 2020-2021 The Khronos Group Inc. 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# Author: Spencer Fricke <s.fricke@samsung.com> 18 19import os,re,sys,string,json 20import xml.etree.ElementTree as etree 21from generator import * 22from collections import namedtuple 23from common_codegen import * 24 25# This is a workaround to use a Python 2.7 and 3.x compatible syntax 26from io import open 27 28class SpirvValidationHelperOutputGeneratorOptions(GeneratorOptions): 29 def __init__(self, 30 conventions = None, 31 filename = None, 32 directory = '.', 33 genpath = None, 34 apiname = 'vulkan', 35 profile = None, 36 versions = '.*', 37 emitversions = '.*', 38 defaultExtensions = 'vulkan', 39 addExtensions = None, 40 removeExtensions = None, 41 emitExtensions = None, 42 emitSpirv = None, 43 sortProcedure = regSortFeatures, 44 genFuncPointers = True, 45 protectFile = True, 46 protectFeature = False, 47 apicall = 'VKAPI_ATTR ', 48 apientry = 'VKAPI_CALL ', 49 apientryp = 'VKAPI_PTR *', 50 indentFuncProto = True, 51 indentFuncPointer = False, 52 alignFuncParam = 48, 53 expandEnumerants = False): 54 GeneratorOptions.__init__(self, 55 conventions = conventions, 56 filename = filename, 57 directory = directory, 58 genpath = genpath, 59 apiname = apiname, 60 profile = profile, 61 versions = versions, 62 emitversions = emitversions, 63 defaultExtensions = defaultExtensions, 64 addExtensions = addExtensions, 65 removeExtensions = removeExtensions, 66 emitExtensions = emitExtensions, 67 emitSpirv = emitSpirv, 68 sortProcedure = sortProcedure) 69 self.genFuncPointers = genFuncPointers 70 self.protectFile = protectFile 71 self.protectFeature = protectFeature 72 self.apicall = apicall 73 self.apientry = apientry 74 self.apientryp = apientryp 75 self.indentFuncProto = indentFuncProto 76 self.indentFuncPointer = indentFuncPointer 77 self.alignFuncParam = alignFuncParam 78 self.expandEnumerants = expandEnumerants 79# 80# SpirvValidationHelperOutputGenerator - Generate SPIR-V validation 81# for SPIR-V extensions and capabilities 82class SpirvValidationHelperOutputGenerator(OutputGenerator): 83 def __init__(self, 84 errFile = sys.stderr, 85 warnFile = sys.stderr, 86 diagFile = sys.stdout): 87 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 88 self.extensions = dict() 89 self.capabilities = dict() 90 91 # TODO - Remove these ExludeList array in future when script is been used in a few releases 92 # 93 # Sometimes the Vulkan-Headers XML will mention new SPIR-V capability or extensions 94 # That require an update of the SPIRV-Headers which might not be ready to pull in. 95 # These 2 arrays SHOULD be empty when possible and when the SPIR-V Headers are updated these 96 # should be attempted to be cleared 97 self.extensionExcludeList = [] 98 self.capabilityExcludeList = [] 99 100 # This is a list that maps the Vulkan struct a feature field is with the internal 101 # state tracker's enabled features value 102 # 103 # If a new SPIR-V Capability is added to uses a new feature struct, it will need to be 104 # added here with the name added in 'DeviceFeatures' struct 105 self.featureMap = [ 106 # {'vulkan' : <Vulkan Spec Feature Struct Name>, 'layer' : <Name of variable in CoreChecks DeviceFeatures>}, 107 {'vulkan' : 'VkPhysicalDeviceFeatures', 'layer' : 'core'}, 108 {'vulkan' : 'VkPhysicalDeviceVulkan11Features', 'layer' : 'core11'}, 109 {'vulkan' : 'VkPhysicalDeviceVulkan12Features', 'layer' : 'core12'}, 110 {'vulkan' : 'VkPhysicalDeviceTransformFeedbackFeaturesEXT', 'layer' : 'transform_feedback_features'}, 111 {'vulkan' : 'VkPhysicalDeviceCooperativeMatrixFeaturesNV', 'layer' : 'cooperative_matrix_features'}, 112 {'vulkan' : 'VkPhysicalDeviceComputeShaderDerivativesFeaturesNV', 'layer' : 'compute_shader_derivatives_features'}, 113 {'vulkan' : 'VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV', 'layer' : 'fragment_shader_barycentric_features'}, 114 {'vulkan' : 'VkPhysicalDeviceShaderImageFootprintFeaturesNV', 'layer' : 'shader_image_footprint_features'}, 115 {'vulkan' : 'VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT', 'layer' : 'fragment_shader_interlock_features'}, 116 {'vulkan' : 'VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT', 'layer' : 'demote_to_helper_invocation_features'}, 117 {'vulkan' : 'VkPhysicalDeviceRayQueryFeaturesKHR', 'layer' : 'ray_query_features'}, 118 {'vulkan' : 'VkPhysicalDeviceRayTracingPipelineFeaturesKHR', 'layer' : 'ray_tracing_pipeline_features'}, 119 {'vulkan' : 'VkPhysicalDeviceAccelerationStructureFeaturesKHR', 'layer' : 'ray_tracing_acceleration_structure_features'}, 120 {'vulkan' : 'VkPhysicalDeviceFragmentDensityMapFeaturesEXT', 'layer' : 'fragment_density_map_features'}, 121 {'vulkan' : 'VkPhysicalDeviceBufferDeviceAddressFeaturesEXT', 'layer' : 'buffer_device_address_ext_features'}, 122 {'vulkan' : 'VkPhysicalDeviceFragmentShadingRateFeaturesKHR', 'layer' : 'fragment_shading_rate_features'}, 123 {'vulkan' : 'VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL', 'layer' : 'shader_integer_functions2_features'}, 124 {'vulkan' : 'VkPhysicalDeviceShaderSMBuiltinsFeaturesNV', 'layer' : 'shader_sm_builtins_features'}, 125 {'vulkan' : 'VkPhysicalDeviceShadingRateImageFeaturesNV', 'layer' : 'shading_rate_image_features'}, 126 {'vulkan' : 'VkPhysicalDeviceShaderAtomicFloatFeaturesEXT', 'layer' : 'shader_atomic_float_features'}, 127 {'vulkan' : 'VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT', 'layer' : 'shader_image_atomic_int64_features'}, 128 {'vulkan' : 'VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR', 'layer' : 'workgroup_memory_explicit_layout_features'}, 129 {'vulkan' : 'VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT', 'layer' : 'shader_atomic_float2_features'}, 130 {'vulkan' : 'VkPhysicalDeviceRayTracingMotionBlurFeaturesNV', 'layer' : 'ray_tracing_motion_blur_features'}, 131 {'vulkan' : 'VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR', 'layer' : 'shader_integer_dot_product_features'}, 132 ] 133 134 # Promoted features structure in state_tracker.cpp are put in the VkPhysicalDeviceVulkan*Features structs 135 # but the XML can still list them. This list all promoted structs to ignore since they are aliased. 136 # Tried to generate these, but no reliable way from vk.xml 137 self.promotedFeatures = [ 138 # 1.1 139 "VkPhysicalDevice16BitStorageFeatures", 140 "VkPhysicalDeviceMultiviewFeatures", 141 "VkPhysicalDeviceVariablePointersFeatures", 142 "VkPhysicalDeviceProtectedMemoryFeatures", 143 "VkPhysicalDeviceSamplerYcbcrConversionFeatures", 144 "VkPhysicalDeviceShaderDrawParametersFeatures", 145 # 1.2 146 "VkPhysicalDevice8BitStorageFeatures", 147 "VkPhysicalDeviceShaderFloat16Int8Features", 148 "VkPhysicalDeviceDescriptorIndexingFeatures", 149 "VkPhysicalDeviceScalarBlockLayoutFeatures", 150 "VkPhysicalDeviceImagelessFramebufferFeatures", 151 "VkPhysicalDeviceUniformBufferStandardLayoutFeatures", 152 "VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures", 153 "VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures", 154 "VkPhysicalDeviceTimelineSemaphoreFeatures", 155 "VkPhysicalDeviceBufferDeviceAddressFeatures", 156 "VkPhysicalDeviceShaderAtomicInt64Features", 157 "VkPhysicalDeviceVulkanMemoryModelFeatures", 158 ] 159 160 # Properties are harder to handle genearted without generating a template for every property struct type 161 # The simpler solution is create strings that will be printed out as static comparisons at compile time 162 # The Map is used to map Vulkan property structs with the state tracker variable name 163 self.propertyInfo = dict() 164 self.propertyMap = { 165 'VkPhysicalDeviceVulkan11Properties' : 'phys_dev_props_core11', 166 'VkPhysicalDeviceVulkan12Properties' : 'phys_dev_props_core12', 167 } 168 169 # 170 # Called at beginning of processing as file is opened 171 def beginFile(self, genOpts): 172 OutputGenerator.beginFile(self, genOpts) 173 # File Comment 174 file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' 175 file_comment += '// See spirv_validation_generator.py for modifications\n' 176 write(file_comment, file=self.outFile) 177 # Copyright Statement 178 copyright = '' 179 copyright += '\n' 180 copyright += '/***************************************************************************\n' 181 copyright += ' *\n' 182 copyright += ' * Copyright (c) 2020-2021 The Khronos Group Inc.\n' 183 copyright += ' *\n' 184 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 185 copyright += ' * you may not use this file except in compliance with the License.\n' 186 copyright += ' * You may obtain a copy of the License at\n' 187 copyright += ' *\n' 188 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 189 copyright += ' *\n' 190 copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 191 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 192 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 193 copyright += ' * See the License for the specific language governing permissions and\n' 194 copyright += ' * limitations under the License.\n' 195 copyright += ' *\n' 196 copyright += ' * Author: Spencer Fricke <s.fricke@samsung.com>\n' 197 copyright += ' *\n' 198 copyright += ' * This file is related to anything that is found in the Vulkan XML related\n' 199 copyright += ' * to SPIR-V. Anything related to the SPIR-V grammar belongs in spirv_grammar_helper\n' 200 copyright += ' *\n' 201 copyright += ' ****************************************************************************/\n' 202 write(copyright, file=self.outFile) 203 write('#include <string>', file=self.outFile) 204 write('#include <functional>', file=self.outFile) 205 write('#include <spirv/unified1/spirv.hpp>', file=self.outFile) 206 write('#include "vk_extension_helper.h"', file=self.outFile) 207 write('#include "shader_module.h"', file=self.outFile) 208 write('#include "device_state.h"', file=self.outFile) 209 write('#include "core_validation.h"', file=self.outFile) 210 write(self.featurePointer(), file=self.outFile) 211 write(self.mapStructDeclarations(), file=self.outFile) 212 # 213 # Write generated file content to output file 214 def endFile(self): 215 write(self.capabilityStruct(), file=self.outFile) 216 write(self.extensionStruct(), file=self.outFile) 217 write(self.enumHelper(), file=self.outFile) 218 write(self.validateFunction(), file=self.outFile) 219 # Finish processing in superclass 220 OutputGenerator.endFile(self) 221 # 222 # Processing point at beginning of each extension definition 223 def beginFeature(self, interface, emit): 224 OutputGenerator.beginFeature(self, interface, emit) 225 self.featureExtraProtect = GetFeatureProtect(interface) 226 # 227 # Capture all SPIR-V elements from registry 228 def genSpirv(self, spirvinfo, spirvName, alias): 229 OutputGenerator.genSpirv(self, spirvinfo, spirvName, alias) 230 spirvElem = spirvinfo.elem 231 name = spirvElem.get('name') 232 enables = [] 233 for elem in spirvElem: 234 if elem.tag != 'enable': 235 self.logMsg('error', 'should only be <enable> tags in ' + name) 236 # Each <enable> holds only one possible requirment 237 # This internal python dict is to represent the struct generated later 238 enable = { 239 'version' : None, 240 'feature' : None, 241 'extension' : None, 242 'property' : None, 243 } 244 if 'version' in elem.attrib: 245 enable['version'] = elem.attrib['version'] 246 elif 'feature' in elem.attrib: 247 if elem.attrib['struct'] in self.promotedFeatures: 248 continue 249 enable['feature'] = { 250 'feature' : elem.attrib['feature'], 251 'struct' : elem.attrib['struct'] 252 } 253 elif 'extension' in elem.attrib: 254 enable['extension'] = elem.attrib['extension'] 255 elif 'property' in elem.attrib: 256 enable['property'] = { 257 'property' : elem.attrib['property'], 258 'member' : elem.attrib['member'], 259 'value' : elem.attrib['value'] 260 } 261 else: 262 self.logMsg('error', 'No known attributes in <enable> for ' + name) 263 enables.append(enable) 264 if spirvElem.tag == 'spirvcapability': 265 self.capabilities[name] = enables 266 elif spirvElem.tag == 'spirvextension': 267 self.extensions[name] = enables 268 # 269 # Creates the Enum string helpers for better error messages. Same idea of vk_enum_string_helper.h but for SPIR-V 270 def enumHelper(self): 271 # There are some enums that share the same value in the SPIR-V header. 272 # This array remove the duplicate to not print out, usually due to being the older value given 273 excludeList = ['ShaderViewportIndexLayerNV', 'ShadingRateNV'] 274 output = 'static inline const char* string_SpvCapability(uint32_t input_value) {\n' 275 output += ' switch ((spv::Capability)input_value) {\n' 276 for name, enables in sorted(self.capabilities.items()): 277 if (name not in excludeList) and (name not in self.capabilityExcludeList): 278 output += ' case spv::Capability' + name + ':\n' 279 output += ' return \"' + name + '\";\n' 280 output += ' default:\n' 281 output += ' return \"Unhandled OpCapability\";\n' 282 output += ' };\n' 283 output += '};' 284 return output 285 # 286 # Creates the FeaturePointer struct to map features with those in the layers state tracker 287 def featurePointer(self): 288 output = '\n' 289 output += 'struct FeaturePointer {\n' 290 output += ' // Callable object to test if this feature is enabled in the given aggregate feature struct\n' 291 output += ' const std::function<VkBool32(const DeviceFeatures &)> IsEnabled;\n' 292 output += '\n' 293 output += ' // Test if feature pointer is populated\n' 294 output += ' explicit operator bool() const { return static_cast<bool>(IsEnabled); }\n' 295 output += '\n' 296 output += ' // Default and nullptr constructor to create an empty FeaturePointer\n' 297 output += ' FeaturePointer() : IsEnabled(nullptr) {}\n' 298 output += ' FeaturePointer(std::nullptr_t ptr) : IsEnabled(nullptr) {}\n' 299 output += '\n' 300 output += ' // Constructors to populate FeaturePointer based on given pointer to member\n' 301 for feature in self.featureMap: 302 output += ' FeaturePointer(VkBool32 ' + feature['vulkan'] + '::*ptr)\n' 303 output += ' : IsEnabled([=](const DeviceFeatures &features) { return features.' + feature['layer'] + '.*ptr; }) {}\n' 304 output += '};\n' 305 return output 306 # 307 # Declare the struct that contains requirement for the spirv info 308 def mapStructDeclarations(self): 309 output = '// Each instance of the struct will only have a singel field non-null\n' 310 output += 'struct RequiredSpirvInfo {\n' 311 output += ' uint32_t version;\n' 312 output += ' FeaturePointer feature;\n' 313 output += ' ExtEnabled DeviceExtensions::*extension;\n' 314 output += ' const char* property; // For human readability and make some capabilities unique\n' 315 output += '};\n' 316 return output 317 # 318 # Creates the value of the struct declared in mapStructDeclarations() 319 def createMapValue(self, name, enable, isExtension): 320 output = '' 321 if enable['version'] != None: 322 # Version should be VK_VERSION_x_x as defined in header but need to get as VK_API_VERSION_x_x 323 version = enable['version'].replace('VK_VERSION', 'VK_API_VERSION') 324 output = '{' + version + ', nullptr, nullptr, ""}' 325 elif enable['feature'] != None: 326 output = '{0, &' + enable['feature']['struct'] + '::' + enable['feature']['feature'] + ', nullptr, ""}' 327 elif enable['extension'] != None: 328 # All fields in DeviceExtensions should just be the extension name lowercase 329 output = '{0, nullptr, &DeviceExtensions::' + enable['extension'].lower() + ', ""}' 330 elif enable['property'] != None: 331 propertyStruct = enable['property']['property'] 332 # Need to make sure to return a boolean value to prevent compiler warning for implicit conversions 333 propertyLogic = "(" + propertyStruct + '::' + enable['property']['member'] + ' & ' + enable['property']['value'] + ") != 0" 334 # Property might have multiple items per capability/extension 335 if name not in self.propertyInfo: 336 self.propertyInfo[name] = [] 337 # Save info later to be printed out 338 self.propertyInfo[name].append({ 339 "logic" : propertyLogic, 340 "struct" : propertyStruct, 341 "isExtension" : isExtension 342 }) 343 # For properties, this string is just for human readableness 344 output = '{0, nullptr, nullptr, "' + propertyLogic + '"}' 345 else: 346 output = '{0, nullptr, nullptr, ""}' 347 return output 348 # 349 # Build the struct with all the requirments for the spirv capabilities 350 def capabilityStruct(self): 351 output = '// clang-format off\n' 352 output += 'static const std::unordered_multimap<uint32_t, RequiredSpirvInfo> spirvCapabilities = {\n' 353 354 # Sort so the order is the same on Windows and Unix 355 for name, enables in sorted(self.capabilities.items()): 356 for enable in enables: 357 # Prepend with comment and comment out line if in exclude list as explained in declaration 358 if name in self.capabilityExcludeList: 359 output += ' // Not found in current SPIR-V Headers\n //' 360 output += ' {spv::Capability' + name + ', ' + self.createMapValue(name, enable, False) + '},\n' 361 output += '};\n' 362 output += '// clang-format on\n' 363 return output 364 # 365 # Build the struct with all the requirments for the spirv extensions 366 def extensionStruct(self): 367 output = '// clang-format off\n' 368 output += 'static const std::unordered_multimap<std::string, RequiredSpirvInfo> spirvExtensions = {\n' 369 370 # Sort so the order is the same on Windows and Unix 371 for name, enables in sorted(self.extensions.items()): 372 for enable in enables: 373 # Prepend with comment and comment out line if in exclude list as explained in declaration 374 if name in self.extensionExcludeList: 375 output += ' // Not found in current SPIR-V Headers\n //' 376 output += ' {\"' + name + '\", ' + self.createMapValue(name, enable, True) + '},\n' 377 output += '};\n' 378 output += '// clang-format on\n' 379 return output 380 # 381 # The main function to validate all the extensions and capabilities 382 def validateFunction(self): 383 output = ''' 384bool CoreChecks::ValidateShaderCapabilitiesAndExtensions(SHADER_MODULE_STATE const *src, spirv_inst_iter& insn) const { 385 bool skip = false; 386 387 if (insn.opcode() == spv::OpCapability) { 388 // All capabilities are generated so if it is not in the list it is not supported by Vulkan 389 if (spirvCapabilities.count(insn.word(1)) == 0) { 390 skip |= LogError(device, "VUID-VkShaderModuleCreateInfo-pCode-01090", 391 "vkCreateShaderModule(): A SPIR-V Capability (%s) was declared that is not supported by Vulkan.", string_SpvCapability(insn.word(1))); 392 return skip; // no known capability to validate 393 } 394 395 // Each capability has one or more requirements to check 396 // Only one item has to be satisfied and an error only occurs 397 // when all are not satisfied 398 auto caps = spirvCapabilities.equal_range(insn.word(1)); 399 bool has_support = false; 400 for (auto it = caps.first; (it != caps.second) && (has_support == false); ++it) { 401 if (it->second.version) { 402 if (api_version >= it->second.version) { 403 has_support = true; 404 } 405 } else if (it->second.feature) { 406 if (it->second.feature.IsEnabled(enabled_features)) { 407 has_support = true; 408 } 409 } else if (it->second.extension) { 410 // kEnabledByApiLevel is not valid as some extension are promoted with feature bits to be used. 411 // If the new Api Level gives support, it will be caught in the "it->second.version" check instead. 412 if (IsExtEnabledByCreateinfo(device_extensions.*(it->second.extension))) { 413 has_support = true; 414 } 415 } else if (it->second.property) { 416 // support is or'ed as only one has to be supported (if applicable) 417 switch (insn.word(1)) {''' 418 419 for name, infos in sorted(self.propertyInfo.items()): 420 # Only capabilities here (all items in array are the same) 421 if infos[0]['isExtension'] == True: 422 continue 423 424 # use triple-tick syntax to keep tab alignment for generated code 425 output += ''' 426 case spv::Capability{}:'''.format(name) 427 for info in infos: 428 # Need to string replace property string to create valid C++ logic 429 logic = info['logic'].replace('::', '.') 430 logic = logic.replace(info['struct'], self.propertyMap[info['struct']]) 431 output += ''' 432 has_support |= ({});'''.format(logic) 433 output += ''' 434 break;''' 435 436 output += ''' 437 default: 438 break; 439 } 440 } 441 } 442 443 if (has_support == false) { 444 skip |= LogError(device, "VUID-VkShaderModuleCreateInfo-pCode-01091", 445 "vkCreateShaderModule(): The SPIR-V Capability (%s) was declared, but none of the requirements were met to use it.", string_SpvCapability(insn.word(1))); 446 } 447 448 // Portability checks 449 if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) { 450 if ((VK_FALSE == enabled_features.portability_subset_features.shaderSampleRateInterpolationFunctions) && 451 (spv::CapabilityInterpolationFunction == insn.word(1))) { 452 skip |= LogError(device, "VUID-RuntimeSpirv-shaderSampleRateInterpolationFunctions-06325", 453 "Invalid shader capability (portability error): interpolation functions are not supported " 454 "by this platform"); 455 } 456 } 457 } else if (insn.opcode() == spv::OpExtension) { 458 static const std::string spv_prefix = "SPV_"; 459 std::string extension_name = (char const *)&insn.word(1); 460 461 if (0 == extension_name.compare(0, spv_prefix.size(), spv_prefix)) { 462 if (spirvExtensions.count(extension_name) == 0) { 463 skip |= LogError(device, "VUID-VkShaderModuleCreateInfo-pCode-04146", 464 "vkCreateShaderModule(): A SPIR-V Extension (%s) was declared that is not supported by Vulkan.", extension_name.c_str()); 465 return skip; // no known extension to validate 466 } 467 } else { 468 skip |= LogError(device, kVUID_Core_Shader_InvalidExtension, 469 "vkCreateShaderModule(): The SPIR-V code uses the '%s' extension which is not a SPIR-V extension. Please use a SPIR-V" 470 " extension (https://github.com/KhronosGroup/SPIRV-Registry) for OpExtension instructions. Non-SPIR-V extensions can be" 471 " recorded in SPIR-V using the OpSourceExtension instruction.", extension_name.c_str()); 472 return skip; // no known extension to validate 473 } 474 475 // Each SPIR-V Extension has one or more requirements to check 476 // Only one item has to be satisfied and an error only occurs 477 // when all are not satisfied 478 auto ext = spirvExtensions.equal_range(extension_name); 479 bool has_support = false; 480 for (auto it = ext.first; (it != ext.second) && (has_support == false); ++it) { 481 if (it->second.version) { 482 if (api_version >= it->second.version) { 483 has_support = true; 484 } 485 } else if (it->second.feature) { 486 if (it->second.feature.IsEnabled(enabled_features)) { 487 has_support = true; 488 } 489 } else if (it->second.extension) { 490 if (IsExtEnabled(device_extensions.*(it->second.extension))) { 491 has_support = true; 492 } 493 } else if (it->second.property) { 494 // support is or'ed as only one has to be supported (if applicable) 495 switch (insn.word(1)) {''' 496 497 for name, infos in sorted(self.propertyInfo.items()): 498 # Only extensions here (all items in array are the same) 499 if infos[0]['isExtension'] == False: 500 continue 501 502 # use triple-tick syntax to keep tab alignment for generated code 503 output += ''' 504 case spv::Capability{}:'''.format(name) 505 for info in infos: 506 # Need to string replace property string to create valid C++ logic 507 logic = info['logic'].replace('::', '.') 508 logic = logic.replace(info['struct'], self.propertyMap[info['struct']]) 509 output += ''' 510 has_support |= ({});'''.format(logic) 511 output += ''' 512 break;''' 513 514 output += ''' 515 default: 516 break; 517 } 518 } 519 } 520 521 if (has_support == false) { 522 skip |= LogError(device, "VUID-VkShaderModuleCreateInfo-pCode-04147", 523 "vkCreateShaderModule(): The SPIR-V Extension (%s) was declared, but none of the requirements were met to use it.", extension_name.c_str()); 524 } 525 } //spv::OpExtension 526 return skip; 527}''' 528 return output 529